Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 27 additions & 13 deletions src/services/goToDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,10 @@ namespace ts.GoToDefinition {
// get the aliased symbol instead. This allows for goto def on an import e.g.
// import {A, B} from "mod";
// to jump to the implementation directly.
if (symbol.flags & SymbolFlags.Alias) {
const declaration = symbol.declarations[0];

// Go to the original declaration for cases:
//
// (1) when the aliased symbol was declared in the location(parent).
// (2) when the aliased symbol is originating from a named import.
//
if (node.kind === SyntaxKind.Identifier &&
(node.parent === declaration ||
(declaration.kind === SyntaxKind.ImportSpecifier && declaration.parent && declaration.parent.kind === SyntaxKind.NamedImports))) {

symbol = typeChecker.getAliasedSymbol(symbol);
if (symbol.flags & SymbolFlags.Alias && shouldSkipAlias(node, symbol.declarations[0])) {
const aliased = typeChecker.getAliasedSymbol(symbol);
if (aliased.declarations) {
symbol = aliased;
}
}

Expand Down Expand Up @@ -136,6 +127,29 @@ namespace ts.GoToDefinition {
return getDefinitionFromSymbol(typeChecker, type.symbol, node);
}

// Go to the original declaration for cases:
//
// (1) when the aliased symbol was declared in the location(parent).
// (2) when the aliased symbol is originating from an import.
//
function shouldSkipAlias(node: Node, declaration: Node): boolean {
if (node.kind !== SyntaxKind.Identifier) {
return false;
}
if (node.parent === declaration) {
return true;
}
switch (declaration.kind) {
case SyntaxKind.ImportClause:
case SyntaxKind.ImportEqualsDeclaration:
return true;
case SyntaxKind.ImportSpecifier:
return declaration.parent.kind === SyntaxKind.NamedImports;
default:
return false;
}
}

function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: Node): DefinitionInfo[] {
const result: DefinitionInfo[] = [];
const declarations = symbol.getDeclarations();
Expand Down
4 changes: 2 additions & 2 deletions tests/cases/fourslash/ambientShorthandGotoDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

verify.quickInfoAt("useFoo", "import foo");
verify.goToDefinition({
useFoo: "importFoo",
useFoo: "module",
importFoo: "module"
});

Expand All @@ -27,6 +27,6 @@ verify.goToDefinition({

verify.quickInfoAt("useBang", "import bang = require(\"jquery\")");
verify.goToDefinition({
useBang: "importBang",
useBang: "module",
importBang: "module"
});
26 changes: 26 additions & 0 deletions tests/cases/fourslash/goToDefinitionImports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/// <reference path='fourslash.ts'/>

// @Filename: /a.ts
////export default function /*fDef*/f() {}
////export const /*xDef*/x = 0;

// @Filename: /b.ts
/////*bDef*/declare const b: number;
////export = b;

// @Filename: /b.ts
////import f, { x } from "./a";
////import * as /*aDef*/a from "./a";
////import b = require("./b");
/////*fUse*/f;
/////*xUse*/x;
/////*aUse*/a;
/////*bUse*/b;

verify.goToDefinition({
aUse: "aDef", // Namespace import isn't "skipped"
fUse: "fDef",
xUse: "xDef",
bUse: "bDef",
});

6 changes: 3 additions & 3 deletions tests/cases/fourslash/goToDefinition_untypedModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
////not read

// @Filename: /a.ts
////import { f } from "foo";
/////**/f();
////import { /*def*/f } from "foo";
/////*use*/f();

verify.goToDefinition("", []);
verify.goToDefinition("use", "def");
8 changes: 4 additions & 4 deletions tests/cases/fourslash/quickInfoMeaning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
// @Filename: foo.d.ts
////declare const /*foo_value_declaration*/foo: number;
////declare module "foo_module" {
//// interface I { x: number; y: number }
//// interface /*foo_type_declaration*/I { x: number; y: number }
//// export = I;
////}

// @Filename: foo_user.ts
///////<reference path="foo.d.ts" />
////import /*foo_type_declaration*/foo = require("foo_module");
////import foo = require("foo_module");
////const x = foo/*foo_value*/;
////const i: foo/*foo_type*/ = { x: 1, y: 2 };

Expand All @@ -39,13 +39,13 @@ verify.goToDefinitionIs("foo_type_declaration");
// @Filename: bar.d.ts
////declare interface /*bar_type_declaration*/bar { x: number; y: number }
////declare module "bar_module" {
//// const x: number;
//// const /*bar_value_declaration*/x: number;
//// export = x;
////}

// @Filename: bar_user.ts
///////<reference path="bar.d.ts" />
////import /*bar_value_declaration*/bar = require("bar_module");
////import bar = require("bar_module");
////const x = bar/*bar_value*/;
////const i: bar/*bar_type*/ = { x: 1, y: 2 };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
// @jsx: preserve

// @Filename: C.tsx
////export default class C {}
////export default class /*def*/C {}

// @Filename: a.tsx
////import /*def*/C from "./C";
////import C from "./C";
////const foo = </*use*/C />;

verify.noErrors();
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/fourslash/untypedModuleImport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ const [r0, r1, r2] = test.ranges();
verify.singleReferenceGroup('"foo"', [r1]);

goTo.marker("foo");
verify.goToDefinitionIs([]);
verify.goToDefinitionIs("foo");
verify.quickInfoIs("import foo");
verify.singleReferenceGroup("import foo", [r0, r2]);