Fix tests

This commit is contained in:
Andy Hanson 2017-01-24 12:56:21 -08:00
parent 0ca4cb25d6
commit e8c3d548eb
7 changed files with 105 additions and 55 deletions

View file

@ -17,7 +17,7 @@ namespace ts.DocumentHighlights {
}
function getSemanticDocumentHighlights(node: Node, typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch, /*findInStrings*/false, /*findInComments*/false, /*implementations*/false);
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch);
return referencedSymbols && convertReferencedSymbols(referencedSymbols);
}

View file

@ -1,11 +1,11 @@
/* @internal */
namespace ts.FindAllReferences {
export function findReferencedSymbols(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFiles: SourceFile[], sourceFile: SourceFile, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] | undefined {
export function findReferencedSymbols(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFiles: SourceFile[], sourceFile: SourceFile, position: number, findInStrings: boolean, findInComments: boolean, isForRename: boolean): ReferencedSymbol[] | undefined {
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, /*implementations*/false);
return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, isForRename);
}
export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean, implementations: boolean): ReferencedSymbol[] | undefined {
export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings?: boolean, findInComments?: boolean, isForRename?: boolean, implementations?: boolean): ReferencedSymbol[] | undefined {
if (!implementations) {
const special = getReferencedSymbolsSpecial(node, sourceFiles, typeChecker, cancellationToken);
if (special) {
@ -33,11 +33,16 @@ namespace ts.FindAllReferences {
return undefined;
}
const aliasedSymbol = followAliasIfNecessary(symbol, node, typeChecker);
const isShorthandModule = ts.isShorthandAmbientModuleSymbol(aliasedSymbol);
// Don't follow alias for shorthand modules because we lose information that way.
if (!isShorthandModule) {
symbol = aliasedSymbol;
const { symbol: aliasedSymbol, shorthandModuleSymbol } = followAliases(symbol, node, typeChecker, isForRename);
symbol = aliasedSymbol;
// Build the set of symbols to search for, initially it has only the current symbol
const searchSymbols = populateSearchSymbolSet(symbol, node, typeChecker, implementations);
if (shorthandModuleSymbol) {
searchSymbols.push(shorthandModuleSymbol);
}
function isSearchedFor(symbol: Symbol): boolean {
return contains(searchSymbols, symbol);
}
// Compute the meaning from the location and the symbol it references
@ -48,12 +53,6 @@ namespace ts.FindAllReferences {
const symbolToIndex: number[] = [];
const inheritsFromCache: Map<boolean> = createMap<boolean>();
// Build the set of symbols to search for, initially it has only the current symbol
const searchSymbols = populateSearchSymbolSet(symbol, node, typeChecker, implementations, isShorthandModule ? aliasedSymbol : undefined);
function isSearchedFor(symbol: Symbol): boolean {
return contains(searchSymbols, symbol);
}
// Get the text to search for.
// Note: if this is an external module symbol, the name doesn't include quotes.
const declaredName = stripQuotes(getDeclaredName(typeChecker, symbol, node));
@ -116,6 +115,31 @@ namespace ts.FindAllReferences {
return undefined;
}
/**
* Follows aliases to get to the original declaration of a symbol.
* For a shorthand ambient module, we don't follow the alias to it, but we will need to add it to the set of search symbols.
*/
function followAliases(symbol: Symbol, node: Node, typeChecker: TypeChecker, isForRename: boolean): { symbol: Symbol, shorthandModuleSymbol?: Symbol } {
while (true) {
// When renaming a default import, only rename in the current file
if (isForRename && isImportDefaultSymbol(symbol)) {
return { symbol };
}
const aliasedSymbol = getAliasSymbolForPropertyNameSymbol(symbol, node, typeChecker);
// Don't follow alias if it goes to unknown symbol. This can happen if it points to an untyped module.
if (!aliasedSymbol || !aliasedSymbol.declarations) {
return { symbol };
}
if (ts.isShorthandAmbientModuleSymbol(aliasedSymbol)) {
return { symbol, shorthandModuleSymbol: aliasedSymbol };
}
symbol = aliasedSymbol;
}
}
function sourceFileHasName(sourceFile: SourceFile, name: string): boolean {
return getNameTable(sourceFile).get(name) !== undefined;
}
@ -157,29 +181,30 @@ namespace ts.FindAllReferences {
}
function getAliasSymbolForPropertyNameSymbol(symbol: Symbol, location: Node, typeChecker: TypeChecker): Symbol | undefined {
if (symbol.flags & SymbolFlags.Alias) {
// Default import get alias
const defaultImport = getDeclarationOfKind(symbol, SyntaxKind.ImportClause);
if (defaultImport) {
return typeChecker.getAliasedSymbol(symbol);
}
const importOrExportSpecifier = <ImportOrExportSpecifier>forEach(symbol.declarations,
declaration => (declaration.kind === SyntaxKind.ImportSpecifier ||
declaration.kind === SyntaxKind.ExportSpecifier) ? declaration : undefined);
if (importOrExportSpecifier &&
// export { a }
(!importOrExportSpecifier.propertyName ||
// export {a as class } where a is location
importOrExportSpecifier.propertyName === location)) {
// If Import specifier -> get alias
// else Export specifier -> get local target
return importOrExportSpecifier.kind === SyntaxKind.ImportSpecifier ?
typeChecker.getAliasedSymbol(symbol) :
typeChecker.getExportSpecifierLocalTargetSymbol(importOrExportSpecifier);
}
if (!(symbol.flags & SymbolFlags.Alias)) {
return undefined;
}
// Default import get alias
const defaultImport = getDeclarationOfKind(symbol, SyntaxKind.ImportClause);
if (defaultImport) {
return typeChecker.getAliasedSymbol(symbol);
}
const importOrExportSpecifier = <ImportOrExportSpecifier>forEach(symbol.declarations,
declaration => (declaration.kind === SyntaxKind.ImportSpecifier ||
declaration.kind === SyntaxKind.ExportSpecifier) ? declaration : undefined);
if (importOrExportSpecifier &&
// export { a }
(!importOrExportSpecifier.propertyName ||
// export {a as class } where a is location
importOrExportSpecifier.propertyName === location)) {
// If Import specifier -> get alias
// else Export specifier -> get local target
return importOrExportSpecifier.kind === SyntaxKind.ImportSpecifier ?
typeChecker.getAliasedSymbol(symbol) :
typeChecker.getExportSpecifierLocalTargetSymbol(importOrExportSpecifier);
}
return undefined;
}
function followAliasIfNecessary(symbol: Symbol, location: Node, typeChecker: TypeChecker): Symbol {
@ -1022,9 +1047,9 @@ namespace ts.FindAllReferences {
}
}
function populateSearchSymbolSet(symbol: Symbol, location: Node, typeChecker: TypeChecker, implementations: boolean, aliasSymbol?: Symbol): Symbol[] {
function populateSearchSymbolSet(symbol: Symbol, location: Node, typeChecker: TypeChecker, implementations: boolean): Symbol[] {
// The search set contains at least the current symbol
let result = [symbol];
const result = [symbol];
// If the location is name of property symbol from object literal destructuring pattern
// Search the property symbol
@ -1037,10 +1062,6 @@ namespace ts.FindAllReferences {
}
}
if (aliasSymbol) {
result = result.concat(populateSearchSymbolSet(aliasSymbol, location, typeChecker, implementations));
}
// If the location is in a context sensitive location (i.e. in an object literal) try
// to get a contextual type for it, and add the property symbol from the contextual
// type to the search set
@ -1072,7 +1093,7 @@ namespace ts.FindAllReferences {
// Property Declaration symbol is a member of the class, so the symbol is stored in its class Declaration.symbol.members
if (symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.Parameter &&
isParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration)) {
result = result.concat(typeChecker.getSymbolsOfParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration, symbol.name));
addRange(result, typeChecker.getSymbolsOfParameterPropertyDeclaration(<ParameterDeclaration>symbol.valueDeclaration, symbol.name));
}
// If this is symbol of binding element without propertyName declaration in Object binding pattern
@ -1447,4 +1468,8 @@ namespace ts.FindAllReferences {
return false;
}
function isImportDefaultSymbol(symbol: Symbol): boolean {
return symbol.declarations[0].kind === SyntaxKind.ImportClause;
}
}

View file

@ -17,7 +17,7 @@ namespace ts.GoToImplementation {
else {
// Perform "Find all References" and retrieve only those that are implementations
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken,
node, sourceFiles, /*findInStrings*/false, /*findInComments*/false, /*implementations*/true);
node, sourceFiles, /*findInStrings*/false, /*findInComments*/false, /*isForRename*/false, /*implementations*/true);
const result = flatMap(referencedSymbols, symbol =>
map(symbol.references, ({ textSpan, fileName }) => ({ textSpan, fileName })));

View file

@ -1406,25 +1406,25 @@ namespace ts {
}
function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] {
const referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments);
const referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments, /*isForRename*/true);
return FindAllReferences.convertReferences(referencedSymbols);
}
function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] {
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false);
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false);
return FindAllReferences.convertReferences(referencedSymbols);
}
function findReferences(fileName: string, position: number): ReferencedSymbol[] {
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false);
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false);
// Only include referenced symbols that have a valid definition.
return filter(referencedSymbols, rs => !!rs.definition);
}
function findReferencedSymbols(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] {
function findReferencedSymbols(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, isForRename: boolean): ReferencedSymbol[] {
synchronizeHostData();
return FindAllReferences.findReferencedSymbols(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position, findInStrings, findInComments);
return FindAllReferences.findReferencedSymbols(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position, findInStrings, findInComments, isForRename);
}
/// NavigateTo

View file

@ -1,7 +1,7 @@
/// <reference path='fourslash.ts' />
// @Filename: B.ts
////export default class [|B|] {
////export default class /*1*/[|B|] {
//// test() {
//// }
////}
@ -11,4 +11,17 @@
////let b = new [|B|]();
////b.test();
verify.rangesAreRenameLocations();
goTo.marker("1");
verify.occurrencesAtPositionCount(1);
const [C, B0, B1] = test.ranges();
verify.rangesReferenceEachOther();
goTo.rangeStart(C);
verify.renameLocations(false, false, [C, B0, B1]);
const rangesInB = [B0, B1];
for (const r of rangesInB) {
goTo.rangeStart(r);
verify.renameLocations(false, false, rangesInB);
}

View file

@ -1,7 +1,7 @@
/// <reference path='fourslash.ts' />
// @Filename: B.ts
////export default class /*1*/C {
////export default class /*1*/[|C|] {
//// test() {
//// }
////}
@ -14,4 +14,14 @@
goTo.marker("1");
verify.occurrencesAtPositionCount(1);
verify.rangesAreRenameLocations();
const [C, B0, B1] = test.ranges();
verify.rangesReferenceEachOther();
goTo.rangeStart(C);
verify.renameLocations(false, false, [C, B0, B1]);
const rangesInB = [B0, B1];
for (const r of rangesInB) {
goTo.rangeStart(r);
verify.renameLocations(false, false, rangesInB);
}

View file

@ -3,4 +3,6 @@
////import [|a|] from "module";
////export { [|a|] };
verify.rangesAreRenameLocations();
const [r0, r1] = test.ranges();
verify.referencesOf(r1, [r0, r1]);
//verify.rangesAreRenameLocations();