Skip to content

Commit 9cd6daf

Browse files
authored
Functions for running "access path suggestions" queries (#3294)
1 parent 9b07be0 commit 9cd6daf

3 files changed

Lines changed: 401 additions & 0 deletions

File tree

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import type { CodeQLCliServer } from "../codeql-cli/cli";
2+
import type { Mode } from "./shared/mode";
3+
import { resolveQueriesFromPacks } from "../local-queries";
4+
import { modeTag } from "./mode-tag";
5+
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
6+
import type { NotificationLogger } from "../common/logging";
7+
import { showAndLogExceptionWithTelemetry } from "../common/logging";
8+
import { telemetryListener } from "../common/vscode/telemetry";
9+
import { redactableError } from "../common/errors";
10+
import { runQuery } from "../local-queries/run-query";
11+
import type { QueryRunner } from "../query-server";
12+
import type { DatabaseItem } from "../databases/local-databases";
13+
import type { ProgressCallback } from "../common/vscode/progress";
14+
import type { CancellationToken } from "vscode";
15+
import type { DecodedBqrsChunk } from "../common/bqrs-cli-types";
16+
import type {
17+
AccessPathSuggestionRow,
18+
AccessPathSuggestionRows,
19+
} from "./suggestions";
20+
21+
type RunQueryOptions = {
22+
parseResults: (
23+
results: DecodedBqrsChunk,
24+
) => AccessPathSuggestionRow[] | Promise<AccessPathSuggestionRow[]>;
25+
26+
cliServer: CodeQLCliServer;
27+
queryRunner: QueryRunner;
28+
logger: NotificationLogger;
29+
databaseItem: DatabaseItem;
30+
queryStorageDir: string;
31+
32+
progress: ProgressCallback;
33+
token: CancellationToken;
34+
};
35+
36+
const maxStep = 2000;
37+
38+
export async function runSuggestionsQuery(
39+
mode: Mode,
40+
{
41+
parseResults,
42+
cliServer,
43+
queryRunner,
44+
logger,
45+
databaseItem,
46+
queryStorageDir,
47+
progress,
48+
token,
49+
}: RunQueryOptions,
50+
): Promise<AccessPathSuggestionRows | undefined> {
51+
progress({
52+
message: "Resolving QL packs",
53+
step: 1,
54+
maxStep,
55+
});
56+
const additionalPacks = getOnDiskWorkspaceFolders();
57+
const extensionPacks = Object.keys(
58+
await cliServer.resolveQlpacks(additionalPacks, true),
59+
);
60+
61+
progress({
62+
message: "Resolving query",
63+
step: 2,
64+
maxStep,
65+
});
66+
67+
const queryPath = await resolveSuggestionsQuery(
68+
cliServer,
69+
databaseItem.language,
70+
mode,
71+
);
72+
if (!queryPath) {
73+
void showAndLogExceptionWithTelemetry(
74+
logger,
75+
telemetryListener,
76+
redactableError`The ${mode} access path suggestions query could not be found. Try re-opening the model editor. If that doesn't work, try upgrading the CodeQL libraries.`,
77+
);
78+
return undefined;
79+
}
80+
81+
// Run the actual query
82+
const completedQuery = await runQuery({
83+
queryRunner,
84+
databaseItem,
85+
queryPath,
86+
queryStorageDir,
87+
additionalPacks,
88+
extensionPacks,
89+
progress: (update) =>
90+
progress({
91+
step: update.step + 500,
92+
maxStep,
93+
message: update.message,
94+
}),
95+
token,
96+
});
97+
98+
if (!completedQuery) {
99+
return undefined;
100+
}
101+
102+
// Read the results and convert to internal representation
103+
progress({
104+
message: "Decoding results",
105+
step: 1600,
106+
maxStep,
107+
});
108+
109+
const bqrs = await cliServer.bqrsDecodeAll(completedQuery.outputDir.bqrsPath);
110+
111+
progress({
112+
message: "Finalizing results",
113+
step: 1950,
114+
maxStep,
115+
});
116+
117+
const inputChunk = bqrs["input"];
118+
const outputChunk = bqrs["output"];
119+
120+
if (!inputChunk && !outputChunk) {
121+
void logger.log(
122+
`No results found for ${mode} access path suggestions query`,
123+
);
124+
return undefined;
125+
}
126+
127+
const inputSuggestions = inputChunk ? await parseResults(inputChunk) : [];
128+
const outputSuggestions = outputChunk ? await parseResults(outputChunk) : [];
129+
130+
return {
131+
input: inputSuggestions,
132+
output: outputSuggestions,
133+
};
134+
}
135+
136+
/**
137+
* Resolve the query path to the model editor access path suggestions query. All queries are tagged like this:
138+
* modeleditor access-path-suggestions <mode>
139+
* Example: modeleditor access-path-suggestions framework-mode
140+
*
141+
* @param cliServer The CodeQL CLI server to use.
142+
* @param language The language of the query pack to use.
143+
* @param mode The mode to resolve the query for.
144+
* @param additionalPackNames Additional pack names to search.
145+
* @param additionalPackPaths Additional pack paths to search.
146+
*/
147+
async function resolveSuggestionsQuery(
148+
cliServer: CodeQLCliServer,
149+
language: string,
150+
mode: Mode,
151+
additionalPackNames: string[] = [],
152+
additionalPackPaths: string[] = [],
153+
): Promise<string | undefined> {
154+
const packsToSearch = [`codeql/${language}-queries`, ...additionalPackNames];
155+
156+
const queries = await resolveQueriesFromPacks(
157+
cliServer,
158+
packsToSearch,
159+
{
160+
kind: "table",
161+
"tags contain all": [
162+
"modeleditor",
163+
"access-path-suggestions",
164+
modeTag(mode),
165+
],
166+
},
167+
additionalPackPaths,
168+
);
169+
if (queries.length > 1) {
170+
throw new Error(
171+
`Found multiple suggestions queries for ${mode}. Can't continue`,
172+
);
173+
}
174+
175+
if (queries.length === 0) {
176+
return undefined;
177+
}
178+
179+
return queries[0];
180+
}

extensions/ql-vscode/src/model-editor/suggestions.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ export type AccessPathSuggestionRow = {
2525
details: string;
2626
};
2727

28+
export type AccessPathSuggestionRows = {
29+
input: AccessPathSuggestionRow[];
30+
output: AccessPathSuggestionRow[];
31+
};
32+
2833
export type AccessPathOption = {
2934
label: string;
3035
value: string;

0 commit comments

Comments
 (0)