use NodeBuilderContext

This commit is contained in:
Arthur Ozga 2017-03-25 14:14:36 -07:00
parent 85986ddaee
commit a94f874b06
3 changed files with 373 additions and 332 deletions

View file

@ -2204,45 +2204,52 @@ namespace ts {
function createNodeBuilder(): NodeBuilder { function createNodeBuilder(): NodeBuilder {
let encounteredError = false; interface NodeBuilderContext {
readonly enclosingDeclaration: Node | undefined;
readonly flags: NodeBuilderFlags | undefined;
encounteredError: boolean;
inObjectTypeLiteral: boolean;
checkAlias: boolean;
symbolStack: Symbol[] | undefined;
}
function createNodeBuilderContext(enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): NodeBuilderContext {
return {
enclosingDeclaration,
flags,
encounteredError: false,
inObjectTypeLiteral: false,
checkAlias: true,
symbolStack: undefined
};
}
let context: NodeBuilderContext;
return { return {
typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => { typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => {
Debug.assert(encounteredError === false, "Nested call into nodeBuilder are forbidden."); context = createNodeBuilderContext(enclosingDeclaration, flags);
encounteredError = false; const resultingNode = typeToTypeNodeHelper(type);
const resultingNode = typeToTypeNodeHelper(type, enclosingDeclaration, flags); const result = context.encounteredError ? undefined : resultingNode;
const result = encounteredError ? undefined : resultingNode;
encounteredError = false;
return result; return result;
}, },
indexInfoToIndexSignatureDeclaration: (indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => { indexInfoToIndexSignatureDeclaration: (indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => {
Debug.assert(encounteredError === false, "Nested call into nodeBuilder are forbidden."); context = createNodeBuilderContext(enclosingDeclaration, flags);
encounteredError = false; const resultingNode = indexInfoToIndexSignatureDeclarationHelper(indexInfo, kind);
const resultingNode = indexInfoToIndexSignatureDeclarationHelper(indexInfo, kind, enclosingDeclaration, flags); const result = context.encounteredError ? undefined : resultingNode;
const result = encounteredError ? undefined : resultingNode;
encounteredError = false;
return result; return result;
}, },
signatureToSignatureDeclaration: (signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => { signatureToSignatureDeclaration: (signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => {
Debug.assert(encounteredError === false, "Nested call into nodeBuilder are forbidden."); context = createNodeBuilderContext(enclosingDeclaration, flags);
encounteredError = false; const resultingNode = signatureToSignatureDeclarationHelper(signature, kind);
const resultingNode = signatureToSignatureDeclarationHelper(signature, kind, enclosingDeclaration, flags); const result = context.encounteredError ? undefined : resultingNode;
const result = encounteredError ? undefined : resultingNode;
encounteredError = false;
return result; return result;
} }
}; };
function typeToTypeNodeHelper(type: Type, enclosingDeclaration: Node, flags: NodeBuilderFlags): TypeNode { function typeToTypeNodeHelper(type: Type): TypeNode {
let inObjectTypeLiteral = false;
let checkAlias = true;
let symbolStack: Symbol[] = undefined;
return typeToTypeNodeWorker(type);
function typeToTypeNodeWorker(type: Type): TypeNode {
if (!type) { if (!type) {
encounteredError = true; context.encounteredError = true;
// TODO(aozgaa): should we return implict any (undefined) or explicit any (keywordtypenode)? // TODO(aozgaa): should we return implict any (undefined) or explicit any (keywordtypenode)?
return undefined; return undefined;
} }
@ -2260,7 +2267,7 @@ namespace ts {
return createKeywordTypeNode(SyntaxKind.BooleanKeyword); return createKeywordTypeNode(SyntaxKind.BooleanKeyword);
} }
if (type.flags & TypeFlags.Enum) { if (type.flags & TypeFlags.Enum) {
const name = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags); const name = symbolToName(type.symbol, /*expectsIdentifier*/ false);
return createTypeReferenceNode(name, /*typeArguments*/ undefined); return createTypeReferenceNode(name, /*typeArguments*/ undefined);
} }
if (type.flags & (TypeFlags.StringLiteral)) { if (type.flags & (TypeFlags.StringLiteral)) {
@ -2273,7 +2280,7 @@ namespace ts {
return (<IntrinsicType>type).intrinsicName === "true" ? createTrue() : createFalse(); return (<IntrinsicType>type).intrinsicName === "true" ? createTrue() : createFalse();
} }
if (type.flags & TypeFlags.EnumLiteral) { if (type.flags & TypeFlags.EnumLiteral) {
const name = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags); const name = symbolToName(type.symbol, /*expectsIdentifier*/ false);
return createTypeReferenceNode(name, /*typeArguments*/ undefined); return createTypeReferenceNode(name, /*typeArguments*/ undefined);
} }
if (type.flags & TypeFlags.Void) { if (type.flags & TypeFlags.Void) {
@ -2295,8 +2302,10 @@ namespace ts {
throw new Error("Non primitive not implemented"); throw new Error("Non primitive not implemented");
} }
if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) {
if (inObjectTypeLiteral) { if (context.inObjectTypeLiteral) {
encounteredError = encounteredError || !(flags & NodeBuilderFlags.allowThisInObjectLiteral); if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowThisInObjectLiteral)) {
context.encounteredError = true;
}
} }
return createThis(); return createThis();
} }
@ -2305,29 +2314,39 @@ namespace ts {
if (objectFlags & ObjectFlags.Reference) { if (objectFlags & ObjectFlags.Reference) {
Debug.assert(!!(type.flags & TypeFlags.Object)); Debug.assert(!!(type.flags & TypeFlags.Object));
return typeReferenceToTypeNode (<TypeReference>type); return typeReferenceToTypeNode(<TypeReference>type);
} }
if (objectFlags & ObjectFlags.ClassOrInterface) { if (objectFlags & ObjectFlags.ClassOrInterface) {
Debug.assert(!!(type.flags & TypeFlags.Object)); Debug.assert(!!(type.flags & TypeFlags.Object));
const name = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags); const name = symbolToName(type.symbol, /*expectsIdentifier*/ false);
// TODO(aozgaa): handle type arguments. // TODO(aozgaa): handle type arguments.
return createTypeReferenceNode(name, /*typeArguments*/ undefined); return createTypeReferenceNode(name, /*typeArguments*/ undefined);
} }
if (type.flags & TypeFlags.TypeParameter) { if (type.flags & TypeFlags.TypeParameter) {
const name = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags); const name = symbolToName(type.symbol, /*expectsIdentifier*/ false);
// Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter. // Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter.
return createTypeReferenceNode(name, /*typeArguments*/ undefined); return createTypeReferenceNode(name, /*typeArguments*/ undefined);
} }
if (checkAlias && type.aliasSymbol) { if (context.checkAlias && type.aliasSymbol) {
const name = symbolToName(type.aliasSymbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags); const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false);
const typeArgumentNodes = mapToTypeNodeArray(type.aliasTypeArguments); const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments);
return createTypeReferenceNode(name, typeArgumentNodes); return createTypeReferenceNode(name, typeArgumentNodes);
} }
checkAlias = false; context.checkAlias = false;
if (type.flags & TypeFlags.Union) { if (type.flags & TypeFlags.Union) {
return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, mapToTypeNodeArray(formatUnionTypes((<UnionType>type).types))); const formattedUnionTypes = formatUnionTypes((<UnionType>type).types);
const unionTypeNodes = formattedUnionTypes && mapToTypeNodeArray(formattedUnionTypes);
if (unionTypeNodes && unionTypeNodes.length > 0) {
return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, unionTypeNodes);
}
else {
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowEmptyUnionOrIntersection)) {
context.encounteredError = true;
}
return undefined;
}
} }
if (type.flags & TypeFlags.Intersection) { if (type.flags & TypeFlags.Intersection) {
@ -2342,28 +2361,35 @@ namespace ts {
if (type.flags & TypeFlags.Index) { if (type.flags & TypeFlags.Index) {
const indexedType = (<IndexType>type).type; const indexedType = (<IndexType>type).type;
const indexTypeNode = typeToTypeNodeWorker(indexedType); const indexTypeNode = typeToTypeNodeHelper(indexedType);
return createTypeOperatorNode(indexTypeNode); return createTypeOperatorNode(indexTypeNode);
} }
if (type.flags & TypeFlags.IndexedAccess) { if (type.flags & TypeFlags.IndexedAccess) {
const objectTypeNode = typeToTypeNodeWorker((<IndexedAccessType>type).objectType); const objectTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).objectType);
const indexTypeNode = typeToTypeNodeWorker((<IndexedAccessType>type).indexType); const indexTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).indexType);
return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode); return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
} }
Debug.fail("Should be unreachable."); Debug.fail("Should be unreachable.");
function mapToTypeNodeArray(types: Type[]): NodeArray<TypeNode> { function mapToTypeNodeArray(types: Type[]): TypeNode[] {
return types && asNodeArray(types.map(typeToTypeNodeWorker).filter(node => !!node)); const result = [];
for (const type of types) {
const typeNode = typeToTypeNodeHelper(type);
if (typeNode) {
result.push(typeNode);
}
}
return result;
} }
function createMappedTypeNodeFromType(type: MappedType) { function createMappedTypeNodeFromType(type: MappedType) {
Debug.assert(!!(type.flags & TypeFlags.Object)); Debug.assert(!!(type.flags & TypeFlags.Object));
const typeParameter = getTypeParameterFromMappedType(<MappedType>type); const typeParameter = getTypeParameterFromMappedType(<MappedType>type);
const typeParameterNode = typeParameterToDeclaration(typeParameter, enclosingDeclaration, flags); const typeParameterNode = typeParameterToDeclaration(typeParameter);
const templateType = getTemplateTypeFromMappedType(<MappedType>type); const templateType = getTemplateTypeFromMappedType(<MappedType>type);
const templateTypeNode = templateType && typeToTypeNodeWorker(templateType); const templateTypeNode = templateType && typeToTypeNodeHelper(templateType);
const readonlyToken = (<MappedType>type).declaration && (<MappedType>type).declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined; const readonlyToken = (<MappedType>type).declaration && (<MappedType>type).declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined;
const questionToken = (<MappedType>type).declaration && (<MappedType>type).declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined; const questionToken = (<MappedType>type).declaration && (<MappedType>type).declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined;
@ -2379,12 +2405,12 @@ namespace ts {
shouldWriteTypeOfFunctionSymbol()) { shouldWriteTypeOfFunctionSymbol()) {
return createTypeQueryNodeFromType(type); return createTypeQueryNodeFromType(type);
} }
else if (contains(symbolStack, symbol)) { else if (contains(context.symbolStack, symbol)) {
// If type is an anonymous type literal in a type alias declaration, use type alias name // If type is an anonymous type literal in a type alias declaration, use type alias name
const typeAlias = getTypeAliasForTypeLiteral(type); const typeAlias = getTypeAliasForTypeLiteral(type);
if (typeAlias) { if (typeAlias) {
// The specified symbol flags need to be reinterpreted as type flags // The specified symbol flags need to be reinterpreted as type flags
const entityName = symbolToName(typeAlias, enclosingDeclaration, /*expectsIdentifier*/ false, flags); const entityName = symbolToName(typeAlias, /*expectsIdentifier*/ false);
return createTypeReferenceNode(entityName, /*typeArguments*/ undefined); return createTypeReferenceNode(entityName, /*typeArguments*/ undefined);
} }
else { else {
@ -2394,12 +2420,12 @@ namespace ts {
else { else {
// Since instantiations of the same anonymous type have the same symbol, tracking symbols instead // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead
// of types allows us to catch circular references to instantiations of the same anonymous type // of types allows us to catch circular references to instantiations of the same anonymous type
if (!symbolStack) { if (!context.symbolStack) {
symbolStack = []; context.symbolStack = [];
} }
symbolStack.push(symbol); context.symbolStack.push(symbol);
const result = createTypeNodeFromObjectType(type); const result = createTypeNodeFromObjectType(type);
symbolStack.pop(); context.symbolStack.pop();
return result; return result;
} }
} }
@ -2417,7 +2443,7 @@ namespace ts {
declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock)); declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock));
if (isStaticMethodSymbol || isNonLocalFunctionSymbol) { if (isStaticMethodSymbol || isNonLocalFunctionSymbol) {
// typeof is allowed only for static/non local functions // typeof is allowed only for static/non local functions
return contains(symbolStack, symbol); // it is type of the symbol uses itself recursively return contains(context.symbolStack, symbol); // it is type of the symbol uses itself recursively
} }
} }
} }
@ -2437,25 +2463,25 @@ namespace ts {
if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) {
const signature = resolved.callSignatures[0]; const signature = resolved.callSignatures[0];
return <FunctionTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, enclosingDeclaration, flags); return <FunctionTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType);
} }
if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) {
const signature = resolved.constructSignatures[0]; const signature = resolved.constructSignatures[0];
return <ConstructorTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType, enclosingDeclaration, flags); return <ConstructorTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType);
} }
} }
const saveInObjectTypeLiteral = inObjectTypeLiteral; const saveInObjectTypeLiteral = context.inObjectTypeLiteral;
inObjectTypeLiteral = true; context.inObjectTypeLiteral = true;
const members = createTypeNodesFromResolvedType(resolved); const members = createTypeNodesFromResolvedType(resolved);
inObjectTypeLiteral = saveInObjectTypeLiteral; context.inObjectTypeLiteral = saveInObjectTypeLiteral;
return createTypeLiteralNode(members); return createTypeLiteralNode(members);
} }
function createTypeQueryNodeFromType(type: Type) { function createTypeQueryNodeFromType(type: Type) {
const symbol = type.symbol; const symbol = type.symbol;
if (symbol) { if (symbol) {
const entityName = symbolToName(symbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags); const entityName = symbolToName(symbol, /*expectsIdentifier*/ false);
return createTypeQueryNode(entityName); return createTypeQueryNode(entityName);
} }
} }
@ -2463,11 +2489,20 @@ namespace ts {
function typeReferenceToTypeNode(type: TypeReference) { function typeReferenceToTypeNode(type: TypeReference) {
const typeArguments: Type[] = type.typeArguments || emptyArray; const typeArguments: Type[] = type.typeArguments || emptyArray;
if (type.target === globalArrayType) { if (type.target === globalArrayType) {
const elementType = typeToTypeNodeWorker(typeArguments[0]); const elementType = typeToTypeNodeHelper(typeArguments[0]);
return createArrayTypeNode(elementType); return createArrayTypeNode(elementType);
} }
else if (type.target.objectFlags & ObjectFlags.Tuple) { else if (type.target.objectFlags & ObjectFlags.Tuple) {
return createTupleTypeNode(typeArguments.length > 0 ? mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type))) : undefined); if (typeArguments.length > 0) {
const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type)));
if (tupleConstituentNodes && tupleConstituentNodes.length > 0) {
return createTupleTypeNode(tupleConstituentNodes);
}
}
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowEmptyTuple)) {
context.encounteredError = true;
}
return undefined;
} }
else { else {
const outerTypeParameters = type.target.outerTypeParameters; const outerTypeParameters = type.target.outerTypeParameters;
@ -2485,7 +2520,7 @@ namespace ts {
// When type parameters are their own type arguments for the whole group (i.e. we have // When type parameters are their own type arguments for the whole group (i.e. we have
// the default outer type arguments), we don't show the group. // the default outer type arguments), we don't show the group.
if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) { if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) {
const qualifiedNamePart = symbolToName(parent, enclosingDeclaration, /*expectsIdentifier*/ true, flags); const qualifiedNamePart = symbolToName(parent, /*expectsIdentifier*/ true);
if (!qualifiedName) { if (!qualifiedName) {
qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined); qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined);
} }
@ -2498,7 +2533,7 @@ namespace ts {
} }
} }
let entityName: EntityName = undefined; let entityName: EntityName = undefined;
const nameIdentifier = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ true, flags); const nameIdentifier = symbolToName(type.symbol, /*expectsIdentifier*/ true);
if (qualifiedName) { if (qualifiedName) {
Debug.assert(!qualifiedName.right); Debug.assert(!qualifiedName.right);
qualifiedName.right = nameIdentifier; qualifiedName.right = nameIdentifier;
@ -2508,7 +2543,7 @@ namespace ts {
entityName = nameIdentifier; entityName = nameIdentifier;
} }
const typeParameterCount = (type.target.typeParameters || emptyArray).length; const typeParameterCount = (type.target.typeParameters || emptyArray).length;
const typeArgumentNodes = mapToTypeNodeArray(typeArguments.length > 0 ? typeArguments.slice(i, typeParameterCount - i) : undefined); const typeArgumentNodes = typeArguments.length > 0 ? mapToTypeNodeArray(typeArguments.slice(i, typeParameterCount - i)) : undefined;
return createTypeReferenceNode(entityName, typeArgumentNodes); return createTypeReferenceNode(entityName, typeArgumentNodes);
} }
} }
@ -2516,16 +2551,16 @@ namespace ts {
function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] { function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] {
const typeElements: TypeElement[] = []; const typeElements: TypeElement[] = [];
for (const signature of resolvedType.callSignatures) { for (const signature of resolvedType.callSignatures) {
typeElements.push(<CallSignatureDeclaration>signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature, enclosingDeclaration, flags)); typeElements.push(<CallSignatureDeclaration>signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature));
} }
for (const signature of resolvedType.constructSignatures) { for (const signature of resolvedType.constructSignatures) {
typeElements.push(<ConstructSignatureDeclaration>signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature, enclosingDeclaration, flags)); typeElements.push(<ConstructSignatureDeclaration>signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature));
} }
if (resolvedType.stringIndexInfo) { if (resolvedType.stringIndexInfo) {
typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.stringIndexInfo, IndexKind.String, enclosingDeclaration, flags)); typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.stringIndexInfo, IndexKind.String));
} }
if (resolvedType.numberIndexInfo) { if (resolvedType.numberIndexInfo) {
typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.numberIndexInfo, IndexKind.Number, enclosingDeclaration, flags)); typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.numberIndexInfo, IndexKind.Number));
} }
const properties = resolvedType.properties; const properties = resolvedType.properties;
@ -2544,7 +2579,7 @@ namespace ts {
if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) { if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) {
const signatures = getSignaturesOfType(propertyType, SignatureKind.Call); const signatures = getSignaturesOfType(propertyType, SignatureKind.Call);
for (const signature of signatures) { for (const signature of signatures) {
const methodDeclaration = <MethodSignature>signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, enclosingDeclaration, flags); const methodDeclaration = <MethodSignature>signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature);
methodDeclaration.name = propertyName; methodDeclaration.name = propertyName;
methodDeclaration.questionToken = optionalToken; methodDeclaration.questionToken = optionalToken;
typeElements.push(methodDeclaration); typeElements.push(methodDeclaration);
@ -2553,7 +2588,7 @@ namespace ts {
else { else {
// TODO(aozgaa): should we create a node with explicit or implict any? // TODO(aozgaa): should we create a node with explicit or implict any?
const propertyTypeNode = propertyType ? typeToTypeNodeWorker(propertyType) : createKeywordTypeNode(SyntaxKind.AnyKeyword); const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType) : createKeywordTypeNode(SyntaxKind.AnyKeyword);
typeElements.push(createPropertySignature( typeElements.push(createPropertySignature(
propertyName, propertyName,
optionalToken, optionalToken,
@ -2564,9 +2599,8 @@ namespace ts {
return typeElements.length ? typeElements : undefined; return typeElements.length ? typeElements : undefined;
} }
} }
}
function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node, flags: NodeBuilderFlags): IndexSignatureDeclaration { function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind): IndexSignatureDeclaration {
const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword); const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword);
const name = getNameFromIndexInfo(indexInfo); const name = getNameFromIndexInfo(indexInfo);
@ -2578,7 +2612,7 @@ namespace ts {
/*questionToken*/ undefined, /*questionToken*/ undefined,
indexerTypeNode, indexerTypeNode,
/*initializer*/ undefined); /*initializer*/ undefined);
const typeNode = typeToTypeNodeHelper(indexInfo.type, enclosingDeclaration, flags); const typeNode = typeToTypeNodeHelper(indexInfo.type);
return createIndexSignatureDeclaration( return createIndexSignatureDeclaration(
[indexingParameter], [indexingParameter],
typeNode, typeNode,
@ -2586,37 +2620,37 @@ namespace ts {
indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined); indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined);
} }
function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind, enclosingDeclaration: Node, flags: NodeBuilderFlags): SignatureDeclaration { function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind): SignatureDeclaration {
const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, enclosingDeclaration, flags)); const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter));
const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter, enclosingDeclaration, flags)); const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter));
const returnTypeNode = typeToTypeNodeExceptAny(getReturnTypeOfSignature(signature)); const returnTypeNode = typeToTypeNodeExceptAny(getReturnTypeOfSignature(signature));
return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNode); return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNode);
function typeToTypeNodeExceptAny(type: Type): TypeNode | undefined { function typeToTypeNodeExceptAny(type: Type): TypeNode | undefined {
const typeNode = type && typeToTypeNodeHelper(type, enclosingDeclaration, flags); const typeNode = type && typeToTypeNodeHelper(type);
return typeNode && typeNode.kind !== SyntaxKind.AnyKeyword ? typeNode : undefined; return typeNode && typeNode.kind !== SyntaxKind.AnyKeyword ? typeNode : undefined;
} }
} }
function typeParameterToDeclaration(type: TypeParameter, enclosingDeclaration: Node, flags: NodeBuilderFlags): TypeParameterDeclaration { function typeParameterToDeclaration(type: TypeParameter): TypeParameterDeclaration {
if (!(type && type.symbol && type.flags & TypeFlags.TypeParameter)) { if (!(type && type.symbol && type.flags & TypeFlags.TypeParameter)) {
return undefined; return undefined;
} }
const constraint = getConstraintFromTypeParameter(type); const constraint = getConstraintFromTypeParameter(type);
const constraintNode = constraint && typeToTypeNodeHelper(constraint, enclosingDeclaration, flags); const constraintNode = constraint && typeToTypeNodeHelper(constraint);
const defaultParameter = getDefaultFromTypeParameter(type); const defaultParameter = getDefaultFromTypeParameter(type);
const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter, enclosingDeclaration, flags); const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter);
const name = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ true, flags); const name = symbolToName(type.symbol, /*expectsIdentifier*/ true);
return createTypeParameterDeclaration(name, constraintNode, defaultParameterNode); return createTypeParameterDeclaration(name, constraintNode, defaultParameterNode);
} }
function symbolToParameterDeclaration(parameterSymbol: Symbol, enclosingDeclaration: Node, flags: NodeBuilderFlags): ParameterDeclaration { function symbolToParameterDeclaration(parameterSymbol: Symbol): ParameterDeclaration {
const parameterDeclaration = parameterSymbol.declarations[0] as ParameterDeclaration; const parameterDeclaration = parameterSymbol.declarations[0] as ParameterDeclaration;
const parameterType = getTypeOfSymbol(parameterSymbol); const parameterType = getTypeOfSymbol(parameterSymbol);
const parameterTypeNode = typeToTypeNodeHelper(parameterType, enclosingDeclaration, flags); const parameterTypeNode = typeToTypeNodeHelper(parameterType);
// TODO(aozgaa): check initializer accessibility correctly. // TODO(aozgaa): check initializer accessibility correctly.
const parameterNode = createParameter( const parameterNode = createParameter(
parameterDeclaration.decorators, parameterDeclaration.decorators,
@ -2630,15 +2664,15 @@ namespace ts {
return parameterNode; return parameterNode;
} }
function symbolToName(symbol: Symbol, enclosingDeclaration: Node | undefined, expectsIdentifier: true, flags: NodeBuilderFlags): Identifier; function symbolToName(symbol: Symbol, expectsIdentifier: true): Identifier;
function symbolToName(symbol: Symbol, enclosingDeclaration: Node | undefined, expectsIdentifier: false, flags: NodeBuilderFlags): EntityName; function symbolToName(symbol: Symbol, expectsIdentifier: false): EntityName;
function symbolToName(symbol: Symbol, enclosingDeclaration: Node | undefined, expectsIdentifier: boolean, flags: NodeBuilderFlags): EntityName { function symbolToName(symbol: Symbol, expectsIdentifier: boolean): EntityName {
let parentSymbol: Symbol; let parentSymbol: Symbol;
// Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration. // Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration.
let chain: Symbol[]; let chain: Symbol[];
const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter; const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter;
if (!isTypeParameter && enclosingDeclaration) { if (!isTypeParameter && context.enclosingDeclaration) {
chain = getSymbolChain(symbol, SymbolFlags.None, /*endOfChain*/ true); chain = getSymbolChain(symbol, SymbolFlags.None, /*endOfChain*/ true);
Debug.assert(chain && chain.length > 0); Debug.assert(chain && chain.length > 0);
} }
@ -2648,8 +2682,10 @@ namespace ts {
parentSymbol = undefined; parentSymbol = undefined;
if (expectsIdentifier && chain.length !== 1) { if (expectsIdentifier && chain.length !== 1
encounteredError = encounteredError || !(flags & NodeBuilderFlags.allowQualifedNameInPlaceOfIdentifier); && !context.encounteredError
&& !(context.flags & NodeBuilderFlags.allowQualifedNameInPlaceOfIdentifier)) {
context.encounteredError = true;
} }
return createEntityNameFromSymbolChain(chain, chain.length - 1); return createEntityNameFromSymbolChain(chain, chain.length - 1);
@ -2672,11 +2708,12 @@ namespace ts {
} }
} }
if (typeParameters && typeParameters.length > 0) { if (typeParameters && typeParameters.length > 0) {
encounteredError = encounteredError || !(flags & NodeBuilderFlags.allowTypeParameterInQualifiedName); if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowTypeParameterInQualifiedName)) {
context.encounteredError = true;
}
const writer = getSingleLineStringWriter(); const writer = getSingleLineStringWriter();
const displayBuilder = getSymbolDisplayBuilder(); const displayBuilder = getSymbolDisplayBuilder();
displayBuilder.buildDisplayForTypeParametersAndDelimiters(typeParameters, writer, enclosingDeclaration, 0); displayBuilder.buildDisplayForTypeParametersAndDelimiters(typeParameters, writer, context.enclosingDeclaration, 0);
typeParameterString = writer.string(); typeParameterString = writer.string();
releaseStringWriter(writer); releaseStringWriter(writer);
@ -2691,10 +2728,10 @@ namespace ts {
/** @param endOfChain Set to false for recursive calls; non-recursive calls should always output something. */ /** @param endOfChain Set to false for recursive calls; non-recursive calls should always output something. */
function getSymbolChain(symbol: Symbol, meaning: SymbolFlags, endOfChain: boolean): Symbol[] | undefined { function getSymbolChain(symbol: Symbol, meaning: SymbolFlags, endOfChain: boolean): Symbol[] | undefined {
let accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning, /*useOnlyExternalAliasing*/false); let accessibleSymbolChain = getAccessibleSymbolChain(symbol, context.enclosingDeclaration, meaning, /*useOnlyExternalAliasing*/false);
if (!accessibleSymbolChain || if (!accessibleSymbolChain ||
needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) { needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
// Go up and add our parent. // Go up and add our parent.
const parent = getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol); const parent = getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
@ -2731,7 +2768,9 @@ namespace ts {
if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) { if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) {
return declarationNameToString((<VariableDeclaration>declaration.parent).name); return declarationNameToString((<VariableDeclaration>declaration.parent).name);
} }
encounteredError = encounteredError || !(flags & NodeBuilderFlags.allowAnonymousIdentifier); if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowAnonymousIdentifier)) {
context.encounteredError = true;
}
switch (declaration.kind) { switch (declaration.kind) {
case SyntaxKind.ClassExpression: case SyntaxKind.ClassExpression:
return "(Anonymous class)"; return "(Anonymous class)";

View file

@ -238,10 +238,10 @@ namespace ts {
: node; : node;
} }
export function createTypeReferenceNode(typeName: string | EntityName, typeArguments: NodeArray<TypeNode> | undefined) { export function createTypeReferenceNode(typeName: string | EntityName, typeArguments: TypeNode[] | undefined) {
const typeReference = createSynthesizedNode(SyntaxKind.TypeReference) as TypeReferenceNode; const typeReference = createSynthesizedNode(SyntaxKind.TypeReference) as TypeReferenceNode;
typeReference.typeName = asName(typeName); typeReference.typeName = asName(typeName);
typeReference.typeArguments = typeArguments; typeReference.typeArguments = asNodeArray(typeArguments);
return typeReference; return typeReference;
} }

View file

@ -2548,7 +2548,9 @@ namespace ts {
allowThisInObjectLiteral = 1 << 0, allowThisInObjectLiteral = 1 << 0,
allowQualifedNameInPlaceOfIdentifier = 1 << 1, allowQualifedNameInPlaceOfIdentifier = 1 << 1,
allowTypeParameterInQualifiedName = 1 << 2, allowTypeParameterInQualifiedName = 1 << 2,
allowAnonymousIdentifier = 1 << 3 allowAnonymousIdentifier = 1 << 3,
allowEmptyUnionOrIntersection = 1 << 4,
allowEmptyTuple = 1 << 5
} }
export interface SymbolDisplayBuilder { export interface SymbolDisplayBuilder {