diff --git a/src/vs/workbench/api/common/extHostCommands.ts b/src/vs/workbench/api/common/extHostCommands.ts index 03bfe95e1948f..399a42fdbfd99 100644 --- a/src/vs/workbench/api/common/extHostCommands.ts +++ b/src/vs/workbench/api/common/extHostCommands.ts @@ -369,8 +369,8 @@ export class ApiCommandArgument { static readonly Number = new ApiCommandArgument('number', '', v => typeof v === 'number', v => v); static readonly String = new ApiCommandArgument('string', '', v => typeof v === 'string', v => v); - static readonly CallHierarchyItem = new ApiCommandArgument('item', 'A call hierarchy item', v => v instanceof extHostTypes.CallHierarchyItem, extHostTypeConverter.CallHierarchyItem.to); - static readonly TypeHierarchyItem = new ApiCommandArgument('item', 'A type hierarchy item', v => v instanceof extHostTypes.TypeHierarchyItem, extHostTypeConverter.TypeHierarchyItem.to); + static readonly CallHierarchyItem = new ApiCommandArgument('item', 'A call hierarchy item', v => v instanceof extHostTypes.CallHierarchyItem, extHostTypeConverter.CallHierarchyItem.from); + static readonly TypeHierarchyItem = new ApiCommandArgument('item', 'A type hierarchy item', v => v instanceof extHostTypes.TypeHierarchyItem, extHostTypeConverter.TypeHierarchyItem.from); constructor( readonly name: string, diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 8b41c25c6f509..b021f9c03f721 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -1408,17 +1408,7 @@ class CallHierarchyAdapter { private _cacheAndConvertItem(sessionId: string, item: vscode.CallHierarchyItem): extHostProtocol.ICallHierarchyItemDto { const map = this._cache.get(sessionId)!; - const dto: extHostProtocol.ICallHierarchyItemDto = { - _sessionId: sessionId, - _itemId: map.size.toString(36), - name: item.name, - detail: item.detail, - kind: typeConvert.SymbolKind.from(item.kind), - uri: item.uri, - range: typeConvert.Range.from(item.range), - selectionRange: typeConvert.Range.from(item.selectionRange), - tags: item.tags?.map(typeConvert.SymbolTag.from) - }; + const dto = typeConvert.CallHierarchyItem.from(item, sessionId, map.size.toString(36)); map.set(dto._itemId, item); return dto; } @@ -1492,17 +1482,7 @@ class TypeHierarchyAdapter { private _cacheAndConvertItem(sessionId: string, item: vscode.TypeHierarchyItem): extHostProtocol.ITypeHierarchyItemDto { const map = this._cache.get(sessionId)!; - const dto: extHostProtocol.ICallHierarchyItemDto = { - _sessionId: sessionId, - _itemId: map.size.toString(36), - name: item.name, - detail: item.detail, - kind: typeConvert.SymbolKind.from(item.kind), - uri: item.uri, - range: typeConvert.Range.from(item.range), - selectionRange: typeConvert.Range.from(item.selectionRange), - tags: item.tags?.map(typeConvert.SymbolTag.from) - }; + const dto = typeConvert.TypeHierarchyItem.from(item, sessionId, map.size.toString(36)); map.set(dto._itemId, item); return dto; } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 80e0d32ca8b14..da6da8d82e54c 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -722,6 +722,28 @@ export namespace CallHierarchyItem { return result; } + + export function from(item: vscode.CallHierarchyItem, sessionId?: string, itemId?: string): extHostProtocol.ICallHierarchyItemDto { + + sessionId = sessionId ?? (item)._sessionId; + itemId = itemId ?? (item)._itemId; + + if (sessionId === undefined || itemId === undefined) { + throw new Error('invalid item'); + } + + return { + _sessionId: sessionId, + _itemId: itemId, + name: item.name, + detail: item.detail, + kind: SymbolKind.from(item.kind), + uri: item.uri, + range: Range.from(item.range), + selectionRange: Range.from(item.selectionRange), + tags: item.tags?.map(SymbolTag.from) + }; + } } export namespace CallHierarchyIncomingCall { @@ -1792,4 +1814,26 @@ export namespace TypeHierarchyItem { return result; } + + export function from(item: vscode.TypeHierarchyItem, sessionId?: string, itemId?: string): extHostProtocol.ITypeHierarchyItemDto { + + sessionId = sessionId ?? (item)._sessionId; + itemId = itemId ?? (item)._itemId; + + if (sessionId === undefined || itemId === undefined) { + throw new Error('invalid item'); + } + + return { + _sessionId: sessionId, + _itemId: itemId, + kind: SymbolKind.from(item.kind), + name: item.name, + detail: item.detail ?? '', + uri: item.uri, + range: Range.from(item.range), + selectionRange: Range.from(item.selectionRange), + tags: item.tags?.map(SymbolTag.from) + }; + } } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index eb41a371e8df4..c7611205f4d83 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -1242,6 +1242,7 @@ export class CallHierarchyItem { _itemId?: string; kind: SymbolKind; + tags?: SymbolTag[]; name: string; detail?: string; uri: URI; @@ -3437,6 +3438,7 @@ export class TypeHierarchyItem { _itemId?: string; kind: SymbolKind; + tags?: SymbolTag[]; name: string; detail?: string; uri: URI; diff --git a/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts b/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts index 531aa8c028e3c..4b22daaa1ee1e 100644 --- a/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/browser/api/extHostApiCommands.test.ts @@ -1292,7 +1292,7 @@ suite('ExtHostLanguageFeatureCommands', function () { assert.ok(value[0].parent); }); - // --- call hierarcht + // --- call hierarchy test('CallHierarchy, back and forth', async function () { @@ -1335,6 +1335,40 @@ suite('ExtHostLanguageFeatureCommands', function () { assert.strictEqual(outgoing[0].to.name, 'OUTGOING'); }); + // --- type hierarchy + + test('TypeHierarchy, back and forth', async function () { + + + disposables.push(extHost.registerTypeHierarchyProvider(nullExtensionDescription, defaultSelector, new class implements vscode.TypeHierarchyProvider { + prepareTypeHierarchy(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): vscode.ProviderResult { + return [new types.TypeHierarchyItem(types.SymbolKind.Constant, 'ROOT', 'ROOT', document.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0))]; + } + provideTypeHierarchySupertypes(item: vscode.TypeHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult { + return [new types.TypeHierarchyItem(types.SymbolKind.Constant, 'SUPER', 'SUPER', item.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0))]; + } + provideTypeHierarchySubtypes(item: vscode.TypeHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult { + return [new types.TypeHierarchyItem(types.SymbolKind.Constant, 'SUB', 'SUB', item.uri, new types.Range(0, 0, 0, 0), new types.Range(0, 0, 0, 0))]; + } + })); + + await rpcProtocol.sync(); + + const root = await commands.executeCommand('vscode.prepareTypeHierarchy', model.uri, new types.Position(0, 0)); + + assert.ok(Array.isArray(root)); + assert.strictEqual(root.length, 1); + assert.strictEqual(root[0].name, 'ROOT'); + + const incoming = await commands.executeCommand('vscode.provideSupertypes', root[0]); + assert.strictEqual(incoming.length, 1); + assert.strictEqual(incoming[0].name, 'SUPER'); + + const outgoing = await commands.executeCommand('vscode.provideSubtypes', root[0]); + assert.strictEqual(outgoing.length, 1); + assert.strictEqual(outgoing[0].name, 'SUB'); + }); + test('selectionRangeProvider on inner array always returns outer array #91852', async function () { disposables.push(extHost.registerSelectionRangeProvider(nullExtensionDescription, defaultSelector, {