Skip to content

Commit eefbae6

Browse files
committed
Merge pull request microsoft#2126 from Microsoft/findAllRefsForImports
Find all refs for imports
2 parents 61e6b32 + 07547dc commit eefbae6

17 files changed

+412
-14
lines changed

src/services/breakpoints.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,15 @@ module ts.BreakpointResolver {
178178

179179
case SyntaxKind.ImportEqualsDeclaration:
180180
// import statement without including semicolon
181-
return textSpan(node,(<ImportEqualsDeclaration>node).moduleReference);
181+
return textSpan(node, (<ImportEqualsDeclaration>node).moduleReference);
182+
183+
case SyntaxKind.ImportDeclaration:
184+
// import statement without including semicolon
185+
return textSpan(node, (<ImportDeclaration>node).moduleSpecifier);
186+
187+
case SyntaxKind.ExportDeclaration:
188+
// import statement without including semicolon
189+
return textSpan(node, (<ExportDeclaration>node).moduleSpecifier);
182190

183191
case SyntaxKind.ModuleDeclaration:
184192
// span on complete module if it is instantiated

src/services/formatting/rules.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,13 @@ module ts.formatting {
3535
// Space after keyword but not before ; or : or ?
3636
public NoSpaceBeforeSemicolon: Rule;
3737
public NoSpaceBeforeColon: Rule;
38-
public NoSpaceBeforeQMark: Rule;
38+
public NoSpaceBeforeQuestionMark: Rule;
3939
public SpaceAfterColon: Rule;
40-
public SpaceAfterQMark: Rule;
40+
// insert space after '?' only when it is used in conditional operator
41+
public SpaceAfterQuestionMarkInConditionalOperator: Rule;
42+
// in other cases there should be no space between '?' and next token
43+
public NoSpaceAfterQuestionMark: Rule;
44+
4145
public SpaceAfterSemicolon: Rule;
4246

4347
// Space/new line after }.
@@ -215,9 +219,10 @@ module ts.formatting {
215219
// Space after keyword but not before ; or : or ?
216220
this.NoSpaceBeforeSemicolon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.SemicolonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
217221
this.NoSpaceBeforeColon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.ColonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
218-
this.NoSpaceBeforeQMark = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.QuestionToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
222+
this.NoSpaceBeforeQuestionMark = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.QuestionToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
219223
this.SpaceAfterColon = new Rule(RuleDescriptor.create3(SyntaxKind.ColonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Space));
220-
this.SpaceAfterQMark = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Space));
224+
this.SpaceAfterQuestionMarkInConditionalOperator = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsConditionalOperatorContext), RuleAction.Space));
225+
this.NoSpaceAfterQuestionMark = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
221226
this.SpaceAfterSemicolon = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
222227

