From 999b7fed928cb803b83cbb4555560f623060f10d Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 18 Jul 2014 18:06:37 -0700 Subject: [PATCH] Checker and emitter changes to report errors on inaccessibility of symbols when writing types in declaration file --- src/compiler/checker.ts | 36 ++++++++++++++++++++++++++++++++---- src/compiler/emitter.ts | 30 +++++++++++++++++++++++++++--- src/compiler/types.ts | 14 +++++++++++++- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4e689944394..378e23bf83d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -645,7 +645,7 @@ module ts { } // If symbol is directly available by its name in the symbol table - if (isAccessible(symbols[symbol.name])) { + if (hasProperty(symbols, symbol.name) && isAccessible(symbols[symbol.name])) { return symbol; } @@ -668,7 +668,7 @@ module ts { var qualify = false; forEachSymbolTableInScope(enclosingDeclaration, symbolTable => { // If symbol of this name is not available in the symbol table we are ok - if (!symbolTable[symbol.name]) { + if (!hasProperty(symbolTable, symbol.name)) { // Continue to the next symbol table return false; } @@ -693,8 +693,36 @@ module ts { return qualify } - function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): boolean { - // TODO(shkamat): Actual implementation + function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult { + if (symbol && enclosingDeclaration && !(symbol.flags & SymbolFlags.TypeParameter)) { + var initialSymbol = symbol; + var meaningToLook = meaning; + while (symbol) { + // Symbol is accessible if it by itself is accessible + var accessibleSymbol = getAccessibleSymbol(symbol, enclosingDeclaration, meaningToLook); + if (accessibleSymbol) { + if (forEach(accessibleSymbol.declarations, declaration => !isDeclarationVisible(declaration))) { + return { + accessibility: SymbolAccessibility.NotAccessible, + errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), + errorModuleName: symbol !== initialSymbol ? symbolToString(symbol, enclosingDeclaration, SymbolFlags.Namespace) : undefined + }; + } + return { accessibility: SymbolAccessibility.Accessible }; + } + + meaningToLook = SymbolFlags.Namespace; + symbol = symbol.parent; + } + + // This is a local symbol that cannot be named + return { + accessibility: SymbolAccessibility.CannotBeNamed, + errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), + }; + } + + return { accessibility: SymbolAccessibility.Accessible }; } // Enclosing declaration is optional when we dont want to get qualified name in the enclosing declaration scope diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 0f5e3477778..bf6f8c7fff9 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1854,10 +1854,30 @@ module ts { var decreaseIndent = writer.decreaseIndent; var enclosingDeclaration: Node; + var reportedDeclarationError = false; + + var getSymbolVisibilityDiagnosticMessage: (symbolAccesibilityResult: SymbolAccessiblityResult) => { + errorNode: Node; + diagnosticMessage: DiagnosticMessage; + typeName: Identifier + } function writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) { - // TODO(shkamat): Report error if the symbol is not accessible - resolver.writeSymbol(symbol, enclosingDeclaration, meaning, writer); + var symbolAccesibilityResult = resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning); + // TODO(shkamat): Since we dont have error reporting for all the cases as yet we have this check on handler being present + if (!getSymbolVisibilityDiagnosticMessage || symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) { + resolver.writeSymbol(symbol, enclosingDeclaration, meaning, writer); + } + else { + // Report error + reportedDeclarationError = true; + var errorInfo = getSymbolVisibilityDiagnosticMessage(symbolAccesibilityResult); + diagnostics.push(createDiagnosticForNode(errorInfo.errorNode, + errorInfo.diagnosticMessage, + getSourceTextOfLocalNode(errorInfo.typeName), + symbolAccesibilityResult.errorSymbolName, + symbolAccesibilityResult.errorModuleName)); + } } function emitLines(nodes: Node[]) { @@ -2296,7 +2316,11 @@ module ts { }); } - writeFile(getModuleNameFromFilename(jsFilePath) + ".d.ts", referencePathsOutput + writer.getText()); + // TODO(shkamat): Should we not write any declaration file if any of them can produce error, + // or should we just not write this file like we are doing now + if (!reportedDeclarationError) { + writeFile(getModuleNameFromFilename(jsFilePath) + ".d.ts", referencePathsOutput + writer.getText()); + } } var shouldEmitDeclarations = resolver.shouldEmitDeclarations(); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9b446ff0153..6bf3f971a95 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -611,6 +611,18 @@ module ts { WriteArrayAsGenericType = 0x00000001, // Declarations } + export enum SymbolAccessibility { + Accessible, + NotAccessible, + CannotBeNamed + } + + export interface SymbolAccessiblityResult { + accessibility: SymbolAccessibility; + errorSymbolName?: string // Optional symbol name that results in error + errorModuleName?: string // If the symbol is not visibile from module, module's name + } + export interface EmitResolver { getProgram(): Program; getModuleObjectName(node: ModuleDeclaration): string; @@ -627,7 +639,7 @@ module ts { writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void; writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void; writeSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, writer: TextWriter): void; - isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): boolean; + isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult; } export enum SymbolFlags {