Merge branch 'createTypeNode2' into createTypeNode

This commit is contained in:
Arthur Ozga 2017-03-23 14:12:25 -07:00
commit bfb1bb4801
5 changed files with 178 additions and 117 deletions

View file

@ -2192,16 +2192,13 @@ namespace ts {
return result; return result;
} }
function unwrapNodeBuilderResult<T>(result: NodeBuilderResult<T>, returnValueOnError: boolean): T | undefined {
return !result.error || returnValueOnError ? result.value : undefined;
}
function getNodeBuilder(): NodeBuilder { function getNodeBuilder(): NodeBuilder {
if (nodeBuilderCache) { if (nodeBuilderCache) {
return nodeBuilderCache; return nodeBuilderCache;
} }
let encounteredError = false; let encounteredError = false;
nodeBuilderCache = { nodeBuilderCache = {
typeToTypeNode, typeToTypeNode,
indexInfoToIndexSignatureDeclaration, indexInfoToIndexSignatureDeclaration,
@ -2210,21 +2207,40 @@ namespace ts {
return nodeBuilderCache; return nodeBuilderCache;
function typeToTypeNode(type: Type, enclosingDeclaration?: Node, emitNodeOnError?: boolean): NodeBuilderResult<TypeNode> { function typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode {
let toNodeEncounteredErrorCache = encounteredError; const helper = () => typeToTypeNodeHelper(type, enclosingDeclaration, flags);
encounteredError = false; return callHelperWithErrorHandling(helper);
}
function indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration {
const helper = () => indexInfoToIndexSignatureDeclarationHelper(indexInfo, kind, enclosingDeclaration, flags);
return callHelperWithErrorHandling(helper);
}
function signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration {
const helper = () => signatureToSignatureDeclarationHelper(signature, kind, enclosingDeclaration, flags);
return callHelperWithErrorHandling(helper);
}
function callHelperWithErrorHandling<T extends Node>(nodeBuilderHelper: () => T): T | undefined {
const encounteredErrorCache = encounteredError;
const resultingNode = nodeBuilderHelper();
const result = encounteredError ? undefined : resultingNode;
encounteredError = encounteredErrorCache;
return result;
}
function typeToTypeNodeHelper(type: Type, enclosingDeclaration: Node, flags: NodeBuilderFlags): TypeNode {
let inObjectTypeLiteral = false; let inObjectTypeLiteral = false;
let checkAlias = true; let checkAlias = true;
let symbolStack: Symbol[] = undefined; let symbolStack: Symbol[] = undefined;
const resultingNode = typeToTypeNodeWorker(type); return typeToTypeNodeWorker(type);
const result = encounteredError && !emitNodeOnError ? undefined : resultingNode;
encounteredError = toNodeEncounteredErrorCache;
return result;
function typeToTypeNodeWorker(type: Type): NodeBuilderResult<TypeNode> { function typeToTypeNodeWorker(type: Type): TypeNode {
if (!type) { if (!type) {
encounteredError = true; encounteredError = true;
// TODO(aozgaa): should we return implict any (undefined) or explicit any (keywordtypenode)?
return undefined; return undefined;
} }
@ -2241,7 +2257,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); const name = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags);
return createTypeReferenceNode(name, /*typeArguments*/ undefined); return createTypeReferenceNode(name, /*typeArguments*/ undefined);
} }
if (type.flags & (TypeFlags.StringLiteral)) { if (type.flags & (TypeFlags.StringLiteral)) {
@ -2254,7 +2270,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); const name = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags);
return createTypeReferenceNode(name, /*typeArguments*/ undefined); return createTypeReferenceNode(name, /*typeArguments*/ undefined);
} }
if (type.flags & TypeFlags.Void) { if (type.flags & TypeFlags.Void) {
@ -2277,7 +2293,7 @@ namespace ts {
} }
if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) {
if (inObjectTypeLiteral) { if (inObjectTypeLiteral) {
encounteredError = true; encounteredError = encounteredError || !(flags & NodeBuilderFlags.allowThisInObjectLiteral);
} }
return createThis(); return createThis();
} }
@ -2286,22 +2302,22 @@ namespace ts {
if (objectFlags & ObjectFlags.Reference) { if (objectFlags & ObjectFlags.Reference) {
Debug.assert(!!(type.flags & TypeFlags.Object)); Debug.assert(!!(type.flags & TypeFlags.Object));
return typeReferenceToTypeReferenceNode(<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); const name = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags);
// 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); const name = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags);
// 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 (checkAlias && type.aliasSymbol) {
const name = symbolToName(type.aliasSymbol, enclosingDeclaration); const name = symbolToName(type.aliasSymbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags);
const typeArgumentNodes = mapToTypeNodeArray(type.aliasTypeArguments); const typeArgumentNodes = mapToTypeNodeArray(type.aliasTypeArguments);
return createTypeReferenceNode(name, typeArgumentNodes); return createTypeReferenceNode(name, typeArgumentNodes);
} }
@ -2335,15 +2351,16 @@ namespace ts {
Debug.fail("Should be unreachable."); Debug.fail("Should be unreachable.");
function mapToTypeNodeArray(types: Type[]): NodeArray<TypeNode> { function mapToTypeNodeArray(types: Type[]): NodeArray<TypeNode> {
return types && asNodeArray(types.map(typeToTypeNodeWorker) as TypeNode[]); return types && asNodeArray(types.map(typeToTypeNodeWorker).filter(node => !!node));
} }
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); const typeParameterNode = typeParameterToDeclaration(typeParameter, enclosingDeclaration, flags);
const templateTypeNode = typeToTypeNodeWorker(getTemplateTypeFromMappedType(<MappedType>type)); const templateType = getTemplateTypeFromMappedType(<MappedType>type)
const templateTypeNode = templateType && typeToTypeNodeWorker(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;
@ -2364,7 +2381,7 @@ namespace ts {
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); const entityName = symbolToName(typeAlias, enclosingDeclaration, /*expectsIdentifier*/ false, flags);
return createTypeReferenceNode(entityName, /*typeArguments*/ undefined); return createTypeReferenceNode(entityName, /*typeArguments*/ undefined);
} }
else { else {
@ -2417,11 +2434,11 @@ 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>signatureToSignatureDeclaration(signature, SyntaxKind.FunctionType, enclosingDeclaration, emitNodeOnError); return <FunctionTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, enclosingDeclaration, flags);
} }
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>signatureToSignatureDeclaration(signature, SyntaxKind.ConstructorType, enclosingDeclaration, emitNodeOnError); return <ConstructorTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType, enclosingDeclaration, flags);
} }
} }
@ -2435,12 +2452,12 @@ namespace ts {
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); const entityName = symbolToName(symbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags);
return createTypeQueryNode(entityName); return createTypeQueryNode(entityName);
} }
} }
function typeReferenceToTypeReferenceNode(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 = typeToTypeNodeWorker(typeArguments[0]);
@ -2465,7 +2482,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, /*mustBeIdentifier*/ true); const qualifiedNamePart = symbolToName(parent, enclosingDeclaration, /*expectsIdentifier*/ true, flags);
if (!qualifiedName) { if (!qualifiedName) {
qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined); qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined);
} }
@ -2478,7 +2495,7 @@ namespace ts {
} }
} }
let entityName: EntityName = undefined; let entityName: EntityName = undefined;
const nameIdentifier = symbolToName(type.symbol, enclosingDeclaration, /*mustBeIdentifier*/ true); const nameIdentifier = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ true, flags);
if (qualifiedName) { if (qualifiedName) {
Debug.assert(!qualifiedName.right); Debug.assert(!qualifiedName.right);
qualifiedName.right = nameIdentifier; qualifiedName.right = nameIdentifier;
@ -2496,16 +2513,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>signatureToSignatureDeclaration(signature, SyntaxKind.CallSignature, enclosingDeclaration, emitNodeOnError)); typeElements.push(<CallSignatureDeclaration>signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature, enclosingDeclaration, flags));
} }
for (const signature of resolvedType.constructSignatures) { for (const signature of resolvedType.constructSignatures) {
typeElements.push(<ConstructSignatureDeclaration>signatureToSignatureDeclaration(signature, SyntaxKind.ConstructSignature, enclosingDeclaration, emitNodeOnError)); typeElements.push(<ConstructSignatureDeclaration>signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature, enclosingDeclaration, flags));
} }
if (resolvedType.stringIndexInfo) { if (resolvedType.stringIndexInfo) {
typeElements.push(indexInfoToIndexSignatureDeclaration(resolvedType.stringIndexInfo, IndexKind.String, enclosingDeclaration, emitNodeOnError)); typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.stringIndexInfo, IndexKind.String, enclosingDeclaration, flags));
} }
if (resolvedType.numberIndexInfo) { if (resolvedType.numberIndexInfo) {
typeElements.push(indexInfoToIndexSignatureDeclaration(resolvedType.numberIndexInfo, IndexKind.Number, enclosingDeclaration, emitNodeOnError)); typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.numberIndexInfo, IndexKind.Number, enclosingDeclaration, flags));
} }
const properties = resolvedType.properties; const properties = resolvedType.properties;
@ -2524,17 +2541,20 @@ 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>signatureToSignatureDeclaration(signature, SyntaxKind.MethodSignature, enclosingDeclaration, emitNodeOnError); const methodDeclaration = <MethodSignature>signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, enclosingDeclaration, flags);
methodDeclaration.name = propertyName; methodDeclaration.name = propertyName;
methodDeclaration.questionToken = optionalToken; methodDeclaration.questionToken = optionalToken;
typeElements.push(methodDeclaration); typeElements.push(methodDeclaration);
} }
} }
else { else {
// TODO(aozgaa): should we create a node with explicit or implict any?
const propertyTypeNode = propertyType ? typeToTypeNodeWorker(propertyType) : createKeywordTypeNode(SyntaxKind.AnyKeyword);
typeElements.push(createPropertySignature( typeElements.push(createPropertySignature(
propertyName, propertyName,
optionalToken, optionalToken,
typeToTypeNodeWorker(propertyType), propertyTypeNode,
/*initializer*/undefined)); /*initializer*/undefined));
} }
} }
@ -2543,10 +2563,7 @@ namespace ts {
} }
} }
function indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node, emitNodeOnError?: boolean): IndexSignatureDeclaration { function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node, flags: NodeBuilderFlags): IndexSignatureDeclaration {
const encounteredErrorCache = encounteredError;
encounteredError = false;
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);
@ -2558,55 +2575,46 @@ namespace ts {
/*questionToken*/ undefined, /*questionToken*/ undefined,
indexerTypeNode, indexerTypeNode,
/*initializer*/ undefined); /*initializer*/ undefined);
const typeNode = typeToTypeNode(indexInfo.type, enclosingDeclaration, emitNodeOnError); const typeNode = typeToTypeNodeHelper(indexInfo.type, enclosingDeclaration, flags);
const result = !encounteredError || emitNodeOnError ? createIndexSignatureDeclaration( return createIndexSignatureDeclaration(
[indexingParameter], [indexingParameter],
typeNode, typeNode,
/*decorators*/ undefined, /*decorators*/ undefined,
indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined) indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined);
: undefined;
encounteredError = encounteredErrorCache;
return result;
} }
function signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, emitNodeOnError?: boolean): SignatureDeclaration { function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind, enclosingDeclaration: Node, flags: NodeBuilderFlags): SignatureDeclaration {
const encounteredErrorCache = encounteredError;
encounteredError = false;
const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, enclosingDeclaration)); const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, enclosingDeclaration, flags));
const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter, enclosingDeclaration)); const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter, enclosingDeclaration, flags));
const type = typeToTypeNodeExceptAny(getReturnTypeOfSignature(signature)); const type = typeToTypeNodeExceptAny(getReturnTypeOfSignature(signature));
const result = !encounteredError || emitNodeOnError ? createSignatureDeclaration(kind, typeParameters, parameters, type) : undefined; return createSignatureDeclaration(kind, typeParameters, parameters, type);
encounteredError = encounteredErrorCache;
return result;
function typeToTypeNodeExceptAny(type: Type): TypeNode | undefined { function typeToTypeNodeExceptAny(type: Type): TypeNode | undefined {
const typeNode = typeToTypeNode(type, enclosingDeclaration, emitNodeOnError); // Note, this call will *not* mark encounteredError.
const typeNode = typeToTypeNode(type, enclosingDeclaration);
return typeNode && typeNode.kind !== SyntaxKind.AnyKeyword ? typeNode : undefined; return typeNode && typeNode.kind !== SyntaxKind.AnyKeyword ? typeNode : undefined;
} }
} }
function typeParameterToDeclaration(type: TypeParameter, enclosingDeclaration?: Node, returnNodeOnError?: boolean): TypeParameterDeclaration { function typeParameterToDeclaration(type: TypeParameter, enclosingDeclaration: Node, flags: NodeBuilderFlags): TypeParameterDeclaration {
if (!(type && type.symbol && type.flags & TypeFlags.TypeParameter)) { if (!(type && type.symbol && type.flags & TypeFlags.TypeParameter)) {
return undefined; return undefined;
} }
const constraint = typeToTypeNode(getConstraintFromTypeParameter(type), enclosingDeclaration); const constraint = getConstraintFromTypeParameter(type);
const defaultParameter = typeToTypeNode(getDefaultFromTypeParameter(type), enclosingDeclaration); const constraintNode = constraint && typeToTypeNodeHelper(constraint, enclosingDeclaration, flags);
const defaultParameter = getDefaultFromTypeParameter(type);
let toNodeEncounteredErrorCache = encounteredError; const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter, enclosingDeclaration, flags);
encounteredError = false; const name = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ true, flags);
const name = symbolToName(type.symbol, enclosingDeclaration, /*mustBeIdentifier*/ true); return createTypeParameterDeclaration(name, constraintNode, defaultParameterNode);
let result = encounteredError && !returnNodeOnError ? undefined : createTypeParameterDeclaration(name, constraint, defaultParameter);
encounteredError = toNodeEncounteredErrorCache;
return result;
} }
function symbolToParameterDeclaration(parameterSymbol: Symbol, enclosingDeclaration?: Node): ParameterDeclaration { function symbolToParameterDeclaration(parameterSymbol: Symbol, enclosingDeclaration: Node, flags: NodeBuilderFlags): 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 = typeToTypeNode(parameterType, enclosingDeclaration); const parameterTypeNode = typeToTypeNodeHelper(parameterType, enclosingDeclaration, flags);
// TODO(aozgaa): check initializer accessibility correctly. // TODO(aozgaa): check initializer accessibility correctly.
const parameterNode = createParameter( const parameterNode = createParameter(
parameterDeclaration.decorators, parameterDeclaration.decorators,
@ -2620,19 +2628,17 @@ namespace ts {
return parameterNode; return parameterNode;
} }
function symbolToName(symbol: Symbol, enclosingDeclaration: Node | undefined, mustBeIdentifier: true): Identifier; function symbolToName(symbol: Symbol, enclosingDeclaration: Node | undefined, expectsIdentifier: true, flags: NodeBuilderFlags): Identifier;
function symbolToName(symbol: Symbol, enclosingDeclaration?: Node, mustBeIdentifier?: false): EntityName; function symbolToName(symbol: Symbol, enclosingDeclaration: Node | undefined, expectsIdentifier: false, flags: NodeBuilderFlags): EntityName;
function symbolToName(symbol: Symbol, enclosingDeclaration: Node | undefined, mustBeIdentifier: boolean | undefined): EntityName { function symbolToName(symbol: Symbol, enclosingDeclaration: Node | undefined, expectsIdentifier: boolean, flags: NodeBuilderFlags): EntityName {
let parentSymbol: Symbol; let parentSymbol: Symbol;
let meaning: SymbolFlags; let meaning: SymbolFlags;
// Get qualified name if the symbol is not a type parameter // Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration.
// 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 && enclosingDeclaration) {
chain = getSymbolChain(symbol, meaning, /*endOfChain*/ true); chain = getSymbolChain(symbol, meaning, /*endOfChain*/ true);
// TODO: check whether type pointed to by symbol requires type arguments to be printed.
Debug.assert(chain && chain.length > 0); Debug.assert(chain && chain.length > 0);
} }
else { else {
@ -2640,10 +2646,9 @@ namespace ts {
} }
parentSymbol = undefined; parentSymbol = undefined;
if (mustBeIdentifier && chain.length !== 1) {
encounteredError = true; if (expectsIdentifier && chain.length !== 1) {
// TODO: failing to get an identifier when we expect one generates an unprintable node. encounteredError = encounteredError || !(flags & NodeBuilderFlags.allowQualifedNameInPlaceOfIdentifier);
// Should error handling be more severe?
} }
return createEntityNameFromSymbolChain(chain, chain.length - 1); return createEntityNameFromSymbolChain(chain, chain.length - 1);
@ -2653,7 +2658,7 @@ namespace ts {
const symbol = chain[index]; const symbol = chain[index];
let typeParameterString = ""; let typeParameterString = "";
if (index > 0) { if (index > 0) {
// TODO: is the parentSymbol wrong?
const parentSymbol = chain[index - 1]; const parentSymbol = chain[index - 1];
let typeParameters: TypeParameter[]; let typeParameters: TypeParameter[];
if (getCheckFlags(symbol) & CheckFlags.Instantiated) { if (getCheckFlags(symbol) & CheckFlags.Instantiated) {
@ -2666,7 +2671,8 @@ namespace ts {
} }
} }
if (typeParameters && typeParameters.length > 0) { if (typeParameters && typeParameters.length > 0) {
encounteredError = true; encounteredError = encounteredError || !(flags & NodeBuilderFlags.allowTypeParameterInQualifiedName);;
const writer = getSingleLineStringWriter(); const writer = getSingleLineStringWriter();
const displayBuilder = getSymbolDisplayBuilder(); const displayBuilder = getSymbolDisplayBuilder();
displayBuilder.buildDisplayForTypeParametersAndDelimiters(typeParameters, writer, enclosingDeclaration, 0); displayBuilder.buildDisplayForTypeParametersAndDelimiters(typeParameters, writer, enclosingDeclaration, 0);
@ -2724,7 +2730,7 @@ 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 = true; encounteredError = encounteredError || !(flags & NodeBuilderFlags.allowAnonymousIdentifier);
switch (declaration.kind) { switch (declaration.kind) {
case SyntaxKind.ClassExpression: case SyntaxKind.ClassExpression:
return "(Anonymous class)"; return "(Anonymous class)";

View file

@ -378,28 +378,65 @@ namespace ts {
} }
// TODO: Split according to AST nodes. // TODO: Split according to AST nodes.
export function createSignatureDeclaration<T extends SignatureDeclaration>(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined): T; export function createSignatureDeclaration(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined) {
export function createSignatureDeclaration<T extends SignatureDeclaration & TypeElement>(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined): T; const signatureDeclaration = createSynthesizedNode(kind) as SignatureDeclaration;
export function createSignatureDeclaration<T extends SignatureDeclaration & TypeElement>(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, name?: string | PropertyName, questionToken?: QuestionToken): T {
const signatureDeclaration = createSynthesizedNode(kind) as T;
signatureDeclaration.typeParameters = asNodeArray(typeParameters); signatureDeclaration.typeParameters = asNodeArray(typeParameters);
signatureDeclaration.parameters = asNodeArray(parameters); signatureDeclaration.parameters = asNodeArray(parameters);
signatureDeclaration.type = type; signatureDeclaration.type = type;
signatureDeclaration.name = asName(name);
signatureDeclaration.questionToken = questionToken;
return signatureDeclaration; return signatureDeclaration;
} }
// TODO: figure out right type annotation for this function. export function updateSignatureDeclaration(node: SignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
export function updateSignatureDeclaration<T extends SignatureDeclaration>(node: T, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined): T; return node.typeParameters !== typeParameters
export function updateSignatureDeclaration<T extends SignatureDeclaration & TypeElement>(node: T, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined, name: PropertyName, questionToken: QuestionToken | undefined): T; || node.parameters !== parameters
export function updateSignatureDeclaration<T extends SignatureDeclaration & TypeElement>(node: T, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined, name?: PropertyName, questionToken?: QuestionToken): T { || node.type !== type
? updateNode(createSignatureDeclaration(node.kind, typeParameters, parameters, type), node)
: node;
}
export function createFunctionTypeNode(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined): FunctionTypeNode {
return createSignatureDeclaration(SyntaxKind.FunctionType, typeParameters, parameters, type) as FunctionTypeNode;
}
export function updateFunctionTypeNode(node: FunctionTypeNode, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined): FunctionTypeNode {
return <FunctionTypeNode>updateSignatureDeclaration(node, typeParameters, parameters, type);
}
export function createConstructorTypeNode(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined): ConstructorTypeNode {
return createSignatureDeclaration(SyntaxKind.ConstructorType, typeParameters, parameters, type) as ConstructorTypeNode;
}
export function updateConstructorTypeNode(node: ConstructorTypeNode, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined): ConstructorTypeNode {
return <ConstructorTypeNode>updateSignatureDeclaration(node, typeParameters, parameters, type);
}
export function createCallSignatureDeclaration(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined): CallSignatureDeclaration {
return createSignatureDeclaration(SyntaxKind.CallSignature, typeParameters, parameters, type) as CallSignatureDeclaration;
}
export function updateCallSignatureDeclaration(node: CallSignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined): CallSignatureDeclaration {
return <CallSignatureDeclaration>updateSignatureDeclaration(node, typeParameters, parameters, type);
}
export function createConstructSignatureDeclaration(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined): ConstructSignatureDeclaration {
return createSignatureDeclaration(SyntaxKind.ConstructSignature, typeParameters, parameters, type) as ConstructSignatureDeclaration;
}
export function updateConstructSignatureDeclaration(node: ConstructSignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined): ConstructSignatureDeclaration {
return <ConstructSignatureDeclaration>updateSignatureDeclaration(node, typeParameters, parameters, type);
}
export function createMethodSignature(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined): MethodSignature{
const methodSignature = createSignatureDeclaration(SyntaxKind.MethodSignature, typeParameters, parameters, type) as MethodSignature;
methodSignature.name = asName(name);
methodSignature.questionToken = questionToken;
return methodSignature;
}
export function updateMethodSignature(node: MethodSignature, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined, name?: PropertyName, questionToken?: QuestionToken): MethodSignature {
return node.typeParameters !== typeParameters return node.typeParameters !== typeParameters
|| node.parameters !== parameters || node.parameters !== parameters
|| node.type !== type || node.type !== type
|| node.name !== name || node.name !== name
|| node.questionToken !== questionToken || node.questionToken !== questionToken
? updateNode(createSignatureDeclaration<T>(node.kind, typeParameters, parameters, type, name, questionToken), node) ? updateNode(createMethodSignature(typeParameters, parameters, type, name, questionToken), node)
: node; : node;
} }
@ -502,7 +539,7 @@ namespace ts {
: node; : node;
} }
export function createMethod(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) { export function createMethodDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
const node = <MethodDeclaration>createSynthesizedNode(SyntaxKind.MethodDeclaration); const node = <MethodDeclaration>createSynthesizedNode(SyntaxKind.MethodDeclaration);
node.decorators = asNodeArray(decorators); node.decorators = asNodeArray(decorators);
node.modifiers = asNodeArray(modifiers); node.modifiers = asNodeArray(modifiers);
@ -525,7 +562,7 @@ namespace ts {
|| node.parameters !== parameters || node.parameters !== parameters
|| node.type !== type || node.type !== type
|| node.body !== body || node.body !== body
? updateNode(createMethod(decorators, modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body), node) ? updateNode(createMethodDeclaration(decorators, modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body), node)
: node; : node;
} }

View file

@ -2473,11 +2473,12 @@ namespace ts {
getNonNullableType(type: Type): Type; getNonNullableType(type: Type): Type;
/** Note that the resulting nodes cannot be checked. */ /** Note that the resulting nodes cannot be checked. */
typeToTypeNode(type: Type, enclosingDeclaration?: Node, returnNodeOnError?: boolean): TypeNode;
typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode;
/** Note that the resulting nodes cannot be checked. */ /** Note that the resulting nodes cannot be checked. */
signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, returnNodeOnError?: boolean): SignatureDeclaration; signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration;
/** Note that the resulting nodes cannot be checked. */ /** Note that the resulting nodes cannot be checked. */
indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, returnNodeOnError?: boolean): IndexSignatureDeclaration; indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration;
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
getSymbolAtLocation(node: Node): Symbol; getSymbolAtLocation(node: Node): Symbol;
@ -2530,18 +2531,20 @@ namespace ts {
/* @internal */ getTypeCount(): number; /* @internal */ getTypeCount(): number;
} }
/** Note that the resulting nodes cannot be checked. */ /** Note that any resulting nodes cannot be checked. */
/* @internal */ /* @internal */
export interface NodeBuilder { export interface NodeBuilder {
typeToTypeNode(type: Type, enclosingDeclaration?: Node, returnNodeOnError?: boolean): NodeBuilderResult<TypeNode>; typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode;
signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node): NodeBuilderResult<SignatureDeclaration>; signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration;
indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node): NodeBuilderResult<IndexSignatureDeclaration>; indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration;
} }
/* @internal */ export enum NodeBuilderFlags {
export interface NodeBuilderResult<T> { None = 0,
value: T; allowThisInObjectLiteral = 1 << 0,
error?: boolean; allowQualifedNameInPlaceOfIdentifier = 1 << 1,
allowTypeParameterInQualifiedName = 1 << 2,
allowAnonymousIdentifier = 1 << 3
} }
export interface SymbolDisplayBuilder { export interface SymbolDisplayBuilder {

View file

@ -260,21 +260,36 @@ namespace ts {
// Signatures and Signature Elements // Signatures and Signature Elements
case SyntaxKind.FunctionType: case SyntaxKind.FunctionType:
return updateFunctionTypeNode(<FunctionTypeNode>node,
nodesVisitor((<FunctionTypeNode>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<FunctionTypeNode>node).parameters, visitor, context, nodesVisitor),
visitNode((<FunctionTypeNode>node).type, visitor, isTypeNode));
case SyntaxKind.ConstructorType: case SyntaxKind.ConstructorType:
return updateConstructorTypeNode(<ConstructorTypeNode>node,
nodesVisitor((<ConstructorTypeNode>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<ConstructorTypeNode>node).parameters, visitor, context, nodesVisitor),
visitNode((<ConstructorTypeNode>node).type, visitor, isTypeNode));
case SyntaxKind.CallSignature: case SyntaxKind.CallSignature:
return updateCallSignatureDeclaration(<CallSignatureDeclaration>node,
nodesVisitor((<CallSignatureDeclaration>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<CallSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
visitNode((<CallSignatureDeclaration>node).type, visitor, isTypeNode));
case SyntaxKind.ConstructSignature: case SyntaxKind.ConstructSignature:
return updateSignatureDeclaration(<SignatureDeclaration>node, return updateConstructSignatureDeclaration(<ConstructSignatureDeclaration>node,
nodesVisitor((<SignatureDeclaration>node).typeParameters, visitor, isTypeParameter), nodesVisitor((<ConstructSignatureDeclaration>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<SignatureDeclaration>node).parameters, visitor, context, nodesVisitor), visitParameterList((<ConstructSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
visitNode((<SignatureDeclaration>node).type, visitor, isTypeNode)); visitNode((<ConstructSignatureDeclaration>node).type, visitor, isTypeNode));
case SyntaxKind.MethodSignature: case SyntaxKind.MethodSignature:
return updateSignatureDeclaration(<SignatureDeclaration & TypeElement>node, return updateMethodSignature(<MethodSignature>node,
nodesVisitor((<SignatureDeclaration & TypeElement>node).typeParameters, visitor, isTypeParameter), nodesVisitor((<MethodSignature>node).typeParameters, visitor, isTypeParameter),
visitParameterList((<SignatureDeclaration & TypeElement>node).parameters, visitor, context, nodesVisitor), visitParameterList((<MethodSignature>node).parameters, visitor, context, nodesVisitor),
visitNode((<SignatureDeclaration & TypeElement>node).type, visitor, isTypeNode), visitNode((<MethodSignature>node).type, visitor, isTypeNode),
visitNode((<SignatureDeclaration & TypeElement>node).name, visitor, isPropertyName), visitNode((<MethodSignature>node).name, visitor, isPropertyName),
visitNode((<SignatureDeclaration & TypeElement>node).questionToken, tokenVisitor, isToken)); visitNode((<MethodSignature>node).questionToken, tokenVisitor, isToken));
case SyntaxKind.IndexSignature: case SyntaxKind.IndexSignature:
return updateIndexSignatureDeclaration(<IndexSignatureDeclaration>node, return updateIndexSignatureDeclaration(<IndexSignatureDeclaration>node,

View file

@ -100,7 +100,7 @@ namespace ts.codefix {
if (declarations.length === 1) { if (declarations.length === 1) {
Debug.assert(signatures.length === 1); Debug.assert(signatures.length === 1);
const signature = signatures[0]; const signature = signatures[0];
const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration) as MethodDeclaration; const signatureDeclaration = <MethodDeclaration>checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration);
signatureDeclaration.modifiers = modifiers; signatureDeclaration.modifiers = modifiers;
signatureDeclaration.name = name; signatureDeclaration.name = name;
signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined; signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined;
@ -111,7 +111,7 @@ namespace ts.codefix {
let signatureDeclarations = []; let signatureDeclarations = [];
for (let i = 0; i < signatures.length; i++) { for (let i = 0; i < signatures.length; i++) {
const signature = signatures[i]; const signature = signatures[i];
const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration) as MethodDeclaration; const signatureDeclaration = <MethodDeclaration>checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration);
signatureDeclaration.modifiers = modifiers; signatureDeclaration.modifiers = modifiers;
signatureDeclaration.name = name; signatureDeclaration.name = name;
signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined; signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined;
@ -120,7 +120,7 @@ namespace ts.codefix {
if (declarations.length > signatures.length) { if (declarations.length > signatures.length) {
let signature = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration); let signature = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration);
const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration) as MethodDeclaration; const signatureDeclaration = <MethodDeclaration>checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration);
signatureDeclaration.modifiers = modifiers; signatureDeclaration.modifiers = modifiers;
signatureDeclaration.name = name; signatureDeclaration.name = name;
signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined; signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined;
@ -197,7 +197,7 @@ namespace ts.codefix {
} }
export function createStubbedMethod(modifiers: Modifier[], name: PropertyName, optional: boolean, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], returnType: TypeNode | undefined) { export function createStubbedMethod(modifiers: Modifier[], name: PropertyName, optional: boolean, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], returnType: TypeNode | undefined) {
return createMethod( return createMethodDeclaration(
/*decorators*/ undefined, /*decorators*/ undefined,
modifiers, modifiers,
/*asteriskToken*/ undefined, /*asteriskToken*/ undefined,