Merge pull request #1528 from Microsoft/goToDefOnUnionMethod

Fix crash on go-to-def on union method
This commit is contained in:
Daniel Rosenwasser 2014-12-18 12:11:05 -08:00
commit af9b56bdd9
10 changed files with 207 additions and 145 deletions

View File

@ -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';
@ -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"));
}
}

View File

@ -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;
@ -3097,6 +3097,83 @@ module ts {
/// Goto definition
function getDefinitionAtPosition(filename: string, position: number): DefinitionInfo[] {
synchronizeHostData();
filename = normalizeSlashes(filename);
var sourceFile = getSourceFile(filename);
var node = getTouchingPropertyName(sourceFile, position);
if (!node) {
return undefined;
}
// Labels
if (isJumpStatementTarget(node)) {
var labelName = (<Identifier>node).text;
var label = getTargetLabel((<BreakOrContinueStatement>node.parent), (<Identifier>node).text);
return label ? [getDefinitionInfo(label, ScriptElementKind.label, labelName, /*containerName*/ undefined)] : undefined;
}
/// Triple slash reference comments
var comment = forEach(sourceFile.referencedFiles, r => (r.pos <= position && position < r.end) ? r : undefined);
if (comment) {
var referenceFile = tryResolveScriptReference(program, sourceFile, comment);
if (referenceFile) {
return [{
fileName: referenceFile.filename,
textSpan: createTextSpanFromBounds(0, 0),
kind: ScriptElementKind.scriptElement,
name: comment.filename,
containerName: undefined,
containerKind: undefined
}];
}
return undefined;
}
var symbol = typeInfoResolver.getSymbolAtLocation(node);
// Could not find a symbol e.g. node is string or number keyword,
// or the symbol was an internal symbol and does not have a declaration e.g. undefined symbol
if (!symbol) {
return undefined;
}
var result: DefinitionInfo[] = [];
// Because name in short-hand property assignment has two different meanings: property name and property value,
// using go-to-definition at such position should go to the variable declaration of the property value rather than
// go to the declaration of the property name (in this case stay at the same position). However, if go-to-definition
// is performed at the location of property access, we would like to go to definition of the property in the short-hand
// assignment. This case and others are handled by the following code.
if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
var shorthandSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(symbol.valueDeclaration);
var shorthandDeclarations = shorthandSymbol.getDeclarations();
var shorthandSymbolKind = getSymbolKind(shorthandSymbol, typeInfoResolver, node);
var shorthandSymbolName = typeInfoResolver.symbolToString(shorthandSymbol);
var shorthandContainerName = typeInfoResolver.symbolToString(symbol.parent, node);
forEach(shorthandDeclarations, declaration => {
result.push(getDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName));
});
return result
}
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, node);
var containerSymbol = symbol.parent;
var containerName = containerSymbol ? typeInfoResolver.symbolToString(containerSymbol, node) : "";
if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) &&
!tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) {
// Just add all the declarations.
forEach(declarations, declaration => {
result.push(getDefinitionInfo(declaration, symbolKind, symbolName, containerName));
});
}
return result;
function getDefinitionInfo(node: Node, symbolKind: string, symbolName: string, containerName: string): DefinitionInfo {
return {
fileName: node.getSourceFile().filename,
@ -3152,83 +3229,6 @@ module ts {
}
return false;
}
synchronizeHostData();
filename = normalizeSlashes(filename);
var sourceFile = getSourceFile(filename);
var node = getTouchingPropertyName(sourceFile, position);
if (!node) {
return undefined;
}
// Labels
if (isJumpStatementTarget(node)) {
var labelName = (<Identifier>node).text;
var label = getTargetLabel((<BreakOrContinueStatement>node.parent), (<Identifier>node).text);
return label ? [getDefinitionInfo(label, ScriptElementKind.label, labelName, /*containerName*/ undefined)] : undefined;
}
/// Triple slash reference comments
var comment = forEach(sourceFile.referencedFiles, r => (r.pos <= position && position < r.end) ? r : undefined);
if (comment) {
var referenceFile = tryResolveScriptReference(program, sourceFile, comment);
if (referenceFile) {
return [{
fileName: referenceFile.filename,
textSpan: createTextSpanFromBounds(0, 0),
kind: ScriptElementKind.scriptElement,
name: comment.filename,
containerName: undefined,
containerKind: undefined
}];
}
return undefined;
}
var symbol = typeInfoResolver.getSymbolAtLocation(node);
// Could not find a symbol e.g. node is string or number keyword,
// or the symbol was an internal symbol and does not have a declaration e.g. undefined symbol
if (!symbol) {
return undefined;
}
var result: DefinitionInfo[] = [];
// Because name in short-hand property assignment has two different meanings: property name and property value,
// using go-to-definition at such position should go to the variable declaration of the property value rather than
// go to the declaration of the property name (in this case stay at the same position). However, if go-to-definition
// is performed at the location of property access, we would like to go to definition of the property in the short-hand
// assignment. This case and others are handled by the following code.
if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
var shorthandSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(symbol.valueDeclaration);
var shorthandDeclarations = shorthandSymbol.getDeclarations();
var shorthandSymbolKind = getSymbolKind(shorthandSymbol, typeInfoResolver);
var shorthandSymbolName = typeInfoResolver.symbolToString(shorthandSymbol);
var shorthandContainerName = typeInfoResolver.symbolToString(symbol.parent, node);
forEach(shorthandDeclarations, declaration => {
result.push(getDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName));
});
return result
}
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 containerSymbol = symbol.parent;
var containerName = containerSymbol ? typeInfoResolver.symbolToString(containerSymbol, node) : "";
if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) &&
!tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) {
// Just add all the declarations.
forEach(declarations, declaration => {
result.push(getDefinitionInfo(declaration, symbolKind, symbolName, containerName));
});
}
return result;
}
/// References and Occurrences
@ -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),

View File

@ -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);
}

View File

@ -1,4 +1,4 @@
/// <reference path='fourslash.ts'/>
/// <reference path='fourslash.ts'/>
// @Filename: b.ts
////import n = require('unknown/*1*/');

View File

@ -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');

View File

@ -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');

View File

@ -1,5 +1,5 @@
/// <reference path='fourslash.ts' />
/// <reference path='fourslash.ts' />
////interface One {
//// /*propertyDefinition1*/commonProperty: number;
//// commonFunction(): number;
@ -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");

View File

@ -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; };
////}
@ -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");

View File

@ -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");

View File

@ -0,0 +1,32 @@
/// <reference path='fourslash.ts' />
////interface SnapCrackle {
//// /*def1*/pop(): string;
////}
////
////interface Magnitude {
//// /*def2*/pop(): number;
////}
////
////interface Art {
//// /*def3*/pop(): boolean;
////}
////
////var art: Art;
////var magnitude: Magnitude;
////var snapcrackle: SnapCrackle;
////
////var x = (snapcrackle || magnitude || art)./*usage*/pop;
goTo.marker("usage");
verify.definitionCountIs(3);
goTo.definition(0);
verify.caretAtMarker("def1");
goTo.marker("usage");
goTo.definition(1);
verify.caretAtMarker("def2");
goTo.marker("usage");
goTo.definition(2);
verify.caretAtMarker("def3");