Skip to content

Commit 1347621

Browse files
committed
Report error if the entityname reference in the import declaration is using private module
1 parent c643f39 commit 1347621

22 files changed

+1165
-838
lines changed

src/compiler/checker.ts

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ module ts {
308308
else {
309309
return returnResolvedSymbol(result);
310310
}
311-
}
311+
}
312312
break;
313313
case SyntaxKind.Method:
314314
case SyntaxKind.Constructor:
@@ -448,7 +448,7 @@ module ts {
448448
return moduleSymbol;
449449
}
450450

451-
function getExportAssignmentSymbol(symbol: Symbol): Symbol {
451+
function getExportAssignmentSymbol(symbol: Symbol): Symbol {
452452
checkTypeOfExportAssignmentSymbol(symbol);
453453
var symbolLinks = getSymbolLinks(symbol);
454454
return symbolLinks.exportAssignSymbol === unknownSymbol ? undefined : symbolLinks.exportAssignSymbol;
@@ -662,7 +662,7 @@ module ts {
662662
}
663663

664664
function getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): Symbol[] {
665-
function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable): Symbol[]{
665+
function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable): Symbol[] {
666666
function canQualifySymbol(symbolFromSymbolTable: Symbol, meaning: SymbolFlags) {
667667
// If the symbol is equivalent and doesnt need futher qualification, this symbol is accessible
668668
if (!needsQualification(symbolFromSymbolTable, enclosingDeclaration, meaning)) {
@@ -697,7 +697,7 @@ module ts {
697697

698698
// Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain
699699
// but only if the symbolFromSymbolTable can be qualified
700-
var accessibleSymbolsFromExports = resolvedImportedSymbol.exports ? getAccessibleSymbolChainFromSymbolTable(resolvedImportedSymbol.exports): undefined;
700+
var accessibleSymbolsFromExports = resolvedImportedSymbol.exports ? getAccessibleSymbolChainFromSymbolTable(resolvedImportedSymbol.exports) : undefined;
701701
if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, SymbolFlags.Namespace)) {
702702
return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports);
703703
}
@@ -740,22 +740,22 @@ module ts {
740740
}
741741

742742
function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult {
743-
var aliasesToMakeVisible: ImportDeclaration[];
744743
if (symbol && enclosingDeclaration && !(symbol.flags & SymbolFlags.TypeParameter)) {
745744
var initialSymbol = symbol;
746745
var meaningToLook = meaning;
747746
while (symbol) {
748747
// Symbol is accessible if it by itself is accessible
749748
var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook);
750749
if (accessibleSymbolChain) {
751-
if (forEach(accessibleSymbolChain[0].declarations, declaration => !getIsDeclarationVisible(declaration))) {
750+
var hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0]);
751+
if (!hasAccessibleDeclarations) {
752752
return {
753753
accessibility: SymbolAccessibility.NotAccessible,
754754
errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
755755
errorModuleName: symbol !== initialSymbol ? symbolToString(symbol, enclosingDeclaration, SymbolFlags.Namespace) : undefined,
756756
};
757757
}
758-
return { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible: aliasesToMakeVisible };
758+
return { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible: hasAccessibleDeclarations.aliasesToMakeVisible };
759759
}
760760

761761
// TODO(shkamat): Handle static method of class
@@ -784,6 +784,14 @@ module ts {
784784
}
785785

786786
return { accessibility: SymbolAccessibility.Accessible };
787+
}
788+
789+
function hasVisibleDeclarations(symbol: Symbol): { aliasesToMakeVisible?: ImportDeclaration[]; } {
790+
var aliasesToMakeVisible: ImportDeclaration[];
791+
if (forEach(symbol.declarations, declaration => !getIsDeclarationVisible(declaration))) {
792+
return undefined;
793+
}
794+
return { aliasesToMakeVisible: aliasesToMakeVisible };
787795

788796
function getIsDeclarationVisible(declaration: Declaration) {
789797
if (!isDeclarationVisible(declaration)) {
@@ -812,6 +820,17 @@ module ts {
812820
}
813821
}
814822

823+
function isImportDeclarationEntityNameReferenceDeclarationVisibile(entityName: EntityName): SymbolAccessiblityResult {
824+
var firstIdentifier = getFirstIdentifier(entityName);
825+
var firstIdentifierName = identifierToString(<Identifier>firstIdentifier);
826+
var symbolOfNameSpace = resolveName(entityName.parent, (<Identifier>firstIdentifier).text, SymbolFlags.Namespace, Diagnostics.Cannot_find_name_0, firstIdentifierName);
827+
// Verify if the symbol is accessible
828+
var hasNamespaceDeclarationsVisibile = hasVisibleDeclarations(symbolOfNameSpace);
829+
return hasNamespaceDeclarationsVisibile ?
830+
{ accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible: hasNamespaceDeclarationsVisibile.aliasesToMakeVisible } :
831+
{ accessibility: SymbolAccessibility.NotAccessible, errorSymbolName: firstIdentifierName };
832+
}
833+
815834
// Enclosing declaration is optional when we dont want to get qualified name in the enclosing declaration scope
816835
// Meaning needs to be specified if the enclosing declaration is given
817836
function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
@@ -830,7 +849,7 @@ module ts {
830849
// Properties/methods/Signatures/Constructors/TypeParameters do not need qualification
831850
!(symbol.flags & SymbolFlags.PropertyOrAccessor & SymbolFlags.Signature & SymbolFlags.Constructor & SymbolFlags.Method & SymbolFlags.TypeParameter)) {
832851
var symbolName: string;
833-
while (symbol) {
852+
while (symbol) {
834853
var isFirstName = !symbolName;
835854
var meaningToLook = isFirstName ? meaning : SymbolFlags.Namespace;
836855
var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook);
@@ -864,7 +883,7 @@ module ts {
864883
};
865884
}
866885

867-
function typeToString(type: Type, enclosingDeclaration?:Node, flags?: TypeFormatFlags): string {
886+
function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string {
868887
var stringWriter = createSingleLineTextWriter();
869888
// TODO(shkamat): typeToString should take enclosingDeclaration as input, once we have implemented enclosingDeclaration
870889
writeTypeToTextWriter(type, enclosingDeclaration, flags, stringWriter);
@@ -6787,7 +6806,8 @@ module ts {
67876806
writeTypeAtLocation: writeTypeAtLocation,
67886807
writeReturnTypeOfSignatureDeclaration: writeReturnTypeOfSignatureDeclaration,
67896808
writeSymbol: writeSymbolToTextWriter,
6790-
isSymbolAccessible: isSymbolAccessible
6809+
isSymbolAccessible: isSymbolAccessible,
6810+
isImportDeclarationEntityNameReferenceDeclarationVisibile: isImportDeclarationEntityNameReferenceDeclarationVisibile
67916811
};
67926812
checkProgram();
67936813
return emitFiles(resolver);

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ module ts {
156156
Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1: { code: 2065, category: DiagnosticCategory.Error, key: "Return type of public method from exported class has or is using name '{0}' from private module '{1}'." },
157157
Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1: { code: 2066, category: DiagnosticCategory.Error, key: "Return type of method from exported interface has or is using name '{0}' from private module '{1}'." },
158158
Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1: { code: 2067, category: DiagnosticCategory.Error, key: "Return type of exported function has or is using name '{0}' from private module '{1}'." },
159+
Import_declaration_0_is_using_private_name_1: { code: 2181, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
159160
Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1: { code: 2208, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of constructor signature from exported interface has or is using private name '{1}'." },
160161
Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1: { code: 2209, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of call signature from exported interface has or is using private name '{1}'." },
161162
Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1: { code: 2210, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of public static method from exported class has or is using private name '{1}'." },

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,10 @@
616616
"category": "Error",
617617
"code": 2067
618618
},
619+
"Import declaration '{0}' is using private name '{1}'.": {
620+
"category": "Error",
621+
"code": 2181
622+
},
619623
"Type parameter '{0}' of constructor signature from exported interface has or is using private name '{1}'.": {
620624
"category": "Error",
621625
"code": 2208

src/compiler/emitter.ts

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1882,25 +1882,29 @@ module ts {
18821882
typeName?: Identifier
18831883
}
18841884

1885+
function writeAsychronousImportDeclarations(importDeclarations: ImportDeclaration[]) {
1886+
var oldWriter = writer;
1887+
forEach(importDeclarations.sort(), aliasToWrite => {
1888+
var aliasEmitInfo = forEach(aliasDeclarationEmitInfo, declEmitInfo => declEmitInfo.declaration === aliasToWrite ? declEmitInfo : undefined);
1889+
writer = createTextWriter(writeSymbol);
1890+
for (var declarationIndent = aliasEmitInfo.indent; declarationIndent; declarationIndent--) {
1891+
writer.increaseIndent();
1892+
}
1893+
1894+
writeImportDeclaration(aliasToWrite);
1895+
aliasEmitInfo.asynchronousOutput = writer.getText();
1896+
});
1897+
writer = oldWriter;
1898+
}
1899+
18851900
function writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
18861901
var symbolAccesibilityResult = resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning);
18871902
if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) {
18881903
resolver.writeSymbol(symbol, enclosingDeclaration, meaning, writer);
18891904

18901905
// write the aliases
18911906
if (symbolAccesibilityResult && symbolAccesibilityResult.aliasesToMakeVisible) {
1892-
var oldWriter = writer;
1893-
forEach(symbolAccesibilityResult.aliasesToMakeVisible.sort(), aliasToWrite => {
1894-
var aliasEmitInfo = forEach(aliasDeclarationEmitInfo, declEmitInfo => declEmitInfo.declaration === aliasToWrite ? declEmitInfo : undefined);
1895-
writer = createTextWriter(writeSymbol);
1896-
for (var declarationIndent = aliasEmitInfo.indent; declarationIndent; declarationIndent--) {
1897-
writer.increaseIndent();
1898-
}
1899-
1900-
writeImportDeclaration(aliasToWrite);
1901-
aliasEmitInfo.asynchronousOutput = writer.getText();
1902-
});
1903-
writer = oldWriter;
1907+
writeAsychronousImportDeclarations(symbolAccesibilityResult.aliasesToMakeVisible);
19041908
}
19051909
}
19061910
else {
@@ -2007,6 +2011,7 @@ module ts {
20072011
writer.write(getSourceTextOfLocalNode(node.name));
20082012
writer.write(" = ");
20092013
if (node.entityName) {
2014+
checkEntityNameAccessible();
20102015
writer.write(getSourceTextOfLocalNode(node.entityName));
20112016
writer.write(";");
20122017
}
@@ -2016,6 +2021,24 @@ module ts {
20162021
writer.write(");");
20172022
}
20182023
writer.writeLine();
2024+
2025+
function checkEntityNameAccessible() {
2026+
var symbolAccesibilityResult = resolver.isImportDeclarationEntityNameReferenceDeclarationVisibile(node.entityName);
2027+
if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) {
2028+
// write the aliases
2029+
if (symbolAccesibilityResult.aliasesToMakeVisible) {
2030+
writeAsychronousImportDeclarations(symbolAccesibilityResult.aliasesToMakeVisible);
2031+
}
2032+
}
2033+
else {
2034+
// Report error
2035+
reportedDeclarationError = true;
2036+
diagnostics.push(createDiagnosticForNode(node,
2037+
Diagnostics.Import_declaration_0_is_using_private_name_1,
2038+
getSourceTextOfLocalNode(node.name),
2039+
symbolAccesibilityResult.errorSymbolName));
2040+
}
2041+
}
20192042
}
20202043

20212044
function emitModuleDeclaration(node: ModuleDeclaration) {

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ module ts {
658658
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void;
659659
writeSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, writer: TextWriter): void;
660660
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult;
661+
isImportDeclarationEntityNameReferenceDeclarationVisibile(entityName: EntityName): SymbolAccessiblityResult;
661662
}
662663

663664
export enum SymbolFlags {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
==== tests/cases/compiler/aliasInaccessibleModule.ts (1 errors) ====
2+
module M {
3+
module N {
4+
}
5+
export import X = N;
6+
~~~~~~~~~~~~~~~~~~~~
7+
!!! Import declaration 'X' is using private name 'N'.
8+
}

tests/baselines/reference/aliasInaccessibleModule.js

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,3 @@ module M {
99
var M;
1010
(function (M) {
1111
})(M || (M = {}));
12-
13-
14-
//// [aliasInaccessibleModule.d.ts]
15-
declare module M {
16-
export import X = N;
17-
}
18-
19-
20-
//// [DtsFileErrors]
21-
22-
23-
==== tests/cases/compiler/aliasInaccessibleModule.d.ts (1 errors) ====
24-
declare module M {
25-
export import X = N;
26-
~~~~~~~~~~~~~~~~~~~~
27-
!!! Cannot find name 'N'.
28-
}
29-
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
==== tests/cases/compiler/aliasInaccessibleModule2.ts (1 errors) ====
2+
module M {
3+
module N {
4+
class C {
5+
}
6+
7+
}
8+
import R = N;
9+
~~~~~~~~~~~~~
10+
!!! Import declaration 'R' is using private name 'N'.
11+
export import X = R;
12+
}

tests/baselines/reference/aliasInaccessibleModule2.js

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,3 @@ var M;
2323
var R = N;
2424
M.X = R;
2525
})(M || (M = {}));
26-
27-
28-
//// [aliasInaccessibleModule2.d.ts]
29-
declare module M {
30-
export import X = R;
31-
}
32-
33-
34-
//// [DtsFileErrors]
35-
36-
37-
==== tests/cases/compiler/aliasInaccessibleModule2.d.ts (1 errors) ====
38-
declare module M {
39-
export import X = R;
40-
~~~~~~~~~~~~~~~~~~~~
41-
!!! Cannot find name 'R'.
42-
}
43-

tests/baselines/reference/declarationEmit_nameConflicts.js

Lines changed: 1 addition & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ declare module f {
145145
}
146146
export = f;
147147
//// [declarationEmit_nameConflicts_0.d.ts]
148+
import im = require('declarationEmit_nameConflicts_1');
148149
export declare module M {
149150
function f(): void;
150151
class C {
@@ -193,67 +194,3 @@ export declare module M.Q {
193194
}
194195
}
195196
}
196-
197-
198-
//// [DtsFileErrors]
199-
200-
201-
==== tests/cases/compiler/declarationEmit_nameConflicts_0.d.ts (1 errors) ====
202-
export declare module M {
203-
function f(): void;
204-
class C {
205-
}
206-
module N {
207-
function g(): void;
208-
interface I {
209-
}
210-
}
211-
export import a = M.f;
212-
export import b = M.C;
213-
export import c = N;
214-
export import d = im;
215-
~~~~~~~~~~~~~~~~~~~~~
216-
!!! Cannot find name 'im'.
217-
}
218-
export declare module M.P {
219-
function f(): void;
220-
class C {
221-
}
222-
module N {
223-
function g(): void;
224-
interface I {
225-
}
226-
}
227-
export import im = M.P.f;
228-
var a: () => void;
229-
var b: typeof M.C;
230-
var c: typeof M.N;
231-
var g: () => void;
232-
var d: typeof M.d;
233-
}
234-
export declare module M.Q {
235-
function f(): void;
236-
class C {
237-
}
238-
module N {
239-
function g(): void;
240-
interface I {
241-
}
242-
}
243-
interface b extends M.C {
244-
}
245-
interface I extends M.c.I {
246-
}
247-
module c {
248-
interface I extends M.c.I {
249-
}
250-
}
251-
}
252-
253-
==== tests/cases/compiler/declarationEmit_nameConflicts_1.d.ts (0 errors) ====
254-
declare module f {
255-
class c {
256-
}
257-
}
258-
export = f;
259-

0 commit comments

Comments
 (0)