Skip to content

Commit 78284cb

Browse files
committed
Merge remote-tracking branch 'origin/main' into koesie10/sort-usages-panel
2 parents 0e1afce + 0d70022 commit 78284cb

30 files changed

+732
-268
lines changed

extensions/ql-vscode/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
- Fix a bug where the query server was restarted twice after configuration changes. [#2884](https://github.com/github/vscode-codeql/pull/2884).
99
- Add support for the `telemetry.telemetryLevel` setting. For more information, see the [telemetry documentation](https://codeql.github.com/docs/codeql-for-visual-studio-code/about-telemetry-in-codeql-for-visual-studio-code). [#2824](https://github.com/github/vscode-codeql/pull/2824).
1010
- Fix syntax highlighting directly after import statements with instantiation arguments. [#2792](https://github.com/github/vscode-codeql/pull/2792)
11+
- The `debug.saveBeforeStart` setting is now respected when running variant analyses. [#2950](https://github.com/github/vscode-codeql/pull/2950)
12+
- The 'open database' button of the model editor was renamed to 'open source'. Also, it's now only available if the source archive is available as a workspace folder. [#2945](https://github.com/github/vscode-codeql/pull/2945)
1113

1214
## 1.9.1 - 29 September 2023
1315

extensions/ql-vscode/src/common/interface-types.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ interface SetMethodsMessage {
507507

508508
interface SetModeledMethodsMessage {
509509
t: "setModeledMethods";
510-
methods: Record<string, ModeledMethod>;
510+
methods: Record<string, ModeledMethod[]>;
511511
}
512512

513513
interface SetModifiedMethodsMessage {
@@ -577,6 +577,12 @@ interface SetModeledMethodMessage {
577577
method: ModeledMethod;
578578
}
579579

580+
interface SetMultipleModeledMethodsMessage {
581+
t: "setMultipleModeledMethods";
582+
methodSignature: string;
583+
modeledMethods: ModeledMethod[];
584+
}
585+
580586
interface SetInModelingModeMessage {
581587
t: "setInModelingMode";
582588
inModelingMode: boolean;
@@ -643,14 +649,14 @@ interface SetMethodModifiedMessage {
643649
interface SetSelectedMethodMessage {
644650
t: "setSelectedMethod";
645651
method: Method;
646-
modeledMethod?: ModeledMethod;
652+
modeledMethods: ModeledMethod[];
647653
isModified: boolean;
648654
}
649655

650656
export type ToMethodModelingMessage =
651657
| SetMethodModelingPanelViewStateMessage
652658
| SetMethodMessage
653-
| SetModeledMethodMessage
659+
| SetMultipleModeledMethodsMessage
654660
| SetMethodModifiedMessage
655661
| SetSelectedMethodMessage
656662
| SetInModelingModeMessage;

extensions/ql-vscode/src/databases/local-databases/database-item-impl.ts

+9
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,15 @@ export class DatabaseItemImpl implements DatabaseItem {
167167
return encodeArchiveBasePath(sourceArchive.fsPath);
168168
}
169169

170+
/**
171+
* Returns true if the database's source archive is in the workspace.
172+
*/
173+
public hasSourceArchiveInExplorer(): boolean {
174+
return (vscode.workspace.workspaceFolders || []).some((folder) =>
175+
this.belongsToSourceArchiveExplorerUri(folder.uri),
176+
);
177+
}
178+
170179
public verifyZippedSources(): string | undefined {
171180
const sourceArchive = this.sourceArchive;
172181
if (sourceArchive === undefined) {

extensions/ql-vscode/src/databases/local-databases/database-item.ts

+5
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ export interface DatabaseItem {
5656
*/
5757
getSourceArchiveExplorerUri(): vscode.Uri;
5858

59+
/**
60+
* Returns true if the database's source archive is in the workspace.
61+
*/
62+
hasSourceArchiveInExplorer(): boolean;
63+
5964
/**
6065
* Holds if `uri` belongs to this database's source archive.
6166
*/

extensions/ql-vscode/src/model-editor/method-modeling/method-modeling-view-provider.ts

+12-23
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ import { assertNever } from "../../common/helpers-pure";
1414
import { ModelEditorViewTracker } from "../model-editor-view-tracker";
1515
import { ModelConfigListener } from "../../config";
1616
import { DatabaseItem } from "../../databases/local-databases";
17-
import {
18-
convertFromLegacyModeledMethod,
19-
convertToLegacyModeledMethod,
20-
} from "../shared/modeled-methods-legacy";
17+
import { convertFromLegacyModeledMethod } from "../shared/modeled-methods-legacy";
2118

2219
export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
2320
ToMethodModelingMessage,
@@ -77,9 +74,7 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
7774
await this.postMessage({
7875
t: "setSelectedMethod",
7976
method: selectedMethod.method,
80-
modeledMethod: convertToLegacyModeledMethod(
81-
selectedMethod.modeledMethods,
82-
),
77+
modeledMethods: selectedMethod.modeledMethods,
8378
isModified: selectedMethod.isModified,
8479
});
8580
}
@@ -149,29 +144,23 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
149144
return;
150145
}
151146

152-
const views = this.editorViewTracker.getViews(
147+
const view = this.editorViewTracker.getView(
153148
this.databaseItem.databaseUri.toString(),
154149
);
155-
if (views.length === 0) {
156-
return;
157-
}
158-
159-
await Promise.all(views.map((view) => view.revealMethod(method)));
150+
await view?.revealMethod(method);
160151
}
161152

162153
private registerToModelingStoreEvents(): void {
163154
this.push(
164155
this.modelingStore.onModeledMethodsChanged(async (e) => {
165-
if (this.webviewView && e.isActiveDb) {
166-
const modeledMethods = e.modeledMethods[this.method?.signature ?? ""];
156+
if (this.webviewView && e.isActiveDb && this.method) {
157+
const modeledMethods = e.modeledMethods[this.method.signature];
167158
if (modeledMethods) {
168-
const modeledMethod = convertToLegacyModeledMethod(modeledMethods);
169-
if (modeledMethod) {
170-
await this.postMessage({
171-
t: "setModeledMethod",
172-
method: modeledMethod,
173-
});
174-
}
159+
await this.postMessage({
160+
t: "setMultipleModeledMethods",
161+
methodSignature: this.method.signature,
162+
modeledMethods,
163+
});
175164
}
176165
}
177166
}),
@@ -198,7 +187,7 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
198187
await this.postMessage({
199188
t: "setSelectedMethod",
200189
method: e.method,
201-
modeledMethod: convertToLegacyModeledMethod(e.modeledMethods),
190+
modeledMethods: e.modeledMethods,
202191
isModified: e.isModified,
203192
});
204193
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,12 @@ export function getArgumentsList(methodParameters: string): string[] {
6868

6969
export function canMethodBeModeled(
7070
method: Method,
71-
modeledMethod: ModeledMethod | undefined,
71+
modeledMethods: ModeledMethod[],
7272
methodIsUnsaved: boolean,
7373
): boolean {
7474
return (
7575
!method.supported ||
76-
(modeledMethod && modeledMethod?.type !== "none") ||
76+
modeledMethods.some((modeledMethod) => modeledMethod.type !== "none") ||
7777
methodIsUnsaved
7878
);
7979
}

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

+20
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,15 @@ export class ModelEditorModule extends DisposableObject {
127127
return;
128128
}
129129

130+
const existingView = this.editorViewTracker.getView(
131+
db.databaseUri.toString(),
132+
);
133+
if (existingView) {
134+
await existingView.focusView();
135+
136+
return;
137+
}
138+
130139
return withProgress(
131140
async (progress) => {
132141
const maxStep = 4;
@@ -191,6 +200,17 @@ export class ModelEditorModule extends DisposableObject {
191200
maxStep,
192201
});
193202

203+
// Check again just before opening the editor to ensure no model editor has been opened between
204+
// our first check and now.
205+
const existingView = this.editorViewTracker.getView(
206+
db.databaseUri.toString(),
207+
);
208+
if (existingView) {
209+
await existingView.focusView();
210+
211+
return;
212+
}
213+
194214
const view = new ModelEditorView(
195215
this.app,
196216
this.modelingStore,

extensions/ql-vscode/src/model-editor/model-editor-view-tracker.ts

+7-15
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,25 @@ interface ModelEditorViewInterface {
99
export class ModelEditorViewTracker<
1010
T extends ModelEditorViewInterface = ModelEditorViewInterface,
1111
> {
12-
private readonly views = new Map<string, T[]>();
12+
private readonly views = new Map<string, T>();
1313

1414
constructor() {}
1515

1616
public registerView(view: T): void {
1717
const databaseUri = view.databaseUri;
1818

19-
if (!this.views.has(databaseUri)) {
20-
this.views.set(databaseUri, []);
19+
if (this.views.has(databaseUri)) {
20+
throw new Error(`View for database ${databaseUri} already registered`);
2121
}
2222

23-
this.views.get(databaseUri)?.push(view);
23+
this.views.set(databaseUri, view);
2424
}
2525

2626
public unregisterView(view: T): void {
27-
const views = this.views.get(view.databaseUri);
28-
if (!views) {
29-
return;
30-
}
31-
32-
const index = views.indexOf(view);
33-
if (index !== -1) {
34-
views.splice(index, 1);
35-
}
27+
this.views.delete(view.databaseUri);
3628
}
3729

38-
public getViews(databaseUri: string): T[] {
39-
return this.views.get(databaseUri) ?? [];
30+
public getView(databaseUri: string): T | undefined {
31+
return this.views.get(databaseUri);
4032
}
4133
}

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

+30-5
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,7 @@ import { AutoModeler } from "./auto-modeler";
4343
import { telemetryListener } from "../common/vscode/telemetry";
4444
import { ModelingStore } from "./modeling-store";
4545
import { ModelEditorViewTracker } from "./model-editor-view-tracker";
46-
import {
47-
convertFromLegacyModeledMethod,
48-
convertToLegacyModeledMethods,
49-
} from "./shared/modeled-methods-legacy";
46+
import { convertFromLegacyModeledMethod } from "./shared/modeled-methods-legacy";
5047

5148
export class ModelEditorView extends AbstractWebview<
5249
ToModelEditorMessage,
@@ -353,6 +350,10 @@ export class ModelEditorView extends AbstractWebview<
353350
return this.databaseItem.databaseUri.toString();
354351
}
355352

353+
public async focusView(): Promise<void> {
354+
this.panel?.reveal();
355+
}
356+
356357
public async revealMethod(method: Method): Promise<void> {
357358
this.panel?.reveal();
358359

@@ -366,6 +367,9 @@ export class ModelEditorView extends AbstractWebview<
366367
const showLlmButton =
367368
this.databaseItem.language === "java" && this.modelConfig.llmGeneration;
368369

370+
const sourceArchiveAvailable =
371+
this.databaseItem.hasSourceArchiveInExplorer();
372+
369373
await this.postMessage({
370374
t: "setModelEditorViewState",
371375
viewState: {
@@ -374,6 +378,7 @@ export class ModelEditorView extends AbstractWebview<
374378
showLlmButton,
375379
showMultipleModels: this.modelConfig.showMultipleModels,
376380
mode: this.modelingStore.getMode(this.databaseItem),
381+
sourceArchiveAvailable,
377382
},
378383
});
379384
}
@@ -526,6 +531,15 @@ export class ModelEditorView extends AbstractWebview<
526531
return;
527532
}
528533

534+
let existingView = this.viewTracker.getView(
535+
addedDatabase.databaseUri.toString(),
536+
);
537+
if (existingView) {
538+
await existingView.focusView();
539+
540+
return;
541+
}
542+
529543
const modelFile = await pickExtensionPack(
530544
this.cliServer,
531545
addedDatabase,
@@ -538,6 +552,17 @@ export class ModelEditorView extends AbstractWebview<
538552
return;
539553
}
540554

555+
// Check again just before opening the editor to ensure no model editor has been opened between
556+
// our first check and now.
557+
existingView = this.viewTracker.getView(
558+
addedDatabase.databaseUri.toString(),
559+
);
560+
if (existingView) {
561+
await existingView.focusView();
562+
563+
return;
564+
}
565+
541566
const view = new ModelEditorView(
542567
this.app,
543568
this.modelingStore,
@@ -646,7 +671,7 @@ export class ModelEditorView extends AbstractWebview<
646671
if (event.dbUri === this.databaseItem.databaseUri.toString()) {
647672
await this.postMessage({
648673
t: "setModeledMethods",
649-
methods: convertToLegacyModeledMethods(event.modeledMethods),
674+
methods: event.modeledMethods,
650675
});
651676
}
652677
}),

extensions/ql-vscode/src/model-editor/shared/modeled-methods-legacy.ts

-27
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,5 @@
11
import { ModeledMethod } from "../modeled-method";
22

3-
/**
4-
* Converts a record of a single ModeledMethod indexed by signature to a record of ModeledMethod[] indexed by signature
5-
* for legacy usage. This function should always be used instead of the trivial conversion to track usages of this
6-
* conversion.
7-
*
8-
* This method should only be called inside a `postMessage` call. If it's used anywhere else, consider whether the
9-
* boundary is correct: the boundary should as close as possible to the extension host -> webview boundary.
10-
*
11-
* @param modeledMethods The record of a single ModeledMethod indexed by signature
12-
*/
13-
export function convertToLegacyModeledMethods(
14-
modeledMethods: Record<string, ModeledMethod[]>,
15-
): Record<string, ModeledMethod> {
16-
// Always take the first modeled method in the array
17-
return Object.fromEntries(
18-
Object.entries(modeledMethods)
19-
.map(([signature, modeledMethods]) => {
20-
const modeledMethod = convertToLegacyModeledMethod(modeledMethods);
21-
if (!modeledMethod) {
22-
return null;
23-
}
24-
return [signature, modeledMethod];
25-
})
26-
.filter((entry): entry is [string, ModeledMethod] => entry !== null),
27-
);
28-
}
29-
303
/**
314
* Converts a single ModeledMethod to a ModeledMethod[] for legacy usage. This function should always be used instead
325
* of the trivial conversion to track usages of this conversion.

extensions/ql-vscode/src/model-editor/shared/view-state.ts

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export interface ModelEditorViewState {
77
showLlmButton: boolean;
88
showMultipleModels: boolean;
99
mode: Mode;
10+
sourceArchiveAvailable: boolean;
1011
}
1112

1213
export interface MethodModelingPanelViewState {

0 commit comments

Comments
 (0)