@@ -16,7 +16,7 @@ import {
1616 CMD_SHOW_GPR_LS_OUTPUT ,
1717} from './constants' ;
1818import { AdaInitialDebugConfigProvider , initializeDebugging } from './debugConfigProvider' ;
19- import { logger } from './extension' ;
19+ import { adaExtState , logger } from './extension' ;
2020import { GnatTaskProvider } from './gnatTaskProvider' ;
2121import { initializeTesting } from './gnattest' ;
2222import { GprTaskProvider } from './gprTaskProvider' ;
@@ -153,10 +153,13 @@ export class ExtensionState {
153153
154154 // Add a listener on tasks to open the SARIF Viewer when the
155155 // task that ends outputs a SARIF file.
156- vscode . tasks . onDidEndTaskProcess ( async ( e ) => {
157- const task = e . execution . task ;
158- await openSARIFViewerIfNeeded ( task ) ;
159- } ) ,
156+ vscode . tasks . onDidEndTaskProcess ( openSARIFViewerIfNeeded ) ,
157+ /**
158+ * Add a listener on tasks start to close SARIF report that might
159+ * be overwritten, to avoid parse errors from the SARIF extension
160+ * when the report is being deleted/re-written.
161+ */
162+ vscode . tasks . onDidStartTaskProcess ( closeSARIFViewerIfNeeded ) ,
160163 ] ;
161164 } ;
162165
@@ -696,37 +699,110 @@ export class ExtensionState {
696699 }
697700}
698701
702+ const currentlyOpenedSASSarifs : Set < vscode . Uri > = new Set ( ) ;
703+ const currentlyOpenedGnatproveSarifs : Set < vscode . Uri > = new Set ( ) ;
704+
705+ async function closeSARIFViewerIfNeeded ( e : vscode . TaskEndEvent ) {
706+ /**
707+ * SARIF reports need to be closed and reopened to refresh their content.
708+ *
709+ * Moreover, overwriting a SARIF report that is currently opened in the
710+ * SARIF Viewer seems to trigger sporadic errors. So it's better to close
711+ * the SARIF report at the start of the task.
712+ *
713+ * Reports must be managed separately for GNATprove and for GNAT
714+ * SAS because we don't want an execution of GNAT SAS to close
715+ * reports opened for GNATprove and vice versa.
716+ */
717+
718+ const task = e . execution . task ;
719+ if ( task . definition . type == TASK_TYPE_SPARK || isGnatSASSarifTask ( task ) ) {
720+ const sarif = await getSarifExtAPI ( ) ;
721+ if ( sarif ) {
722+ const current =
723+ task . definition . type == TASK_TYPE_SPARK
724+ ? currentlyOpenedGnatproveSarifs
725+ : currentlyOpenedSASSarifs ;
726+
727+ await sarif . closeLogs ( [ ...current ] ) ;
728+ current . clear ( ) ;
729+ }
730+ }
731+ }
732+
733+ function isGnatSASSarifTask ( task : vscode . Task ) : boolean {
734+ return (
735+ task . definition . type == TASK_TYPE_ADA &&
736+ ! ! ( task . definition as SimpleTaskDef ) . args ?. some ( ( arg ) => getArgValue ( arg ) . includes ( 'sarif' ) )
737+ ) ;
738+ }
739+
699740/**
700741 *
701742 * Open the SARIF Viewer if the given task outputs its results in
702743 * a SARIF file (e.g: GNAT SAS Report task).
703744 */
704- async function openSARIFViewerIfNeeded ( task : vscode . Task ) {
745+ async function openSARIFViewerIfNeeded ( e : vscode . TaskStartEvent ) {
746+ const task = e . execution . task ;
705747 const definition : SimpleTaskDef = task . definition ;
706748
707749 if ( definition ) {
708750 const args = definition . args ;
709751
710- if ( args ?. some ( ( arg ) => getArgValue ( arg ) . includes ( 'sarif' ) ) ) {
711- const execution = task . execution ;
712- let cwd = undefined ;
752+ if ( definition . type == TASK_TYPE_SPARK || isGnatSASSarifTask ( task ) ) {
753+ const sarifExtAPI = await getSarifExtAPI ( ) ;
713754
714- if ( execution && execution instanceof vscode . ShellExecution ) {
715- cwd = execution . options ?. cwd ;
755+ if ( ! sarifExtAPI ) {
756+ // Could not access the SARIF Viewer extension API
757+ logger . warn (
758+ 'Could not access the SARIF Viewer extension API: is the extension installed?' ,
759+ ) ;
760+ return ;
716761 }
717762
718- if ( ! cwd && vscode . workspace . workspaceFolders ) {
719- cwd = vscode . workspace . workspaceFolders [ 0 ] . uri . fsPath ;
720- }
763+ if ( definition . type == TASK_TYPE_SPARK ) {
764+ /**
765+ * Find new reports and open them
766+ */
767+ const objDir = await adaExtState . getObjectDir ( ) ;
768+ const gnatproveDir = path . join ( objDir , 'gnatprove' ) ;
769+ if ( existsSync ( gnatproveDir ) ) {
770+ const gnatProveUri = vscode . Uri . file ( gnatproveDir ) ;
771+ const sarifFiles = await vscode . workspace . fs . readDirectory ( gnatProveUri ) ;
772+ const sarifUris = sarifFiles
773+ . filter (
774+ ( [ name , type ] ) =>
775+ type === vscode . FileType . File && name . endsWith ( '.sarif' ) ,
776+ )
777+ . map ( ( [ name ] ) => vscode . Uri . joinPath ( gnatProveUri , name ) ) ;
778+
779+ await sarifExtAPI . openLogs ( sarifUris ) ;
780+ sarifUris . forEach ( ( v ) => currentlyOpenedGnatproveSarifs . add ( v ) ) ;
781+ }
782+ } else {
783+ const execution = task . execution ;
784+ let cwd = undefined ;
721785
722- const sarifExt = vscode . extensions . getExtension ( 'ms-sarifvscode.sarif-viewer' ) ;
786+ if ( execution instanceof vscode . ShellExecution ) {
787+ cwd = execution . options ?. cwd ;
788+ }
723789
724- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
725- const sarifExtAPI = sarifExt ? await sarifExt . activate ( ) : undefined ;
790+ if ( ! cwd && vscode . workspace . workspaceFolders ) {
791+ cwd = vscode . workspace . workspaceFolders [ 0 ] . uri . fsPath ;
792+ }
793+
794+ if ( ! cwd ) {
795+ // Could not determine the current working directory
796+ logger . warn ( 'Could not determine the current working directory' ) ;
797+ return ;
798+ }
726799
727- if ( cwd && sarifExtAPI ) {
728800 const cwdURI = vscode . Uri . file ( cwd ) ;
729- const outputFilePathArgRaw = args . find ( ( arg ) =>
801+
802+ /**
803+ * Find the SARIF output file argument
804+ */
805+ const outputFilePathArgRaw = args ! . find ( ( arg ) =>
730806 getArgValue ( arg ) . includes ( '.sarif' ) ,
731807 ) ;
732808
@@ -739,28 +815,49 @@ async function openSARIFViewerIfNeeded(task: vscode.Task) {
739815 const outputFilePath = outputFilePathArg . includes ( '=' )
740816 ? outputFilePathArg . split ( '=' ) . pop ( )
741817 : outputFilePathArg ;
742-
743818 if ( outputFilePath ) {
744819 const sarifFileURI = isAbsolute ( outputFilePath )
745820 ? vscode . Uri . file ( outputFilePath )
746821 : vscode . Uri . joinPath ( cwdURI , outputFilePath ) ;
747-
748- /**
749- * If we open a SARIF report that was already open, the
750- * SARIF Viewer extension does not refresh the
751- * contents. It is necessary to close the report and
752- * reopen it.
753- */
754- // eslint-disable-next-line max-len
755- // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
756- await sarifExtAPI . closeLogs ( [ sarifFileURI ] ) ;
757-
758- // eslint-disable-next-line max-len
759- // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
760- await sarifExtAPI . openLogs ( [ sarifFileURI ] ) ;
822+ if ( existsSync ( sarifFileURI . fsPath ) ) {
823+ await sarifExtAPI . openLogs ( [ sarifFileURI ] ) ;
824+ currentlyOpenedSASSarifs . add ( sarifFileURI ) ;
825+ }
761826 }
762827 }
763828 }
764829 }
765830 }
766831}
832+
833+ /**
834+ * This is the API of the SARIF extension, as defined at
835+ * https://github.com/microsoft/sarif-vscode-extension/blob/main/src/extension/index.d.ts
836+ *
837+ * Since the package is not available on npmjs.org for direct referencing, we
838+ * copy it here to benefit from typing.
839+ */
840+ interface SARIFExtAPI {
841+ /**
842+ * Note: If a log has been modified after open was opened, a close and
843+ * re-open will be required to "refresh" that log.
844+ *
845+ * @param logs - An array of Uris to open.
846+ */
847+ openLogs ( logs : vscode . Uri [ ] ) : Promise < void > ;
848+ closeLogs (
849+ logs : vscode . Uri [ ] ,
850+ _options ?: unknown ,
851+ cancellationToken ?: vscode . CancellationToken ,
852+ ) : Promise < void > ;
853+ closeAllLogs ( ) : Promise < void > ;
854+ selectByIndex ( uri : vscode . Uri , runIndex : number , resultIndex : number ) : Promise < void > ;
855+ uriBases : ReadonlyArray < vscode . Uri > ;
856+ dispose ( ) : void ;
857+ }
858+
859+ async function getSarifExtAPI ( ) : Promise < SARIFExtAPI | undefined > {
860+ const sarifExt = vscode . extensions . getExtension ( 'ms-sarifvscode.sarif-viewer' ) ;
861+ const sarifExtAPI = sarifExt ? ( ( await sarifExt . activate ( ) ) as SARIFExtAPI ) : undefined ;
862+ return sarifExtAPI ;
863+ }
0 commit comments