Skip to content

Commit 4dc9d7c

Browse files
authored
Merge pull request #4037 from github/nickrolfe/run-qls
Add command for running a query suite
2 parents 56fa962 + 459d6a9 commit 4dc9d7c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+737
-249
lines changed

extensions/ql-vscode/package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,10 @@
571571
"command": "codeQL.runQueries",
572572
"title": "CodeQL: Run Queries in Selected Files"
573573
},
574+
{
575+
"command": "codeQL.runQuerySuite",
576+
"title": "CodeQL: Run Selected Query Suite"
577+
},
574578
{
575579
"command": "codeQL.quickEval",
576580
"title": "CodeQL: Quick Evaluation"
@@ -1361,6 +1365,11 @@
13611365
"group": "9_qlCommands",
13621366
"when": "resourceScheme != codeql-zip-archive"
13631367
},
1368+
{
1369+
"command": "codeQL.runQuerySuite",
1370+
"group": "9_qlCommands",
1371+
"when": "resourceScheme != codeql-zip-archive && resourceExtname == .qls && !explorerResourceIsFolder && !listMultiSelection && config.codeQL.canary"
1372+
},
13641373
{
13651374
"command": "codeQL.runVariantAnalysisContextExplorer",
13661375
"group": "9_qlCommands",
@@ -1458,6 +1467,10 @@
14581467
"command": "codeQL.runQueries",
14591468
"when": "false"
14601469
},
1470+
{
1471+
"command": "codeQL.runQuerySuite",
1472+
"when": "false"
1473+
},
14611474
{
14621475
"command": "codeQL.quickEval",
14631476
"when": "editorLangId == ql"

extensions/ql-vscode/src/codeql-cli/cli-version.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface CliFeatures {
1313
featuresInVersionResult?: boolean;
1414
mrvaPackCreate?: boolean;
1515
generateSummarySymbolMap?: boolean;
16+
queryServerRunQueries?: boolean;
1617
}
1718

1819
export interface VersionAndFeatures {

extensions/ql-vscode/src/common/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ export type LocalQueryCommands = {
138138
"codeQLQueries.createQuery": () => Promise<void>;
139139
"codeQL.runLocalQueryFromFileTab": (uri: Uri) => Promise<void>;
140140
"codeQL.runQueries": ExplorerSelectionCommandFunction<Uri>;
141+
"codeQL.runQuerySuite": ExplorerSelectionCommandFunction<Uri>;
141142
"codeQL.quickEval": (uri: Uri) => Promise<void>;
142143
"codeQL.quickEvalCount": (uri: Uri) => Promise<void>;
143144
"codeQL.quickEvalContextEditor": (uri: Uri) => Promise<void>;

extensions/ql-vscode/src/compare/compare-view.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -70,22 +70,20 @@ export class CompareView extends AbstractWebview<
7070
selectedResultSetName?: string,
7171
) {
7272
const [fromSchemas, toSchemas] = await Promise.all([
73-
this.cliServer.bqrsInfo(
74-
from.completedQuery.query.resultsPaths.resultsPath,
75-
),
76-
this.cliServer.bqrsInfo(to.completedQuery.query.resultsPaths.resultsPath),
73+
this.cliServer.bqrsInfo(from.completedQuery.query.resultsPath),
74+
this.cliServer.bqrsInfo(to.completedQuery.query.resultsPath),
7775
]);
7876

7977
const [fromSchemaNames, toSchemaNames] = await Promise.all([
8078
getResultSetNames(
8179
fromSchemas,
8280
from.completedQuery.query.metadata,
83-
from.completedQuery.query.resultsPaths.interpretedResultsPath,
81+
from.completedQuery.query.interpretedResultsPath,
8482
),
8583
getResultSetNames(
8684
toSchemas,
8785
to.completedQuery.query.metadata,
88-
to.completedQuery.query.resultsPaths.interpretedResultsPath,
86+
to.completedQuery.query.interpretedResultsPath,
8987
),
9088
]);
9189

@@ -101,15 +99,14 @@ export class CompareView extends AbstractWebview<
10199
schemaNames: fromSchemaNames,
102100
metadata: from.completedQuery.query.metadata,
103101
interpretedResultsPath:
104-
from.completedQuery.query.resultsPaths.interpretedResultsPath,
102+
from.completedQuery.query.interpretedResultsPath,
105103
},
106104
to,
107105
toInfo: {
108106
schemas: toSchemas,
109107
schemaNames: toSchemaNames,
110108
metadata: to.completedQuery.query.metadata,
111-
interpretedResultsPath:
112-
to.completedQuery.query.resultsPaths.interpretedResultsPath,
109+
interpretedResultsPath: to.completedQuery.query.interpretedResultsPath,
113110
},
114111
commonResultSetNames,
115112
};
@@ -392,12 +389,12 @@ export class CompareView extends AbstractWebview<
392389
this.getResultSet(
393390
fromInfo.schemas,
394391
fromResultSetName,
395-
from.completedQuery.query.resultsPaths.resultsPath,
392+
from.completedQuery.query.resultsPath,
396393
),
397394
this.getResultSet(
398395
toInfo.schemas,
399396
toResultSetName,
400-
to.completedQuery.query.resultsPaths.resultsPath,
397+
to.completedQuery.query.resultsPath,
401398
),
402399
]);
403400