223228
// Space after }.
@@ -341,7 +346,8 @@ module ts.formatting {
341346
this.HighPriorityCommonRules =
342347
[
343348
this.IgnoreBeforeComment, this.IgnoreAfterLineComment,
344-
this.NoSpaceBeforeColon, this.SpaceAfterColon, this.NoSpaceBeforeQMark, this.SpaceAfterQMark,
349+
this.NoSpaceBeforeColon, this.SpaceAfterColon, this.NoSpaceBeforeQuestionMark, this.SpaceAfterQuestionMarkInConditionalOperator,
350+
this.NoSpaceAfterQuestionMark,
345351
this.NoSpaceBeforeDot, this.NoSpaceAfterDot,
346352
this.NoSpaceAfterUnaryPrefixOperator,
347353
this.NoSpaceAfterUnaryPreincrementOperator, this.NoSpaceAfterUnaryPredecrementOperator,
@@ -475,6 +481,10 @@ module ts.formatting {
475481
return !Rules.IsBinaryOpContext(context);
476482
}
477483

484+
static IsConditionalOperatorContext(context: FormattingContext): boolean {
485+
return context.contextNode.kind === SyntaxKind.ConditionalExpression;
486+
}
487+
478488
static IsSameLineTokenOrBeforeMultilineBlockContext(context: FormattingContext): boolean {
479489
//// This check is mainly used inside SpaceBeforeOpenBraceInControl and SpaceBeforeOpenBraceInFunction.
480490
////

src/services/navigationBar.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,38 @@ module ts.NavigationBar {
5050
case SyntaxKind.ArrayBindingPattern:
5151
forEach((<BindingPattern>node).elements, visit);
5252
break;
53+
54+
case SyntaxKind.ExportDeclaration:
55+
// Handle named exports case e.g.:
56+
// export {a, b as B} from "mod";
57+
if ((<ExportDeclaration>node).exportClause) {
58+
forEach((<ExportDeclaration>node).exportClause.elements, visit);
59+
}
60+
break;
61+
62+
case SyntaxKind.ImportDeclaration:
63+
var importClause = (<ImportDeclaration>node).importClause;
64+
if (importClause) {
65+
// Handle default import case e.g.:
66+
// import d from "mod";
67+
if (importClause.name) {
68+
childNodes.push(importClause);
69+
}
70+
71+
// Handle named bindings in imports e.g.:
72+
// import * as NS from "mod";
73+
// import {a, b as B} from "mod";
74+
if (importClause.namedBindings) {
75+
if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
76+
childNodes.push(importClause.namedBindings);
77+
}
78+
else {
79+
forEach((<NamedImports>importClause.namedBindings).elements, visit);
80+
}
81+
}
82+
}
83+
break;
84+
5385
case SyntaxKind.BindingElement:
5486
case SyntaxKind.VariableDeclaration:
5587
if (isBindingPattern((<VariableDeclaration>node).name)) {
@@ -62,7 +94,11 @@ module ts.NavigationBar {
6294
case SyntaxKind.InterfaceDeclaration:
6395
case SyntaxKind.ModuleDeclaration:
6496
case SyntaxKind.FunctionDeclaration:
97+
case SyntaxKind.ImportEqualsDeclaration:
98+
case SyntaxKind.ImportSpecifier:
99+
case SyntaxKind.ExportSpecifier:
65100
childNodes.push(node);
101+
break;
66102
}
67103
}
68104

@@ -291,9 +327,16 @@ module ts.NavigationBar {
291327
else {
292328
return createItem(node, getTextOfNode(name), ts.ScriptElementKind.variableElement);
293329
}
294-
330+
295331
case SyntaxKind.Constructor:
296332
return createItem(node, "constructor", ts.ScriptElementKind.constructorImplementationElement);
333+
334+
case SyntaxKind.ExportSpecifier:
335+
case SyntaxKind.ImportSpecifier:
336+
case SyntaxKind.ImportEqualsDeclaration:
337+
case SyntaxKind.ImportClause:
338+
case SyntaxKind.NamespaceImport:
339+
return createItem(node, getTextOfNode((<Declaration>node).name), ts.ScriptElementKind.alias);
297340
}
298341

299342
return undefined;

src/services/services.ts

Lines changed: 104 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,11 @@ module ts {
802802
case SyntaxKind.EnumDeclaration:
803803
case SyntaxKind.ModuleDeclaration:
804804
case SyntaxKind.ImportEqualsDeclaration:
805+
case SyntaxKind.ExportSpecifier:
806+
case SyntaxKind.ImportSpecifier:
807+
case SyntaxKind.ImportEqualsDeclaration:
808+
case SyntaxKind.ImportClause:
809+
case SyntaxKind.NamespaceImport:
805810
case SyntaxKind.GetAccessor:
806811
case SyntaxKind.SetAccessor:
807812
case SyntaxKind.TypeLiteral:
@@ -841,6 +846,37 @@ module ts {
841846
case SyntaxKind.PropertySignature:
842847
namedDeclarations.push(<Declaration>node);
843848
break;
849+
850+
case SyntaxKind.ExportDeclaration:
851+
// Handle named exports case e.g.:
852+
// export {a, b as B} from "mod";
853+
if ((<ExportDeclaration>node).exportClause) {
854+
forEach((<ExportDeclaration>node).exportClause.elements, visit);
855+
}
856+
break;
857+
858+
case SyntaxKind.ImportDeclaration:
859+
var importClause = (<ImportDeclaration>node).importClause;
860+
if (importClause) {
861+
// Handle default import case e.g.:
862+
// import d from "mod";
863+
if (importClause.name) {
864+
namedDeclarations.push(importClause);
865+
}
866+
867+
// Handle named bindings in imports e.g.:
868+
// import * as NS from "mod";
869+
// import {a, b as B} from "mod";
870+
if (importClause.namedBindings) {
871+
if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
872+
namedDeclarations.push(<NamespaceImport>importClause.namedBindings);
873+
}
874+
else {
875+
forEach((<NamedImports>importClause.namedBindings).elements, visit);
876+
}
877+
}
878+
}
879+
break;
844880
}
845881
});
846882

@@ -2010,6 +2046,12 @@ module ts {
20102046
case SyntaxKind.TypeParameter: return ScriptElementKind.typeParameterElement;
20112047
case SyntaxKind.EnumMember: return ScriptElementKind.variableElement;
20122048
case SyntaxKind.Parameter: return (node.flags & NodeFlags.AccessibilityModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement;
2049+
case SyntaxKind.ImportEqualsDeclaration:
2050+
case SyntaxKind.ImportSpecifier:
2051+
case SyntaxKind.ImportClause:
2052+
case SyntaxKind.ExportSpecifier:
2053+
case SyntaxKind.NamespaceImport:
2054+
return ScriptElementKind.alias;
20132055
}
20142056
return ScriptElementKind.unknown;
20152057
}
@@ -3986,7 +4028,7 @@ module ts {
39864028
var searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), declarations);
39874029

