Skip to content

Commit 9a41301

Browse files
committed
Proposal for call hierarchy
add new `textDocument/calls` request. LSP issue: language-server-protocol#468 Signed-off-by: Alex Tugarev <alex.tugarev@typefox.io>
1 parent 1631753 commit 9a41301

File tree

5 files changed

+338
-0
lines changed

5 files changed

+338
-0
lines changed

client/src/callHierarchy.proposed.ts

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/* --------------------------------------------------------------------------------------------
2+
* Copyright (c) TypeFox. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
* ------------------------------------------------------------------------------------------ */
5+
'use strict';
6+
7+
import { Disposable } from 'vscode';
8+
import {
9+
TextDocumentRegistrationOptions, ClientCapabilities, ServerCapabilities, DocumentSelector, Proposed
10+
} from 'vscode-languageserver-protocol';
11+
12+
import * as UUID from './utils/uuid';
13+
import * as Is from './utils/is';
14+
import { TextDocumentFeature, BaseLanguageClient } from './client';
15+
16+
export class CallHierarchyFeature extends TextDocumentFeature<TextDocumentRegistrationOptions> {
17+
18+
constructor(client: BaseLanguageClient) {
19+
super(client, Proposed.CallHierarchyRequest.type);
20+
}
21+
22+
fillClientCapabilities(capabilities: ClientCapabilities): void {
23+
if (!!capabilities.textDocument) {
24+
capabilities.textDocument = {};
25+
}
26+
let callHierarchyClientCapabilities = capabilities as Proposed.CallHierarchyClientCapabilities;
27+
callHierarchyClientCapabilities.textDocument!.callHierarchy = {
28+
dynamicRegistration: true
29+
};
30+
}
31+
32+
initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void {
33+
let callHierarchyServerCapabilities = capabilities as Proposed.CallHierarchyServerCapabilities;
34+
if (!callHierarchyServerCapabilities.callHierarchyProvider) {
35+
return;
36+
}
37+
if (callHierarchyServerCapabilities.callHierarchyProvider === true) {
38+
if (!documentSelector) {
39+
return;
40+
}
41+
this.register(this.messages, {
42+
id: UUID.generateUuid(),
43+
registerOptions: Object.assign({}, { documentSelector: documentSelector })
44+
});
45+
} else {
46+
const implCapabilities = callHierarchyServerCapabilities.callHierarchyProvider;
47+
const id = Is.string(implCapabilities.id) && implCapabilities.id.length > 0 ? implCapabilities.id : UUID.generateUuid();
48+
const selector = implCapabilities.documentSelector || documentSelector;
49+
if (selector) {
50+
this.register(this.messages, {
51+
id,
52+
registerOptions: Object.assign({}, { documentSelector: selector })
53+
});
54+
}
55+
}
56+
}
57+
58+
protected registerLanguageProvider(_options: TextDocumentRegistrationOptions): Disposable {
59+
return new Disposable(() => { });
60+
}
61+
62+
}

client/src/main.ts