extensions/ql-vscode/src/compare/interpreted-results.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,9 @@ export async function compareInterpretedResults(
3636

3737
const [fromResultSet, toResultSet, sourceLocationPrefix] = await Promise.all([
3838
getInterpretedResults(
39-
fromQuery.completedQuery.query.resultsPaths.interpretedResultsPath,
40-
),
41-
getInterpretedResults(
42-
toQuery.completedQuery.query.resultsPaths.interpretedResultsPath,
39+
fromQuery.completedQuery.query.interpretedResultsPath,
4340
),
41+
getInterpretedResults(toQuery.completedQuery.query.interpretedResultsPath),
4442
database.getSourceLocationPrefix(cliServer),
4543
]);
4644

extensions/ql-vscode/src/debugger/debug-protocol.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export interface EvaluationCompletedEvent extends Event {
3939
resultType: QueryResultType;
4040
message: string | undefined;
4141
evaluationTime: number;
42+
outputBaseName: string;
4243
};
4344
}
4445

extensions/ql-vscode/src/debugger/debug-session.ts

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import type { BaseLogger, LogOptions } from "../common/logging";
1616
import { queryServerLogger } from "../common/logging/vscode";
1717
import { QueryResultType } from "../query-server/messages";
1818
import type {
19-
CoreQueryResults,
19+
CoreQueryResult,
2020
CoreQueryRun,
2121
QueryRunner,
2222
} from "../query-server";
@@ -25,6 +25,7 @@ import type * as CodeQLProtocol from "./debug-protocol";
2525
import type { QuickEvalContext } from "../run-queries-shared";
2626
import { getErrorMessage } from "../common/helpers-pure";
2727
import { DisposableObject } from "../common/disposable-object";
28+
import { basename } from "path";
2829

2930
// More complete implementations of `Event` for certain events, because the classes from
3031
// `@vscode/debugadapter` make it more difficult to provide some of the message values.
@@ -107,9 +108,9 @@ class EvaluationCompletedEvent
107108
public readonly event = "codeql-evaluation-completed";
108109
public readonly body: CodeQLProtocol.EvaluationCompletedEvent["body"];
109110

110-
constructor(results: CoreQueryResults) {
111+
constructor(result: CoreQueryResult) {
111112
super("codeql-evaluation-completed");
112-
this.body = results;
113+
this.body = result;
113114
}
114115
}
115116

