diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c9564927f5e..3ce7fe5e1cf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -74,7 +74,7 @@ module ts { isImplementationOfOverload, getAliasedSymbol: resolveAlias, getEmitResolver, - getExportsOfExternalModule, + getExportsOfModule: getExportsOfModuleAsArray, }; let unknownSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "unknown"); @@ -898,6 +898,10 @@ module ts { return moduleSymbol.exports["export="]; } + function getExportsOfModuleAsArray(moduleSymbol: Symbol): Symbol[] { + return symbolsToArray(getExportsOfModule(moduleSymbol)); + } + function getExportsOfSymbol(symbol: Symbol): SymbolTable { return symbol.flags & SymbolFlags.Module ? getExportsOfModule(symbol) : symbol.exports || emptySymbols; } @@ -3032,17 +3036,6 @@ module ts { return result; } - function getExportsOfExternalModule(node: ImportDeclaration): Symbol[] { - if (!node.moduleSpecifier) { - return emptyArray; - } - let module = resolveExternalModuleName(node, node.moduleSpecifier); - if (!module) { - return emptyArray; - } - return symbolsToArray(getExportsOfModule(module)); - } - function getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature { let links = getNodeLinks(declaration); if (!links.resolvedSignature) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ce78dee5a01..fbb7805d998 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -933,7 +933,7 @@ module ts { // import "mod" => importClause = undefined, moduleSpecifier = "mod" // In rest of the cases, module specifier is string literal corresponding to module // ImportClause information is shown at its declaration below. - export interface ImportDeclaration extends Statement, ModuleElement { + export interface ImportDeclaration extends ModuleElement { importClause?: ImportClause; moduleSpecifier: Expression; } @@ -1146,7 +1146,7 @@ module ts { getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number; isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean; getAliasedSymbol(symbol: Symbol): Symbol; - getExportsOfExternalModule(node: ImportDeclaration): Symbol[]; + getExportsOfModule(moduleSymbol: Symbol): Symbol[]; // Should not be called directly. Should only be accessed through the Program instance. /* @internal */ getDiagnostics(sourceFile?: SourceFile): Diagnostic[]; diff --git a/src/services/services.ts b/src/services/services.ts index 7492c0cf98b..1d142e6bcd3 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2598,7 +2598,8 @@ module ts { if (symbol && symbol.flags & SymbolFlags.HasExports) { // Extract module or enum members - forEachValue(symbol.exports, symbol => { + let exportedSymbols = typeInfoResolver.getExportsOfModule(symbol); + forEach(exportedSymbols, symbol => { if (typeInfoResolver.isValidPropertyAccess((node.parent), symbol.name)) { symbols.push(symbol); } @@ -2642,8 +2643,17 @@ module ts { if (showCompletionsInImportsClause(contextToken)) { let importDeclaration = getAncestor(contextToken, SyntaxKind.ImportDeclaration); Debug.assert(importDeclaration !== undefined); - let exports = typeInfoResolver.getExportsOfExternalModule(importDeclaration); - symbols = filterModuleExports(exports, importDeclaration); + + let exports: Symbol[]; + if (importDeclaration.moduleSpecifier) { + let moduleSpecifierSymbol = typeInfoResolver.getSymbolAtLocation(importDeclaration.moduleSpecifier); + if (moduleSpecifierSymbol) { + exports = typeInfoResolver.getExportsOfModule(moduleSpecifierSymbol); + } + } + + //let exports = typeInfoResolver.getExportsOfImportDeclaration(importDeclaration); + symbols = exports ? filterModuleExports(exports, importDeclaration) : emptyArray; } } else { diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index 854f1414165..9f729564fa6 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -760,7 +760,7 @@ declare module "typescript" { interface ExternalModuleReference extends Node { expression?: Expression; } - interface ImportDeclaration extends Statement, ModuleElement { + interface ImportDeclaration extends ModuleElement { importClause?: ImportClause; moduleSpecifier: Expression; } @@ -902,7 +902,7 @@ declare module "typescript" { getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number; isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean; getAliasedSymbol(symbol: Symbol): Symbol; - getExportsOfExternalModule(node: ImportDeclaration): Symbol[]; + getExportsOfModule(moduleSymbol: Symbol): Symbol[]; } interface SymbolDisplayBuilder { buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index b89a0c02bd3..d0ff06ce765 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -2307,9 +2307,8 @@ declare module "typescript" { >expression : Expression >Expression : Expression } - interface ImportDeclaration extends Statement, ModuleElement { + interface ImportDeclaration extends ModuleElement { >ImportDeclaration : ImportDeclaration ->Statement : Statement >ModuleElement : ModuleElement importClause?: ImportClause; @@ -2818,10 +2817,10 @@ declare module "typescript" { >Symbol : Symbol >Symbol : Symbol - getExportsOfExternalModule(node: ImportDeclaration): Symbol[]; ->getExportsOfExternalModule : (node: ImportDeclaration) => Symbol[] ->node : ImportDeclaration ->ImportDeclaration : ImportDeclaration + getExportsOfModule(moduleSymbol: Symbol): Symbol[]; +>getExportsOfModule : (moduleSymbol: Symbol) => Symbol[] +>moduleSymbol : Symbol +>Symbol : Symbol >Symbol : Symbol } interface SymbolDisplayBuilder { diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index d7a1d02262a..1945ded072d 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -791,7 +791,7 @@ declare module "typescript" { interface ExternalModuleReference extends Node { expression?: Expression; } - interface ImportDeclaration extends Statement, ModuleElement { + interface ImportDeclaration extends ModuleElement { importClause?: ImportClause; moduleSpecifier: Expression; } @@ -933,7 +933,7 @@ declare module "typescript" { getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number; isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean; getAliasedSymbol(symbol: Symbol): Symbol; - getExportsOfExternalModule(node: ImportDeclaration): Symbol[]; + getExportsOfModule(moduleSymbol: Symbol): Symbol[]; } interface SymbolDisplayBuilder { buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 991af4841ca..c3acb15dd9d 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -2453,9 +2453,8 @@ declare module "typescript" { >expression : Expression >Expression : Expression } - interface ImportDeclaration extends Statement, ModuleElement { + interface ImportDeclaration extends ModuleElement { >ImportDeclaration : ImportDeclaration ->Statement : Statement >ModuleElement : ModuleElement importClause?: ImportClause; @@ -2964,10 +2963,10 @@ declare module "typescript" { >Symbol : Symbol >Symbol : Symbol - getExportsOfExternalModule(node: ImportDeclaration): Symbol[]; ->getExportsOfExternalModule : (node: ImportDeclaration) => Symbol[] ->node : ImportDeclaration ->ImportDeclaration : ImportDeclaration + getExportsOfModule(moduleSymbol: Symbol): Symbol[]; +>getExportsOfModule : (moduleSymbol: Symbol) => Symbol[] +>moduleSymbol : Symbol +>Symbol : Symbol >Symbol : Symbol } interface SymbolDisplayBuilder { diff --git a/tests/baselines/reference/APISample_linter.types.pull b/tests/baselines/reference/APISample_linter.types.pull index e2a29716fcc..68ff796104b 100644 --- a/tests/baselines/reference/APISample_linter.types.pull +++ b/tests/baselines/reference/APISample_linter.types.pull @@ -2453,9 +2453,8 @@ declare module "typescript" { >expression : Expression >Expression : Expression } - interface ImportDeclaration extends Statement, ModuleElement { + interface ImportDeclaration extends ModuleElement { >ImportDeclaration : ImportDeclaration ->Statement : Statement >ModuleElement : ModuleElement importClause?: ImportClause; @@ -2964,10 +2963,10 @@ declare module "typescript" { >Symbol : Symbol >Symbol : Symbol - getExportsOfExternalModule(node: ImportDeclaration): Symbol[]; ->getExportsOfExternalModule : (node: ImportDeclaration) => Symbol[] ->node : ImportDeclaration ->ImportDeclaration : ImportDeclaration + getExportsOfModule(moduleSymbol: Symbol): Symbol[]; +>getExportsOfModule : (moduleSymbol: Symbol) => Symbol[] +>moduleSymbol : Symbol +>Symbol : Symbol >Symbol : Symbol } interface SymbolDisplayBuilder { diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index 63777b515a7..c7ab72c95a9 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -792,7 +792,7 @@ declare module "typescript" { interface ExternalModuleReference extends Node { expression?: Expression; } - interface ImportDeclaration extends Statement, ModuleElement { + interface ImportDeclaration extends ModuleElement { importClause?: ImportClause; moduleSpecifier: Expression; } @@ -934,7 +934,7 @@ declare module "typescript" { getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number; isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean; getAliasedSymbol(symbol: Symbol): Symbol; - getExportsOfExternalModule(node: ImportDeclaration): Symbol[]; + getExportsOfModule(moduleSymbol: Symbol): Symbol[]; } interface SymbolDisplayBuilder { buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index 4a9810e779f..6b80e4ccde6 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -2403,9 +2403,8 @@ declare module "typescript" { >expression : Expression >Expression : Expression } - interface ImportDeclaration extends Statement, ModuleElement { + interface ImportDeclaration extends ModuleElement { >ImportDeclaration : ImportDeclaration ->Statement : Statement >ModuleElement : ModuleElement importClause?: ImportClause; @@ -2914,10 +2913,10 @@ declare module "typescript" { >Symbol : Symbol >Symbol : Symbol - getExportsOfExternalModule(node: ImportDeclaration): Symbol[]; ->getExportsOfExternalModule : (node: ImportDeclaration) => Symbol[] ->node : ImportDeclaration ->ImportDeclaration : ImportDeclaration + getExportsOfModule(moduleSymbol: Symbol): Symbol[]; +>getExportsOfModule : (moduleSymbol: Symbol) => Symbol[] +>moduleSymbol : Symbol +>Symbol : Symbol >Symbol : Symbol } interface SymbolDisplayBuilder { diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index 9b6dcdde162..9d6aa24ec62 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -829,7 +829,7 @@ declare module "typescript" { interface ExternalModuleReference extends Node { expression?: Expression; } - interface ImportDeclaration extends Statement, ModuleElement { + interface ImportDeclaration extends ModuleElement { importClause?: ImportClause; moduleSpecifier: Expression; } @@ -971,7 +971,7 @@ declare module "typescript" { getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number; isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean; getAliasedSymbol(symbol: Symbol): Symbol; - getExportsOfExternalModule(node: ImportDeclaration): Symbol[]; + getExportsOfModule(moduleSymbol: Symbol): Symbol[]; } interface SymbolDisplayBuilder { buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void; diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index 71c617a5c4e..8462f3e7ce9 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -2576,9 +2576,8 @@ declare module "typescript" { >expression : Expression >Expression : Expression } - interface ImportDeclaration extends Statement, ModuleElement { + interface ImportDeclaration extends ModuleElement { >ImportDeclaration : ImportDeclaration ->Statement : Statement >ModuleElement : ModuleElement importClause?: ImportClause; @@ -3087,10 +3086,10 @@ declare module "typescript" { >Symbol : Symbol >Symbol : Symbol - getExportsOfExternalModule(node: ImportDeclaration): Symbol[]; ->getExportsOfExternalModule : (node: ImportDeclaration) => Symbol[] ->node : ImportDeclaration ->ImportDeclaration : ImportDeclaration + getExportsOfModule(moduleSymbol: Symbol): Symbol[]; +>getExportsOfModule : (moduleSymbol: Symbol) => Symbol[] +>moduleSymbol : Symbol +>Symbol : Symbol >Symbol : Symbol } interface SymbolDisplayBuilder { diff --git a/tests/cases/fourslash/completionListForTransitivelyExportedMembers01.ts b/tests/cases/fourslash/completionListForTransitivelyExportedMembers01.ts new file mode 100644 index 00000000000..017b04592c1 --- /dev/null +++ b/tests/cases/fourslash/completionListForTransitivelyExportedMembers01.ts @@ -0,0 +1,39 @@ +/// + +// @Filename: A.ts +////export interface I1 { one: number } +////export interface I2 { two: string } +////export type I1_OR_I2 = I1 | I2; +//// +////export class C1 { +//// one: string; +////} +//// +////export module Inner { +//// export interface I3 { +//// three: boolean +//// } +//// +//// export var varVar = 100; +//// export let letVar = 200; +//// export const constVar = 300; +////} + +// @Filename: B.ts +////export var bVar = "bee!"; + +// @Filename: C.ts +////export var cVar = "see!"; +////export * from "A"; +////export * from "B" + +// @Filename: D.ts +////import * as c from "C"; +////var x = c./**/ + +goTo.marker(); +verify.completionListContains("C1"); +verify.completionListContains("Inner"); +verify.completionListContains("bVar"); +verify.completionListContains("cVar"); +verify.not.completionListContains("__export"); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListForTransitivelyExportedMembers02.ts b/tests/cases/fourslash/completionListForTransitivelyExportedMembers02.ts new file mode 100644 index 00000000000..868859746b4 --- /dev/null +++ b/tests/cases/fourslash/completionListForTransitivelyExportedMembers02.ts @@ -0,0 +1,39 @@ +/// + + +// @Filename: A.ts +////export interface I1 { one: number } +////export interface I2 { two: string } +////export type I1_OR_I2 = I1 | I2; +//// +////export class C1 { +//// one: string; +////} +//// +////export module Inner { +//// export interface I3 { +//// three: boolean +//// } +//// +//// export var varVar = 100; +//// export let letVar = 200; +//// export const constVar = 300; +////} + +// @Filename: B.ts +////export var bVar = "bee!"; + +// @Filename: C.ts +////export var cVar = "see!"; +////export * from "A"; +////export * from "B" + +// @Filename: D.ts +////import * as c from "C"; +////var x = c.Inner./**/ + +goTo.marker(); +verify.completionListContains("varVar"); +verify.completionListContains("letVar"); +verify.completionListContains("constVar"); +verify.not.completionListContains("__export"); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListForTransitivelyExportedMembers03.ts b/tests/cases/fourslash/completionListForTransitivelyExportedMembers03.ts new file mode 100644 index 00000000000..78ef3ec7c72 --- /dev/null +++ b/tests/cases/fourslash/completionListForTransitivelyExportedMembers03.ts @@ -0,0 +1,40 @@ +/// + + +// @Filename: A.ts +////export interface I1 { one: number } +////export interface I2 { two: string } +////export type I1_OR_I2 = I1 | I2; +//// +////export class C1 { +//// one: string; +////} +//// +////export module Inner { +//// export interface I3 { +//// three: boolean +//// } +//// +//// export var varVar = 100; +//// export let letVar = 200; +//// export const constVar = 300; +////} + +// @Filename: B.ts +////export var bVar = "bee!"; + +// @Filename: C.ts +////export var cVar = "see!"; +////export * from "A"; +////export * from "B" + +// @Filename: D.ts +////import * as c from "C"; +////var x: c./**/ + +goTo.marker(); +verify.completionListContains("I1"); +verify.completionListContains("I2"); +verify.completionListContains("I1_OR_I2"); +verify.completionListContains("C1"); +verify.not.completionListContains("__export"); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListForTransitivelyExportedMembers04.ts b/tests/cases/fourslash/completionListForTransitivelyExportedMembers04.ts new file mode 100644 index 00000000000..114e370d31d --- /dev/null +++ b/tests/cases/fourslash/completionListForTransitivelyExportedMembers04.ts @@ -0,0 +1,37 @@ +/// + + +// @Filename: A.ts +////export interface I1 { one: number } +////export interface I2 { two: string } +////export type I1_OR_I2 = I1 | I2; +//// +////export class C1 { +//// one: string; +////} +//// +////export module Inner { +//// export interface I3 { +//// three: boolean +//// } +//// +//// export var varVar = 100; +//// export let letVar = 200; +//// export const constVar = 300; +////} + +// @Filename: B.ts +////export var bVar = "bee!"; + +// @Filename: C.ts +////export var cVar = "see!"; +////export * from "A"; +////export * from "B" + +// @Filename: D.ts +////import * as c from "C"; +////var x: c.Inner./**/ + +goTo.marker(); +verify.completionListContains("I3"); +verify.not.completionListContains("__export"); \ No newline at end of file