+5
Original file line numberDiff line numberDiff line change
@@ -506,9 +506,14 @@ export class SettingMonitor {
506506

507507
// Exporting proposed protocol.
508508

509+
import * as callHierarchy from './callHierarchy.proposed';
510+
509511
export namespace ProposedFeatures {
512+
export const CallHierarchyFeature = callHierarchy.CallHierarchyFeature;
513+
510514
export function createAll(_client: BaseLanguageClient): (StaticFeature | DynamicFeature<any>)[] {
511515
let result: (StaticFeature | DynamicFeature<any>)[] = [];
516+
result.push(new CallHierarchyFeature(_client));
512517
return result;
513518
}
514519
}

protocol/src/main.ts

+13
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,20 @@ export * from './protocol';
3535

3636
export { FoldingRangeParams as FoldingRangeRequestParam } from './protocol'; // for backward compatibility
3737

38+
import * as callHierarchy from './protocol.callHierarchy.proposed';
39+
3840
export namespace Proposed {
41+
export type CallHierarchyClientCapabilities = callHierarchy.CallHierarchyClientCapabilities;
42+
export type CallHierarchyServerCapabilities = callHierarchy.CallHierarchyServerCapabilities;
43+
44+
export namespace CallHierarchyRequest {
45+
export const type = callHierarchy.CallHierarchyRequest.type;
46+
export type HandlerSignature = callHierarchy.CallHierarchyRequest.HandlerSignature;
47+
}
48+
49+
export type CallHierarchyParams = callHierarchy.CallHierarchyParams;
50+
export type ResolveCallHierarchyItemParams = callHierarchy.ResolveCallHierarchyItemParams;
51+
export type CallHierarchyItem = callHierarchy.CallHierarchyItem;
3952
}
4053

4154
export interface ProtocolConnection {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
2+
#### Call Hierarchy
3+
4+
The LSP provides retrieving the call hierachy information with the following request.
5+
6+
_Client Capabilities_:
7+
8+
```ts
9+
CallHierarchyClientCapabilities {
10+
/**
11+
* The text document client capabilities
12+
*/
13+
textDocument?: {
14+
/**
15+
* Capabilities specific to the `textDocument/callHierarchy`
16+
*/
17+
callHierarchy?: {
18+
/**
19+
* Whether implementation supports dynamic registration. If this is set to `true`
20+
* the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
21+
* return value for the corresponding server capability as well.
22+
*/
23+
dynamicRegistration?: boolean;
24+
};
25+
}
26+
```
27+
28+
_Server Capabilities_:
29+
30+
```ts
31+
CallHierarchyServerCapabilities {
32+
/**
33+
* The server provides Call Hierarchy support.
34+
*/
35+
callHierarchyProvider?: boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions);
36+
}
37+
```
38+
39+
##### Call Hierarchy Request
40+
41+
_Request_:
42+
43+
The `textDocument/callHierarchy` request is sent from the client to the server to request the call hierarchy for a symbol at the given text document position. Subsequent requests include unresolved items from the previous responses.
44+
45+
Returns a call hierarchy item for the requested call direction.
46+
47+
* method: ‘textDocument/callHierarchy'
48+
* params: `CallHierarchyParams | ResolveCallHierarchyItemParams` defined as follows:
49+
50+
```ts
51+
export interface CallHierarchyParams extends TextDocumentPositionParams {
52+
resolve?: number;
53+
direction?: 'incoming' | 'outgoing';
54+
}
55+
56+
export interface ResolveCallHierarchyItemParams {
57+
item: CallHierarchyItem;
58+
resolve: number;
59+
direction: 'incoming' | 'outgoing';
60+
}
61+
```
62+
63+
_Response_:
64+
65+
The server will send a `CallHierarchyItem` object containing the information about the targeted symbol. The item will be undefined, if no such symbol is found.
66+
67+
The item is _unresolved_ if the lists of callers and callees are undefined. Unresolved items can be resolved via `textDocument/callHierarchy` requests.
68+
69+
The resolved item includes callers or callees of type `CallHierarchyItem`. Those objects provide the actual locations of the calls.
70+
71+
* result: `CallHierarchyItem` defined as follows:
72+
73+
```ts
74+
export interface CallHierarchyItem {
75+
/**
76+
* The name of the symbol targeted by the call hierarchy request.
77+
*/
78+
name: string;
79+
/**
80+
* More detail for this symbol, e.g the signature of a function.
81+
*/
82+
detail?: string;
83+
/**
84+
* The kind of this symbol.
85+
*/
86+
kind: SymbolKind;
87+
/**
88+
* URI of the document containing the symbol.
89+
*/
90+
uri: string;
91+
/**
92+
* The range enclosing this symbol not including leading/trailing whitespace but everything else
93+
* like comments. This information is typically used to determine if the the clients cursor is
94+
* inside the symbol to reveal in the symbol in the UI.
95+
*/
96+
range: Range;
97+
/**
98+
* The range that should be selected and revealed when this symbol is being picked, e.g the name of a function.
99+
* Must be contained by the the `range`.
100+
*/
101+
selectionRange: Range;
102+
103+
/**
104+
* The actual location of the call.
105+
*
106+
* Must be defined in resolved callers/callees.
107+
*/
108+
callLocation?: Location;
109+
110+
/**
111+
* List of incoming calls.
112+
*
113+
* *Note*: The items is _unresolved_ if `callers` and `callees` is undefined.
114+
*/
115+
callers?: CallHierarchyItem[];
116+
/**
117+
* List of outgoing calls.
118+
*
119+
* *Note*: The items is _unresolved_ if `callers` and `callees` is undefined.
120+
*/
121+
callees?: CallHierarchyItem[];
122+
}
123+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/* --------------------------------------------------------------------------------------------
2+
* Copyright (c) TypeFox and others. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
* ------------------------------------------------------------------------------------------ */
5+
'use strict';
6+
7+
import { RequestType, RequestHandler } from 'vscode-jsonrpc';
8+
import { Location, SymbolKind, Range } from 'vscode-languageserver-types';
9+
import { TextDocumentRegistrationOptions, StaticRegistrationOptions, TextDocumentPositionParams } from './protocol';
10+
11+
export interface CallHierarchyClientCapabilities {
12+
/**
13+
* The text document client capabilities
14+
*/
15+
textDocument?: {
16+
/**
17+
* Capabilities specific to the `textDocument/callHierarchy`
18+
*/
19+
callHierarchy?: {
20+
/**
21+
* Whether implementation supports dynamic registration. If this is set to `true`
22+
* the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
23+
* return value for the corresponding server capability as well.
24+
*/
25+
dynamicRegistration?: boolean;
26+
};
27+
}
28+
}
29+
30+
export interface CallHierarchyServerCapabilities {
31+
/**
32+
* The server provides Call Hierarchy support.
33+
*/
34+
callHierarchyProvider?: boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions);
35+
}
36+
37+
/**
38+
* Request to request the call hierarchy at a given text document position.
39+
*
40+
* The request's parameter for the first request is of type [CallHierarchyParams](#CallHierarchyParams). The request's
41+
* parameter for the subsequent requests is of type [ResolveCallHierarchyItemParams](#ResolveCallHierarchyItemParams).
42+
*
43+
* The response is of type [CallHierarchyItem](#CallHierarchyItem) or a Thenable that resolves to such.
44+
*/
45+
export namespace CallHierarchyRequest {
46+
export const type = new RequestType<CallHierarchyParams | ResolveCallHierarchyItemParams, CallHierarchyItem, void, TextDocumentRegistrationOptions>('textDocument/callHierarchy');
47+
export type HandlerSignature = RequestHandler<CallHierarchyParams | ResolveCallHierarchyItemParams, CallHierarchyItem | null, void>;
48+
}
49+
50+
/**
51+
* The parameters of a `textDocument/callHierarchy` request.
52+
*/
53+
export interface CallHierarchyParams extends TextDocumentPositionParams {
54+
/**
55+
* The number of levels to resolve.
56+
*/
57+
resolve?: number;
58+
/**
59+
* Outgoing direction for callees.
60+
* The default is incoming for callers.
61+
*/
62+
direction?: 'incoming' | 'outgoing';
63+
}
64+
65+
/**
66+
* The parameters of a `textDocument/callHierarchy` request.
67+
*/
68+
export interface ResolveCallHierarchyItemParams {
69+
/**
70+
* Unresolved item.
71+
*/
72+
item: CallHierarchyItem;
73+
/**
74+
* The number of levels to resolve.
75+
*/
76+
resolve: number;
77+
/**
78+
* Outgoing direction for callees.
79+
* The default is incoming for callers.
80+
*/
81+
direction: 'incoming' | 'outgoing';
82+
}
83+
84+
/**
85+
* The result of a `textDocument/callHierarchy` request.
86+
*/
87+
export interface CallHierarchyItem {
88+
/**
89+
* The name of the symbol targeted by the call hierarchy request.
90+
*/
91+
name: string;
92+
/**
93+
* More detail for this symbol, e.g the signature of a function.
94+
*/
95+
detail?: string;
96+
/**
97+
* The kind of this symbol.
98+
*/
99+
kind: SymbolKind;
100+
/**
101+
* URI of the document containing the symbol.
102+
*/
103+
uri: string;
104+
/**
105+
* The range enclosing this symbol not including leading/trailing whitespace but everything else
106+
* like comments. This information is typically used to determine if the the clients cursor is
107+
* inside the symbol to reveal in the symbol in the UI.
108+
*/
109+
range: Range;
110+
/**
111+
* The range that should be selected and revealed when this symbol is being picked, e.g the name of a function.
112+
* Must be contained by the the `range`.
113+
*/
114+
selectionRange: Range;
115+
116+
/**
117+
* The actual location of the call.
118+
*
119+
* **Must be defined** in resolved callers/callees.
120+
*/
121+
callLocation?: Location;
122+
123+
/**
124+
* List of incoming calls.
125+
*
126+
* *Note*: The items is _unresolved_ if `callers` and `callees` is undefined.
127+
*/
128+
callers?: CallHierarchyItem[];
129+
/**
130+
* List of outgoing calls.
131+
*
132+
* *Note*: The items is _unresolved_ if `callers` and `callees` is undefined.
133+
*/
134+
callees?: CallHierarchyItem[];
135+
}

0 commit comments

Comments
 (0)