@@ -143,6 +144,7 @@ const QUERY_THREAD_NAME = "Evaluation thread";
143144
class RunningQuery extends DisposableObject {
144145
private readonly tokenSource = this.push(new CancellationTokenSource());
145146
public readonly queryRun: CoreQueryRun;
147+
private readonly queryPath: string;
146148

147149
public constructor(
148150
queryRunner: QueryRunner,
@@ -154,21 +156,25 @@ class RunningQuery extends DisposableObject {
154156
) {
155157
super();
156158

159+
this.queryPath = config.query;
157160
// Create the query run, which will give us some information about the query even before the
158161
// evaluation has completed.
159162
this.queryRun = queryRunner.createQueryRun(
160163
config.database,
161-
{
162-
queryPath: config.query,
163-
quickEvalPosition: quickEvalContext?.quickEvalPosition,
164-
quickEvalCountOnly: quickEvalContext?.quickEvalCount,
165-
},
164+
[
165+
{
166+
queryPath: this.queryPath,
167+
outputBaseName: "results",
168+
quickEvalPosition: quickEvalContext?.quickEvalPosition,
169+
quickEvalCountOnly: quickEvalContext?.quickEvalCount,
170+
},
171+
],
166172
true,
167173
config.additionalPacks,
168174
config.extensionPacks,
169175
config.additionalRunQueryArgs,
170176
queryStorageDir,
171-
undefined,
177+
basename(config.query),
172178
undefined,
173179
);
174180
}
@@ -208,7 +214,7 @@ class RunningQuery extends DisposableObject {
208214
progressStart.body.cancellable = true;
209215
this.sendEvent(progressStart);
210216
try {
211-
return await this.queryRun.evaluate(
217+
const completedQuery = await this.queryRun.evaluate(
212218
(p) => {
213219
const progressUpdate = new ProgressUpdateEvent(
214220
this.queryRun.id,
@@ -220,6 +226,14 @@ class RunningQuery extends DisposableObject {
220226
this.tokenSource.token,
221227
this.logger,
222228
);
229+
return (
230+
completedQuery.results.get(this.queryPath) ?? {
231+
resultType: QueryResultType.OTHER_ERROR,
232+
message: "Missing query results",
233+
evaluationTime: 0,
234+
outputBaseName: "unknown",
235+
}
236+
);
223237
} finally {
224238
this.sendEvent(new ProgressEndEvent(this.queryRun.id));
225239
}
@@ -229,6 +243,7 @@ class RunningQuery extends DisposableObject {
229243
resultType: QueryResultType.OTHER_ERROR,
230244
message,
231245
evaluationTime: 0,
246+
outputBaseName: "unknown",
232247
};
233248
}
234249
}

extensions/ql-vscode/src/debugger/debugger-ui.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { debug, Uri, CancellationTokenSource } from "vscode";
88
import type { DebuggerCommands } from "../common/commands";
99
import type { DatabaseManager } from "../databases/local-databases";
1010
import { DisposableObject } from "../common/disposable-object";
11-
import type { CoreQueryResults } from "../query-server";
11+
import type { CoreQueryResult } from "../query-server";
1212
import {
1313
getQuickEvalContext,
1414
saveBeforeStart,
@@ -134,8 +134,15 @@ class QLDebugAdapterTracker
134134
body: EvaluationCompletedEvent["body"],
135135
): Promise<void> {
136136
if (this.localQueryRun !== undefined) {
137-
const results: CoreQueryResults = body;
138-
await this.localQueryRun.complete(results, (_) => {});
137+
const results: CoreQueryResult = body;
138+
await this.localQueryRun.complete(
139+
{
140+
results: new Map<string, CoreQueryResult>([
141+
[this.configuration.query, results],
142+
]),
143+
},
144+
(_) => {},
145+
);
139146
this.localQueryRun = undefined;
140147
}
141148
}

extensions/ql-vscode/src/language-support/ast-viewer/ast-builder.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import type {
77
import type { DatabaseItem } from "../../databases/local-databases";
88
import type { ChildAstItem, AstItem } from "./ast-viewer";
99
import type { Uri } from "vscode";
10-
import type { QueryOutputDir } from "../../local-queries/query-output-dir";
1110
import { fileRangeFromURI } from "../contextual/file-range-from-uri";
1211
import { mapUrlValue } from "../../common/bqrs-raw-results-mapper";
1312

@@ -17,15 +16,12 @@ import { mapUrlValue } from "../../common/bqrs-raw-results-mapper";
1716
*/
1817
export class AstBuilder {
1918
private roots: AstItem[] | undefined;
20-
private bqrsPath: string;
2119
constructor(
22-
outputDir: QueryOutputDir,
20+
private readonly bqrsPath: string,
2321
private cli: CodeQLCliServer,
2422
public db: DatabaseItem,
2523
public fileName: Uri,
26-
) {
27-
this.bqrsPath = outputDir.bqrsPath;
28-
}
24+
) {}
2925

3026
async getRoots(): Promise<AstItem[]> {
3127
if (!this.roots) {

extensions/ql-vscode/src/language-support/contextual/location-finder.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import {
2121
} from "./query-resolver";
2222
import type { CancellationToken, LocationLink } from "vscode";
2323
import { Uri } from "vscode";
24-
import type { QueryOutputDir } from "../../local-queries/query-output-dir";
2524
import type { QueryRunner } from "../../query-server";
2625
import { QueryResultType } from "../../query-server/messages";
2726
import { fileRangeFromURI } from "./file-range-from-uri";
@@ -84,23 +83,28 @@ export async function getLocationsForUriString(
8483
token,
8584
templates,
8685
);
87-
if (results.resultType === QueryResultType.SUCCESS) {
86+
const queryResult = results.results.get(query);
87+
if (queryResult?.resultType === QueryResultType.SUCCESS) {
8888
links.push(
89-
...(await getLinksFromResults(results.outputDir, cli, db, filter)),
89+
...(await getLinksFromResults(
90+
results.outputDir.getBqrsPath(queryResult.outputBaseName),
91+
cli,
92+
db,
93+
filter,
94+
)),
9095
);
9196
}
9297
}
9398
return links;
9499
}
95100

96101
async function getLinksFromResults(
97-
outputDir: QueryOutputDir,
102+
bqrsPath: string,
98103
cli: CodeQLCliServer,
99104
db: DatabaseItem,
100105
filter: (srcFile: string, destFile: string) => boolean,
101106
): Promise<FullLocationLink[]> {
102107
const localLinks: FullLocationLink[] = [];
103-
const bqrsPath = outputDir.bqrsPath;
104108
const info = await cli.bqrsInfo(bqrsPath);
105109
const selectInfo = info["result-sets"].find(
106110
(schema) => schema.name === SELECT_QUERY_NAME,

extensions/ql-vscode/src/language-support/contextual/query-resolver.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type { CancellationToken } from "vscode";
1414
import type { ProgressCallback } from "../../common/vscode/progress";
1515
import type { CoreCompletedQuery, QueryRunner } from "../../query-server";
1616
import { createLockFileForStandardQuery } from "../../local-queries/standard-queries";
17+
import { basename } from "path";
1718

1819
/**
1920
* This wil try to determine the qlpacks for a given database. If it can't find a matching
@@ -80,13 +81,19 @@ export async function runContextualQuery(
8081
const { cleanup } = await createLockFileForStandardQuery(cli, query);
8182
const queryRun = qs.createQueryRun(
8283
db.databaseUri.fsPath,
83-
{ queryPath: query, quickEvalPosition: undefined },
84+
[
85+
{
86+
queryPath: query,
87+
outputBaseName: "results",
88+
quickEvalPosition: undefined,
89+
},
90+
],
8491
false,
8592
getOnDiskWorkspaceFolders(),
8693
undefined,
8794
{},
8895
queryStorageDir,
89-
undefined,
96+
basename(query),
9097
templates,
9198
);
9299
void extLogger.log(

extensions/ql-vscode/src/language-support/contextual/template-provider.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,14 @@ export class TemplatePrintAstProvider {
209209
? await this.cache.get(fileUri.toString(), progress, token)
210210
: await this.getAst(fileUri.toString(), progress, token);
211211

212+
const queryResults = Array.from(completedQuery.results.values());
213+
if (queryResults.length !== 1) {
214+
throw new Error(
215+
`Expected exactly one query result, but found ${queryResults.length}.`,
216+
);
217+
}
212218
return new AstBuilder(
213-
completedQuery.outputDir,
219+
completedQuery.outputDir.getBqrsPath(queryResults[0].outputBaseName),
214220
this.cli,
215221
this.dbm.findDatabaseItem(Uri.file(completedQuery.dbPath))!,
216222
fileUri,

0 commit comments

Comments
 (0)