Skip to content

Commit 14dbb65

Browse files
Change sort order to place AI predictions at the start
1 parent 8f3ab61 commit 14dbb65

7 files changed

Lines changed: 133 additions & 27 deletions

File tree

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ export function getCandidates(
5050
// Sort the same way as the UI so we send the first ones listed in the UI first
5151
const grouped = groupMethods(candidateMethods, mode);
5252
const sortedGroupNames = sortGroupNames(grouped);
53-
return sortedGroupNames.flatMap((name) => sortMethods(grouped[name]));
53+
return sortedGroupNames.flatMap((name) =>
54+
// We can safely pass empty sets for `modifiedSignatures` and `processedByAutoModelMethods`
55+
// because we've filtered out all methods that are already modeled or have already been processed by auto-model.
56+
sortMethods(grouped[name], modeledMethodsBySignature, new Set(), new Set()),
57+
);
5458
}
5559

5660
/**

extensions/ql-vscode/src/model-editor/methods-usage/methods-usage-data-provider.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export class MethodsUsageDataProvider
6363
mode: Mode,
6464
modeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>,
6565
modifiedMethodSignatures: ReadonlySet<string>,
66+
processedByAutoModelMethods: ReadonlySet<string>,
6667
): Promise<void> {
6768
if (
6869
this.methods !== methods ||
@@ -74,7 +75,13 @@ export class MethodsUsageDataProvider
7475
) {
7576
this.methods = methods;
7677
this.sortedTreeItems = createTreeItems(
77-
sortMethodsInGroups(methods, mode),
78+
sortMethodsInGroups(
79+
methods,
80+
modeledMethods,
81+
mode,
82+
modifiedMethodSignatures,
83+
processedByAutoModelMethods,
84+
),
7885
);
7986
this.databaseItem = databaseItem;
8087
this.sourceLocationPrefix =
@@ -246,15 +253,26 @@ function urlValueResolvablesAreEqual(
246253
return false;
247254
}
248255

249-
function sortMethodsInGroups(methods: readonly Method[], mode: Mode): Method[] {
256+
function sortMethodsInGroups(
257+
methods: readonly Method[],
258+
modeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>,
259+
mode: Mode,
260+
modifiedMethodSignatures: ReadonlySet<string>,
261+
processedByAutoModelMethods: ReadonlySet<string>,
262+
): Method[] {
250263
const grouped = groupMethods(methods, mode);
251264

252265
const sortedGroupNames = sortGroupNames(grouped);
253266

254267
return sortedGroupNames.flatMap((groupName) => {
255268
const group = grouped[groupName];
256269

257-
return sortMethods(group);
270+
return sortMethods(
271+
group,
272+
modeledMethods,
273+
modifiedMethodSignatures,
274+
processedByAutoModelMethods,
275+
);
258276
});
259277
}
260278

extensions/ql-vscode/src/model-editor/methods-usage/methods-usage-panel.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export class MethodsUsagePanel extends DisposableObject {
3939
mode: Mode,
4040
modeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>,
4141
modifiedMethodSignatures: ReadonlySet<string>,
42+
processedByAutoModelMethods: ReadonlySet<string>,
4243
): Promise<void> {
4344
await this.dataProvider.setState(
4445
methods,
@@ -47,6 +48,7 @@ export class MethodsUsagePanel extends DisposableObject {
4748
mode,
4849
modeledMethods,
4950
modifiedMethodSignatures,
51+
processedByAutoModelMethods,
5052
);
5153
const numOfApis = hideModeledMethods
5254
? methods.filter((api) => !api.supported).length
@@ -120,6 +122,7 @@ export class MethodsUsagePanel extends DisposableObject {
120122
activeState.mode,
121123
activeState.modeledMethods,
122124
activeState.modifiedMethodSignatures,
125+
activeState.processedByAutoModelMethods,
123126
);
124127
}
125128
}

extensions/ql-vscode/src/model-editor/shared/sorting.ts

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Method } from "../method";
2+
import type { ModeledMethod } from "../modeled-method";
23
import { Mode } from "./mode";
34
import { calculateModeledPercentage } from "./modeled-percentage";
45

@@ -27,12 +28,76 @@ export function sortGroupNames(
2728
);
2829
}
2930

30-
export function sortMethods(methods: readonly Method[]): Method[] {
31+
/**
32+
* Primarily sorts methods into the following order:
33+
* - Unsaved positive AutoModel predictions
34+
* - Negative AutoModel predictions
35+
* - Unsaved manual models
36+
* - Umodeled
37+
* - Modeled and saved (AutoModel and manual)
38+
*
39+
* Secondary sort order is by number of usages descending, then by method signature ascending.
40+
*/
41+
export function sortMethods(
42+
methods: readonly Method[],
43+
modeledMethodsMap: Record<string, readonly ModeledMethod[]>,
44+
modifiedSignatures: ReadonlySet<string>,
45+
processedByAutoModelMethods: ReadonlySet<string>,
46+
): Method[] {
3147
const sortedMethods = [...methods];
32-
sortedMethods.sort((a, b) => compareMethod(a, b));
48+
sortedMethods.sort((a, b) => {
49+
const methodAPrimarySortOrdinal = getMethodPrimarySortOrdinal(
50+
!!modeledMethodsMap[a.signature]?.length,
51+
modifiedSignatures.has(a.signature),
52+
processedByAutoModelMethods.has(a.signature),
53+
);
54+
const methodBPrimarySortOrdinal = getMethodPrimarySortOrdinal(
55+
!!modeledMethodsMap[b.signature]?.length,
56+
modifiedSignatures.has(b.signature),
57+
processedByAutoModelMethods.has(b.signature),
58+
);
59+
if (methodAPrimarySortOrdinal !== methodBPrimarySortOrdinal) {
60+
return methodAPrimarySortOrdinal - methodBPrimarySortOrdinal;
61+
}
62+
63+
// Then sort by number of usages descending
64+
const usageDifference = b.usages.length - a.usages.length;
65+
if (usageDifference !== 0) {
66+
return usageDifference;
67+
}
68+
69+
// Then sort by method signature ascending
70+
return a.signature.localeCompare(b.signature);
71+
});
3372
return sortedMethods;
3473
}
3574

