Skip to content

Refactor findAllReferences. Now supports renamed exports and imports. #14001

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
16 commits merged into from
Apr 14, 2017
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
1 change: 1 addition & 0 deletions Gulpfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const cmdLineOptions = minimist(process.argv.slice(2), {
boolean: ["debug", "inspect", "light", "colors", "lint", "soft"],
string: ["browser", "tests", "host", "reporter", "stackTraceLimit"],
alias: {
b: "browser",
d: "debug",
t: "tests",
test: "tests",
Expand Down
92 changes: 51 additions & 41 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ namespace ts {
isUndefinedSymbol: symbol => symbol === undefinedSymbol,
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
isUnknownSymbol: symbol => symbol === unknownSymbol,
getMergedSymbol,
getDiagnostics,
getGlobalDiagnostics,
getTypeOfSymbolAtLocation: (symbol, location) => {
Expand Down Expand Up @@ -172,6 +173,17 @@ namespace ts {
node = getParseTreeNode(node, isFunctionLike);
return node ? isImplementationOfOverload(node) : undefined;
},
getImmediateAliasedSymbol: symbol => {
Debug.assert((symbol.flags & SymbolFlags.Alias) !== 0, "Should only get Alias here.");
const links = getSymbolLinks(symbol);
if (!links.immediateTarget) {
const node = getDeclarationOfAliasSymbol(symbol);
Debug.assert(!!node);
links.immediateTarget = getTargetOfAliasDeclaration(node, /*dontRecursivelyResolve*/ true);
}

return links.immediateTarget;
},
getAliasedSymbol: resolveAlias,
getEmitResolver,
getExportsOfModule: getExportsOfModuleAsArray,
Expand Down Expand Up @@ -1253,14 +1265,14 @@ namespace ts {
return find<Declaration>(symbol.declarations, isAliasSymbolDeclaration);
}

function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration): Symbol {
function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration, dontResolveAlias: boolean): Symbol {
if (node.moduleReference.kind === SyntaxKind.ExternalModuleReference) {
return resolveExternalModuleSymbol(resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node)));
}
return getSymbolOfPartOfRightHandSideOfImportEquals(<EntityName>node.moduleReference);
return getSymbolOfPartOfRightHandSideOfImportEquals(<EntityName>node.moduleReference, dontResolveAlias);
}

function getTargetOfImportClause(node: ImportClause): Symbol {
function getTargetOfImportClause(node: ImportClause, dontResolveAlias: boolean): Symbol {
const moduleSymbol = resolveExternalModuleName(node, (<ImportDeclaration>node.parent).moduleSpecifier);

if (moduleSymbol) {
Expand All @@ -1272,22 +1284,22 @@ namespace ts {
const exportValue = moduleSymbol.exports.get("export=");
exportDefaultSymbol = exportValue
? getPropertyOfType(getTypeOfSymbol(exportValue), "default")
: resolveSymbol(moduleSymbol.exports.get("default"));
: resolveSymbol(moduleSymbol.exports.get("default"), dontResolveAlias);
}

if (!exportDefaultSymbol && !allowSyntheticDefaultImports) {
error(node.name, Diagnostics.Module_0_has_no_default_export, symbolToString(moduleSymbol));
}
else if (!exportDefaultSymbol && allowSyntheticDefaultImports) {
return resolveExternalModuleSymbol(moduleSymbol) || resolveSymbol(moduleSymbol);
return resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias);
}
return exportDefaultSymbol;
}
}

function getTargetOfNamespaceImport(node: NamespaceImport): Symbol {
function getTargetOfNamespaceImport(node: NamespaceImport, dontResolveAlias: boolean): Symbol {
const moduleSpecifier = (<ImportDeclaration>node.parent.parent).moduleSpecifier;
return resolveESModuleSymbol(resolveExternalModuleName(node, moduleSpecifier), moduleSpecifier);
return resolveESModuleSymbol(resolveExternalModuleName(node, moduleSpecifier), moduleSpecifier, dontResolveAlias);
}

// This function creates a synthetic symbol that combines the value side of one symbol with the
Expand Down Expand Up @@ -1321,12 +1333,9 @@ namespace ts {
return result;
}

function getExportOfModule(symbol: Symbol, name: string): Symbol {
function getExportOfModule(symbol: Symbol, name: string, dontResolveAlias: boolean): Symbol {
if (symbol.flags & SymbolFlags.Module) {
const exportedSymbol = getExportsOfSymbol(symbol).get(name);
if (exportedSymbol) {
return resolveSymbol(exportedSymbol);
}
return resolveSymbol(getExportsOfSymbol(symbol).get(name), dontResolveAlias);
}
}

Expand All @@ -1339,9 +1348,9 @@ namespace ts {
}
}

function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration, specifier: ImportOrExportSpecifier): Symbol {
function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration, specifier: ImportOrExportSpecifier, dontResolveAlias?: boolean): Symbol {
const moduleSymbol = resolveExternalModuleName(node, node.moduleSpecifier);
const targetSymbol = resolveESModuleSymbol(moduleSymbol, node.moduleSpecifier);
const targetSymbol = resolveESModuleSymbol(moduleSymbol, node.moduleSpecifier, dontResolveAlias);
if (targetSymbol) {
const name = specifier.propertyName || specifier.name;
if (name.text) {
Expand All @@ -1358,11 +1367,11 @@ namespace ts {
symbolFromVariable = getPropertyOfVariable(targetSymbol, name.text);
}
// if symbolFromVariable is export - get its final target
symbolFromVariable = resolveSymbol(symbolFromVariable);
let symbolFromModule = getExportOfModule(targetSymbol, name.text);
symbolFromVariable = resolveSymbol(symbolFromVariable, dontResolveAlias);
let symbolFromModule = getExportOfModule(targetSymbol, name.text, dontResolveAlias);
// If the export member we're looking for is default, and there is no real default but allowSyntheticDefaultImports is on, return the entire module as the default
if (!symbolFromModule && allowSyntheticDefaultImports && name.text === "default") {
symbolFromModule = resolveExternalModuleSymbol(moduleSymbol) || resolveSymbol(moduleSymbol);
symbolFromModule = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias);
}
const symbol = symbolFromModule && symbolFromVariable ?
combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) :
Expand All @@ -1375,45 +1384,46 @@ namespace ts {
}
}

function getTargetOfImportSpecifier(node: ImportSpecifier): Symbol {
return getExternalModuleMember(<ImportDeclaration>node.parent.parent.parent, node);
function getTargetOfImportSpecifier(node: ImportSpecifier, dontResolveAlias: boolean): Symbol {
return getExternalModuleMember(<ImportDeclaration>node.parent.parent.parent, node, dontResolveAlias);
}

function getTargetOfNamespaceExportDeclaration(node: NamespaceExportDeclaration): Symbol {
return resolveExternalModuleSymbol(node.parent.symbol);
function getTargetOfNamespaceExportDeclaration(node: NamespaceExportDeclaration, dontResolveAlias: boolean): Symbol {
return resolveExternalModuleSymbol(node.parent.symbol, dontResolveAlias);
}

function getTargetOfExportSpecifier(node: ExportSpecifier): Symbol {
function getTargetOfExportSpecifier(node: ExportSpecifier, dontResolveAlias?: boolean): Symbol {
return (<ExportDeclaration>node.parent.parent).moduleSpecifier ?
getExternalModuleMember(<ExportDeclaration>node.parent.parent, node) :
resolveEntityName(node.propertyName || node.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
getExternalModuleMember(<ExportDeclaration>node.parent.parent, node, dontResolveAlias) :
resolveEntityName(node.propertyName || node.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias);
}

function getTargetOfExportAssignment(node: ExportAssignment): Symbol {
return resolveEntityName(<EntityNameExpression>node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
function getTargetOfExportAssignment(node: ExportAssignment, dontResolveAlias: boolean): Symbol {
return resolveEntityName(<EntityNameExpression>node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias);
}

function getTargetOfAliasDeclaration(node: Declaration): Symbol {
function getTargetOfAliasDeclaration(node: Declaration, dontRecursivelyResolve?: boolean): Symbol {
switch (node.kind) {
case SyntaxKind.ImportEqualsDeclaration:
return getTargetOfImportEqualsDeclaration(<ImportEqualsDeclaration>node);
return getTargetOfImportEqualsDeclaration(<ImportEqualsDeclaration>node, dontRecursivelyResolve);
case SyntaxKind.ImportClause:
return getTargetOfImportClause(<ImportClause>node);
return getTargetOfImportClause(<ImportClause>node, dontRecursivelyResolve);
case SyntaxKind.NamespaceImport:
return getTargetOfNamespaceImport(<NamespaceImport>node);
return getTargetOfNamespaceImport(<NamespaceImport>node, dontRecursivelyResolve);
case SyntaxKind.ImportSpecifier:
return getTargetOfImportSpecifier(<ImportSpecifier>node);
return getTargetOfImportSpecifier(<ImportSpecifier>node, dontRecursivelyResolve);
case SyntaxKind.ExportSpecifier:
return getTargetOfExportSpecifier(<ExportSpecifier>node);
return getTargetOfExportSpecifier(<ExportSpecifier>node, dontRecursivelyResolve);
case SyntaxKind.ExportAssignment:
return getTargetOfExportAssignment(<ExportAssignment>node);
return getTargetOfExportAssignment(<ExportAssignment>node, dontRecursivelyResolve);
case SyntaxKind.NamespaceExportDeclaration:
return getTargetOfNamespaceExportDeclaration(<NamespaceExportDeclaration>node);
return getTargetOfNamespaceExportDeclaration(<NamespaceExportDeclaration>node, dontRecursivelyResolve);
}
}

function resolveSymbol(symbol: Symbol): Symbol {
return symbol && symbol.flags & SymbolFlags.Alias && !(symbol.flags & (SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace)) ? resolveAlias(symbol) : symbol;
function resolveSymbol(symbol: Symbol, dontResolveAlias?: boolean): Symbol {
const shouldResolve = !dontResolveAlias && symbol && symbol.flags & SymbolFlags.Alias && !(symbol.flags & (SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace));
return shouldResolve ? resolveAlias(symbol) : symbol;
}

function resolveAlias(symbol: Symbol): Symbol {
Expand Down Expand Up @@ -1653,16 +1663,16 @@ namespace ts {

// An external module with an 'export =' declaration resolves to the target of the 'export =' declaration,
// and an external module with no 'export =' declaration resolves to the module itself.
function resolveExternalModuleSymbol(moduleSymbol: Symbol): Symbol {
return moduleSymbol && getMergedSymbol(resolveSymbol(moduleSymbol.exports.get("export="))) || moduleSymbol;
function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol {
return moduleSymbol && getMergedSymbol(resolveSymbol(moduleSymbol.exports.get("export="), dontResolveAlias)) || moduleSymbol;
}

// An external module with an 'export =' declaration may be referenced as an ES6 module provided the 'export ='
// references a symbol that is at least declared as a module or a variable. The target of the 'export =' may
// combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable).
function resolveESModuleSymbol(moduleSymbol: Symbol, moduleReferenceExpression: Expression): Symbol {
let symbol = resolveExternalModuleSymbol(moduleSymbol);
if (symbol && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable))) {
function resolveESModuleSymbol(moduleSymbol: Symbol, moduleReferenceExpression: Expression, dontResolveAlias: boolean): Symbol {
let symbol = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias);
if (!dontResolveAlias && symbol && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable))) {
error(moduleReferenceExpression, Diagnostics.Module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct, symbolToString(moduleSymbol));
symbol = undefined;
}
Expand Down
8 changes: 5 additions & 3 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -887,10 +887,12 @@ namespace ts {
}

/** Shims `Array.from`. */
export function arrayFrom<T>(iterator: Iterator<T>): T[] {
const result: T[] = [];
export function arrayFrom<T, U>(iterator: Iterator<T>, map: (t: T) => U): U[];
export function arrayFrom<T>(iterator: Iterator<T>): T[];
export function arrayFrom(iterator: Iterator<any>, map?: (t: any) => any): any[] {
const result: any[] = [];
for (let { value, done } = iterator.next(); !done; { value, done } = iterator.next()) {
result.push(value);
result.push(map ? map(value) : value);
}
return result;
}
Expand Down
1 change: 1 addition & 0 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ namespace ts {
return Parser.parseIsolatedEntityName(text, languageVersion);
}

// See also `isExternalOrCommonJsModule` in utilities.ts
export function isExternalModule(file: SourceFile): boolean {
return file.externalModuleIndicator !== undefined;
}
Expand Down
11 changes: 9 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1886,6 +1886,7 @@ namespace ts {
kind: SyntaxKind.ImportDeclaration;
parent?: SourceFile | ModuleBlock;
importClause?: ImportClause;
/** If this is not a StringLiteral it will be a grammar error. */
moduleSpecifier: Expression;
}

Expand Down Expand Up @@ -1919,6 +1920,7 @@ namespace ts {
kind: SyntaxKind.ExportDeclaration;
parent?: SourceFile | ModuleBlock;
exportClause?: NamedExports;
/** If this is not a StringLiteral it will be a grammar error. */
moduleSpecifier?: Expression;
}

Expand Down Expand Up @@ -2305,8 +2307,8 @@ namespace ts {
// Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead
/* @internal */ resolvedModules: Map<ResolvedModuleFull>;
/* @internal */ resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
/* @internal */ imports: LiteralExpression[];
/* @internal */ moduleAugmentations: LiteralExpression[];
/* @internal */ imports: StringLiteral[];
/* @internal */ moduleAugmentations: StringLiteral[];
/* @internal */ patternAmbientModules?: PatternAmbientModule[];
/* @internal */ ambientModuleNames: string[];
/* @internal */ checkJsDirective: CheckJsDirective | undefined;
Expand Down Expand Up @@ -2522,10 +2524,14 @@ namespace ts {
isUndefinedSymbol(symbol: Symbol): boolean;
isArgumentsSymbol(symbol: Symbol): boolean;
isUnknownSymbol(symbol: Symbol): boolean;
/* @internal */ getMergedSymbol(symbol: Symbol): Symbol;

getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean;
/** Follow all aliases to get the original symbol. */
getAliasedSymbol(symbol: Symbol): Symbol;
/** Follow a *single* alias to get the immediately aliased symbol. */
/* @internal */ getImmediateAliasedSymbol(symbol: Symbol): Symbol;
getExportsOfModule(moduleSymbol: Symbol): Symbol[];
/** Unlike `getExportsOfModule`, this includes properties of an `export =` value. */
/* @internal */ getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[];
Expand Down Expand Up @@ -2841,6 +2847,7 @@ namespace ts {

/* @internal */
export interface SymbolLinks {
immediateTarget?: Symbol; // Immediate target of an alias. May be another alias. Do not access directly, use `checker.getImmediateAliasedSymbol` instead.
target?: Symbol; // Resolved (non-alias) target of an alias
type?: Type; // Type of value symbol
declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3134,7 +3134,7 @@ namespace ts {
return isExportDefaultSymbol(symbol) ? symbol.valueDeclaration.localSymbol : undefined;
}

export function isExportDefaultSymbol(symbol: Symbol): boolean {
function isExportDefaultSymbol(symbol: Symbol): boolean {
return symbol && symbol.valueDeclaration && hasModifier(symbol.valueDeclaration, ModifierFlags.Default);
}

Expand Down
Loading