Skip to content

Commit

Permalink
Proposal for call hierarchy
Browse files Browse the repository at this point in the history
add new `textDocument/calls` request.

LSP issue: language-server-protocol#468

Signed-off-by: Alex Tugarev <alex.tugarev@typefox.io>
  • Loading branch information
AlexTugarev committed Oct 5, 2018
1 parent d168533 commit 1cec34b
Show file tree
Hide file tree
Showing 5 changed files with 302 additions and 0 deletions.
62 changes: 62 additions & 0 deletions client/src/calls.proposed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) TypeFox. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
'use strict';

import { Disposable } from 'vscode';
import {
TextDocumentRegistrationOptions, ClientCapabilities, ServerCapabilities, DocumentSelector, Proposed
} from 'vscode-languageserver-protocol';

import * as UUID from './utils/uuid';
import * as Is from './utils/is';
import { TextDocumentFeature, BaseLanguageClient } from './client';

export class CallsFeature extends TextDocumentFeature<TextDocumentRegistrationOptions> {

constructor(client: BaseLanguageClient) {
super(client, Proposed.CallsRequest.type);
}

fillClientCapabilities(capabilities: ClientCapabilities): void {
if (!!capabilities.textDocument) {
capabilities.textDocument = {};
}
let callsClientCapabilities = capabilities as Proposed.CallsClientCapabilities;
callsClientCapabilities.textDocument!.calls = {
dynamicRegistration: true
};
}

initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector): void {
let callsServerCapabilities = capabilities as Proposed.CallsServerCapabilities;
if (!callsServerCapabilities.callsProvider) {
return;
}
if (callsServerCapabilities.callsProvider === true) {
if (!documentSelector) {
return;
}
this.register(this.messages, {
id: UUID.generateUuid(),
registerOptions: Object.assign({}, { documentSelector: documentSelector })
});
} else {
const implCapabilities = callsServerCapabilities.callsProvider;
const id = Is.string(implCapabilities.id) && implCapabilities.id.length > 0 ? implCapabilities.id : UUID.generateUuid();
const selector = implCapabilities.documentSelector || documentSelector;
if (selector) {
this.register(this.messages, {
id,
registerOptions: Object.assign({}, { documentSelector: selector })
});
}
}
}

