Skip to content

Commit 9344499

Browse files
author
Dave Bartolomeo
committed
Merge remote-tracking branch 'origin/main' into dbartol/debug-adapter
2 parents 785f009 + 807eb92 commit 9344499

39 files changed

Lines changed: 1192 additions & 650 deletions

extensions/ql-vscode/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@
428428
"title": "CodeQL: Quick Query"
429429
},
430430
{
431-
"command": "codeQL.createSkeletonQuery",
431+
"command": "codeQL.createQuery",
432432
"title": "CodeQL: Create Query"
433433
},
434434
{
@@ -1435,6 +1435,10 @@
14351435
{
14361436
"command": "codeQL.mockGitHubApiServer.unloadScenario",
14371437
"when": "config.codeQL.mockGitHubApiServer.enabled && codeQL.mockGitHubApiServer.scenarioLoaded"
1438+
},
1439+
{
1440+
"command": "codeQL.createQuery",
1441+
"when": "config.codeQL.canary"
14381442
}
14391443
],
14401444
"editor/context": [

extensions/ql-vscode/src/cli.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,21 @@ export type MlModelInfo = {
107107
/** The expected output of `codeql resolve ml-models`. */
108108
export type MlModelsInfo = { models: MlModelInfo[] };
109109

110+
/** Information about a data extension predicate, as resolved by `codeql resolve extensions`. */
111+
export type DataExtensionResult = {
112+
predicate: string;
113+
file: string;
114+
index: number;
115+
};
116+
117+
/** The expected output of `codeql resolve extensions`. */
118+
export type ResolveExtensionsResult = {
119+
models: MlModelInfo[];
120+
data: {
121+
[path: string]: DataExtensionResult[];
122+
};
123+
};
124+
110125
/**
111126
* The expected output of `codeql resolve qlref`.
112127
*/
@@ -1192,6 +1207,29 @@ export class CodeQLCliServer implements Disposable {
11921207
);
11931208
}
11941209

1210+
/**
1211+
* Gets information about available extensions
1212+
* @param suite The suite to resolve.
1213+
* @param additionalPacks A list of directories to search for qlpacks.
1214+
* @returns An object containing the list of models and extensions
1215+
*/
1216+
async resolveExtensions(
1217+
suite: string,
1218+
additionalPacks: string[],
1219+
): Promise<ResolveExtensionsResult> {
1220+
const args = this.getAdditionalPacksArg(additionalPacks);
1221+
args.push(suite);
1222+
1223+
return this.runJsonCodeQlCliCommand<ResolveExtensionsResult>(
1224+
["resolve", "extensions"],
1225+
args,
1226+
"Resolving extensions",
1227+
{
1228+
addFormat: false,
1229+
},
1230+
);
1231+
}
1232+
11951233
/**
11961234
* Gets information about the available languages.
11971235
* @returns A dictionary mapping language name to the directory it comes from

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

Lines changed: 74 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,53 @@ import type {
1414
import { QLDebugConfiguration } from "../debugger/debug-configuration";
1515

1616
// A command function matching the signature that VS Code calls when
17-
// a command on a selection is invoked.
18-
export type SelectionCommandFunction<Item> = (
17+
// a command is invoked from the title bar of a TreeView with
18+
// canSelectMany set to true.
19+
//
20+
// It is possible to get any combination of singleItem and multiSelect
21+
// to be undefined. This is because it is possible to click a title bar
22+
// option without interacting with any individual items first, or even
23+
// when there are no items present at all.
24+
// If both singleItem and multiSelect are defined, then singleItem will
25+
// be contained within multiSelect.
26+
export type TreeViewTitleMultiSelectionCommandFunction<Item> = (
27+
singleItem: Item | undefined,
28+
multiSelect: Item[] | undefined,
29+
) => Promise<void>;
30+
31+
// A command function matching the signature that VS Code calls when
32+
// a command is invoked from a context menu on a TreeView with
33+
// canSelectMany set to true.
34+
//
35+
// singleItem will always be defined and corresponds to the item that
36+
// was hovered or right-clicked. If precisely one item was selected then
37+
// multiSelect will be undefined. If more than one item is selected then
38+
// multiSelect will contain all selected items, including singleItem.
39+
export type TreeViewContextMultiSelectionCommandFunction<Item> = (
1940
singleItem: Item,
20-
multiSelect: Item[],
41+
multiSelect: Item[] | undefined,
2142
) => Promise<void>;
2243

2344
// A command function matching the signature that VS Code calls when
24-
// a command on a selection is invoked when canSelectMany is false.
25-
export type SingleSelectionCommandFunction<Item> = (
45+
// a command is invoked from a context menu on a TreeView with
46+
// canSelectMany set to false.
47+
//
48+
// It is guaranteed that precisely one item will be selected.
49+
export type TreeViewContextSingleSelectionCommandFunction<Item> = (
2650
singleItem: Item,
2751
) => Promise<void>;
2852

53+
// A command function matching the signature that VS Code calls when
54+
// a command is invoked from a context menu on the file explorer.
55+
//
56+
// singleItem corresponds to the item that was right-clicked.
57+
// multiSelect will always been defined and non-empty and contains
58+
// all selected items, including singleItem.
59+
export type ExplorerSelectionCommandFunction<Item> = (
60+
singleItem: Item,
61+
multiSelect: Item[],
62+
) => Promise<void>;
63+
2964
/**
3065
* Contains type definitions for all commands used by the extension.
3166
*
@@ -104,13 +139,13 @@ export type LocalQueryCommands = {
104139
"codeQL.runQueryOnMultipleDatabasesContextEditor": (
105140
uri?: Uri,
106141
) => Promise<void>;
107-
"codeQL.runQueries": SelectionCommandFunction<Uri>;
142+
"codeQL.runQueries": ExplorerSelectionCommandFunction<Uri>;
108143
"codeQL.quickEval": (uri: Uri) => Promise<void>;
109144
"codeQL.quickEvalContextEditor": (uri: Uri) => Promise<void>;
110145
"codeQL.codeLensQuickEval": (uri: Uri, range: Range) => Promise<void>;
111146
"codeQL.quickQuery": () => Promise<void>;
112147
"codeQL.getCurrentQuery": () => Promise<string>;
113-
"codeQL.createSkeletonQuery": () => Promise<void>;
148+
"codeQL.createQuery": () => Promise<void>;
114149
};
115150

116151
// Debugger commands
@@ -140,28 +175,28 @@ export type QueryHistoryCommands = {
140175
"codeQLQueryHistory.sortByCount": () => Promise<void>;
141176

142177
// Commands in the context menu or in the hover menu
143-
"codeQLQueryHistory.openQueryTitleMenu": SelectionCommandFunction<QueryHistoryInfo>;
144-
"codeQLQueryHistory.openQueryContextMenu": SelectionCommandFunction<QueryHistoryInfo>;
145-
"codeQLQueryHistory.removeHistoryItemTitleMenu": SelectionCommandFunction<QueryHistoryInfo>;
146-
"codeQLQueryHistory.removeHistoryItemContextMenu": SelectionCommandFunction<QueryHistoryInfo>;
147-
"codeQLQueryHistory.removeHistoryItemContextInline": SelectionCommandFunction<QueryHistoryInfo>;
148-
"codeQLQueryHistory.renameItem": SelectionCommandFunction<QueryHistoryInfo>;
149-
"codeQLQueryHistory.compareWith": SelectionCommandFunction<QueryHistoryInfo>;
150-
"codeQLQueryHistory.showEvalLog": SelectionCommandFunction<QueryHistoryInfo>;
151-
"codeQLQueryHistory.showEvalLogSummary": SelectionCommandFunction<QueryHistoryInfo>;
152-
"codeQLQueryHistory.showEvalLogViewer": SelectionCommandFunction<QueryHistoryInfo>;
153-
"codeQLQueryHistory.showQueryLog": SelectionCommandFunction<QueryHistoryInfo>;
154-
"codeQLQueryHistory.showQueryText": SelectionCommandFunction<QueryHistoryInfo>;
155-
"codeQLQueryHistory.openQueryDirectory": SelectionCommandFunction<QueryHistoryInfo>;
156-
"codeQLQueryHistory.cancel": SelectionCommandFunction<QueryHistoryInfo>;
157-
"codeQLQueryHistory.exportResults": SelectionCommandFunction<QueryHistoryInfo>;
158-
"codeQLQueryHistory.viewCsvResults": SelectionCommandFunction<QueryHistoryInfo>;
159-
"codeQLQueryHistory.viewCsvAlerts": SelectionCommandFunction<QueryHistoryInfo>;
160-
"codeQLQueryHistory.viewSarifAlerts": SelectionCommandFunction<QueryHistoryInfo>;
161-
"codeQLQueryHistory.viewDil": SelectionCommandFunction<QueryHistoryInfo>;
162-
"codeQLQueryHistory.itemClicked": SelectionCommandFunction<QueryHistoryInfo>;
163-
"codeQLQueryHistory.openOnGithub": SelectionCommandFunction<QueryHistoryInfo>;
164-
"codeQLQueryHistory.copyRepoList": SelectionCommandFunction<QueryHistoryInfo>;
178+
"codeQLQueryHistory.openQueryTitleMenu": TreeViewTitleMultiSelectionCommandFunction<QueryHistoryInfo>;
179+
"codeQLQueryHistory.openQueryContextMenu": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
180+
"codeQLQueryHistory.removeHistoryItemTitleMenu": TreeViewTitleMultiSelectionCommandFunction<QueryHistoryInfo>;
181+
"codeQLQueryHistory.removeHistoryItemContextMenu": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
182+
"codeQLQueryHistory.removeHistoryItemContextInline": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
183+
"codeQLQueryHistory.renameItem": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
184+
"codeQLQueryHistory.compareWith": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
185+
"codeQLQueryHistory.showEvalLog": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
186+
"codeQLQueryHistory.showEvalLogSummary": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
187+
"codeQLQueryHistory.showEvalLogViewer": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
188+
"codeQLQueryHistory.showQueryLog": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
189+
"codeQLQueryHistory.showQueryText": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
190+
"codeQLQueryHistory.openQueryDirectory": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
191+
"codeQLQueryHistory.cancel": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
192+
"codeQLQueryHistory.exportResults": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
193+
"codeQLQueryHistory.viewCsvResults": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
194+
"codeQLQueryHistory.viewCsvAlerts": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
195+
"codeQLQueryHistory.viewSarifAlerts": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
196+
"codeQLQueryHistory.viewDil": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
197+
"codeQLQueryHistory.itemClicked": TreeViewTitleMultiSelectionCommandFunction<QueryHistoryInfo>;
198+
"codeQLQueryHistory.openOnGithub": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
199+
"codeQLQueryHistory.copyRepoList": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
165200

166201
// Commands in the command palette
167202
"codeQL.exportSelectedVariantAnalysisResults": () => Promise<void>;
@@ -194,11 +229,11 @@ export type LocalDatabasesCommands = {
194229
) => Promise<void>;
195230

196231
// Database panel selection commands
197-
"codeQLDatabases.removeDatabase": SelectionCommandFunction<DatabaseItem>;
198-
"codeQLDatabases.upgradeDatabase": SelectionCommandFunction<DatabaseItem>;
199-
"codeQLDatabases.renameDatabase": SelectionCommandFunction<DatabaseItem>;
200-
"codeQLDatabases.openDatabaseFolder": SelectionCommandFunction<DatabaseItem>;
201-
"codeQLDatabases.addDatabaseSource": SelectionCommandFunction<DatabaseItem>;
232+
"codeQLDatabases.removeDatabase": TreeViewContextMultiSelectionCommandFunction<DatabaseItem>;
233+
"codeQLDatabases.upgradeDatabase": TreeViewContextMultiSelectionCommandFunction<DatabaseItem>;
234+
"codeQLDatabases.renameDatabase": TreeViewContextMultiSelectionCommandFunction<DatabaseItem>;
235+
"codeQLDatabases.openDatabaseFolder": TreeViewContextMultiSelectionCommandFunction<DatabaseItem>;
236+
"codeQLDatabases.addDatabaseSource": TreeViewContextMultiSelectionCommandFunction<DatabaseItem>;
202237

203238
// Codespace template commands
204239
"codeQL.setDefaultTourDatabase": () => Promise<void>;
@@ -244,11 +279,11 @@ export type DatabasePanelCommands = {
244279
"codeQLVariantAnalysisRepositories.addNewList": () => Promise<void>;
245280
"codeQLVariantAnalysisRepositories.setupControllerRepository": () => Promise<void>;
246281

247-
"codeQLVariantAnalysisRepositories.setSelectedItem": SingleSelectionCommandFunction<DbTreeViewItem>;
248-
"codeQLVariantAnalysisRepositories.setSelectedItemContextMenu": SingleSelectionCommandFunction<DbTreeViewItem>;
249-
"codeQLVariantAnalysisRepositories.openOnGitHubContextMenu": SingleSelectionCommandFunction<DbTreeViewItem>;
250-
"codeQLVariantAnalysisRepositories.renameItemContextMenu": SingleSelectionCommandFunction<DbTreeViewItem>;
251-
"codeQLVariantAnalysisRepositories.removeItemContextMenu": SingleSelectionCommandFunction<DbTreeViewItem>;
282+
"codeQLVariantAnalysisRepositories.setSelectedItem": TreeViewContextSingleSelectionCommandFunction<DbTreeViewItem>;
283+
"codeQLVariantAnalysisRepositories.setSelectedItemContextMenu": TreeViewContextSingleSelectionCommandFunction<DbTreeViewItem>;
284+
"codeQLVariantAnalysisRepositories.openOnGitHubContextMenu": TreeViewContextSingleSelectionCommandFunction<DbTreeViewItem>;
285+
"codeQLVariantAnalysisRepositories.renameItemContextMenu": TreeViewContextSingleSelectionCommandFunction<DbTreeViewItem>;
286+
"codeQLVariantAnalysisRepositories.removeItemContextMenu": TreeViewContextSingleSelectionCommandFunction<DbTreeViewItem>;
252287
};
253288

254289
export type AstCfgCommands = {

extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-module.ts

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { ensureDir } from "fs-extra";
88
import { join } from "path";
99
import { App } from "../common/app";
1010
import { showAndLogErrorMessage } from "../helpers";
11+
import { withProgress } from "../progress";
12+
import { pickExtensionPackModelFile } from "./extension-pack-picker";
1113

1214
export class DataExtensionsEditorModule {
1315
private readonly queryStorageDir: string;
@@ -49,31 +51,46 @@ export class DataExtensionsEditorModule {
4951

5052
public getCommands(): DataExtensionsEditorCommands {
5153
return {
52-
"codeQL.openDataExtensionsEditor": async () => {
53-
const db = this.databaseManager.currentDatabaseItem;
54-
if (!db) {
55-
void showAndLogErrorMessage("No database selected");
56-
return;
57-
}
54+
"codeQL.openDataExtensionsEditor": async () =>
55+
withProgress(
56+
async (progress) => {
57+
const db = this.databaseManager.currentDatabaseItem;
58+
if (!db) {
59+
void showAndLogErrorMessage("No database selected");
60+
return;
61+
}
5862

59-
if (!(await this.cliServer.cliConstraints.supportsQlpacksKind())) {
60-
void showAndLogErrorMessage(
61-
`This feature requires CodeQL CLI version ${CliVersionConstraint.CLI_VERSION_WITH_QLPACKS_KIND.format()} or later.`,
62-
);
63-
return;
64-
}
63+
if (!(await this.cliServer.cliConstraints.supportsQlpacksKind())) {
64+
void showAndLogErrorMessage(
65+
`This feature requires CodeQL CLI version ${CliVersionConstraint.CLI_VERSION_WITH_QLPACKS_KIND.format()} or later.`,
66+
);
67+
return;
68+
}
6569

66-
const view = new DataExtensionsEditorView(
67-
this.ctx,
68-
this.app,
69-
this.databaseManager,
70-
this.cliServer,
71-
this.queryRunner,
72-
this.queryStorageDir,
73-
db,
74-
);
75-
await view.openView();
76-
},
70+
const modelFile = await pickExtensionPackModelFile(
71+
this.cliServer,
72+
progress,
73+
);
74+
if (!modelFile) {
75+
return;
76+
}
77+
78+
const view = new DataExtensionsEditorView(
79+
this.ctx,
80+
this.app,
81+
this.databaseManager,
82+
this.cliServer,
83+
this.queryRunner,
84+
this.queryStorageDir,
85+
db,
86+
modelFile,
87+
);
88+
await view.openView();
89+
},
90+
{
91+
title: "Opening Data Extensions Editor",
92+
},
93+
),
7794
};
7895
}
7996

extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-view.ts

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {
22
CancellationTokenSource,
33
ExtensionContext,
4-
Uri,
54
ViewColumn,
65
window,
76
workspace,
@@ -61,6 +60,7 @@ export class DataExtensionsEditorView extends AbstractWebview<
6160
private readonly queryRunner: QueryRunner,
6261
private readonly queryStorageDir: string,
6362
private readonly databaseItem: DatabaseItem,
63+
private readonly modelFilename: string,
6464
) {
6565
super(ctx);
6666
}
@@ -148,29 +148,19 @@ export class DataExtensionsEditorView extends AbstractWebview<
148148
externalApiUsages: ExternalApiUsage[],
149149
modeledMethods: Record<string, ModeledMethod>,
150150
): Promise<void> {
151-
const modelFilename = this.calculateModelFilename();
152-
if (!modelFilename) {
153-
return;
154-
}
155-
156151
const yaml = createDataExtensionYaml(externalApiUsages, modeledMethods);
157152

158-
await writeFile(modelFilename, yaml);
153+
await writeFile(this.modelFilename, yaml);
159154

160-
void extLogger.log(`Saved data extension YAML to ${modelFilename}`);
155+
void extLogger.log(`Saved data extension YAML to ${this.modelFilename}`);
161156
}
162157

163158
protected async loadExistingModeledMethods(): Promise<void> {
164-
const modelFilename = this.calculateModelFilename();
165-
if (!modelFilename) {
166-
return;
167-
}
168-
169159
try {
170-
const yaml = await readFile(modelFilename, "utf8");
160+
const yaml = await readFile(this.modelFilename, "utf8");
171161

172162
const data = loadYaml(yaml, {
173-
filename: modelFilename,
163+
filename: this.modelFilename,
174164
});
175165

176166
const existingModeledMethods = loadDataExtensionYaml(data);
@@ -365,17 +355,4 @@ export class DataExtensionsEditorView extends AbstractWebview<
365355
message: "",
366356
});
367357
}
368-
369-
private calculateModelFilename(): string | undefined {
370-
const workspaceFolder = getQlSubmoduleFolder();
371-
if (!workspaceFolder) {
372-
return;
373-
}
374-
375-
return Uri.joinPath(
376-
workspaceFolder.uri,
377-
"java/ql/lib/ext",
378-
`${this.databaseItem.name.replaceAll("/", ".")}.model.yml`,
379-
).fsPath;
380-
}
381358
}

0 commit comments

Comments
 (0)