Skip to content

Commit dd9fafc

Browse files
authored
Merge pull request #407 from jcreedcmu/jcreed/view-sarif
Allow viewing SARIF from query history view
2 parents 7172505 + 7b99bdf commit dd9fafc

File tree

6 files changed

+51
-16
lines changed

6 files changed

+51
-16
lines changed

extensions/ql-vscode/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Better formatting and autoindentation when adding QLDoc comments to `.ql` and `.qll` files.
66
- Allow for more flexibility when opening a database in the workspace. A user can now choose the actual database folder, or the nested `db-*` folder.
7+
- Add query history menu command for viewing corresponding SARIF file.
78

89
## 1.2.0 - 19 May 2020
910

extensions/ql-vscode/package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@
284284
"command": "codeQLQueryHistory.showQueryText",
285285
"title": "Show Query Text"
286286
},
287+
{
288+
"command": "codeQLQueryHistory.viewSarif",
289+
"title": "View SARIF"
290+
},
287291
{
288292
"command": "codeQLQueryResults.nextPathStep",
289293
"title": "CodeQL: Show Next Step on Path"
@@ -388,6 +392,11 @@
388392
"group": "9_qlCommands",
389393
"when": "view == codeQLQueryHistory"
390394
},
395+
{
396+
"command": "codeQLQueryHistory.viewSarif",
397+
"group": "9_qlCommands",
398+
"when": "view == codeQLQueryHistory && viewItem == interpretedResultsItem"
399+
},
391400
{
392401
"command": "codeQLTests.showOutputDifferences",
393402
"group": "qltest@1",
@@ -484,6 +493,10 @@
484493
"command": "codeQLQueryHistory.showQueryText",
485494
"when": "false"
486495
},
496+
{
497+
"command": "codeQLQueryHistory.viewSarif",
498+
"when": "false"
499+
},
487500
{
488501
"command": "codeQLQueryHistory.setLabel",
489502
"when": "false"

extensions/ql-vscode/src/interface.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ export class InterfaceManager extends DisposableObject {
402402
const sarif = await interpretResults(
403403
this.cliServer,
404404
metadata,
405-
resultsPaths.resultsPath,
405+
resultsPaths,
406406
sourceInfo
407407
);
408408
// For performance reasons, limit the number of results we try
@@ -440,7 +440,7 @@ export class InterfaceManager extends DisposableObject {
440440
): Promise<Interpretation | undefined> {
441441
let interpretation: Interpretation | undefined = undefined;
442442
if (
443-
(await query.hasInterpretedResults()) &&
443+
(await query.canHaveInterpretedResults()) &&
444444
query.quickEvalPosition === undefined // never do results interpretation if quickEval
445445
) {
446446
try {

extensions/ql-vscode/src/query-history.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class HistoryTreeDataProvider implements vscode.TreeDataProvider<CompletedQuery>
7474
constructor(private ctx: ExtensionContext) {
7575
}
7676

77-
getTreeItem(element: CompletedQuery): vscode.TreeItem {
77+
async getTreeItem(element: CompletedQuery): Promise<vscode.TreeItem> {
7878
const it = new vscode.TreeItem(element.toString());
7979

8080
it.command = {
@@ -83,6 +83,11 @@ class HistoryTreeDataProvider implements vscode.TreeDataProvider<CompletedQuery>
8383
arguments: [element],
8484
};
8585

86+
// Mark this query history item according to whether it has a
87+
// SARIF file so that we can make context menu items conditionally
88+
// available.
89+
it.contextValue = await element.query.hasInterpretedResults() ? 'interpretedResultsItem' : 'rawResultsItem';
90+
8691
if (!element.didRunSuccessfully) {
8792
it.iconPath = path.join(this.ctx.extensionPath, FAILED_QUERY_HISTORY_ITEM_ICON);
8893
}
@@ -257,6 +262,22 @@ export class QueryHistoryManager {
257262
}
258263
}
259264

265+
async handleViewSarif(queryHistoryItem: CompletedQuery) {
266+
try {
267+
const hasInterpretedResults = await queryHistoryItem.query.canHaveInterpretedResults();
268+
if (hasInterpretedResults) {
269+
const textDocument = await vscode.workspace.openTextDocument(vscode.Uri.file(queryHistoryItem.query.resultsPaths.interpretedResultsPath));
270+
await vscode.window.showTextDocument(textDocument, vscode.ViewColumn.One);
271+
}
272+
else {
273+
const label = queryHistoryItem.getLabel();
274+
helpers.showAndLogInformationMessage(`Query ${label} has no interpreted results.`);
275+
}
276+
} catch (e) {
277+
helpers.showAndLogErrorMessage(e.message);
278+
}
279+
}
280+
260281
async getQueryText(queryHistoryItem: CompletedQuery): Promise<string> {
261282
if (queryHistoryItem.options.queryText) {
262283
return queryHistoryItem.options.queryText;
@@ -296,6 +317,7 @@ export class QueryHistoryManager {
296317
ctx.subscriptions.push(vscode.commands.registerCommand('codeQLQueryHistory.setLabel', this.handleSetLabel.bind(this)));
297318
ctx.subscriptions.push(vscode.commands.registerCommand('codeQLQueryHistory.showQueryLog', this.handleShowQueryLog.bind(this)));
298319
ctx.subscriptions.push(vscode.commands.registerCommand('codeQLQueryHistory.showQueryText', this.handleShowQueryText.bind(this)));
320+
ctx.subscriptions.push(vscode.commands.registerCommand('codeQLQueryHistory.viewSarif', this.handleViewSarif.bind(this)));
299321
ctx.subscriptions.push(vscode.commands.registerCommand('codeQLQueryHistory.itemClicked', async (item) => {
300322
return this.handleItemClicked(item);
301323
}));

extensions/ql-vscode/src/query-results.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as cli from './cli';
55
import * as sarif from 'sarif';
66
import * as fs from 'fs-extra';
77
import * as path from 'path';
8-
import { RawResultsSortState, SortedResultSetInfo, DatabaseInfo, QueryMetadata, InterpretedResultsSortState } from "./interface-types";
8+
import { RawResultsSortState, SortedResultSetInfo, DatabaseInfo, QueryMetadata, InterpretedResultsSortState, ResultsPaths } from "./interface-types";
99
import { QueryHistoryConfig } from "./config";
1010
import { QueryHistoryItemOptions } from "./query-history";
1111

@@ -54,13 +54,6 @@ export class CompletedQuery implements QueryWithResults {
5454
return helpers.getQueryName(this.query);
5555
}
5656

57-
/**
58-
* Holds if this query should produce interpreted results.
59-
*/
60-
canInterpretedResults(): Promise<boolean> {
61-
return this.query.dbItem.hasMetadataFile();
62-
}
63-
6457
get statusString(): string {
6558
switch (this.result.resultType) {
6659
case messages.QueryResultType.CANCELLATION:
@@ -130,9 +123,8 @@ export class CompletedQuery implements QueryWithResults {
130123
/**
131124
* Call cli command to interpret results.
132125
*/
133-
export async function interpretResults(server: cli.CodeQLCliServer, metadata: QueryMetadata | undefined, resultsPath: string, sourceInfo?: cli.SourceInfo): Promise<sarif.Log> {
134-
const interpretedResultsPath = resultsPath + ".interpreted.sarif";
135-
126+
export async function interpretResults(server: cli.CodeQLCliServer, metadata: QueryMetadata | undefined, resultsPaths: ResultsPaths, sourceInfo?: cli.SourceInfo): Promise<sarif.Log> {
127+
const { resultsPath, interpretedResultsPath } = resultsPaths;
136128
if (await fs.pathExists(interpretedResultsPath)) {
137129
return JSON.parse(await fs.readFile(interpretedResultsPath, 'utf8'));
138130
}

extensions/ql-vscode/src/run-queries.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,15 +157,22 @@ export class QueryInfo {
157157
}
158158

159159
/**
160-
* Holds if this query should produce interpreted results.
160+
* Holds if this query can in principle produce interpreted results.
161161
*/
162-
async hasInterpretedResults(): Promise<boolean> {
162+
async canHaveInterpretedResults(): Promise<boolean> {
163163
const hasMetadataFile = await this.dbItem.hasMetadataFile();
164164
if (!hasMetadataFile) {
165165
logger.log("Cannot produce interpreted results since the database does not have a .dbinfo or codeql-database.yml file.");
166166
}
167167
return hasMetadataFile;
168168
}
169+
170+
/**
171+
* Holds if this query actually has produced interpreted results.
172+
*/
173+
async hasInterpretedResults(): Promise<boolean> {
174+
return fs.pathExists(this.resultsPaths.interpretedResultsPath);
175+
}
169176
}
170177

171178
export interface QueryWithResults {

0 commit comments

Comments
 (0)