75+
/**
76+
* Assigns numbers to the following classes of methods:
77+
* - Unsaved positive AutoModel predictions => 0
78+
* - Negative AutoModel predictions => 1
79+
* - Unsaved manual models => 2
80+
* - Umodeled => 3
81+
* - Modeled and saved (AutoModel and manual) => 4
82+
*/
83+
function getMethodPrimarySortOrdinal(
84+
isModeled: boolean,
85+
isModified: boolean,
86+
isProcessedByAutoModel: boolean,
87+
): number {
88+
if (isModeled && isModified && isProcessedByAutoModel) {
89+
return 0;
90+
} else if (!isModeled && isProcessedByAutoModel) {
91+
return 1;
92+
} else if (isModeled && isModified) {
93+
return 2;
94+
} else if (!isModeled) {
95+
return 3;
96+
} else {
97+
return 4;
98+
}
99+
}
100+
36101
function compareGroups(
37102
a: readonly Method[],
38103
aName: string,
@@ -69,22 +134,3 @@ function compareGroups(
69134
// Then sort by number of usages descending
70135
return numberOfUsagesB - numberOfUsagesA;
71136
}
72-
73-
function compareMethod(a: Method, b: Method): number {
74-
// Sort first by supported, putting unmodeled methods first.
75-
if (a.supported && !b.supported) {
76-
return 1;
77-
}
78-
if (!a.supported && b.supported) {
79-
return -1;
80-
}
81-
82-
// Then sort by number of usages descending
83-
const usageDifference = b.usages.length - a.usages.length;
84-
if (usageDifference !== 0) {
85-
return usageDifference;
86-
}
87-
88-
// Then sort by method signature ascending
89-
return a.signature.localeCompare(b.signature);
90-
}

extensions/ql-vscode/src/view/model-editor/ModeledMethodDataGrid.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@ export const ModeledMethodDataGrid = ({
4848
] = useMemo(() => {
4949
const methodsWithModelability = [];
5050
let numHiddenMethods = 0;
51-
for (const method of sortMethods(methods)) {
51+
for (const method of sortMethods(
52+
methods,
53+
modeledMethodsMap,
54+
modifiedSignatures,
55+
processedByAutoModelMethods,
56+
)) {
5257
const modeledMethods = modeledMethodsMap[method.signature] ?? [];
5358
const methodIsUnsaved = modifiedSignatures.has(method.signature);
5459
const methodCanBeModeled = canMethodBeModeled(
@@ -64,7 +69,13 @@ export const ModeledMethodDataGrid = ({
6469
}
6570
}
6671
return [methodsWithModelability, numHiddenMethods];
67-
}, [hideModeledMethods, methods, modeledMethodsMap, modifiedSignatures]);
72+
}, [
73+
hideModeledMethods,
74+
methods,
75+
modeledMethodsMap,
76+
modifiedSignatures,
77+
processedByAutoModelMethods,
78+
]);
6879

6980
const someMethodsAreVisible = methodsWithModelability.length > 0;
7081

extensions/ql-vscode/test/vscode-tests/no-workspace/model-editor/methods-usage/methods-usage-data-provider.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ describe("MethodsUsageDataProvider", () => {
2727
const methods: Method[] = [];
2828
const modeledMethods: Record<string, ModeledMethod[]> = {};
2929
const modifiedMethodSignatures: Set<string> = new Set();
30+
const processedByAutoModelMethods: Set<string> = new Set();
3031
const dbItem = mockedObject<DatabaseItem>({
3132
getSourceLocationPrefix: () => "test",
3233
});
@@ -39,6 +40,7 @@ describe("MethodsUsageDataProvider", () => {
3940
mode,
4041
modeledMethods,
4142
modifiedMethodSignatures,
43+
processedByAutoModelMethods,
4244
);
4345

4446
const onDidChangeTreeDataListener = jest.fn();
@@ -51,6 +53,7 @@ describe("MethodsUsageDataProvider", () => {
5153
mode,
5254
modeledMethods,
5355
modifiedMethodSignatures,
56+
processedByAutoModelMethods,
5457
);
5558

5659
expect(onDidChangeTreeDataListener).not.toHaveBeenCalled();
@@ -66,6 +69,7 @@ describe("MethodsUsageDataProvider", () => {
6669
mode,
6770
modeledMethods,
6871
modifiedMethodSignatures,
72+
processedByAutoModelMethods,
6973
);
7074

7175
const onDidChangeTreeDataListener = jest.fn();
@@ -78,6 +82,7 @@ describe("MethodsUsageDataProvider", () => {
7882
mode,
7983
modeledMethods,
8084
modifiedMethodSignatures,
85+
processedByAutoModelMethods,
8186
);
8287

8388
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
@@ -95,6 +100,7 @@ describe("MethodsUsageDataProvider", () => {
95100
mode,
96101
modeledMethods,
97102
modifiedMethodSignatures,
103+
processedByAutoModelMethods,
98104
);
99105

100106
const onDidChangeTreeDataListener = jest.fn();
@@ -107,6 +113,7 @@ describe("MethodsUsageDataProvider", () => {
107113
mode,
108114
modeledMethods,
109115
modifiedMethodSignatures,
116+
processedByAutoModelMethods,
110117
);
111118

112119
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
@@ -120,6 +127,7 @@ describe("MethodsUsageDataProvider", () => {
120127
mode,
121128
modeledMethods,
122129
modifiedMethodSignatures,
130+
processedByAutoModelMethods,
123131
);
124132

125133
const onDidChangeTreeDataListener = jest.fn();
@@ -132,6 +140,7 @@ describe("MethodsUsageDataProvider", () => {
132140
mode,
133141
modeledMethods,
134142
modifiedMethodSignatures,
143+
processedByAutoModelMethods,
135144
);
136145

137146
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
@@ -147,6 +156,7 @@ describe("MethodsUsageDataProvider", () => {
147156
mode,
148157
modeledMethods,
149158
modifiedMethodSignatures,
159+
processedByAutoModelMethods,
150160
);
151161

152162
const onDidChangeTreeDataListener = jest.fn();
@@ -159,6 +169,7 @@ describe("MethodsUsageDataProvider", () => {
159169
mode,
160170
modeledMethods2,
161171
modifiedMethodSignatures,
172+
processedByAutoModelMethods,
162173
);
163174

164175
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
@@ -174,6 +185,7 @@ describe("MethodsUsageDataProvider", () => {
174185
mode,
175186
modeledMethods,
176187
modifiedMethodSignatures,
188+
processedByAutoModelMethods,
177189
);
178190

179191
const onDidChangeTreeDataListener = jest.fn();
@@ -186,6 +198,7 @@ describe("MethodsUsageDataProvider", () => {
186198
mode,
187199
modeledMethods,
188200
modifiedMethodSignatures2,
201+
processedByAutoModelMethods,
189202
);
190203

191204
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
@@ -204,6 +217,7 @@ describe("MethodsUsageDataProvider", () => {
204217
mode,
205218
modeledMethods,
206219
modifiedMethodSignatures,
220+
processedByAutoModelMethods,
207221
);
208222

209223
const onDidChangeTreeDataListener = jest.fn();
@@ -216,6 +230,7 @@ describe("MethodsUsageDataProvider", () => {
216230
mode,
217231
modeledMethods,
218232
modifiedMethodSignatures,
233+
processedByAutoModelMethods,
219234
);
220235

221236
expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1);
@@ -255,6 +270,7 @@ describe("MethodsUsageDataProvider", () => {
255270
createSinkModeledMethod(),
256271
];
257272
const modifiedMethodSignatures: Set<string> = new Set();
273+
const processedByAutoModelMethods: Set<string> = new Set();
258274

259275
const dbItem = mockedObject<DatabaseItem>({
260276
getSourceLocationPrefix: () => "test",
@@ -291,6 +307,7 @@ describe("MethodsUsageDataProvider", () => {
291307
mode,
292308
modeledMethods,
293309
modifiedMethodSignatures,
310+
processedByAutoModelMethods,
294311
);
295312
expect(dataProvider.getChildren().length).toEqual(4);
296313
});
@@ -304,6 +321,7 @@ describe("MethodsUsageDataProvider", () => {
304321
mode,
305322
modeledMethods,
306323
modifiedMethodSignatures,
324+
processedByAutoModelMethods,
307325
);
308326
expect(dataProvider.getChildren().length).toEqual(3);
309327
});
@@ -400,6 +418,7 @@ describe("MethodsUsageDataProvider", () => {
400418
mode,
401419
modeledMethods,
402420
modifiedMethodSignatures,
421+
processedByAutoModelMethods,
403422
);
404423
expect(
405424
dataProvider

0 commit comments

Comments
 (0)