Keep reference to original items in usage data provider
This changes the usage data provider tree items to keep a reference to the method and usage instead of only including their properties in the tree item. This makes it easier to find the original method and usage when revealing an item in the tree. It also removes the `getParent` call in `getTreeItem`. The main reason for this fix is to ensure `codeQLModelEditor.jumpToMethod` gets the correct `usage` argument. It received the tree item before, but now we can actually pass the usage that was clicked on.
This commit is contained in:
@@ -89,26 +89,26 @@ export class MethodsUsageDataProvider
|
||||
|
||||
getTreeItem(item: MethodsUsageTreeViewItem): TreeItem {
|
||||
if (isMethodTreeViewItem(item)) {
|
||||
const { method } = item;
|
||||
|
||||
return {
|
||||
label: `${item.packageName}.${item.typeName}.${item.methodName}${item.methodParameters}`,
|
||||
label: `${method.packageName}.${method.typeName}.${method.methodName}${method.methodParameters}`,
|
||||
collapsibleState: TreeItemCollapsibleState.Collapsed,
|
||||
iconPath: this.getModelingStatusIcon(item),
|
||||
iconPath: this.getModelingStatusIcon(method),
|
||||
};
|
||||
} else {
|
||||
const method = this.getParent(item);
|
||||
if (!method || !isMethodTreeViewItem(method)) {
|
||||
throw new Error("Parent not found for tree item");
|
||||
}
|
||||
const { method, usage } = item;
|
||||
|
||||
return {
|
||||
label: item.label,
|
||||
description: `${this.relativePathWithinDatabase(item.url.uri)} [${
|
||||
item.url.startLine
|
||||
}, ${item.url.endLine}]`,
|
||||
label: usage.label,
|
||||
description: `${this.relativePathWithinDatabase(usage.url.uri)} [${
|
||||
usage.url.startLine
|
||||
}, ${usage.url.endLine}]`,
|
||||
collapsibleState: TreeItemCollapsibleState.None,
|
||||
command: {
|
||||
title: "Show usage",
|
||||
command: "codeQLModelEditor.jumpToMethod",
|
||||
arguments: [method, item, this.databaseItem],
|
||||
arguments: [method, usage, this.databaseItem],
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -146,7 +146,7 @@ export class MethodsUsageDataProvider
|
||||
getChildren(item?: MethodsUsageTreeViewItem): MethodsUsageTreeViewItem[] {
|
||||
if (item === undefined) {
|
||||
if (this.hideModeledMethods) {
|
||||
return this.sortedTreeItems.filter((api) => !api.supported);
|
||||
return this.sortedTreeItems.filter((api) => !api.method.supported);
|
||||
} else {
|
||||
return [...this.sortedTreeItems];
|
||||
}
|
||||
@@ -172,21 +172,24 @@ export class MethodsUsageDataProvider
|
||||
usage: Usage,
|
||||
): UsageTreeViewItem | undefined {
|
||||
const method = this.sortedTreeItems.find(
|
||||
(m) => m.signature === methodSignature,
|
||||
(m) => m.method.signature === methodSignature,
|
||||
);
|
||||
if (!method) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return method.children.find((u) => usagesAreEqual(u, usage));
|
||||
return method.children.find((u) => usagesAreEqual(u.usage, usage));
|
||||
}
|
||||
}
|
||||
|
||||
type MethodTreeViewItem = Method & {
|
||||
type MethodTreeViewItem = {
|
||||
method: Method;
|
||||
children: UsageTreeViewItem[];
|
||||
};
|
||||
|
||||
type UsageTreeViewItem = Usage & {
|
||||
type UsageTreeViewItem = {
|
||||
method: Method;
|
||||
usage: Usage;
|
||||
parent: MethodTreeViewItem;
|
||||
};
|
||||
|
||||
@@ -195,7 +198,7 @@ export type MethodsUsageTreeViewItem = MethodTreeViewItem | UsageTreeViewItem;
|
||||
function isMethodTreeViewItem(
|
||||
item: MethodsUsageTreeViewItem,
|
||||
): item is MethodTreeViewItem {
|
||||
return "children" in item && "usages" in item;
|
||||
return "children" in item && "method" in item;
|
||||
}
|
||||
|
||||
function usagesAreEqual(u1: Usage, u2: Usage): boolean {
|
||||
@@ -225,12 +228,13 @@ function sortMethodsInGroups(methods: readonly Method[], mode: Mode): Method[] {
|
||||
function createTreeItems(methods: readonly Method[]): MethodTreeViewItem[] {
|
||||
return methods.map((method) => {
|
||||
const newMethod: MethodTreeViewItem = {
|
||||
...method,
|
||||
method,
|
||||
children: [],
|
||||
};
|
||||
|
||||
newMethod.children = method.usages.map((usage) => ({
|
||||
...usage,
|
||||
method,
|
||||
usage,
|
||||
// This needs to be a reference to the parent method, not a copy of it.
|
||||
parent: newMethod,
|
||||
}));
|
||||
|
||||
@@ -246,12 +246,13 @@ describe("MethodsUsageDataProvider", () => {
|
||||
const usage = createUsage({});
|
||||
|
||||
const methodTreeItem: MethodsUsageTreeViewItem = {
|
||||
...supportedMethod,
|
||||
method: supportedMethod,
|
||||
children: [],
|
||||
};
|
||||
|
||||
const usageTreeItem: MethodsUsageTreeViewItem = {
|
||||
...usage,
|
||||
method: supportedMethod,
|
||||
usage,
|
||||
parent: methodTreeItem,
|
||||
};
|
||||
methodTreeItem.children = [usageTreeItem];
|
||||
@@ -383,7 +384,9 @@ describe("MethodsUsageDataProvider", () => {
|
||||
expect(
|
||||
dataProvider
|
||||
.getChildren()
|
||||
.map((item) => (item as Method).signature),
|
||||
.map(
|
||||
(item) => (item as MethodsUsageTreeViewItem).method.signature,
|
||||
),
|
||||
).toEqual(["b.a.C.d()", "b.a.C.b()", "b.a.C.a()", "a.b.C.d()"]);
|
||||
// reasoning for sort order:
|
||||
// b.a.C.d() has more usages than b.a.C.b()
|
||||
|
||||
@@ -86,7 +86,10 @@ describe("MethodsUsagePanel", () => {
|
||||
await panel.revealItem(method.signature, usage);
|
||||
|
||||
expect(mockTreeView.reveal).toHaveBeenCalledWith(
|
||||
expect.objectContaining(usage),
|
||||
expect.objectContaining({
|
||||
method,
|
||||
usage,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user