Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Refactor findAllReferences. Now supports renamed exports and imports.
  • Loading branch information
Andy Hanson committed Feb 16, 2017
commit 42a832ad3d13d151f91d1a098b6dcc4c5dd68381
1 change: 1 addition & 0 deletions Gulpfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const cmdLineOptions = minimist(process.argv.slice(2), {
boolean: ["debug", "light", "colors", "lint", "soft"],
string: ["browser", "tests", "host", "reporter", "stackTraceLimit"],
alias: {
b: "browser",
d: "debug",
t: "tests",
test: "tests",
Expand Down
94 changes: 53 additions & 41 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ namespace ts {
isUndefinedSymbol: symbol => symbol === undefinedSymbol,
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
isUnknownSymbol: symbol => symbol === unknownSymbol,
getMergedSymbol,
getDiagnostics,
getGlobalDiagnostics,
getTypeOfSymbolAtLocation,
Expand Down Expand Up @@ -106,6 +107,7 @@ namespace ts {
isValidPropertyAccess,
getSignatureFromDeclaration,
isImplementationOfOverload,
getImmediateAliasedSymbol,
getAliasedSymbol: resolveAlias,
getEmitResolver,
getExportsOfModule: getExportsOfModuleAsArray,
Expand Down Expand Up @@ -1161,14 +1163,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 @@ -1180,22 +1182,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 @@ -1229,12 +1231,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 @@ -1247,9 +1246,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 @@ -1266,11 +1265,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 @@ -1283,45 +1282,58 @@ 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 getImmediateAliasedSymbol(symbol: Symbol): 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;
}

function resolveAlias(symbol: Symbol): Symbol {
Expand Down Expand Up @@ -1538,16 +1550,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 @@ -457,6 +457,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
14 changes: 12 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1818,6 +1818,7 @@
}

export interface ExternalModuleReference extends Node {
parent: ImportEqualsDeclaration;
kind: SyntaxKind.ExternalModuleReference;
expression?: Expression;
}
Expand All @@ -1829,6 +1830,7 @@
export interface ImportDeclaration extends Statement {
kind: SyntaxKind.ImportDeclaration;
importClause?: ImportClause;
/** If this is not a StringLiteral it will be a grammar error. */
moduleSpecifier: Expression;
}

Expand Down Expand Up @@ -1860,6 +1862,7 @@
export interface ExportDeclaration extends DeclarationStatement {
kind: SyntaxKind.ExportDeclaration;
exportClause?: NamedExports;
/** If this is not a StringLiteral it will be a grammar error. */
moduleSpecifier?: Expression;
}

Expand All @@ -1869,6 +1872,7 @@
}

export interface NamedExports extends Node {
parent: ExportDeclaration;
kind: SyntaxKind.NamedExports;
elements: NodeArray<ExportSpecifier>;
}
Expand All @@ -1882,6 +1886,7 @@
}

export interface ExportSpecifier extends Declaration {
parent: NamedExports;
kind: SyntaxKind.ExportSpecifier;
propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent)
name: Identifier; // Declared name
Expand Down Expand Up @@ -2219,8 +2224,8 @@
// 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[];
}
Expand Down Expand Up @@ -2418,10 +2423,14 @@
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 @@ -2728,6 +2737,7 @@

/* @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 @@ -3103,7 +3103,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