Skip to content
Merged
12 changes: 10 additions & 2 deletions src/harness/fourslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1515,6 +1515,14 @@ module FourSlash {
}
}

public verifyDefinitionsCount(negative: boolean, expectedCount: number) {
var assertFn = negative ? assert.notEqual : assert.equal;

var definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);

assertFn(definitions.length, expectedCount, this.messageAtLastKnownMarker("Definitions Count"));
}

public verifyDefinitionsName(negative: boolean, expectedName: string, expectedContainerName: string) {
this.taoInvalidReason = 'verifyDefinititionsInfo NYI';

Expand All @@ -1523,10 +1531,10 @@ module FourSlash {
var actualDefinitionContainerName = definitions && definitions.length ? definitions[0].containerName : "";
if (negative) {
assert.notEqual(actualDefinitionName, expectedName, this.messageAtLastKnownMarker("Definition Info Name"));
assert.notEqual(actualDefinitionName, expectedName, this.messageAtLastKnownMarker("Definition Info Container Name"));
assert.notEqual(actualDefinitionContainerName, expectedContainerName, this.messageAtLastKnownMarker("Definition Info Container Name"));
} else {
assert.equal(actualDefinitionName, expectedName, this.messageAtLastKnownMarker("Definition Info Name"));
assert.equal(actualDefinitionName, expectedName, this.messageAtLastKnownMarker("Definition Info Container Name"));
assert.equal(actualDefinitionContainerName, expectedContainerName, this.messageAtLastKnownMarker("Definition Info Container Name"));
}
}

Expand Down
120 changes: 60 additions & 60 deletions src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2598,7 +2598,7 @@ module ts {
}

// TODO(drosen): use contextual SemanticMeaning.
function getSymbolKind(symbol: Symbol, typeResolver: TypeChecker, location?: Node): string {
function getSymbolKind(symbol: Symbol, typeResolver: TypeChecker, location: Node): string {
var flags = symbol.getFlags();

if (flags & SymbolFlags.Class) return ScriptElementKind.classElement;
Expand Down Expand Up @@ -3097,62 +3097,6 @@ module ts {

/// Goto definition
function getDefinitionAtPosition(filename: string, position: number): DefinitionInfo[] {
function getDefinitionInfo(node: Node, symbolKind: string, symbolName: string, containerName: string): DefinitionInfo {
return {
fileName: node.getSourceFile().filename,
textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()),
kind: symbolKind,
name: symbolName,
containerKind: undefined,
containerName
};
}

function tryAddSignature(signatureDeclarations: Declaration[], selectConstructors: boolean, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) {
var declarations: Declaration[] = [];
var definition: Declaration;

forEach(signatureDeclarations, d => {
if ((selectConstructors && d.kind === SyntaxKind.Constructor) ||
(!selectConstructors && (d.kind === SyntaxKind.FunctionDeclaration || d.kind === SyntaxKind.MethodDeclaration || d.kind === SyntaxKind.MethodSignature))) {
declarations.push(d);
if ((<FunctionLikeDeclaration>d).body) definition = d;
}
});

if (definition) {
result.push(getDefinitionInfo(definition, symbolKind, symbolName, containerName));
return true;
}
else if (declarations.length) {
result.push(getDefinitionInfo(declarations[declarations.length - 1], symbolKind, symbolName, containerName));
return true;
}

return false;
}

function tryAddConstructSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) {
// Applicable only if we are in a new expression, or we are on a constructor declaration
// and in either case the symbol has a construct signature definition, i.e. class
if (isNewExpressionTarget(location) || location.kind === SyntaxKind.ConstructorKeyword) {
if (symbol.flags & SymbolFlags.Class) {
var classDeclaration = <ClassDeclaration>symbol.getDeclarations()[0];
Debug.assert(classDeclaration && classDeclaration.kind === SyntaxKind.ClassDeclaration);

return tryAddSignature(classDeclaration.members, /*selectConstructors*/ true, symbolKind, symbolName, containerName, result);
}
}
return false;
}

function tryAddCallSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) {
if (isCallExpressionTarget(location) || isNewExpressionTarget(location) || isNameOfFunctionDeclaration(location)) {
return tryAddSignature(symbol.declarations, /*selectConstructors*/ false, symbolKind, symbolName, containerName, result);
}
return false;
}

synchronizeHostData();

filename = normalizeSlashes(filename);
Expand Down Expand Up @@ -3205,7 +3149,7 @@ module ts {
if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
var shorthandSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(symbol.valueDeclaration);
var shorthandDeclarations = shorthandSymbol.getDeclarations();
var shorthandSymbolKind = getSymbolKind(shorthandSymbol, typeInfoResolver);
var shorthandSymbolKind = getSymbolKind(shorthandSymbol, typeInfoResolver, node);
var shorthandSymbolName = typeInfoResolver.symbolToString(shorthandSymbol);
var shorthandContainerName = typeInfoResolver.symbolToString(symbol.parent, node);
forEach(shorthandDeclarations, declaration => {
Expand All @@ -3216,7 +3160,7 @@ module ts {

var declarations = symbol.getDeclarations();
var symbolName = typeInfoResolver.symbolToString(symbol); // Do not get scoped name, just the name of the symbol
var symbolKind = getSymbolKind(symbol, typeInfoResolver);
var symbolKind = getSymbolKind(symbol, typeInfoResolver, node);
var containerSymbol = symbol.parent;
var containerName = containerSymbol ? typeInfoResolver.symbolToString(containerSymbol, node) : "";

Expand All @@ -3229,6 +3173,62 @@ module ts {
}

return result;

function getDefinitionInfo(node: Node, symbolKind: string, symbolName: string, containerName: string): DefinitionInfo {
return {
fileName: node.getSourceFile().filename,
textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()),
kind: symbolKind,
name: symbolName,
containerKind: undefined,
containerName
};
}

function tryAddSignature(signatureDeclarations: Declaration[], selectConstructors: boolean, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) {
var declarations: Declaration[] = [];
var definition: Declaration;

forEach(signatureDeclarations, d => {
if ((selectConstructors && d.kind === SyntaxKind.Constructor) ||
(!selectConstructors && (d.kind === SyntaxKind.FunctionDeclaration || d.kind === SyntaxKind.MethodDeclaration || d.kind === SyntaxKind.MethodSignature))) {
declarations.push(d);
if ((<FunctionLikeDeclaration>d).body) definition = d;
}
});

if (definition) {
result.push(getDefinitionInfo(definition, symbolKind, symbolName, containerName));
return true;
}
else if (declarations.length) {
result.push(getDefinitionInfo(declarations[declarations.length - 1], symbolKind, symbolName, containerName));
return true;
}

return false;
}

function tryAddConstructSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) {
// Applicable only if we are in a new expression, or we are on a constructor declaration
// and in either case the symbol has a construct signature definition, i.e. class
if (isNewExpressionTarget(location) || location.kind === SyntaxKind.ConstructorKeyword) {
if (symbol.flags & SymbolFlags.Class) {
var classDeclaration = <ClassDeclaration>symbol.getDeclarations()[0];
Debug.assert(classDeclaration && classDeclaration.kind === SyntaxKind.ClassDeclaration);

return tryAddSignature(classDeclaration.members, /*selectConstructors*/ true, symbolKind, symbolName, containerName, result);
}
}
return false;
}

function tryAddCallSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) {
if (isCallExpressionTarget(location) || isNewExpressionTarget(location) || isNameOfFunctionDeclaration(location)) {
return tryAddSignature(symbol.declarations, /*selectConstructors*/ false, symbolKind, symbolName, containerName, result);
}
return false;
}
}

/// References and Occurrences
Expand Down Expand Up @@ -5273,7 +5273,7 @@ module ts {

// Only allow a symbol to be renamed if it actually has at least one declaration.
if (symbol && symbol.getDeclarations() && symbol.getDeclarations().length > 0) {
var kind = getSymbolKind(symbol, typeInfoResolver);
var kind = getSymbolKind(symbol, typeInfoResolver, node);
if (kind) {
return getRenameInfo(symbol.name, typeInfoResolver.getFullyQualifiedName(symbol), kind,
getSymbolModifiers(symbol),
Expand Down
4 changes: 4 additions & 0 deletions tests/cases/fourslash/fourslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,10 @@ module FourSlashInterface {
FourSlash.currentTestState.verifyQuickInfoExists(this.negative);
}

public definitionCountIs(expectedCount: number) {
FourSlash.currentTestState.verifyDefinitionsCount(this.negative, expectedCount);
}

public definitionLocationExists() {
FourSlash.currentTestState.verifyDefinitionLocationExists(this.negative);
}
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/fourslash/goToDefinitionExternamModuleName4.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/// <reference path='fourslash.ts'/>
/// <reference path='fourslash.ts'/>

// @Filename: b.ts
////import n = require('unknown/*1*/');
Expand Down
34 changes: 17 additions & 17 deletions tests/cases/fourslash/goToDefinitionFunctionOverloads.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
/// <reference path='fourslash.ts' />

/////*functionOverload1*/function /*functionOverload*/functionOverload();
/////*functionOverload2*/function functionOverload(value: string);
/////*functionOverloadDefinition*/function functionOverload() {}
////
/// <reference path='fourslash.ts' />
/////*functionOverload1*/function /*functionOverload*/functionOverload();
/////*functionOverload2*/function functionOverload(value: string);
/////*functionOverloadDefinition*/function functionOverload() {}
////
/////*functionOverloadReference1*/functionOverload();
/////*functionOverloadReference2*/functionOverload("123");

goTo.marker('functionOverloadReference1');
goTo.definition();
verify.caretAtMarker('functionOverloadDefinition');

goTo.marker('functionOverloadReference2');
goTo.definition();
verify.caretAtMarker('functionOverloadDefinition');

goTo.marker('functionOverload');
goTo.definition();
verify.caretAtMarker('functionOverloadDefinition');
goTo.marker('functionOverloadReference1');
goTo.definition();
verify.caretAtMarker('functionOverloadDefinition');
goTo.marker('functionOverloadReference2');
goTo.definition();
verify.caretAtMarker('functionOverloadDefinition');
goTo.marker('functionOverload');
goTo.definition();
verify.caretAtMarker('functionOverloadDefinition');
42 changes: 21 additions & 21 deletions tests/cases/fourslash/goToDefinitionFunctionOverloadsInClass.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
/// <reference path='fourslash.ts'/>

////class clsInOverload {
//// static fnOverload();
//// static /*staticFunctionOverload*/fnOverload(foo: string);
//// /*staticFunctionOverloadDefinition*/static fnOverload(foo: any) { }
//// public /*functionOverload*/fnOverload(): any;
//// public fnOverload(foo: string);
//// /*functionOverloadDefinition*/public fnOverload(foo: any) { return "foo" }
////
//// constructor() { }
////}

/// <reference path='fourslash.ts'/>
////class clsInOverload {
//// static fnOverload();
//// static /*staticFunctionOverload*/fnOverload(foo: string);
//// /*staticFunctionOverloadDefinition*/static fnOverload(foo: any) { }
//// public /*functionOverload*/fnOverload(): any;
//// public fnOverload(foo: string);
//// /*functionOverloadDefinition*/public fnOverload(foo: any) { return "foo" }
////
//// constructor() { }
////}
// this line triggers a semantic/syntactic error check, remove line when 788570 is fixed
edit.insert('');

goTo.marker('staticFunctionOverload');
goTo.definition();
verify.caretAtMarker('staticFunctionOverloadDefinition');

goTo.marker('functionOverload');
goTo.definition();
edit.insert('');
goTo.marker('staticFunctionOverload');
goTo.definition();
verify.caretAtMarker('staticFunctionOverloadDefinition');
goTo.marker('functionOverload');
goTo.definition();
verify.caretAtMarker('functionOverloadDefinition');
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// <reference path='fourslash.ts' />

/// <reference path='fourslash.ts' />
////interface One {
//// /*propertyDefinition1*/commonProperty: number;
//// commonFunction(): number;
Expand All @@ -13,12 +13,14 @@
////var x : One | Two;
////
////x./*propertyReference*/commonProperty;
////x./*3*/commonFunction;

goTo.marker("propertyReference");
goTo.definition(0);
verify.caretAtMarker("propertyDefinition1");

goTo.marker("propertyReference");
goTo.definition(1);
verify.caretAtMarker("propertyDefinition2");
////x./*3*/commonFunction;


goTo.marker("propertyReference");
verify.definitionCountIs(2);
goTo.definition(0);
verify.caretAtMarker("propertyDefinition1");

goTo.marker("propertyReference");
goTo.definition(1);
verify.caretAtMarker("propertyDefinition2");
29 changes: 15 additions & 14 deletions tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/// <reference path='fourslash.ts' />
////interface HasAOrB {
//// /*propertyDefinition1*/a: string;
//// b: string;
////}
////
/// <reference path='fourslash.ts' />
////interface HasAOrB {
//// /*propertyDefinition1*/a: string;
//// b: string;
////}
////
////interface One {
//// common: { /*propertyDefinition2*/a : number; };
////}
Expand All @@ -15,11 +15,12 @@
////var x : One | Two;
////
////x.common./*propertyReference*/a;

goTo.marker("propertyReference");
goTo.definition(0);
verify.caretAtMarker("propertyDefinition2");

goTo.marker("propertyReference");
goTo.definition(1);
verify.caretAtMarker("propertyDefinition1");

goTo.marker("propertyReference");
verify.definitionCountIs(2);
goTo.definition(0);
verify.caretAtMarker("propertyDefinition2");

goTo.marker("propertyReference");
goTo.definition(1);
verify.caretAtMarker("propertyDefinition1");
15 changes: 15 additions & 0 deletions tests/cases/fourslash/goToDefinitionUnionTypeProperty3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/// <reference path='fourslash.ts' />

////interface Array<T> {
//// /*definition*/specialPop(): T
////}
////
////var strings: string[];
////var numbers: number[];
////
////var x = (strings || numbers)./*usage*/specialPop()

goTo.marker("usage");
verify.definitionCountIs(1);
goTo.definition();
verify.caretAtMarker("definition");
Loading