Skip to content

Commit 999b7fe

Browse files
committed
Checker and emitter changes to report errors on inaccessibility of symbols when writing types in declaration file
1 parent bbb36dc commit 999b7fe

File tree

3 files changed

+72
-8
lines changed

3 files changed

+72
-8
lines changed

src/compiler/checker.ts

+32-4
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ module ts {
645645
}
646646

647647
// If symbol is directly available by its name in the symbol table
648-
if (isAccessible(symbols[symbol.name])) {
648+
if (hasProperty(symbols, symbol.name) && isAccessible(symbols[symbol.name])) {
649649
return symbol;
650650
}
651651

@@ -668,7 +668,7 @@ module ts {
668668
var qualify = false;
669669
forEachSymbolTableInScope(enclosingDeclaration, symbolTable => {
670670
// If symbol of this name is not available in the symbol table we are ok
671-
if (!symbolTable[symbol.name]) {
671+
if (!hasProperty(symbolTable, symbol.name)) {
672672
// Continue to the next symbol table
673673
return false;
674674
}
@@ -693,8 +693,36 @@ module ts {
693693
return qualify
694694
}
695695

696-
function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): boolean {
697-
// TODO(shkamat): Actual implementation
696+
function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult {
697+
if (symbol && enclosingDeclaration && !(symbol.flags & SymbolFlags.TypeParameter)) {
698+
var initialSymbol = symbol;
699+
var meaningToLook = meaning;
700+
while (symbol) {
701+
// Symbol is accessible if it by itself is accessible
702+
var accessibleSymbol = getAccessibleSymbol(symbol, enclosingDeclaration, meaningToLook);
703+
if (accessibleSymbol) {
704+
if (forEach(accessibleSymbol.declarations, declaration => !isDeclarationVisible(declaration))) {
705+
return {
706+
accessibility: SymbolAccessibility.NotAccessible,
707+
errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
708+
errorModuleName: symbol !== initialSymbol ? symbolToString(symbol, enclosingDeclaration, SymbolFlags.Namespace) : undefined
709+
};
710+
}
711+
return { accessibility: SymbolAccessibility.Accessible };
712+
}
713+
714+
meaningToLook = SymbolFlags.Namespace;
715+
symbol = symbol.parent;
716+
}
717+
718+
// This is a local symbol that cannot be named
719+
return {
720+
accessibility: SymbolAccessibility.CannotBeNamed,
721+
errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
722+
};
723+
}
724+
725+
return { accessibility: SymbolAccessibility.Accessible };
698726
}
699727

700728
// Enclosing declaration is optional when we dont want to get qualified name in the enclosing declaration scope

src/compiler/emitter.ts

+27-3
Original file line numberDiff line numberDiff line change
@@ -1854,10 +1854,30 @@ module ts {
18541854
var decreaseIndent = writer.decreaseIndent;
18551855

18561856
var enclosingDeclaration: Node;
1857+
var reportedDeclarationError = false;
1858+
1859+
var getSymbolVisibilityDiagnosticMessage: (symbolAccesibilityResult: SymbolAccessiblityResult) => {
1860+
errorNode: Node;
1861+
diagnosticMessage: DiagnosticMessage;
1862+
typeName: Identifier
1863+
}
18571864

18581865
function writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
1859-
// TODO(shkamat): Report error if the symbol is not accessible
1860-
resolver.writeSymbol(symbol, enclosingDeclaration, meaning, writer);
1866+
var symbolAccesibilityResult = resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning);
1867+
// TODO(shkamat): Since we dont have error reporting for all the cases as yet we have this check on handler being present
1868+
if (!getSymbolVisibilityDiagnosticMessage || symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) {
1869+
resolver.writeSymbol(symbol, enclosingDeclaration, meaning, writer);
1870+
}
1871+
else {
1872+
// Report error
1873+
reportedDeclarationError = true;
1874+
var errorInfo = getSymbolVisibilityDiagnosticMessage(symbolAccesibilityResult);
1875+
diagnostics.push(createDiagnosticForNode(errorInfo.errorNode,
1876+
errorInfo.diagnosticMessage,
1877+
getSourceTextOfLocalNode(errorInfo.typeName),
1878+
symbolAccesibilityResult.errorSymbolName,
1879+
symbolAccesibilityResult.errorModuleName));
1880+
}
18611881
}
18621882

18631883
function emitLines(nodes: Node[]) {
@@ -2296,7 +2316,11 @@ module ts {
22962316
});
22972317
}
22982318

2299-
writeFile(getModuleNameFromFilename(jsFilePath) + ".d.ts", referencePathsOutput + writer.getText());
2319+
// TODO(shkamat): Should we not write any declaration file if any of them can produce error,
2320+
// or should we just not write this file like we are doing now
2321+
if (!reportedDeclarationError) {
2322+
writeFile(getModuleNameFromFilename(jsFilePath) + ".d.ts", referencePathsOutput + writer.getText());
2323+
}
23002324
}
23012325

23022326
var shouldEmitDeclarations = resolver.shouldEmitDeclarations();

src/compiler/types.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,18 @@ module ts {
611611
WriteArrayAsGenericType = 0x00000001, // Declarations
612612
}
613613

614+
export enum SymbolAccessibility {
615+
Accessible,
616+
NotAccessible,
617+
CannotBeNamed
618+
}
619+
620+
export interface SymbolAccessiblityResult {
621+
accessibility: SymbolAccessibility;
622+
errorSymbolName?: string // Optional symbol name that results in error
623+
errorModuleName?: string // If the symbol is not visibile from module, module's name
624+
}
625+
614626
export interface EmitResolver {
615627
getProgram(): Program;
616628
getModuleObjectName(node: ModuleDeclaration): string;
@@ -627,7 +639,7 @@ module ts {
627639
writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void;
628640
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void;
629641
writeSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, writer: TextWriter): void;
630-
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): boolean;
642+
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult;
631643
}
632644

633645
export enum SymbolFlags {

0 commit comments

Comments
 (0)