Emit the type annotation as it is in the declaration file if we have it

This commit is contained in:
Sheetal Nandi 2014-11-10 15:36:10 -08:00
parent 04e2169f03
commit 9ba4d37d7b
3 changed files with 399 additions and 159 deletions

View File

@ -883,13 +883,13 @@ module ts {
if (accessibleSymbolChain) {
var hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0]);
if (!hasAccessibleDeclarations) {
return {
return <SymbolAccessiblityResult>{
accessibility: SymbolAccessibility.NotAccessible,
errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
errorModuleName: symbol !== initialSymbol ? symbolToString(symbol, enclosingDeclaration, SymbolFlags.Namespace) : undefined,
};
}
return { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible: hasAccessibleDeclarations.aliasesToMakeVisible };
return hasAccessibleDeclarations;
}
// If we haven't got the accessible symbol, it doesn't mean the symbol is actually inaccessible.
@ -946,12 +946,12 @@ module ts {
(declaration.kind === SyntaxKind.SourceFile && isExternalModule(<SourceFile>declaration));
}
function hasVisibleDeclarations(symbol: Symbol): { aliasesToMakeVisible?: ImportDeclaration[]; } {
function hasVisibleDeclarations(symbol: Symbol): SymbolVisibilityResult {
var aliasesToMakeVisible: ImportDeclaration[];
if (forEach(symbol.declarations, declaration => !getIsDeclarationVisible(declaration))) {
return undefined;
}
return { aliasesToMakeVisible: aliasesToMakeVisible };
return { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible: aliasesToMakeVisible };
function getIsDeclarationVisible(declaration: Declaration) {
if (!isDeclarationVisible(declaration)) {
@ -980,14 +980,50 @@ module ts {
}
}
function isImportDeclarationEntityNameReferenceDeclarationVisibile(entityName: EntityName): SymbolAccessiblityResult {
function isEntityNameVisible(entityName: EntityName, enclosingDeclaration: Node): SymbolVisibilityResult {
// get symbol of the first identifier of the entityName
var meaning: SymbolFlags;
if (entityName.parent.kind === SyntaxKind.TypeQuery) {
// Typeof value
meaning = SymbolFlags.Value | SymbolFlags.ExportValue;
}
else if (entityName.kind === SyntaxKind.QualifiedName ||
entityName.parent.kind === SyntaxKind.ImportDeclaration) {
// Left identifier from type reference or TypeAlias
// Entity name of the import declaration
meaning = SymbolFlags.Namespace;
}
else {
// Type Reference or TypeAlias entity = Identifier
meaning = SymbolFlags.Type;
}
var firstIdentifier = getFirstIdentifier(entityName);
var symbolOfNameSpace = resolveName(entityName.parent, (<Identifier>firstIdentifier).text, SymbolFlags.Namespace, Diagnostics.Cannot_find_name_0, firstIdentifier);
var symbol = resolveName(enclosingDeclaration, (<Identifier>firstIdentifier).text, meaning, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined);
// Verify if the symbol is accessible
var hasNamespaceDeclarationsVisibile = hasVisibleDeclarations(symbolOfNameSpace);
return hasNamespaceDeclarationsVisibile ?
{ accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible: hasNamespaceDeclarationsVisibile.aliasesToMakeVisible } :
{ accessibility: SymbolAccessibility.NotAccessible, errorSymbolName: declarationNameToString(<Identifier>firstIdentifier) };
var isVisible = hasVisibleDeclarations(symbol);
if (isVisible) {
return isVisible;
}
// Not visible populate error info
var errorSymbolName: string;
var errorModuleName: string;
// TODO(shkamat) For now lets just do this for alias declarations, but in all cases only first identifier text should be enough
if (entityName.parent.kind === SyntaxKind.ImportDeclaration) {
errorSymbolName = getTextOfNode(firstIdentifier);
}
else {
errorSymbolName = getTextOfNode(entityName);
errorModuleName = entityName.kind === SyntaxKind.QualifiedName ?
getTextOfNode(firstIdentifier) :
undefined;
}
return <SymbolAccessiblityResult>{
accessibility: SymbolAccessibility.NotAccessible,
errorSymbolName: errorSymbolName,
errorModuleName: errorModuleName
};
}
function releaseStringWriter(writer: StringSymbolWriter) {
@ -1599,6 +1635,7 @@ module ts {
case SyntaxKind.IndexSignature:
case SyntaxKind.Parameter:
case SyntaxKind.ModuleBlock:
case SyntaxKind.TypeParameter:
return isDeclarationVisible(node.parent);
// Source file is always visible
@ -8918,7 +8955,7 @@ module ts {
writeTypeAtLocation: writeTypeAtLocation,
writeReturnTypeOfSignatureDeclaration: writeReturnTypeOfSignatureDeclaration,
isSymbolAccessible: isSymbolAccessible,
isImportDeclarationEntityNameReferenceDeclarationVisibile: isImportDeclarationEntityNameReferenceDeclarationVisibile,
isEntityNameVisible: isEntityNameVisible,
getConstantValue: getConstantValue,
};
checkProgram();

View File

@ -6,6 +6,7 @@
module ts {
interface EmitTextWriter {
write(s: string): void;
writeTextOfNode(node: Node): void;
writeLine(): void;
increaseIndent(): void;
decreaseIndent(): void;
@ -18,7 +19,15 @@ module ts {
getIndent(): number;
}
interface SymbolAccessibilityDiagnostic {
errorNode: Node;
diagnosticMessage: DiagnosticMessage;
typeName?: DeclarationName;
}
type GetSymbolAccessibilityDiagnostic = (symbolAccesibilityResult: SymbolAccessiblityResult) => SymbolAccessibilityDiagnostic;
interface EmitTextWriterWithSymbolWriter extends EmitTextWriter, SymbolWriter{
getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic;
}
var indentStrings: string[] = ["", " "];
@ -156,9 +165,14 @@ module ts {
}
}
function writeTextOfNode(node: Node) {
write(getSourceTextOfLocalNode(node));
}
return {
write: write,
rawWrite: rawWrite,
writeTextOfNode: writeTextOfNode,
writeLiteral: writeLiteral,
writeLine: writeLine,
increaseIndent: () => indent++,
@ -317,6 +331,7 @@ module ts {
function emitJavaScript(jsFilePath: string, root?: SourceFile) {
var writer = createTextWriter();
var write = writer.write;
var writeTextOfNode = writer.writeTextOfNode;
var writeLine = writer.writeLine;
var increaseIndent = writer.increaseIndent;
var decreaseIndent = writer.decreaseIndent;
@ -920,7 +935,7 @@ module ts {
write((<LiteralExpression>node).text);
}
else {
write(getSourceTextOfLocalNode(node));
writeTextOfNode(node);
}
write("\"");
@ -965,7 +980,7 @@ module ts {
write(".");
}
}
write(getSourceTextOfLocalNode(node));
writeTextOfNode(node);
}
function emitThis(node: Node) {
@ -2489,11 +2504,13 @@ module ts {
}
function emitDeclarations(jsFilePath: string, root?: SourceFile) {
var writer = createTextWriterWithSymbolWriter();
var write = writer.write;
var writeLine = writer.writeLine;
var increaseIndent = writer.increaseIndent;
var decreaseIndent = writer.decreaseIndent;
var write: (s: string) => void;
var writeLine: () => void;
var increaseIndent: () => void;
var decreaseIndent: () => void;
var writeTextOfNode: (node: Node) => void;
var writer = createAndSetNewTextWriterWithSymbolWriter();
var enclosingDeclaration: Node;
var reportedDeclarationError = false;
@ -2507,13 +2524,7 @@ module ts {
asynchronousOutput?: string; // If the output for alias was written asynchronously, the corresponding output
}[] = [];
var getSymbolVisibilityDiagnosticMessage: (symbolAccesibilityResult: SymbolAccessiblityResult) => {
errorNode: Node;
diagnosticMessage: DiagnosticMessage;
typeName?: DeclarationName
}
function createTextWriterWithSymbolWriter(): EmitTextWriterWithSymbolWriter {
function createAndSetNewTextWriterWithSymbolWriter(): EmitTextWriterWithSymbolWriter {
var writer = <EmitTextWriterWithSymbolWriter>createTextWriter();
writer.trackSymbol = trackSymbol;
writer.writeKeyword = writer.write;
@ -2523,28 +2534,36 @@ module ts {
writer.writeStringLiteral = writer.writeLiteral;
writer.writeParameter = writer.write;
writer.writeSymbol = writer.write;
setWriter(writer);
return writer;
}
function setWriter(newWriter: EmitTextWriterWithSymbolWriter) {
writer = newWriter;
write = newWriter.write;
writeTextOfNode = newWriter.writeTextOfNode;
writeLine = newWriter.writeLine;
increaseIndent = newWriter.increaseIndent;
decreaseIndent = newWriter.decreaseIndent;
}
function writeAsychronousImportDeclarations(importDeclarations: ImportDeclaration[]) {
var oldWriter = writer;
forEach(importDeclarations, aliasToWrite => {
var aliasEmitInfo = forEach(aliasDeclarationEmitInfo, declEmitInfo => declEmitInfo.declaration === aliasToWrite ? declEmitInfo : undefined);
writer = createTextWriterWithSymbolWriter();
createAndSetNewTextWriterWithSymbolWriter();
for (var declarationIndent = aliasEmitInfo.indent; declarationIndent; declarationIndent--) {
writer.increaseIndent();
increaseIndent();
}
writeImportDeclaration(aliasToWrite);
aliasEmitInfo.asynchronousOutput = writer.getText();
});
writer = oldWriter;
setWriter(oldWriter);
}
function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
var symbolAccesibilityResult = resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning);
function handleSymbolAccessibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) {
// write the aliases
if (symbolAccesibilityResult && symbolAccesibilityResult.aliasesToMakeVisible) {
writeAsychronousImportDeclarations(symbolAccesibilityResult.aliasesToMakeVisible);
@ -2553,7 +2572,7 @@ module ts {
else {
// Report error
reportedDeclarationError = true;
var errorInfo = getSymbolVisibilityDiagnosticMessage(symbolAccesibilityResult);
var errorInfo = writer.getSymbolAccessibilityDiagnostic(symbolAccesibilityResult);
if (errorInfo) {
if (errorInfo.typeName) {
diagnostics.push(createDiagnosticForNode(errorInfo.errorNode,
@ -2572,23 +2591,55 @@ module ts {
}
}
function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning));
}
function writeTypeAtLocation(location: Node, type: TypeNode, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
write(": ");
if (type) {
// Write the type
emitType(type);
}
else {
resolver.writeTypeAtLocation(location, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
}
}
function writeReturnTypeAtSignature(signature: SignatureDeclaration, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
write(": ");
if (signature.type) {
// Write the type
emitType(signature.type);
}
else {
resolver.writeReturnTypeOfSignatureDeclaration(signature, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
}
}
function emitLines(nodes: Node[]) {
for (var i = 0, n = nodes.length; i < n; i++) {
emitNode(nodes[i]);
}
}
function emitCommaList(nodes: Node[], eachNodeEmitFn: (node: Node) => void) {
function emitSeparatedList(nodes: Node[], separator: string, eachNodeEmitFn: (node: Node) => void) {
var currentWriterPos = writer.getTextPos();
for (var i = 0, n = nodes.length; i < n; i++) {
if (currentWriterPos !== writer.getTextPos()) {
write(", ");
write(separator);
}
currentWriterPos = writer.getTextPos();
eachNodeEmitFn(nodes[i]);
}
}
function emitCommaList(nodes: Node[], eachNodeEmitFn: (node: Node) => void) {
emitSeparatedList(nodes, ", ", eachNodeEmitFn);
}
function writeJsDocComments(declaration: Declaration) {
if (declaration) {
var jsDocComments = getJsDocComments(declaration, currentSourceFile);
@ -2598,8 +2649,121 @@ module ts {
}
}
function emitSourceTextOfNode(node: Node) {
write(getSourceTextOfLocalNode(node));
function emitTypeWithNewGetSymbolAccessibilityDiangostic(type: TypeNode, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
emitType(type);
}
function emitType(type: TypeNode) {
switch (type.kind) {
case SyntaxKind.AnyKeyword:
case SyntaxKind.StringKeyword:
case SyntaxKind.NumberKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.StringLiteral:
return writeTextOfNode(type);
case SyntaxKind.TypeReference:
return emitTypeReference(<TypeReferenceNode>type);
case SyntaxKind.TypeQuery:
return emitTypeQuery(<TypeQueryNode>type);
case SyntaxKind.ArrayType:
return emitArrayType(<ArrayTypeNode>type);
case SyntaxKind.TupleType:
return emitTupleType(<TupleTypeNode>type);
case SyntaxKind.UnionType:
return emitUnionType(<UnionTypeNode>type);
case SyntaxKind.ParenType:
return emitParenType(<ParenTypeNode>type);
case SyntaxKind.TypeLiteral:
return emitTypeLiteral(<TypeLiteralNode>type);
case SyntaxKind.Identifier:
return emitEntityName(<Identifier>type);
case SyntaxKind.QualifiedName:
return emitEntityName(<QualifiedName>type);
default:
Debug.fail("Unknown type annotation: " + type.kind);
}
function emitEntityName(entityName: EntityName) {
var visibilityResult = resolver.isEntityNameVisible(entityName,
// Aliases can be written asynchronously so use correct enclosing declaration
entityName.parent.kind === SyntaxKind.ImportDeclaration ? entityName.parent : enclosingDeclaration);
handleSymbolAccessibilityError(visibilityResult);
writeEntityName(entityName);
function writeEntityName(entityName: EntityName) {
if (entityName.kind === SyntaxKind.Identifier) {
writeTextOfNode(entityName);
}
else {
var qualifiedName = <QualifiedName>entityName;
writeEntityName(qualifiedName.left);
write(".");
writeTextOfNode(qualifiedName.right);
}
}
}
function emitTypeReference(type: TypeReferenceNode) {
emitEntityName(type.typeName);
if (type.typeArguments) {
write("<");
emitCommaList(type.typeArguments, emitType);
write(">");
}
}
function emitTypeQuery(type: TypeQueryNode) {
write("typeof ");
emitEntityName(type.exprName);
}
function emitArrayType(type: ArrayTypeNode) {
emitType(type.elementType);
write("[]");
}
function emitTupleType(type: TupleTypeNode) {
write("[");
emitCommaList(type.elementTypes, emitType);
write("]");
}
function emitUnionType(type: UnionTypeNode) {
emitSeparatedList(type.types, " | ", emitType);
}
function emitParenType(type: ParenTypeNode) {
write("(");
emitType(type.type);
write(")");
}
function emitTypeLiteral(type: TypeLiteralNode) {
if (getTokenPosOfNode(type, currentSourceFile) !== skipTrivia(currentSourceFile.text, type.members.pos)) {
write("{");
if (type.members.length) {
writeLine();
increaseIndent();
// write members
emitLines(type.members);
decreaseIndent();
}
write("}");
}
else {
// Write call/construct signature as arrow style
var signature = <SignatureDeclaration>type.members[0];
if (signature.kind === SyntaxKind.CallSignature) {
emitSignatureDeclaration(signature, /*arrowStyle*/true);
}
else {
emitConstructSignatureDeclaration(signature, /*arrowStyle*/ true);
}
}
}
}
function emitSourceFile(node: SourceFile) {
@ -2610,42 +2774,38 @@ module ts {
function emitExportAssignment(node: ExportAssignment) {
write("export = ");
emitSourceTextOfNode(node.exportName);
writeTextOfNode(node.exportName);
write(";");
writeLine();
}
function emitDeclarationFlags(node: Declaration) {
if (node.flags & NodeFlags.Static) {
if (node.flags & NodeFlags.Private) {
write("private ");
function emitModuleElementDeclarationFlags(node: Declaration) {
// If the node is parented in the current source file we need to emit export declare or just export
if (node.parent === currentSourceFile) {
// If the node is exported
if (node.flags & NodeFlags.Export) {
write("export ");
}
else if (node.flags & NodeFlags.Protected) {
write("protected ");
}
write("static ");
}
else {
if (node.flags & NodeFlags.Private) {
write("private ");
}
else if (node.flags & NodeFlags.Protected) {
write("protected ");
}
// If the node is parented in the current source file we need to emit export declare or just export
else if (node.parent === currentSourceFile) {
// If the node is exported
if (node.flags & NodeFlags.Export) {
write("export ");
}
if (node.kind !== SyntaxKind.InterfaceDeclaration) {
write("declare ");
}
if (node.kind !== SyntaxKind.InterfaceDeclaration) {
write("declare ");
}
}
}
function emitClassMemberDeclarationFlags(node: Declaration) {
if (node.flags & NodeFlags.Private) {
write("private ");
}
else if (node.flags & NodeFlags.Protected) {
write("protected ");
}
if (node.flags & NodeFlags.Static) {
write("static ");
}
}
function emitImportDeclaration(node: ImportDeclaration) {
var nodeEmitInfo = {
declaration: node,
@ -2664,52 +2824,41 @@ module ts {
// correct writer especially to handle asynchronous alias writing
emitJsDocComments(node);
if (node.flags & NodeFlags.Export) {
writer.write("export ");
write("export ");
}
writer.write("import ");
writer.write(getSourceTextOfLocalNode(node.name));
writer.write(" = ");
write("import ");
writeTextOfNode(node.name);
write(" = ");
if (node.entityName) {
checkEntityNameAccessible();
writer.write(getSourceTextOfLocalNode(node.entityName));
writer.write(";");
emitTypeWithNewGetSymbolAccessibilityDiangostic(node.entityName, getImportEntityNameVisibilityError);
write(";");
}
else {
writer.write("require(");
writer.write(getSourceTextOfLocalNode(node.externalModuleName));
writer.write(");");
write("require(");
writeTextOfNode(node.externalModuleName);
write(");");
}
writer.writeLine();
function checkEntityNameAccessible() {
var symbolAccesibilityResult = resolver.isImportDeclarationEntityNameReferenceDeclarationVisibile(node.entityName);
if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) {
// write the aliases
if (symbolAccesibilityResult.aliasesToMakeVisible) {
writeAsychronousImportDeclarations(symbolAccesibilityResult.aliasesToMakeVisible);
}
}
else {
// Report error
reportedDeclarationError = true;
diagnostics.push(createDiagnosticForNode(node,
Diagnostics.Import_declaration_0_is_using_private_name_1,
getSourceTextOfLocalNode(node.name),
symbolAccesibilityResult.errorSymbolName));
}
function getImportEntityNameVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
return {
diagnosticMessage: Diagnostics.Import_declaration_0_is_using_private_name_1,
errorNode: node,
typeName: node.name
};
}
}
function emitModuleDeclaration(node: ModuleDeclaration) {
if (resolver.isDeclarationVisible(node)) {
emitJsDocComments(node);
emitDeclarationFlags(node);
emitModuleElementDeclarationFlags(node);
write("module ");
emitSourceTextOfNode(node.name);
writeTextOfNode(node.name);
while (node.body.kind !== SyntaxKind.ModuleBlock) {
node = <ModuleDeclaration>node.body;
write(".");
emitSourceTextOfNode(node.name);
writeTextOfNode(node.name);
}
var prevEnclosingDeclaration = enclosingDeclaration;
enclosingDeclaration = node;
@ -2727,12 +2876,11 @@ module ts {
function emitTypeAliasDeclaration(node: TypeAliasDeclaration) {
if (resolver.isDeclarationVisible(node)) {
emitJsDocComments(node);
emitDeclarationFlags(node);
emitModuleElementDeclarationFlags(node);
write("type ");
emitSourceTextOfNode(node.name);
writeTextOfNode(node.name);
write(" = ");
getSymbolVisibilityDiagnosticMessage = getTypeAliasDeclarationVisibilityError;
resolver.writeTypeAtLocation(node.type, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
emitTypeWithNewGetSymbolAccessibilityDiangostic(node.type, getTypeAliasDeclarationVisibilityError);
write(";");
writeLine();
}
@ -2753,12 +2901,12 @@ module ts {
function emitEnumDeclaration(node: EnumDeclaration) {
if (resolver.isDeclarationVisible(node)) {
emitJsDocComments(node);
emitDeclarationFlags(node);
emitModuleElementDeclarationFlags(node);
if (isConstEnumDeclaration(node)) {
write("const ")
}
write("enum ");
emitSourceTextOfNode(node.name);
writeTextOfNode(node.name);
write(" {");
writeLine();
increaseIndent();
@ -2771,7 +2919,7 @@ module ts {
function emitEnumMemberDeclaration(node: EnumMember) {
emitJsDocComments(node);
emitSourceTextOfNode(node.name);
writeTextOfNode(node.name);
var enumMemberValue = resolver.getEnumMemberValue(node);
if (enumMemberValue !== undefined) {
write(" = ");
@ -2783,7 +2931,25 @@ module ts {
function emitTypeParameters(typeParameters: TypeParameterDeclaration[]) {
function emitTypeParameter(node: TypeParameterDeclaration) {
function getTypeParameterConstraintVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
increaseIndent();
emitJsDocComments(node);
decreaseIndent();
writeTextOfNode(node.name);
// If there is constraint present and this is not a type parameter of the private method emit the constraint
if (node.constraint && (node.parent.kind !== SyntaxKind.Method || !(node.parent.flags & NodeFlags.Private))) {
write(" extends ");
if (node.parent.parent && node.parent.parent.kind === SyntaxKind.TypeLiteral) {
Debug.assert(node.parent.kind === SyntaxKind.Method ||
node.parent.kind === SyntaxKind.CallSignature ||
node.parent.kind === SyntaxKind.ConstructSignature);
emitType(node.constraint);
}
else {
emitTypeWithNewGetSymbolAccessibilityDiangostic(node.constraint, getTypeParameterConstraintVisibilityError);
}
}
function getTypeParameterConstraintVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
// Type parameter constraints are named by user so we should always be able to name it
var diagnosticMessage: DiagnosticMessage;
switch (node.parent.kind) {
@ -2845,17 +3011,6 @@ module ts {
typeName: node.name
};
}
increaseIndent();
emitJsDocComments(node);
decreaseIndent();
emitSourceTextOfNode(node.name);
// If there is constraint present and this is not a type parameter of the private method emit the constraint
if (node.constraint && (node.parent.kind !== SyntaxKind.Method || !(node.parent.flags & NodeFlags.Private))) {
write(" extends ");
getSymbolVisibilityDiagnosticMessage = getTypeParameterConstraintVisibilityError;
resolver.writeTypeAtLocation(node.constraint, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
}
}
if (typeParameters) {
@ -2872,10 +3027,9 @@ module ts {
}
function emitTypeOfTypeReference(node: Node) {
getSymbolVisibilityDiagnosticMessage = getHeritageClauseVisibilityError;
resolver.writeTypeAtLocation(node, enclosingDeclaration, TypeFormatFlags.WriteArrayAsGenericType | TypeFormatFlags.UseTypeOfFunction, writer);
emitTypeWithNewGetSymbolAccessibilityDiangostic(node, getHeritageClauseVisibilityError);
function getHeritageClauseVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
function getHeritageClauseVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
var diagnosticMessage: DiagnosticMessage;
// Heritage clause is written by user so it can always be named
if (node.parent.kind === SyntaxKind.ClassDeclaration) {
@ -2926,9 +3080,9 @@ module ts {
if (resolver.isDeclarationVisible(node)) {
emitJsDocComments(node);
emitDeclarationFlags(node);
emitModuleElementDeclarationFlags(node);
write("class ");
emitSourceTextOfNode(node.name);
writeTextOfNode(node.name);
var prevEnclosingDeclaration = enclosingDeclaration;
enclosingDeclaration = node;
emitTypeParameters(node.typeParameters);
@ -2951,9 +3105,9 @@ module ts {
function emitInterfaceDeclaration(node: InterfaceDeclaration) {
if (resolver.isDeclarationVisible(node)) {
emitJsDocComments(node);
emitDeclarationFlags(node);
emitModuleElementDeclarationFlags(node);
write("interface ");
emitSourceTextOfNode(node.name);
writeTextOfNode(node.name);
var prevEnclosingDeclaration = enclosingDeclaration;
enclosingDeclaration = node;
emitTypeParameters(node.typeParameters);
@ -2971,7 +3125,7 @@ module ts {
function emitPropertyDeclaration(node: PropertyDeclaration) {
emitJsDocComments(node);
emitDeclarationFlags(node);
emitClassMemberDeclarationFlags(node);
emitVariableDeclaration(<VariableDeclaration>node);
write(";");
writeLine();
@ -2982,19 +3136,20 @@ module ts {
// If we are emitting property it isn't 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);
writeTextOfNode(node.name);
// If optional property emit ?
if (node.kind === SyntaxKind.Property && (node.flags & NodeFlags.QuestionMark)) {
write("?");
}
if (!(node.flags & NodeFlags.Private)) {
write(": ");
getSymbolVisibilityDiagnosticMessage = getVariableDeclarationTypeVisibilityError;
resolver.writeTypeAtLocation(node, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
if (node.kind === SyntaxKind.Property && node.parent.kind === SyntaxKind.TypeLiteral) {
emitTypeOfVariableDeclarationFromTypeLiteral(node);
}
else if (!(node.flags & NodeFlags.Private)) {
writeTypeAtLocation(node, node.type, getVariableDeclarationTypeVisibilityError);
}
}
function getVariableDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
function getVariableDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
var diagnosticMessage: DiagnosticMessage;
if (node.kind === SyntaxKind.VariableDeclaration) {
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
@ -3036,11 +3191,21 @@ module ts {
}
}
function emitTypeOfVariableDeclarationFromTypeLiteral(node: VariableDeclaration) {
// if this is property of type literal,
// or is parameter of method/call/construct/index signature of type literal
// emit only if type is specified
if (node.type) {
write(": ");
emitType(node.type);
}
}
function emitVariableStatement(node: VariableStatement) {
var hasDeclarationWithEmit = forEach(node.declarations, varDeclaration => resolver.isDeclarationVisible(varDeclaration));
if (hasDeclarationWithEmit) {
emitJsDocComments(node);
emitDeclarationFlags(node);
emitModuleElementDeclarationFlags(node);
if (node.flags & NodeFlags.Let) {
write("let ");
}
@ -3061,22 +3226,38 @@ module ts {
if (node === accessors.firstAccessor) {
emitJsDocComments(accessors.getAccessor);
emitJsDocComments(accessors.setAccessor);
emitDeclarationFlags(node);
emitSourceTextOfNode(node.name);
emitClassMemberDeclarationFlags(node);
writeTextOfNode(node.name);
if (!(node.flags & NodeFlags.Private)) {
write(": ");
getSymbolVisibilityDiagnosticMessage = getAccessorDeclarationTypeVisibilityError;
resolver.writeTypeAtLocation(node, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
var accessorWithTypeAnnotation: AccessorDeclaration = node;
var type = getTypeAnnotationFromAccessor(node);
if (!type) {
// couldn't get type for the first accessor, try the another one
var anotherAccessor = node.kind === SyntaxKind.GetAccessor ? accessors.setAccessor : accessors.getAccessor;
type = getTypeAnnotationFromAccessor(anotherAccessor);
if (type) {
accessorWithTypeAnnotation = anotherAccessor;
}
}
writeTypeAtLocation(node, type, getAccessorDeclarationTypeVisibilityError);
}
write(";");
writeLine();
}
function getAccessorDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
function getTypeAnnotationFromAccessor(accessor: AccessorDeclaration): TypeNode {
if (accessor) {
return accessor.kind === SyntaxKind.GetAccessor ?
accessor.type : // Getter - return type
accessor.parameters[0].type; // Setter parameter type
}
}
function getAccessorDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
var diagnosticMessage: DiagnosticMessage;
if (node.kind === SyntaxKind.SetAccessor) {
if (accessorWithTypeAnnotation.kind === SyntaxKind.SetAccessor) {
// Setters have to have type named and cannot infer it so, the type should always be named
if (node.parent.flags & NodeFlags.Static) {
if (accessorWithTypeAnnotation.parent.flags & NodeFlags.Static) {
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_name_1;
@ -3088,13 +3269,13 @@ module ts {
}
return {
diagnosticMessage: diagnosticMessage,
errorNode: <Node>node.parameters[0],
errorNode: <Node>accessorWithTypeAnnotation.parameters[0],
// TODO(jfreeman): Investigate why we are passing node.name instead of node.parameters[0].name
typeName: node.name
typeName: accessorWithTypeAnnotation.name
};
}
else {
if (node.flags & NodeFlags.Static) {
if (accessorWithTypeAnnotation.flags & NodeFlags.Static) {
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
@ -3110,7 +3291,7 @@ module ts {
}
return {
diagnosticMessage: diagnosticMessage,
errorNode: <Node>node.name,
errorNode: <Node>accessorWithTypeAnnotation.name,
typeName: undefined
};
}
@ -3123,16 +3304,21 @@ module ts {
if ((node.kind !== SyntaxKind.FunctionDeclaration || resolver.isDeclarationVisible(node)) &&
!resolver.isImplementationOfOverload(node)) {
emitJsDocComments(node);
emitDeclarationFlags(node);
if (node.kind === SyntaxKind.FunctionDeclaration) {
emitModuleElementDeclarationFlags(node);
}
else if (node.kind === SyntaxKind.Method) {
emitClassMemberDeclarationFlags(node);
}
if (node.kind === SyntaxKind.FunctionDeclaration) {
write("function ");
emitSourceTextOfNode(node.name);
writeTextOfNode(node.name);
}
else if (node.kind === SyntaxKind.Constructor) {
write("constructor");
}
else {
emitSourceTextOfNode(node.name);
writeTextOfNode(node.name);
if (node.flags & NodeFlags.QuestionMark) {
write("?");
}
@ -3141,13 +3327,13 @@ module ts {
}
}
function emitConstructSignatureDeclaration(node: SignatureDeclaration) {
function emitConstructSignatureDeclaration(node: SignatureDeclaration, arrowStyle?: boolean) {
emitJsDocComments(node);
write("new ");
emitSignatureDeclaration(node);
emitSignatureDeclaration(node, arrowStyle);
}
function emitSignatureDeclaration(node: SignatureDeclaration) {
function emitSignatureDeclaration(node: SignatureDeclaration, arrowStyle?: boolean) {
if (node.kind === SyntaxKind.CallSignature || node.kind === SyntaxKind.IndexSignature) {
// Only index and call signatures are emitted directly, so emit their js doc comments, rest will do that in their own functions
emitJsDocComments(node);
@ -3160,6 +3346,9 @@ module ts {
write("(");
}
var prevEnclosingDeclaration = enclosingDeclaration;
enclosingDeclaration = node;
// Parameters
emitCommaList(node.parameters, emitParameterDeclaration);
@ -3171,15 +3360,25 @@ module ts {
}
// If this is not a constructor and is not private, emit the return type
if (node.kind !== SyntaxKind.Constructor && !(node.flags & NodeFlags.Private)) {
write(": ");
getSymbolVisibilityDiagnosticMessage = getReturnTypeVisibilityError;
resolver.writeReturnTypeOfSignatureDeclaration(node, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
if (node.parent.kind === SyntaxKind.TypeLiteral) {
// Emit type literal signature return type only if specified
if (node.type) {
write(arrowStyle ? " => " : ": ");
emitType(node.type);
}
}
else if (node.kind !== SyntaxKind.Constructor && !(node.flags & NodeFlags.Private)) {
writeReturnTypeAtSignature(node, getReturnTypeVisibilityError);
}
write(";");
writeLine();
function getReturnTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
enclosingDeclaration = prevEnclosingDeclaration;
if (!arrowStyle) {
write(";");
writeLine();
}
function getReturnTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
var diagnosticMessage: DiagnosticMessage;
switch (node.kind) {
case SyntaxKind.ConstructSignature:
@ -3251,19 +3450,20 @@ module ts {
if (node.flags & NodeFlags.Rest) {
write("...");
}
emitSourceTextOfNode(node.name);
writeTextOfNode(node.name);
if (node.initializer || (node.flags & NodeFlags.QuestionMark)) {
write("?");
}
decreaseIndent();
if (!(node.parent.flags & NodeFlags.Private)) {
write(": ");
getSymbolVisibilityDiagnosticMessage = getParameterDeclarationTypeVisibilityError;
resolver.writeTypeAtLocation(node, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
if (node.parent.parent.kind === SyntaxKind.TypeLiteral) {
emitTypeOfVariableDeclarationFromTypeLiteral(node);
}
else if (!(node.parent.flags & NodeFlags.Private)) {
writeTypeAtLocation(node, node.type, getParameterDeclarationTypeVisibilityError);
}
function getParameterDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
function getParameterDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult): SymbolAccessibilityDiagnostic {
var diagnosticMessage: DiagnosticMessage;
switch (node.parent.kind) {
case SyntaxKind.Constructor:

View File

@ -789,11 +789,14 @@ module ts {
CannotBeNamed
}
export interface SymbolAccessiblityResult {
export interface SymbolVisibilityResult {
accessibility: SymbolAccessibility;
aliasesToMakeVisible?: ImportDeclaration[]; // aliases that need to have this symbol visible
}
export interface SymbolAccessiblityResult extends SymbolVisibilityResult {
errorSymbolName?: string // Optional symbol name that results in error
errorModuleName?: string // If the symbol is not visible from module, module's name
aliasesToMakeVisible?: ImportDeclaration[]; // aliases that need to have this symbol visible
}
export interface EmitResolver {
@ -811,7 +814,7 @@ module ts {
writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult;
isImportDeclarationEntityNameReferenceDeclarationVisibile(entityName: EntityName): SymbolAccessiblityResult;
isEntityNameVisible(entityName: EntityName, enclosingDeclaration: Node): SymbolVisibilityResult;
// Returns the constant value this property access resolves to, or 'undefined' for a non-constant
getConstantValue(node: PropertyAccess | IndexedAccess): number;
hasEarlyErrors(sourceFile?: SourceFile): boolean;