diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2d63f5e4d20..aa9d5e606d5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6814,7 +6814,7 @@ module ts { return getSymbolOfNode(node.parent); } - if (isInRightSideOfImportOrExportAssignment(node)) { + if (node.kind === SyntaxKind.Identifier && isInRightSideOfImportOrExportAssignment(node)) { return node.parent.kind === SyntaxKind.ExportAssignment ? getSymbolOfEntityName(node) : getSymbolOfPartOfRightHandSideOfImport(node); diff --git a/src/services/services.ts b/src/services/services.ts index a1922231b06..fff35031f66 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -367,6 +367,10 @@ module ts { identifiers.push((node).text); return undefined; case SyntaxKind.StringLiteral: + if (isNameOfExternalModuleImportOrDeclaration(node)) { + identifiers.push((node).text); + } + // intential fall through case SyntaxKind.NumericLiteral: if (isLiteralNameOfPropertyDeclarationOrIndexAccess(node)) { identifiers.push((node).text); @@ -1322,6 +1326,12 @@ module ts { return false; } + function isNameOfExternalModuleImportOrDeclaration(node: Node): boolean { + return node.kind === SyntaxKind.StringLiteral && + ((node.parent.kind === SyntaxKind.ModuleDeclaration && (node.parent).name === node) || + (node.parent.kind === SyntaxKind.ImportDeclaration && (node.parent).externalModuleName === node)); + } + enum SearchMeaning { Value = 0x1, Type = 0x2, @@ -2126,7 +2136,9 @@ module ts { return undefined; } - if (node.kind !== SyntaxKind.Identifier && !isLiteralNameOfPropertyDeclarationOrIndexAccess(node)) { + if (node.kind !== SyntaxKind.Identifier && + !isLiteralNameOfPropertyDeclarationOrIndexAccess(node) && + !isNameOfExternalModuleImportOrDeclaration(node)) { return undefined; } @@ -2163,27 +2175,36 @@ module ts { // Compute the meaning from the location and the symbol it references var searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), symbol.getDeclarations()); + // Get the text to search for, we need to normalize it as external module names will have quote + var symbolName = getNormalizedSymbolName(symbol.getName()); + var scope = getSymbolScope(symbol); if (scope) { result = []; - getReferencesInNode(scope, symbol, node, searchMeaning, result); + getReferencesInNode(scope, symbol, symbolName, node, searchMeaning, result); } else { - var symbolName = symbol.getName(); - forEach(program.getSourceFiles(), sourceFile => { cancellationToken.throwIfCancellationRequested(); if (sourceFile.getBloomFilter().probablyContains(symbolName)) { result = result || []; - getReferencesInNode(sourceFile, symbol, node, searchMeaning, result); + getReferencesInNode(sourceFile, symbol, symbolName, node, searchMeaning, result); } }); } return result; + function getNormalizedSymbolName(name: string): string { + var length = name.length; + if (length >= 2 && name.charCodeAt(0) === CharacterCodes.doubleQuote && name.charCodeAt(length - 1) === CharacterCodes.doubleQuote) { + return name.substring(1, length - 1); + }; + return name; + } + function getSymbolScope(symbol: Symbol): Node { // If this is private property or method, the scope is the containing class if (symbol.getFlags() && (SymbolFlags.Property | SymbolFlags.Method)) { @@ -2281,17 +2302,16 @@ module ts { return result; } - function isValidReferencePosition(node: Node, searchSymbol: Symbol): boolean { + function isValidReferencePosition(node: Node, searchSymbolName: string): boolean { if (node) { - var searchSymbolName = searchSymbol.getName(); - // Compare the length so we filter out strict superstrings of the symbol we are looking for switch (node.kind) { case SyntaxKind.Identifier: return node.getWidth() === searchSymbolName.length; case SyntaxKind.StringLiteral: - if (isLiteralNameOfPropertyDeclarationOrIndexAccess(node)) { + if (isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || + isNameOfExternalModuleImportOrDeclaration(node)) { // For string literals we have two additional chars for the quotes return node.getWidth() === searchSymbolName.length + 2; } @@ -2309,14 +2329,12 @@ module ts { } /// Search within node "container" for references for a search value, where the search value is defined as a - /// tuple of(searchSymbol, searchLocation, and searchMeaning). + /// tuple of(searchSymbol, searchText, searchLocation, and searchMeaning). /// searchLocation: a node where the search value - function getReferencesInNode(container: Node, searchSymbol: Symbol, searchLocation: Node, searchMeaning: SearchMeaning, result: ReferenceEntry[]): void { - var searchSymbolName = searchSymbol.getName(); - + function getReferencesInNode(container: Node, searchSymbol: Symbol, searchText: string, searchLocation: Node, searchMeaning: SearchMeaning, result: ReferenceEntry[]): void { var sourceFile = container.getSourceFile(); - var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, searchSymbolName, container.getStart(), container.getEnd()); + var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, searchText, container.getStart(), container.getEnd()); if (possiblePositions.length) { // Build the set of symbols to search for, initially it has only the current symbol @@ -2326,7 +2344,7 @@ module ts { cancellationToken.throwIfCancellationRequested(); var referenceLocation = getNodeAtPosition(sourceFile, position); - if (!isValidReferencePosition(referenceLocation, searchSymbol)) { + if (!isValidReferencePosition(referenceLocation, searchText)) { return; } diff --git a/tests/cases/fourslash/referencesForAmbients.ts b/tests/cases/fourslash/referencesForAmbients.ts new file mode 100644 index 00000000000..deea6ec3d29 --- /dev/null +++ b/tests/cases/fourslash/referencesForAmbients.ts @@ -0,0 +1,30 @@ +/// + +////declare module /*1*/"foo" { +//// var f: number; +////} +//// +////declare module "bar" { +//// export import foo = require(/*2*/"foo"); +//// var f2: typeof foo./*4*/f; +////} +//// +////declare module "baz" { +//// import bar = require(/*3*/"bar"); +//// var f2: typeof bar./*5*/foo; +////} + +goTo.marker("1"); +verify.referencesCountIs(2); + +goTo.marker("2"); +verify.referencesCountIs(2); + +goTo.marker("3"); +verify.referencesCountIs(2); + +goTo.marker("4"); +verify.referencesCountIs(2); + +goTo.marker("5"); +verify.referencesCountIs(3); \ No newline at end of file diff --git a/tests/cases/fourslash/referencesForExternalModuleNames.ts b/tests/cases/fourslash/referencesForExternalModuleNames.ts new file mode 100644 index 00000000000..7da6091d9e2 --- /dev/null +++ b/tests/cases/fourslash/referencesForExternalModuleNames.ts @@ -0,0 +1,18 @@ +/// + +// Global interface reference. + +// @Filename: referencesForGlobals_1.ts +////declare module /*1*/"foo" { +//// var f: number; +////} + + +// @Filename: referencesForGlobals_2.ts +////import f = require(/*2*/"foo"); + +goTo.marker("1"); +verify.referencesCountIs(2); + +goTo.marker("2"); +verify.referencesCountIs(2); \ No newline at end of file diff --git a/tests/cases/fourslash/referencesForGlobalsInExternalModule.ts b/tests/cases/fourslash/referencesForGlobalsInExternalModule.ts new file mode 100644 index 00000000000..4afaedf93e8 --- /dev/null +++ b/tests/cases/fourslash/referencesForGlobalsInExternalModule.ts @@ -0,0 +1,24 @@ +/// + +// Global variable reference. + +////var /*1*/topLevelVar = 2; +////var topLevelVar2 = topLevelVar; +//// +////class /*2*/topLevelClass { } +////var c = new topLevelClass(); +//// +////interface topLevelInterface { } +////var i: /*3*/topLevelInterface; +//// +////module topLevelModule { +//// export var x; +////} +////var x = /*4*/topLevelModule.x; +//// +////export = x; + +test.markers().forEach(m => { + goTo.position(m.position, m.fileName); + verify.referencesCountIs(2); +}); \ No newline at end of file