Skip to content

Commit 15f4b58

Browse files
committed
Merge pull request #2966 from Microsoft/getTypeDefinitionAtPosition
Get type definition at position
2 parents 11166d2 + 7fc6142 commit 15f4b58

18 files changed

+405
-66
lines changed

src/harness/fourslash.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,28 @@ module FourSlash {
15701570
this.currentCaretPosition = definition.textSpan.start;
15711571
}
15721572

1573+
public goToTypeDefinition(definitionIndex: number) {
1574+
if (definitionIndex === 0) {
1575+
this.scenarioActions.push('<GoToTypeDefinition />');
1576+
}
1577+
else {
1578+
this.taoInvalidReason = 'GoToTypeDefinition not supported for non-zero definition indices';
1579+
}
1580+
1581+
var definitions = this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
1582+
if (!definitions || !definitions.length) {
1583+
this.raiseError('goToTypeDefinition failed - expected to at least one definition location but got 0');
1584+
}
1585+
1586+
if (definitionIndex >= definitions.length) {
1587+
this.raiseError('goToTypeDefinition failed - definitionIndex value (' + definitionIndex + ') exceeds definition list size (' + definitions.length + ')');
1588+
}
1589+
1590+
var definition = definitions[definitionIndex];
1591+
this.openFile(definition.fileName);
1592+
this.currentCaretPosition = definition.textSpan.start;
1593+
}
1594+
15731595
public verifyDefinitionLocationExists(negative: boolean) {
15741596
this.taoInvalidReason = 'verifyDefinitionLocationExists NYI';
15751597

@@ -1589,8 +1611,18 @@ module FourSlash {
15891611
var assertFn = negative ? assert.notEqual : assert.equal;
15901612

15911613
var definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
1614+
var actualCount = definitions && definitions.length || 0;
1615+
1616+
assertFn(actualCount, expectedCount, this.messageAtLastKnownMarker("Definitions Count"));
1617+
}
1618+
1619+
public verifyTypeDefinitionsCount(negative: boolean, expectedCount: number) {
1620+
var assertFn = negative ? assert.notEqual : assert.equal;
1621+
1622+
var definitions = this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
1623+
var actualCount = definitions && definitions.length || 0;
15921624

1593-
assertFn(definitions.length, expectedCount, this.messageAtLastKnownMarker("Definitions Count"));
1625+
assertFn(actualCount, expectedCount, this.messageAtLastKnownMarker("Type definitions Count"));
15941626
}
15951627

15961628
public verifyDefinitionsName(negative: boolean, expectedName: string, expectedContainerName: string) {

src/harness/harnessLanguageService.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,9 @@ module Harness.LanguageService {
342342
getDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[] {
343343
return unwrapJSONCallResult(this.shim.getDefinitionAtPosition(fileName, position));
344344
}
345+
getTypeDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[]{
346+
return unwrapJSONCallResult(this.shim.getTypeDefinitionAtPosition(fileName, position));
347+
}
345348
getReferencesAtPosition(fileName: string, position: number): ts.ReferenceEntry[] {
346349
return unwrapJSONCallResult(this.shim.getReferencesAtPosition(fileName, position));
347350
}

src/server/client.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,32 @@ module ts.server {
300300
});
301301
}
302302

303+
getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] {
304+
var lineOffset = this.positionToOneBasedLineOffset(fileName, position);
305+
var args: protocol.FileLocationRequestArgs = {
306+
file: fileName,
307+
line: lineOffset.line,
308+
offset: lineOffset.offset,
309+
};
310+
311+
var request = this.processRequest<protocol.TypeDefinitionRequest>(CommandNames.TypeDefinition, args);
312+
var response = this.processResponse<protocol.TypeDefinitionResponse>(request);
313+
314+
return response.body.map(entry => {
315+
var fileName = entry.file;
316+
var start = this.lineOffsetToPosition(fileName, entry.start);
317+
var end = this.lineOffsetToPosition(fileName, entry.end);
318+
return {
319+
containerKind: "",
320+
containerName: "",
321+
fileName: fileName,
322+
textSpan: ts.createTextSpanFromBounds(start, end),
323+
kind: "",
324+
name: ""
325+
};
326+
});
327+
}
328+
303329
findReferences(fileName: string, position: number): ReferencedSymbol[]{
304330
// Not yet implemented.
305331
return [];

src/server/editorServices.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,7 @@ module ts.server {
773773
findConfigFile(searchPath: string): string {
774774
while (true) {
775775
var fileName = ts.combinePaths(searchPath, "tsconfig.json");
776-
if (sys.fileExists(fileName)) {
776+
if (this.host.fileExists(fileName)) {
777777
return fileName;
778778
}
779779
var parentPath = ts.getDirectoryPath(searchPath);
@@ -923,7 +923,7 @@ module ts.server {
923923
var proj = this.createProject(configFilename, projectOptions);
924924
for (var i = 0, len = parsedCommandLine.fileNames.length; i < len; i++) {
925925
var rootFilename = parsedCommandLine.fileNames[i];
926-
if (ts.sys.fileExists(rootFilename)) {
926+
if (this.host.fileExists(rootFilename)) {
927927
var info = this.openFile(rootFilename, clientFileName == rootFilename);
928928
proj.addRoot(info);
929929
}

src/server/protocol.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ declare module ts.server.protocol {
125125
export interface DefinitionRequest extends FileLocationRequest {
126126
}
127127

128+
/**
129+
* Go to type request; value of command field is
130+
* "typeDefinition". Return response giving the file locations that
131+
* define the type for the symbol found in file at location line, col.
132+
*/
133+
export interface TypeDefinitionRequest extends FileLocationRequest {
134+
}
135+
128136
/**
129137
* Location in source code expressed as (one-based) line and character offset.
130138
*/
@@ -165,6 +173,13 @@ declare module ts.server.protocol {
165173
body?: FileSpan[];
166174
}
167175

176+
/**
177+
* Definition response message. Gives text range for definition.
178+
*/
179+
export interface TypeDefinitionResponse extends Response {
180+
body?: FileSpan[];
181+
}
182+
168183
/**
169184
* Get occurrences request; value of command field is
170185
* "occurrences". Return response giving spans that are relevant

src/server/session.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ module ts.server {
9797
export var Rename = "rename";
9898
export var Saveto = "saveto";
9999
export var SignatureHelp = "signatureHelp";
100+
export var TypeDefinition = "typeDefinition";
100101
export var Unknown = "unknown";
101102
}
102103

@@ -285,7 +286,29 @@ module ts.server {
285286
}));
286287
}
287288

288-
getOccurrences(line: number, offset: number, fileName: string): protocol.OccurrencesResponseItem[] {
289+
getTypeDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] {
290+
var file = ts.normalizePath(fileName);
291+
var project = this.projectService.getProjectForFile(file);
292+
if (!project) {
293+
throw Errors.NoProject;
294+
}
295+
296+
var compilerService = project.compilerService;
297+
var position = compilerService.host.lineOffsetToPosition(file, line, offset);
298+
299+
var definitions = compilerService.languageService.getTypeDefinitionAtPosition(file, position);
300+
if (!definitions) {
301+
return undefined;
302+
}
303+
304+
return definitions.map(def => ({
305+
file: def.fileName,
306+
start: compilerService.host.positionToLineOffset(def.fileName, def.textSpan.start),
307+
end: compilerService.host.positionToLineOffset(def.fileName, ts.textSpanEnd(def.textSpan))
308+
}));
309+
}
310+
311+
getOccurrences(line: number, offset: number, fileName: string): protocol.OccurrencesResponseItem[]{
289312
fileName = ts.normalizePath(fileName);
290313
let project = this.projectService.getProjectForFile(fileName);
291314

@@ -817,6 +840,11 @@ module ts.server {
817840
response = this.getDefinition(defArgs.line, defArgs.offset, defArgs.file);
818841
break;
819842
}
843+
case CommandNames.TypeDefinition: {
844+
var defArgs = <protocol.FileLocationRequestArgs>request.arguments;
845+
response = this.getTypeDefinition(defArgs.line, defArgs.offset, defArgs.file);
846+
break;
847+
}
820848
case CommandNames.References: {
821849
var refArgs = <protocol.FileLocationRequestArgs>request.arguments;
822850
response = this.getReferences(refArgs.line, refArgs.offset, refArgs.file);

0 commit comments

Comments
 (0)