Support external module names correctelly

This commit is contained in:
Mohamed Hegazy
2014-08-22 21:28:27 -07:00
parent fefe2fb093
commit c741e26031
5 changed files with 106 additions and 16 deletions

View File

@@ -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(<Identifier>node)
: getSymbolOfPartOfRightHandSideOfImport(node);

View File

@@ -367,6 +367,10 @@ module ts {
identifiers.push((<Identifier>node).text);
return undefined;
case SyntaxKind.StringLiteral:
if (isNameOfExternalModuleImportOrDeclaration(node)) {
identifiers.push((<LiteralExpression>node).text);
}
// intential fall through
case SyntaxKind.NumericLiteral:
if (isLiteralNameOfPropertyDeclarationOrIndexAccess(node)) {
identifiers.push((<LiteralExpression>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 && (<ModuleDeclaration>node.parent).name === node) ||
(node.parent.kind === SyntaxKind.ImportDeclaration && (<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;
}

View File

@@ -0,0 +1,30 @@
/// <reference path='fourslash.ts'/>
////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);

View File

@@ -0,0 +1,18 @@
/// <reference path='fourslash.ts'/>
// 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);

View File

@@ -0,0 +1,24 @@
/// <reference path='fourslash.ts'/>
// 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);
});