Skip to content

Commit 7a2688e

Browse files
Merge pull request #3382 from github/robertbrignull/automodel-sort-order
Update method sort order to place auto-model predictions earlier
2 parents bf35909 + 4096ded commit 7a2688e

File tree

12 files changed

+321
-61
lines changed

12 files changed

+321
-61
lines changed

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/auto-model-candidates.ts

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,37 +19,35 @@ export function getCandidates(
1919
modeledMethodsBySignature: Record<string, readonly ModeledMethod[]>,
2020
processedByAutoModelMethods: Set<string>,
2121
): MethodSignature[] {
22-
// Filter out any methods already processed by auto-model
23-
methods = methods.filter(
24-
(m) => !processedByAutoModelMethods.has(m.signature),
25-
);
26-
27-
// Sort the same way as the UI so we send the first ones listed in the UI first
28-
const grouped = groupMethods(methods, mode);
29-
const sortedGroupNames = sortGroupNames(grouped);
30-
const sortedMethods = sortedGroupNames.flatMap((name) =>
31-
sortMethods(grouped[name]),
32-
);
33-
34-
const candidates: MethodSignature[] = [];
22+
const candidateMethods = methods.filter((method) => {
23+
// Filter out any methods already processed by auto-model
24+
if (processedByAutoModelMethods.has(method.signature)) {
25+
return false;
26+
}
3527

36-
for (const method of sortedMethods) {
3728
const modeledMethods: ModeledMethod[] = [
3829
...(modeledMethodsBySignature[method.signature] ?? []),
3930
];
4031

4132
// Anything that is modeled is not a candidate
4233
if (modeledMethods.some((m) => m.type !== "none")) {
43-
continue;
34+
return false;
4435
}
4536

4637
// A method that is supported is modeled outside of the model file, so it is not a candidate.
4738
if (method.supported) {
48-
continue;
39+
return false;
4940
}
5041

51-
// The rest are candidates
52-
candidates.push(method);
53-
}
54-
return candidates;
42+
return true;
43+
});
44+
45+
// Sort the same way as the UI so we send the first ones listed in the UI first
46+
const grouped = groupMethods(candidateMethods, mode);
47+
const sortedGroupNames = sortGroupNames(grouped);
48+
return sortedGroupNames.flatMap((name) =>
49+
// We can safely pass empty sets for `modifiedSignatures` and `processedByAutoModelMethods`
50+
// because we've filtered out all methods that are already modeled or have already been processed by auto-model.
51+
sortMethods(grouped[name], modeledMethodsBySignature, new Set(), new Set()),
52+
);
5553
}

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

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { canMethodBeModeled } from "../method";
12
import type { Method } from "../method";
3+
import type { ModeledMethod } from "../modeled-method";
24
import { Mode } from "./mode";
35
import { calculateModeledPercentage } from "./modeled-percentage";
46

@@ -27,12 +29,84 @@ export function sortGroupNames(
2729
);
2830
}
2931

30-
export function sortMethods(methods: readonly Method[]): Method[] {
32+
/**
33+
* Primarily sorts methods into the following order:
34+
* - Unsaved positive AutoModel predictions
35+
* - Negative AutoModel predictions
36+
* - Unsaved manual models + unmodeled methods
37+
* - Saved models from this model pack (AutoModel and manual)
38+
* - Methods not modelable in this model pack
39+
*
40+
* Secondary sort order is by number of usages descending, then by method signature ascending.
41+
*/
42+
export function sortMethods(
43+
methods: readonly Method[],
44+
modeledMethodsMap: Record<string, readonly ModeledMethod[]>,
45+
modifiedSignatures: ReadonlySet<string>,
46+
processedByAutoModelMethods: ReadonlySet<string>,
47+
): Method[] {
3148
const sortedMethods = [...methods];
32-
sortedMethods.sort((a, b) => compareMethod(a, b));
49+
sortedMethods.sort((a, b) => {
50+
// First sort by the type of method
51+
const methodAPrimarySortOrdinal = getMethodPrimarySortOrdinal(
52+
a,
53+
modeledMethodsMap[a.signature] ?? [],
54+
modifiedSignatures.has(a.signature),
55+
processedByAutoModelMethods.has(a.signature),
56+
);
57+
const methodBPrimarySortOrdinal = getMethodPrimarySortOrdinal(
58+
b,
59+
modeledMethodsMap[b.signature] ?? [],
60+
modifiedSignatures.has(b.signature),
61+
processedByAutoModelMethods.has(b.signature),
62+
);
63+
if (methodAPrimarySortOrdinal !== methodBPrimarySortOrdinal) {
64+
return methodAPrimarySortOrdinal - methodBPrimarySortOrdinal;
65+
}
66+
67+
// Then sort by number of usages descending
68+
const usageDifference = b.usages.length - a.usages.length;
69+
if (usageDifference !== 0) {
70+
return usageDifference;
71+
}
72+
73+
// Then sort by method signature ascending
74+
return a.signature.localeCompare(b.signature);
75+
});
3376
return sortedMethods;
3477
}
3578

79+
/**
80+
* Assigns numbers to the following classes of methods:
81+
* - Unsaved positive AutoModel predictions => 0
82+
* - Negative AutoModel predictions => 1
83+
* - Unsaved manual models + unmodeled methods => 2
84+
* - Saved models from this model pack (AutoModel and manual) => 3
85+
* - Methods not modelable in this model pack => 4
86+
*/
87+
function getMethodPrimarySortOrdinal(
88+
method: Method,
89+
modeledMethods: readonly ModeledMethod[],
90+
isUnsaved: boolean,
91+
isProcessedByAutoModel: boolean,
92+
): number {
93+
const canBeModeled = canMethodBeModeled(method, modeledMethods, isUnsaved);
94+
const isModeled = modeledMethods.length > 0;
95+
if (canBeModeled) {
96+
if (isModeled && isUnsaved && isProcessedByAutoModel) {
97+
return 0;
98+
} else if (!isModeled && isProcessedByAutoModel) {
99+
return 1;
100+
} else if ((isModeled && isUnsaved) || !isModeled) {
101+
return 2;
102+
} else {
103+
return 3;
104+
}
105+
} else {
106+
return 4;
107+
}
108+
}
109+
36110
function compareGroups(
37111
a: readonly Method[],
38112
aName: string,
@@ -69,22 +143,3 @@ function compareGroups(
69143
// Then sort by number of usages descending
70144
return numberOfUsagesB - numberOfUsagesA;
71145
}
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

0 commit comments

Comments
 (0)