protected registerLanguageProvider(_options: TextDocumentRegistrationOptions): Disposable {
return new Disposable(() => { });
}

}
5 changes: 5 additions & 0 deletions client/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,9 +504,14 @@ export class SettingMonitor {

// Exporting proposed protocol.

import * as calls from './calls.proposed';

export namespace ProposedFeatures {
export const CallsFeature = calls.CallsFeature;

export function createAll(_client: BaseLanguageClient): (StaticFeature | DynamicFeature<any>)[] {
let result: (StaticFeature | DynamicFeature<any>)[] = [];
result.push(new CallsFeature(_client));
return result;
}
}
14 changes: 14 additions & 0 deletions protocol/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,21 @@ export * from './protocol';

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

import * as calls from './protocol.calls.proposed';

export namespace Proposed {
export type CallsClientCapabilities = calls.CallsClientCapabilities;
export type CallsServerCapabilities = calls.CallsServerCapabilities;

export namespace CallsRequest {
export const type = calls.CallsRequest.type;
export type HandlerSignature = calls.CallsRequest.HandlerSignature;
}

export type CallsParams = calls.CallsParams;
export type CallDirection = calls.CallDirection;
export type CallsResult = calls.CallsResult;
export type Call = calls.Call;
}

export interface ProtocolConnection {
Expand Down
110 changes: 110 additions & 0 deletions protocol/src/protocol.calls.proposed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@

#### Calls

The LSP provides retrieving the call hierachy information with the following request.

_Client Capabilities_:

```ts
CallsClientCapabilities {
/**
* The text document client capabilities
*/
textDocument?: {
/**
* Capabilities specific to the `textDocument/calls`
*/
calls?: {
/**
* Whether implementation supports dynamic registration. If this is set to `true`
* the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
* return value for the corresponding server capability as well.
*/
dynamicRegistration?: boolean;
};
}
```
_Server Capabilities_:
```ts
CallsServerCapabilities {
/**
* The server provides Call Hierarchy support.
*/
callsProvider?: boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions);
}
```
##### Calls Request
_Request_:
The `textDocument/calls` request is sent from the client to the server to resolve the callers or callees of a symbol at a given text document position. Returns the callers or callees corresponding to the requested direction.
* method: ‘textDocument/calls’
* params: `CallsParams` defined as follows:
```ts
export interface CallsParams extends TextDocumentPositionParams {
/**
* Outgoing direction for callees.
* The default is incoming for callers.
*/
direction?: CallDirection;
}

export enum CallDirection {
/**
* Incoming calls aka. callers
*/
Incoming = "incoming",
/**
* Outgoing calls aka. callees
*/
Outgoing = "outgoing",
}
```
_Response_:
The server will send a `CallsResult` object containing a `symbol` of a definition which it finds for given text document position. The symbol will be undefined, if no such definition is found.
The result object contains a list of `Call`s which include more information about the call site. It also contains a symbol location of the caller or collee which can be used by clients to make a request for the next level of the call hierarchy.
* result: `CallsResult` defined as follows:
```ts
export interface CallsResult {
/**
* The symbol of a definition for which the request was made.
*
* If no definition is found at a given text document position, the symbol is undefined.
*/
symbol?: DocumentSymbol;
/**
* List of calls.
*/
calls: Call[];
}

export interface Call {
/**
* Direction of the call.
*/
direction: CallDirection;
/**
* Actual location of a call to a definition.
*/
callLocation: Location;
/**
* Symbol refered to by this call. For outgoing calls this is a callee,
* otherwise a caller.
*/
symbol: DocumentSymbol;
/**
* Location of the symbol, which can be used for a follow-up request to obtain the next level of calls.
*/
symbolLocation: Location;
}
```
111 changes: 111 additions & 0 deletions protocol/src/protocol.calls.proposed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) TypeFox and others. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
'use strict';

import { RequestType, RequestHandler } from 'vscode-jsonrpc';
import { DocumentSymbol, Location } from 'vscode-languageserver-types';
import { TextDocumentRegistrationOptions, StaticRegistrationOptions, TextDocumentPositionParams } from './protocol';

export interface CallsClientCapabilities {
/**
* The text document client capabilities
*/
textDocument?: {
/**
* Capabilities specific to the `textDocument/calls`
*/
calls?: {
/**
* Whether implementation supports dynamic registration. If this is set to `true`
* the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
* return value for the corresponding server capability as well.
*/
dynamicRegistration?: boolean;
};
}
}

export interface CallsServerCapabilities {
/**
* The server provides Call Hierarchy support.
*/
callsProvider?: boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions);
}

/**
* A request to resolve all calls at a given text document position of a symbol definition or a call the same.
* The request's parameter is of type [CallsParams](#CallsParams), the response is of type [CallsResult](#CallsResult) or a
* Thenable that resolves to such.
*
*
*/
export namespace CallsRequest {
export const type = new RequestType<CallsParams, CallsResult, void, TextDocumentRegistrationOptions>('textDocument/calls');
export type HandlerSignature = RequestHandler<CallsParams, CallsResult | null, void>;
}

/**
* The parameters of a `textDocument/calls` request.
*/
export interface CallsParams extends TextDocumentPositionParams {
/**
* Outgoing direction for callees.
* The default is incoming for callers.
*/
direction?: CallDirection;
}

/**
* Enum of call direction kinds
*/
export enum CallDirection {
/**
* Incoming calls aka. callers
*/
Incoming = "incoming",
/**
* Outgoing calls aka. callees
*/
Outgoing = "outgoing",
}

/**
* The result of a `textDocument/calls` request.
*/
export interface CallsResult {
/**
* The symbol of a definition for which the request was made.
*
* If no definition is found at a given text document position, the symbol is undefined.
*/
symbol?: DocumentSymbol;
/**
* List of calls.
*/
calls: Call[];
}

/**
* Represents a directed call.
*/
export interface Call {
/**
* Direction of the call.
*/
direction: CallDirection;
/**
* Actual location of a call to a definition.
*/
callLocation: Location;
/**
* Symbol refered to by this call. For outgoing calls this is a callee,
* otherwise a caller.
*/
symbol: DocumentSymbol;
/**
* Location of the symbol, which can be used for a follow-up request to obtain the next level of calls.
*/
symbolLocation: Location;
}

0 comments on commit 1cec34b

Please sign in to comment.