mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 03:23:08 -06:00
Use the isDeclarationVisible in checker to determine if the declaration needs to be emitted
This would help in unifying logic of when to check if the type is visible
This commit is contained in:
parent
5a23dd0684
commit
148abea09d
@ -917,6 +917,125 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function isDeclarationVisible(node: Declaration): boolean {
|
||||
function isGlobalSourceFile(node: Node) {
|
||||
return node.kind === SyntaxKind.SourceFile && !(node.flags & NodeFlags.ExternalModule);
|
||||
}
|
||||
|
||||
function getExternalModule(node: Node) {
|
||||
for (; node; node = node.parent) {
|
||||
if (node.kind === SyntaxKind.ModuleDeclaration) {
|
||||
if ((<ModuleDeclaration>node).name.kind === SyntaxKind.StringLiteral) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
else if (node.kind === SyntaxKind.SourceFile) {
|
||||
return (node.flags & NodeFlags.ExternalModule) ? node : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isUsedInExportAssignment(node: Node) {
|
||||
// Get source File and see if it is external module and has export assigned symbol
|
||||
var externalModule = getExternalModule(node);
|
||||
if (externalModule) {
|
||||
// This is export assigned symbol node
|
||||
var externalModuleSymbol = getSymbolOfNode(externalModule);
|
||||
var exportAssignmentSymbol = getExportAssignmentSymbol(externalModuleSymbol);
|
||||
var symbolOfNode = getSymbolOfNode(node);
|
||||
if (exportAssignmentSymbol === symbolOfNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (exportAssignmentSymbol && !!(exportAssignmentSymbol.flags & SymbolFlags.Import)) {
|
||||
// if export assigned symbol is import declaration, resolve the import
|
||||
var resolvedExportSymbol = resolveImport(exportAssignmentSymbol);
|
||||
if (resolvedExportSymbol === symbolOfNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(shkamat): Chained import assignment
|
||||
// eg. a should be visible too.
|
||||
//module m {
|
||||
// export module c {
|
||||
// export class c {
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//import a = m.c;
|
||||
//import b = a;
|
||||
//export = b;
|
||||
|
||||
// Container of resolvedExportSymbol is visible
|
||||
return forEach(resolvedExportSymbol.declarations, declaration => {
|
||||
while (declaration) {
|
||||
if (declaration === node) {
|
||||
return true;
|
||||
}
|
||||
declaration = declaration.parent;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function determineIfDeclarationIsVisible() {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
if (!(node.flags & NodeFlags.Export)) {
|
||||
// node.parent is variable statement so look at the variable statement's parent
|
||||
return isGlobalSourceFile(node.parent.parent) || isUsedInExportAssignment(node);
|
||||
}
|
||||
// Exported members are visible if parent is visible
|
||||
return isDeclarationVisible(node.parent.parent);
|
||||
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
if (!(node.flags & NodeFlags.Export)) {
|
||||
// TODO(shkamat): non exported aliases can be visible if they are referenced else where for value/type/namespace
|
||||
return isGlobalSourceFile(node.parent) || isUsedInExportAssignment(node);
|
||||
}
|
||||
// Exported members are visible if parent is visible
|
||||
return isDeclarationVisible(node.parent);
|
||||
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.Method:
|
||||
if (node.flags & NodeFlags.Private) {
|
||||
// Private properties/methods are not visible
|
||||
return false;
|
||||
}
|
||||
// Public properties/methods are visible if its parents are visible, so let it fall into next case statement
|
||||
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return isDeclarationVisible(node.parent);
|
||||
|
||||
// Source file is always visible
|
||||
case SyntaxKind.SourceFile:
|
||||
return true;
|
||||
|
||||
default:
|
||||
Debug.fail("isDeclarationVisible unknown: SyntaxKind: " + SyntaxKind[node.kind]);
|
||||
}
|
||||
}
|
||||
|
||||
if (node) {
|
||||
var links = getNodeLinks(node);
|
||||
if (links.isVisible === undefined) {
|
||||
links.isVisible = determineIfDeclarationIsVisible();
|
||||
}
|
||||
return links.isVisible;
|
||||
}
|
||||
}
|
||||
|
||||
function getApparentType(type: Type): ApparentType {
|
||||
if (type.flags & TypeFlags.TypeParameter) {
|
||||
do {
|
||||
@ -4892,7 +5011,7 @@ module ts {
|
||||
checkTypeAssignableTo(checkAndMarkExpression(node.initializer, type), type, node, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
checkCollisionWithCapturedSuperVariable(node, node.name);
|
||||
if (!useTypeFromValueDeclaration) {
|
||||
// TypeScript 1.0 spec (April 2014): 5.1
|
||||
@ -5870,22 +5989,6 @@ module ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isReferencedInExportAssignment(node: Declaration): boolean {
|
||||
var exportAssignedSymbol = getExportAssignmentSymbol(getSymbolOfNode(getContainerOfModuleElementDeclaration(node)));
|
||||
if (exportAssignedSymbol) {
|
||||
var symbol = getSymbolOfNode(node);
|
||||
if (exportAssignedSymbol === symbol) {
|
||||
// This symbol was export assigned symbol
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(shkamat): if export assignment is alias, the alias target would make the node as referenced in export assignment
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isImplementationOfOverload(node: FunctionDeclaration) {
|
||||
if (node.body) {
|
||||
var symbol = getSymbolOfNode(node);
|
||||
@ -5927,7 +6030,7 @@ module ts {
|
||||
getEnumMemberValue: getEnumMemberValue,
|
||||
isTopLevelValueImportedViaEntityName: isTopLevelValueImportedViaEntityName,
|
||||
shouldEmitDeclarations: shouldEmitDeclarations,
|
||||
isReferencedInExportAssignment: isReferencedInExportAssignment,
|
||||
isDeclarationVisible: isDeclarationVisible,
|
||||
isImplementationOfOverload: isImplementationOfOverload,
|
||||
writeTypeAtLocation: writeTypeAtLocation,
|
||||
writeReturnTypeOfSignatureDeclaration: writeReturnTypeOfSignatureDeclaration
|
||||
|
||||
@ -1881,34 +1881,6 @@ module ts {
|
||||
writeLine();
|
||||
}
|
||||
|
||||
function isModuleElementExternallyVisible(node: Declaration) {
|
||||
if (node.flags & NodeFlags.Export) {
|
||||
// Exported member - emit this declaration
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this node is in external module, check if this is export assigned
|
||||
var moduleDeclaration = getContainerOfModuleElementDeclaration(node);
|
||||
if ((moduleDeclaration.flags & NodeFlags.ExternalModule) || // Source file with external module flag
|
||||
// Ambient external module declaration
|
||||
(moduleDeclaration.kind === SyntaxKind.ModuleDeclaration && (<ModuleDeclaration>moduleDeclaration).name.kind === SyntaxKind.StringLiteral)) {
|
||||
return resolver.isReferencedInExportAssignment(node);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function canEmitModuleElementDeclaration(node: Declaration) {
|
||||
if (isModuleElementExternallyVisible(node)) {
|
||||
// Either exported module element or is referenced in export assignment
|
||||
return true;
|
||||
}
|
||||
|
||||
// emit the declaration if this is in global scope source file
|
||||
var moduleDeclaration = getContainerOfModuleElementDeclaration(node);
|
||||
return moduleDeclaration.kind === SyntaxKind.SourceFile && !(moduleDeclaration.flags & NodeFlags.ExternalModule);
|
||||
}
|
||||
|
||||
function emitDeclarationFlags(node: Declaration) {
|
||||
if (node.flags & NodeFlags.Static) {
|
||||
if (node.flags & NodeFlags.Private) {
|
||||
@ -1935,8 +1907,7 @@ module ts {
|
||||
}
|
||||
|
||||
function emitImportDeclaration(node: ImportDeclaration) {
|
||||
// TODO(shkamat): Emit if import decl is used to declare type in this context
|
||||
if (isModuleElementExternallyVisible(node)) {
|
||||
if (resolver.isDeclarationVisible(node)) {
|
||||
if (node.flags & NodeFlags.Export) {
|
||||
write("export ");
|
||||
}
|
||||
@ -1957,7 +1928,7 @@ module ts {
|
||||
}
|
||||
|
||||
function emitModuleDeclaration(node: ModuleDeclaration) {
|
||||
if (canEmitModuleElementDeclaration(node)) {
|
||||
if (resolver.isDeclarationVisible(node)) {
|
||||
emitDeclarationFlags(node);
|
||||
write("module ");
|
||||
emitSourceTextOfNode(node.name);
|
||||
@ -1980,7 +1951,7 @@ module ts {
|
||||
}
|
||||
|
||||
function emitEnumDeclaration(node: EnumDeclaration) {
|
||||
if (canEmitModuleElementDeclaration(node)) {
|
||||
if (resolver.isDeclarationVisible(node)) {
|
||||
emitDeclarationFlags(node);
|
||||
write("enum ");
|
||||
emitSourceTextOfNode(node.name);
|
||||
@ -2043,7 +2014,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
if (canEmitModuleElementDeclaration(node)) {
|
||||
if (resolver.isDeclarationVisible(node)) {
|
||||
emitDeclarationFlags(node);
|
||||
write("class ");
|
||||
emitSourceTextOfNode(node.name);
|
||||
@ -2067,7 +2038,7 @@ module ts {
|
||||
}
|
||||
|
||||
function emitInterfaceDeclaration(node: InterfaceDeclaration) {
|
||||
if (canEmitModuleElementDeclaration(node)) {
|
||||
if (resolver.isDeclarationVisible(node)) {
|
||||
emitDeclarationFlags(node);
|
||||
write("interface ");
|
||||
emitSourceTextOfNode(node.name);
|
||||
@ -2094,8 +2065,9 @@ module ts {
|
||||
}
|
||||
|
||||
function emitVariableDeclaration(node: VariableDeclaration) {
|
||||
// If we are emitting property it isnt moduleElement and doesnt need canEmitModuleElement check
|
||||
if (node.kind !== SyntaxKind.VariableDeclaration || canEmitModuleElementDeclaration(node)) {
|
||||
// If we are emitting property it isnt moduleElement and hence we already know it needs to be emitted
|
||||
// so there is no check needed to see if declaration is visible
|
||||
if (node.kind !== SyntaxKind.VariableDeclaration || resolver.isDeclarationVisible(node)) {
|
||||
emitSourceTextOfNode(node.name);
|
||||
// If optional property emit ?
|
||||
if (node.kind === SyntaxKind.Property && (node.flags & NodeFlags.QuestionMark)) {
|
||||
@ -2109,7 +2081,7 @@ module ts {
|
||||
}
|
||||
|
||||
function emitVariableStatement(node: VariableStatement) {
|
||||
var hasDeclarationWithEmit = forEach(node.declarations, varDeclaration => canEmitModuleElementDeclaration(varDeclaration));
|
||||
var hasDeclarationWithEmit = forEach(node.declarations, varDeclaration => resolver.isDeclarationVisible(varDeclaration));
|
||||
if (hasDeclarationWithEmit) {
|
||||
emitDeclarationFlags(node);
|
||||
write("var ");
|
||||
@ -2134,8 +2106,9 @@ module ts {
|
||||
}
|
||||
|
||||
function emitFunctionDeclaration(node: FunctionDeclaration) {
|
||||
// If we are emitting Method/Constructor it isnt moduleElement and doesnt need canEmitModuleElement check
|
||||
if ((node.kind !== SyntaxKind.FunctionDeclaration || canEmitModuleElementDeclaration(node)) &&
|
||||
// If we are emitting Method/Constructor it isnt moduleElement and hence already determined to be emitting
|
||||
// so no need to verify if the declaration is visible
|
||||
if ((node.kind !== SyntaxKind.FunctionDeclaration || resolver.isDeclarationVisible(node)) &&
|
||||
!resolver.isImplementationOfOverload(node)) {
|
||||
emitDeclarationFlags(node);
|
||||
if (node.kind === SyntaxKind.FunctionDeclaration) {
|
||||
|
||||
@ -273,12 +273,6 @@ module ts {
|
||||
return s.parameters.length > 0 && (s.parameters[s.parameters.length - 1].flags & NodeFlags.Rest) !== 0;
|
||||
}
|
||||
|
||||
export function getContainerOfModuleElementDeclaration(node: Declaration) {
|
||||
// If the declaration is var declaration, then the parent is variable statement but we actually want the module
|
||||
var container = node.kind === SyntaxKind.VariableDeclaration ? node.parent.parent : node.parent;
|
||||
return container.kind == SyntaxKind.ModuleBlock ? container.parent : container;
|
||||
}
|
||||
|
||||
enum ParsingContext {
|
||||
SourceElements, // Elements in source file
|
||||
ModuleElements, // Elements in module declaration
|
||||
|
||||
@ -616,7 +616,7 @@ module ts {
|
||||
getNodeCheckFlags(node: Node): NodeCheckFlags;
|
||||
getEnumMemberValue(node: EnumMember): number;
|
||||
shouldEmitDeclarations(): boolean;
|
||||
isReferencedInExportAssignment(node: Declaration): boolean;
|
||||
isDeclarationVisible(node: Declaration): boolean;
|
||||
isImplementationOfOverload(node: FunctionDeclaration): boolean;
|
||||
writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void;
|
||||
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void;
|
||||
@ -736,6 +736,7 @@ module ts {
|
||||
flags?: NodeCheckFlags; // Set of flags specific to Node
|
||||
enumMemberValue?: number; // Constant value of enum member
|
||||
isIllegalTypeReferenceInConstraint?: boolean; // Is type reference in constraint refers to the type parameter from the same list
|
||||
isVisible?: boolean; // Is this node visible
|
||||
}
|
||||
|
||||
export enum TypeFlags {
|
||||
|
||||
@ -31,5 +31,21 @@ module.exports = m;
|
||||
|
||||
|
||||
//// [declFileExportAssignmentImportInternalModule.d.ts]
|
||||
declare module m3 {
|
||||
module m2 {
|
||||
interface connectModule {
|
||||
(res: any, req: any, next: any): void;
|
||||
}
|
||||
interface connectExport {
|
||||
use: (mod: connectModule) => connectExport;
|
||||
listen: (port: number) => void;
|
||||
}
|
||||
}
|
||||
var server: {
|
||||
(): m2.connectExport;
|
||||
test1: m2.connectModule;
|
||||
test2(): m2.connectModule;
|
||||
};
|
||||
}
|
||||
import m = m3;
|
||||
export = m;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user