Skip to content

Commit

Permalink
calls - remove resolve-function, use document,position tuple when mak…
Browse files Browse the repository at this point in the history
…ing requests
  • Loading branch information
jrieken committed Sep 12, 2019
1 parent 16c39d5 commit 4aa06c2
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 88 deletions.
19 changes: 10 additions & 9 deletions src/vs/vscode.proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,21 @@ declare module 'vscode' {
/**
* Provide a list of callers for the provided item, e.g. all function calling a function.
*/
provideCallHierarchyIncomingCalls(target: CallHierarchyItem, token: CancellationToken): ProviderResult<CallHierarchyIncomingCall[]>;
provideCallHierarchyIncomingCalls(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<CallHierarchyIncomingCall[]>;

/**
* Provide a list of calls for the provided item, e.g. all functions call from a function.
*/
provideCallHierarchyOutgoingCalls(source: CallHierarchyItem, token: CancellationToken): ProviderResult<CallHierarchyOutgoingCall[]>;
provideCallHierarchyOutgoingCalls(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<CallHierarchyOutgoingCall[]>;

/**
* todo@joh not needed?
*
* Given a document and position compute a call hierarchy item. This is justed as
* anchor for call hierarchy and then `resolveCallHierarchyItem` is being called.
*/
resolveCallHierarchyItem(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<CallHierarchyItem>;
// todo@joh this could return as 'prepareCallHierarchy' (similar to the RenameProvider#prepareRename)
//
// /**
// *
// * Given a document and position compute a call hierarchy item. This is justed as
// * anchor for call hierarchy and then `resolveCallHierarchyItem` is being called.
// */
// resolveCallHierarchyItem(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<CallHierarchyItem>;
}

export namespace languages {
Expand Down
11 changes: 4 additions & 7 deletions src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,11 +494,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha

$registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void {
this._registrations.set(handle, callh.CallHierarchyProviderRegistry.register(selector, {
resolveCallHierarchyItem: (document, position, token) => {
return this._proxy.$resolveCallHierarchyItem(handle, document.uri, position, token).then(MainThreadLanguageFeatures._reviveCallHierarchyItemDto);
},
provideOutgoingCalls: async (item, token) => {
const outgoing = await this._proxy.$provideCallHierarchyOutgoingCalls(handle, item, token);
provideOutgoingCalls: async (model, position, token) => {
const outgoing = await this._proxy.$provideCallHierarchyOutgoingCalls(handle, model.uri, position, token);
if (!outgoing) {
return outgoing;
}
Expand All @@ -509,8 +506,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
};
});
},
provideIncomingCalls: async (item, token) => {
const incoming = await this._proxy.$provideCallHierarchyIncomingCalls(handle, item, token);
provideIncomingCalls: async (model, position, token) => {
const incoming = await this._proxy.$provideCallHierarchyIncomingCalls(handle, model.uri, position, token);
if (!incoming) {
return incoming;
}
Expand Down
6 changes: 2 additions & 4 deletions src/vs/workbench/api/common/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
import * as tasks from 'vs/workbench/api/common/shared/tasks';
import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views';
import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { IAdapterDescriptor, IConfig } from 'vs/workbench/contrib/debug/common/debug';
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
import { ITerminalDimensions, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal';
Expand Down Expand Up @@ -1112,9 +1111,8 @@ export interface ExtHostLanguageFeaturesShape {
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo, token: CancellationToken): Promise<modes.IColorPresentation[] | undefined>;
$provideFoldingRanges(handle: number, resource: UriComponents, context: modes.FoldingContext, token: CancellationToken): Promise<modes.FoldingRange[] | undefined>;
$provideSelectionRanges(handle: number, resource: UriComponents, positions: IPosition[], token: CancellationToken): Promise<modes.SelectionRange[][]>;
$resolveCallHierarchyItem(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ICallHierarchyItemDto | undefined>;
$provideCallHierarchyIncomingCalls(handle: number, target: callHierarchy.CallHierarchyItem, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>;
$provideCallHierarchyOutgoingCalls(handle: number, source: callHierarchy.CallHierarchyItem, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>;
$provideCallHierarchyIncomingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>;
$provideCallHierarchyOutgoingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined>;
}

export interface ExtHostQuickOpenShape {
Expand Down
43 changes: 12 additions & 31 deletions src/vs/workbench/api/common/extHostLanguageFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1020,35 +1020,20 @@ class CallHierarchyAdapter {
private readonly _provider: vscode.CallHierarchyItemProvider
) { }

async resolveCallHierarchyItem(resource: URI, pos: IPosition, token: CancellationToken): Promise<undefined | callHierarchy.CallHierarchyItem> {
const document = this._documents.getDocument(resource);
const position = typeConvert.Position.to(pos);

const item = await this._provider.resolveCallHierarchyItem(document, position, token);
if (!item) {
return undefined;
}
return this._fromItem(item);
}

async provideCallsTo(target: callHierarchy.CallHierarchyItem, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined> {
const item = this._cache.get(target._id);
if (!item) {
return undefined;
}
const calls = await this._provider.provideCallHierarchyIncomingCalls(item, token);
async provideCallsTo(uri: URI, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined> {
const doc = this._documents.getDocument(uri);
const pos = typeConvert.Position.to(position);
const calls = await this._provider.provideCallHierarchyIncomingCalls(doc, pos, token);
if (!calls) {
return undefined;
}
return calls.map(call => (<[ICallHierarchyItemDto, IRange[]]>[this._fromItem(call.source), call.sourceRanges.map(typeConvert.Range.from)]));
}

async provideCallsFrom(source: callHierarchy.CallHierarchyItem, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined> {
const item = this._cache.get(source._id);
if (!item) {
return undefined;
}
const calls = await this._provider.provideCallHierarchyOutgoingCalls(item, token);
async provideCallsFrom(uri: URI, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined> {
const doc = this._documents.getDocument(uri);
const pos = typeConvert.Position.to(position);
const calls = await this._provider.provideCallHierarchyOutgoingCalls(doc, pos, token);
if (!calls) {
return undefined;
}
Expand Down Expand Up @@ -1502,16 +1487,12 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
return this._createDisposable(handle);
}

$resolveCallHierarchyItem(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ICallHierarchyItemDto | undefined> {
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.resolveCallHierarchyItem(URI.revive(resource), position, token), undefined);
}

$provideCallHierarchyIncomingCalls(handle: number, target: callHierarchy.CallHierarchyItem, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined> {
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsTo(target, token), undefined);
$provideCallHierarchyIncomingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined> {
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsTo(URI.revive(resource), position, token), undefined);
}

$provideCallHierarchyOutgoingCalls(handle: number, source: callHierarchy.CallHierarchyItem, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined> {
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsFrom(source, token), undefined);
$provideCallHierarchyOutgoingCalls(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<[ICallHierarchyItemDto, IRange[]][] | undefined> {
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsFrom(URI.revive(resource), position, token), undefined);
}

// --- configuration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { PeekContext } from 'vs/editor/contrib/referenceSearch/peekViewWidget';
import { CallHierarchyRoot } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchyTree';

const _ctxHasCompletionItemProvider = new RawContextKey<boolean>('editorHasCallHierarchyProvider', false);
const _ctxCallHierarchyVisible = new RawContextKey<boolean>('callHierarchyVisible', false);
Expand Down Expand Up @@ -93,16 +94,12 @@ class CallHierarchyController extends Disposable implements IEditorContribution
this._sessionDispose.push({ dispose() { cancel.cancel(); } });
this._sessionDispose.push(widget);

Promise.resolve(provider.resolveCallHierarchyItem(model, position, cancel.token)).then(item => {
if (cancel.token.isCancellationRequested) {
return;
}
if (!item) {
widget.showMessage(localize('no.item', "No results"));
return;
}
widget.showItem(item);
});
const root = CallHierarchyRoot.fromEditor(this._editor);
if (root) {
widget.showItem(root);
} else {
widget.showMessage(localize('no.item', "No results"));
}
}

endCallHierarchy(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
private _parent!: HTMLElement;
private _message!: HTMLElement;
private _splitView!: SplitView;
private _tree!: WorkbenchAsyncDataTree<CallHierarchyItem, callHTree.Call, FuzzyScore>;
private _tree!: WorkbenchAsyncDataTree<callHTree.CallHierarchyRoot, callHTree.Call, FuzzyScore>;
private _treeViewStates = new Map<CallHierarchyDirection, IAsyncDataTreeViewState>();
private _editor!: EmbeddedCodeEditorWidget;
private _dim!: Dimension;
Expand Down Expand Up @@ -204,7 +204,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
treeContainer,
new callHTree.VirtualDelegate(),
[this._instantiationService.createInstance(callHTree.CallRenderer)],
new callHTree.SingleDirectionDataSource(this._provider, () => this._direction),
this._instantiationService.createInstance(callHTree.DataSource, this._provider, () => this._direction),
options
);

Expand Down Expand Up @@ -292,7 +292,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
}
node = parent;
}
this.setTitle(this._tree.getInput()!.name, names.join(' → '));
this.setTitle(this._tree.getInput()!.word, names.join(' → '));
}
}));

Expand Down Expand Up @@ -355,7 +355,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
this._message.focus();
}

async showItem(item: CallHierarchyItem): Promise<void> {
async showItem(item: callHTree.CallHierarchyRoot): Promise<void> {

this._show();
const viewState = this._treeViewStates.get(this._direction);
Expand All @@ -367,8 +367,8 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
if (!(firstChild instanceof callHTree.Call)) {
//
this.showMessage(this._direction === CallHierarchyDirection.CallsFrom
? localize('empt.callsFrom', "No calls from '{0}'", item.name)
: localize('empt.callsTo', "No calls to '{0}'", item.name));
? localize('empt.callsFrom', "No calls from '{0}'", item.word)
: localize('empt.callsTo', "No calls to '{0}'", item.word));

} else {
this._parent.dataset['state'] = State.Data;
Expand Down
67 changes: 50 additions & 17 deletions src/vs/workbench/contrib/callHierarchy/browser/callHierarchyTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
import { symbolKindToCssClass, Location } from 'vs/editor/common/modes';
import { hash } from 'vs/base/common/hash';
import { onUnexpectedExternalError } from 'vs/base/common/errors';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { Range } from 'vs/editor/common/core/range';
import { ITextModel } from 'vs/editor/common/model';
import { IPosition } from 'vs/editor/common/core/position';
import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';

export class Call {
constructor(
Expand All @@ -21,61 +26,89 @@ export class Call {
) { }
}

export class SingleDirectionDataSource implements IAsyncDataSource<CallHierarchyItem, Call> {
export class CallHierarchyRoot {

static fromEditor(editor: IActiveCodeEditor): CallHierarchyRoot | undefined {
const model = editor.getModel();
const position = editor.getPosition();
const wordInfo = model.getWordAtPosition(position);
return wordInfo
? new CallHierarchyRoot(model, position, wordInfo.word)
: undefined;
}

constructor(
readonly model: ITextModel,
readonly position: IPosition,
readonly word: string
) { }
}

export class DataSource implements IAsyncDataSource<CallHierarchyRoot, Call> {

constructor(
public provider: CallHierarchyProvider,
public getDirection: () => CallHierarchyDirection
public getDirection: () => CallHierarchyDirection,
@ITextModelService private readonly _modelService: ITextModelService,
) { }

hasChildren(): boolean {
return true;
}

async getChildren(element: CallHierarchyItem | Call): Promise<Call[]> {
if (element instanceof Call) {
const results: Call[] = [];
async getChildren(element: CallHierarchyRoot | Call): Promise<Call[]> {

const results: Call[] = [];

if (element instanceof CallHierarchyRoot) {
if (this.getDirection() === CallHierarchyDirection.CallsFrom) {
await this._getCallsFrom(element, results);
await this._getCallsFrom(element.model, element.position, results);
} else {
await this._getCallsTo(element, results);
await this._getCallsTo(element.model, element.position, results);
}
return results;
} else {
// 'root'
return [new Call(element, [], undefined)];
const reference = await this._modelService.createModelReference(element.item.uri);
const position = Range.lift(element.item.selectionRange).getStartPosition();
if (this.getDirection() === CallHierarchyDirection.CallsFrom) {
await this._getCallsFrom(reference.object.textEditorModel, position, results, element);
} else {
await this._getCallsTo(reference.object.textEditorModel, position, results, element);
}
reference.dispose();
}

return results;
}

private async _getCallsFrom(source: Call, bucket: Call[]): Promise<void> {
private async _getCallsFrom(model: ITextModel, position: IPosition, bucket: Call[], parent?: Call): Promise<void> {
try {
const callsFrom = await this.provider.provideOutgoingCalls(source.item, CancellationToken.None);
const callsFrom = await this.provider.provideOutgoingCalls(model, position, CancellationToken.None);
if (!callsFrom) {
return;
}
for (const callFrom of callsFrom) {
bucket.push(new Call(
callFrom.target,
callFrom.sourceRanges.map(range => ({ range, uri: source.item.uri })),
source
callFrom.sourceRanges.map(range => ({ range, uri: model.uri })),
parent
));
}
} catch (e) {
onUnexpectedExternalError(e);
}
}

private async _getCallsTo(target: Call, bucket: Call[]): Promise<void> {
private async _getCallsTo(model: ITextModel, position: IPosition, bucket: Call[], parent?: Call): Promise<void> {
try {
const callsTo = await this.provider.provideIncomingCalls(target.item, CancellationToken.None);
const callsTo = await this.provider.provideIncomingCalls(model, position, CancellationToken.None);
if (!callsTo) {
return;
}
for (const callTo of callsTo) {
bucket.push(new Call(
callTo.source,
callTo.sourceRanges.map(range => ({ range, uri: callTo.source.uri })),
target
parent
));
}
} catch (e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,9 @@ export interface OutgoingCall {

export interface CallHierarchyProvider {

resolveCallHierarchyItem(document: ITextModel, postion: IPosition, token: CancellationToken): ProviderResult<CallHierarchyItem>;
provideIncomingCalls(document: ITextModel, postion: IPosition, token: CancellationToken): ProviderResult<IncomingCall[]>;

provideIncomingCalls(target: CallHierarchyItem, token: CancellationToken): ProviderResult<IncomingCall[]>;

provideOutgoingCalls(source: CallHierarchyItem, token: CancellationToken): ProviderResult<OutgoingCall[]>;
provideOutgoingCalls(document: ITextModel, postion: IPosition, token: CancellationToken): ProviderResult<OutgoingCall[]>;
}

export const CallHierarchyProviderRegistry = new LanguageFeatureRegistry<CallHierarchyProvider>();
Expand Down

0 comments on commit 4aa06c2

Please sign in to comment.