39884030
// Get the text to search for, we need to normalize it as external module names will have quote
3989-
var declaredName = getDeclaredName(symbol);
4031+
var declaredName = getDeclaredName(symbol, node);
39904032

39914033
// Try to get the smallest valid scope that we can limit our search to;
39924034
// otherwise we'll need to search globally (i.e. include each file).
@@ -4003,7 +4045,7 @@ module ts {
40034045
getReferencesInNode(sourceFiles[0], symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result);
40044046
}
40054047
else {
4006-
var internedName = getInternedName(symbol, declarations)
4048+
var internedName = getInternedName(symbol, node, declarations)
40074049
forEach(sourceFiles, sourceFile => {
40084050
cancellationToken.throwIfCancellationRequested();
40094051

@@ -4023,13 +4065,51 @@ module ts {
40234065

40244066
return result;
40254067

4026-
function getDeclaredName(symbol: Symbol) {
4068+
function isImportOrExportSpecifierName(location: Node): boolean {
4069+
return location.parent &&
4070+
(location.parent.kind === SyntaxKind.ImportSpecifier || location.parent.kind === SyntaxKind.ExportSpecifier) &&
4071+
(<ImportOrExportSpecifier>location.parent).propertyName === location;
4072+
}
4073+
4074+
function isImportOrExportSpecifierImportSymbol(symbol: Symbol) {
4075+
return (symbol.flags & SymbolFlags.Import) && forEach(symbol.declarations, declaration => {
4076+
return declaration.kind === SyntaxKind.ImportSpecifier || declaration.kind === SyntaxKind.ExportSpecifier;
4077+
});
4078+
}
4079+
4080+
function getDeclaredName(symbol: Symbol, location: Node) {
4081+
// Special case for function expressions, whose names are solely local to their bodies.
4082+
var functionExpression = forEach(symbol.declarations, d => d.kind === SyntaxKind.FunctionExpression ? <FunctionExpression>d : undefined);
4083+
4084+
// When a name gets interned into a SourceFile's 'identifiers' Map,
4085+
// its name is escaped and stored in the same way its symbol name/identifier
4086+
// name should be stored. Function expressions, however, are a special case,
4087+
// because despite sometimes having a name, the binder unconditionally binds them
4088+
// to a symbol with the name "__function".
4089+
if (functionExpression && functionExpression.name) {
4090+
var name = functionExpression.name.text;
4091+
}
4092+
4093+
// If this is an export or import specifier it could have been renamed using the as syntax.
4094+
// if so we want to search for whatever under the cursor, the symbol is pointing to the alias (name)
4095+
// so check for the propertyName.
4096+
if (isImportOrExportSpecifierName(location)) {
4097+
return location.getText();
4098+
}
4099+
40274100
var name = typeInfoResolver.symbolToString(symbol);
40284101

40294102
return stripQuotes(name);
40304103
}
40314104

4032-
function getInternedName(symbol: Symbol, declarations: Declaration[]): string {
4105+
function getInternedName(symbol: Symbol, location: Node, declarations: Declaration[]): string {
4106+
// If this is an export or import specifier it could have been renamed using the as syntax.
4107+
// if so we want to search for whatever under the cursor, the symbol is pointing to the alias (name)
4108+
// so check for the propertyName.
4109+
if (isImportOrExportSpecifierName(location)) {
4110+
return location.getText();
4111+
}
4112+
40334113
// Special case for function expressions, whose names are solely local to their bodies.
40344114
var functionExpression = forEach(declarations, d => d.kind === SyntaxKind.FunctionExpression ? <FunctionExpression>d : undefined);
40354115

@@ -4058,16 +4138,22 @@ module ts {
40584138

40594139
function getSymbolScope(symbol: Symbol): Node {
40604140
// If this is private property or method, the scope is the containing class
4061-
if (symbol.getFlags() && (SymbolFlags.Property | SymbolFlags.Method)) {
4141+
if (symbol.flags & (SymbolFlags.Property | SymbolFlags.Method)) {
40624142
var privateDeclaration = forEach(symbol.getDeclarations(), d => (d.flags & NodeFlags.Private) ? d : undefined);
40634143
if (privateDeclaration) {
40644144
return getAncestor(privateDeclaration, SyntaxKind.ClassDeclaration);
40654145
}
40664146
}
40674147

4148+
// If the symbol is an import we would like to find it if we are looking for what it imports.
4149+
// So consider it visibile outside its declaration scope.
4150+
if (symbol.flags & SymbolFlags.Import) {
4151+
return undefined;
4152+
}
4153+
40684154
// if this symbol is visible from its parent container, e.g. exported, then bail out
40694155
// if symbol correspond to the union property - bail out
4070-
if (symbol.parent || (symbol.getFlags() & SymbolFlags.UnionProperty)) {
4156+
if (symbol.parent || (symbol.flags & SymbolFlags.UnionProperty)) {
40714157
return undefined;
40724158
}
40734159

@@ -4422,6 +4508,11 @@ module ts {
44224508
// The search set contains at least the current symbol
44234509
var result = [symbol];
44244510

4511+
// If the symbol is an alias, add what it alaises to the list
4512+
if (isImportOrExportSpecifierImportSymbol(symbol)) {
4513+
result.push(typeInfoResolver.getAliasedSymbol(symbol));
4514+
}
4515+
44254516
// If the location is in a context sensitive location (i.e. in an object literal) try
44264517
// to get a contextual type for it, and add the property symbol from the contextual
44274518
// type to the search set
@@ -4498,6 +4589,13 @@ module ts {
44984589
return true;
44994590
}
45004591

4592+
// If the reference symbol is an alias, check if what it is aliasing is one of the search
4593+
// symbols.
4594+
if (isImportOrExportSpecifierImportSymbol(referenceSymbol) &&
4595+
searchSymbols.indexOf(typeInfoResolver.getAliasedSymbol(referenceSymbol)) >= 0) {
4596+
return true;
4597+
}
4598+
45014599
// If the reference location is in an object literal, try to get the contextual type for the
45024600
// object literal, lookup the property symbol in the contextual type, and use this symbol to
45034601
// compare to our searchSymbol
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
1 >export * from "a";
3+
4+
~~~~~~~~~~~~~~~~~~~ => Pos: (0 to 18) SpanInfo: {"start":0,"length":17}
5+
>export * from "a"
6+
>:=> (line 1, col 0) to (line 1, col 17)
7+
--------------------------------
8+
2 >export {a as A} from "a";
9+
10+
~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (19 to 44) SpanInfo: {"start":19,"length":24}
11+
>export {a as A} from "a"
12+
>:=> (line 2, col 0) to (line 2, col 24)
13+
--------------------------------
14+
3 >export import e = require("a");
15+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (45 to 75) SpanInfo: {"start":45,"length":30}
16+
>export import e = require("a")
17+
>:=> (line 3, col 0) to (line 3, col 30)

0 commit comments

Comments
 (0)