@@ -10,7 +10,7 @@ import { CodeQLCliServer } from './cli';
1010import { DatabaseItem , DatabaseManager } from './databases' ;
1111import { showAndLogErrorMessage } from './helpers' ;
1212import { assertNever } from './helpers-pure' ;
13- import { FromResultsViewMsg , Interpretation , INTERPRETED_RESULTS_PER_RUN_LIMIT , IntoResultsViewMsg , QueryMetadata , ResultsPaths , SortedResultSetInfo , SortedResultsMap } from './interface-types' ;
13+ import { FromResultsViewMsg , Interpretation , INTERPRETED_RESULTS_PER_RUN_LIMIT , IntoResultsViewMsg , QueryMetadata , ResultsPaths , SortedResultSetInfo , SortedResultsMap , InterpretedResultsSortState , SortDirection } from './interface-types' ;
1414import { Logger } from './logging' ;
1515import * as messages from './messages' ;
1616import { CompletedQuery , interpretResults } from './query-results' ;
@@ -86,6 +86,29 @@ export function webviewUriToFileUri(webviewUri: string): Uri {
8686 return Uri . file ( path ) ;
8787}
8888
89+ function sortMultiplier ( sortDirection : SortDirection ) : number {
90+ switch ( sortDirection ) {
91+ case SortDirection . asc : return 1 ;
92+ case SortDirection . desc : return - 1 ;
93+ }
94+ }
95+
96+ function sortInterpretedResults ( results : Sarif . Result [ ] , sortState : InterpretedResultsSortState | undefined ) : void {
97+ if ( sortState !== undefined ) {
98+ const multiplier = sortMultiplier ( sortState . sortDirection ) ;
99+ switch ( sortState . sortBy ) {
100+ case 'alert-message' :
101+ results . sort ( ( a , b ) =>
102+ a . message . text === undefined ? 0 :
103+ b . message . text === undefined ? 0 :
104+ multiplier * ( a . message . text ?. localeCompare ( b . message . text ) ) ) ;
105+ break ;
106+ default :
107+ assertNever ( sortState . sortBy ) ;
108+ }
109+ }
110+ }
111+
89112export class InterfaceManager extends DisposableObject {
90113 private _displayedQuery ?: CompletedQuery ;
91114 private _panel : vscode . WebviewPanel | undefined ;
@@ -138,6 +161,17 @@ export class InterfaceManager extends DisposableObject {
138161 return this . _panel ;
139162 }
140163
164+ private async changeSortState ( update : ( query : CompletedQuery ) => Promise < void > ) : Promise < void > {
165+ if ( this . _displayedQuery === undefined ) {
166+ showAndLogErrorMessage ( "Failed to sort results since evaluation info was unknown." ) ;
167+ return ;
168+ }
169+ // Notify the webview that it should expect new results.
170+ await this . postMessage ( { t : 'resultsUpdating' } ) ;
171+ await update ( this . _displayedQuery ) ;
172+ await this . showResults ( this . _displayedQuery , WebviewReveal . NotForced , true ) ;
173+ }
174+
141175 private async handleMsgFromView ( msg : FromResultsViewMsg ) : Promise < void > {
142176 switch ( msg . t ) {
143177 case 'viewSourceFile' : {
@@ -179,17 +213,12 @@ export class InterfaceManager extends DisposableObject {
179213 this . _panelLoadedCallBacks . forEach ( cb => cb ( ) ) ;
180214 this . _panelLoadedCallBacks = [ ] ;
181215 break ;
182- case 'changeSort' : {
183- if ( this . _displayedQuery === undefined ) {
184- showAndLogErrorMessage ( "Failed to sort results since evaluation info was unknown." ) ;
185- break ;
186- }
187- // Notify the webview that it should expect new results.
188- await this . postMessage ( { t : 'resultsUpdating' } ) ;
189- await this . _displayedQuery . updateSortState ( this . cliServer , msg . resultSetName , msg . sortState ) ;
190- await this . showResults ( this . _displayedQuery , WebviewReveal . NotForced , true ) ;
216+ case 'changeSort' :
217+ await this . changeSortState ( ( query ) => query . updateSortState ( this . cliServer , msg . resultSetName , msg . sortState ) ) ;
218+ break ;
219+ case 'changeInterpretedSort' :
220+ await this . changeSortState ( ( query ) => query . updateInterpretedSortState ( this . cliServer , msg . sortState ) ) ;
191221 break ;
192- }
193222 default :
194223 assertNever ( msg ) ;
195224 }
@@ -223,7 +252,7 @@ export class InterfaceManager extends DisposableObject {
223252 return ;
224253 }
225254
226- const interpretation = await this . interpretResultsInfo ( results . query ) ;
255+ const interpretation = await this . interpretResultsInfo ( results . query , results . interpretedResultsSortState ) ;
227256
228257 const sortedResultsMap : SortedResultsMap = { } ;
229258 results . sortedResultsInfo . forEach ( ( v , k ) =>
@@ -268,28 +297,29 @@ export class InterfaceManager extends DisposableObject {
268297 } ) ;
269298 }
270299
271- private async getTruncatedResults ( metadata : QueryMetadata | undefined , resultsPaths : ResultsPaths , sourceInfo : cli . SourceInfo | undefined , sourceLocationPrefix : string ) : Promise < Interpretation > {
272- const sarif = await interpretResults ( this . cliServer , metadata , resultsPaths . interpretedResultsPath , sourceInfo ) ;
300+ private async getTruncatedResults ( metadata : QueryMetadata | undefined , resultsPaths : ResultsPaths , sourceInfo : cli . SourceInfo | undefined , sourceLocationPrefix : string , sortState : InterpretedResultsSortState | undefined ) : Promise < Interpretation > {
301+ const sarif = await interpretResults ( this . cliServer , metadata , resultsPaths . resultsPath , sourceInfo ) ;
273302 // For performance reasons, limit the number of results we try
274303 // to serialize and send to the webview. TODO: possibly also
275304 // limit number of paths per result, number of steps per path,
276305 // or throw an error if we are in aggregate trying to send
277306 // massively too much data, as it can make the extension
278307 // unresponsive.
308+
279309 let numTruncatedResults = 0 ;
280310 sarif . runs . forEach ( run => {
281311 if ( run . results !== undefined ) {
312+ sortInterpretedResults ( run . results , sortState ) ;
282313 if ( run . results . length > INTERPRETED_RESULTS_PER_RUN_LIMIT ) {
283314 numTruncatedResults += run . results . length - INTERPRETED_RESULTS_PER_RUN_LIMIT ;
284315 run . results = run . results . slice ( 0 , INTERPRETED_RESULTS_PER_RUN_LIMIT ) ;
285316 }
286317 }
287318 } ) ;
288- return { sarif, sourceLocationPrefix, numTruncatedResults } ;
289- ;
319+ return { sarif, sourceLocationPrefix, numTruncatedResults, sortState } ;
290320 }
291321
292- private async interpretResultsInfo ( query : QueryInfo ) : Promise < Interpretation | undefined > {
322+ private async interpretResultsInfo ( query : QueryInfo , sortState : InterpretedResultsSortState | undefined ) : Promise < Interpretation | undefined > {
293323 let interpretation : Interpretation | undefined = undefined ;
294324 if ( await query . hasInterpretedResults ( )
295325 && query . quickEvalPosition === undefined // never do results interpretation if quickEval
@@ -300,7 +330,7 @@ export class InterfaceManager extends DisposableObject {
300330 const sourceInfo = sourceArchiveUri === undefined ?
301331 undefined :
302332 { sourceArchive : sourceArchiveUri . fsPath , sourceLocationPrefix } ;
303- interpretation = await this . getTruncatedResults ( query . metadata , query . resultsPaths , sourceInfo , sourceLocationPrefix ) ;
333+ interpretation = await this . getTruncatedResults ( query . metadata , query . resultsPaths , sourceInfo , sourceLocationPrefix , sortState ) ;
304334 }
305335 catch ( e ) {
306336 // If interpretation fails, accept the error and continue
@@ -318,7 +348,13 @@ export class InterfaceManager extends DisposableObject {
318348 const sourceInfo = sourceArchiveUri === undefined ?
319349 undefined :
320350 { sourceArchive : sourceArchiveUri . fsPath , sourceLocationPrefix } ;
321- const interpretation = await this . getTruncatedResults ( metadata , resultsInfo , sourceInfo , sourceLocationPrefix ) ;
351+ const interpretation = await this . getTruncatedResults (
352+ metadata ,
353+ resultsInfo ,
354+ sourceInfo ,
355+ sourceLocationPrefix ,
356+ undefined ,
357+ ) ;
322358
323359 try {
324360 await this . showProblemResultsAsDiagnostics ( interpretation , database ) ;
0 commit comments