diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2110ef28975..60381824125 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6205,9 +6205,9 @@ module ts { } // True if the given identifier is part of a type reference - function isTypeReferenceIdentifier(identifier: Identifier): boolean { - var node: Node = identifier; - if (node.parent && node.parent.kind === SyntaxKind.QualifiedName) node = node.parent; + function isTypeReferenceIdentifier(entityName: EntityName): boolean { + var node: Node = entityName; + while (node.parent && node.parent.kind === SyntaxKind.QualifiedName) node = node.parent; return node.parent && node.parent.kind === SyntaxKind.TypeReference; } @@ -6271,39 +6271,56 @@ module ts { return false; } - function isRightSideOfQualifiedName(node: Node) { + function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) { return (node.parent.kind === SyntaxKind.QualifiedName || node.parent.kind === SyntaxKind.PropertyAccess) && (node.parent).right === node; } function getSymbolOfIdentifier(identifier: Identifier) { - if (isExpression(identifier)) { - if (isRightSideOfQualifiedName(identifier)) { - var node = identifier.parent; - var symbol = getNodeLinks(node).resolvedSymbol; - if (!symbol) { - checkPropertyAccess(node); - } - return getNodeLinks(node).resolvedSymbol; - } - return resolveName(identifier, identifier.text, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined); - } if (isDeclarationIdentifier(identifier)) { return getSymbolOfNode(identifier.parent); } - if (isTypeReferenceIdentifier(identifier)) { - var entityName = isRightSideOfQualifiedName(identifier) ? identifier.parent : identifier; + + var entityName: Node = identifier; + while (isRightSideOfQualifiedNameOrPropertyAccess(entityName)) + entityName = entityName.parent; + + if (isExpression(entityName)) { + if (entityName.kind === SyntaxKind.Identifier) { + // Include Import in the meaning, this ensures that we do not follow aliases to where they point and instead + // return the alias symbol. + var meaning: SymbolFlags = SymbolFlags.Value | SymbolFlags.Import; + return resolveEntityName(entityName, entityName, meaning); + } + else if (entityName.kind === SyntaxKind.QualifiedName || entityName.kind === SyntaxKind.PropertyAccess) { + var symbol = getNodeLinks(entityName).resolvedSymbol; + if (!symbol) { + checkPropertyAccess(entityName); + } + return getNodeLinks(entityName).resolvedSymbol; + } + else { + // Missing identifier + return; + } + } + else if (isTypeReferenceIdentifier(entityName)) { var meaning = entityName.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace; + // Include Import in the meaning, this ensures that we do not follow aliases to where they point and instead + // return the alias symbol. + meaning |= SymbolFlags.Import; return resolveEntityName(entityName, entityName, meaning); } + + Debug.fail("identifier is neither at a type nor value position"); } function getTypeOfExpression(node: Node) { if (isExpression(node)) { - while (isRightSideOfQualifiedName(node)) { + while (isRightSideOfQualifiedNameOrPropertyAccess(node)) { node = node.parent; } - return getApparentType(checkExpression(node)); + return getApparentType(checkExpression(node)); } return unknownType; } @@ -6344,6 +6361,7 @@ module ts { return getPropertiesOfType(apparentType); } } + // Emitter support function isExternalModuleSymbol(symbol: Symbol): boolean { diff --git a/tests/cases/fourslash/goToDefinitionAlias.ts b/tests/cases/fourslash/goToDefinitionAlias.ts new file mode 100644 index 00000000000..f8141db44e3 --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionAlias.ts @@ -0,0 +1,42 @@ +/// + +// @Filename: b.ts +/////*alias1Definition*/import alias1 = require("fileb"); +////module Module { +//// /*alias2Definition*/export import alias2 = alias1; +////} +//// +////// Type position +////var t1: /*alias1Type*/alias1.IFoo; +////var t2: Module./*alias2Type*/alias2.IFoo; +//// +////// Value posistion +////var v1 = new /*alias1Value*/alias1.Foo(); +////var v2 = new Module./*alias2Value*/alias2.Foo(); + + +// @Filename: a.ts +////export class Foo { +//// private f; +////} +////export interface IFoo { +//// x; +////} + + +goTo.marker('alias1Type'); +goTo.definition(); +verify.caretAtMarker('alias1Definition'); + +goTo.marker('alias2Type'); +goTo.definition(); +verify.caretAtMarker('alias2Definition'); + + +goTo.marker('alias1Value'); +goTo.definition(); +verify.caretAtMarker('alias1Definition'); + +goTo.marker('alias2Value'); +goTo.definition(); +verify.caretAtMarker('alias2Definition');