diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e004a0ca390..0be7f528941 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2192,16 +2192,13 @@ namespace ts { return result; } - function unwrapNodeBuilderResult(result: NodeBuilderResult, returnValueOnError: boolean): T | undefined { - return !result.error || returnValueOnError ? result.value : undefined; - } - function getNodeBuilder(): NodeBuilder { if (nodeBuilderCache) { return nodeBuilderCache; } let encounteredError = false; + nodeBuilderCache = { typeToTypeNode, indexInfoToIndexSignatureDeclaration, @@ -2210,21 +2207,40 @@ namespace ts { return nodeBuilderCache; - function typeToTypeNode(type: Type, enclosingDeclaration?: Node, emitNodeOnError?: boolean): NodeBuilderResult { - let toNodeEncounteredErrorCache = encounteredError; - encounteredError = false; + function typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode { + const helper = () => typeToTypeNodeHelper(type, enclosingDeclaration, flags); + 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(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 checkAlias = true; let symbolStack: Symbol[] = undefined; - const resultingNode = typeToTypeNodeWorker(type); - const result = encounteredError && !emitNodeOnError ? undefined : resultingNode; - encounteredError = toNodeEncounteredErrorCache; - return result; + return typeToTypeNodeWorker(type); - function typeToTypeNodeWorker(type: Type): NodeBuilderResult { + function typeToTypeNodeWorker(type: Type): TypeNode { if (!type) { encounteredError = true; + // TODO(aozgaa): should we return implict any (undefined) or explicit any (keywordtypenode)? return undefined; } @@ -2241,7 +2257,7 @@ namespace ts { return createKeywordTypeNode(SyntaxKind.BooleanKeyword); } 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); } if (type.flags & (TypeFlags.StringLiteral)) { @@ -2254,7 +2270,7 @@ namespace ts { return (type).intrinsicName === "true" ? createTrue() : createFalse(); } 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); } if (type.flags & TypeFlags.Void) { @@ -2277,7 +2293,7 @@ namespace ts { } if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { if (inObjectTypeLiteral) { - encounteredError = true; + encounteredError = encounteredError || !(flags & NodeBuilderFlags.allowThisInObjectLiteral); } return createThis(); } @@ -2286,22 +2302,22 @@ namespace ts { if (objectFlags & ObjectFlags.Reference) { Debug.assert(!!(type.flags & TypeFlags.Object)); - return typeReferenceToTypeReferenceNode(type); + return typeReferenceToTypeNode (type); } if (objectFlags & ObjectFlags.ClassOrInterface) { 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. return createTypeReferenceNode(name, /*typeArguments*/ undefined); } 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. return createTypeReferenceNode(name, /*typeArguments*/ undefined); } if (checkAlias && type.aliasSymbol) { - const name = symbolToName(type.aliasSymbol, enclosingDeclaration); + const name = symbolToName(type.aliasSymbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags); const typeArgumentNodes = mapToTypeNodeArray(type.aliasTypeArguments); return createTypeReferenceNode(name, typeArgumentNodes); } @@ -2335,15 +2351,16 @@ namespace ts { Debug.fail("Should be unreachable."); function mapToTypeNodeArray(types: Type[]): NodeArray { - return types && asNodeArray(types.map(typeToTypeNodeWorker) as TypeNode[]); + return types && asNodeArray(types.map(typeToTypeNodeWorker).filter(node => !!node)); } function createMappedTypeNodeFromType(type: MappedType) { Debug.assert(!!(type.flags & TypeFlags.Object)); const typeParameter = getTypeParameterFromMappedType(type); - const typeParameterNode = typeParameterToDeclaration(typeParameter, enclosingDeclaration); + const typeParameterNode = typeParameterToDeclaration(typeParameter, enclosingDeclaration, flags); - const templateTypeNode = typeToTypeNodeWorker(getTemplateTypeFromMappedType(type)); + const templateType = getTemplateTypeFromMappedType(type) + const templateTypeNode = templateType && typeToTypeNodeWorker(templateType); const readonlyToken = (type).declaration && (type).declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined; const questionToken = (type).declaration && (type).declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined; @@ -2364,7 +2381,7 @@ namespace ts { const typeAlias = getTypeAliasForTypeLiteral(type); if (typeAlias) { // 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); } else { @@ -2417,11 +2434,11 @@ namespace ts { if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { const signature = resolved.callSignatures[0]; - return signatureToSignatureDeclaration(signature, SyntaxKind.FunctionType, enclosingDeclaration, emitNodeOnError); + return signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType, enclosingDeclaration, flags); } if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { const signature = resolved.constructSignatures[0]; - return signatureToSignatureDeclaration(signature, SyntaxKind.ConstructorType, enclosingDeclaration, emitNodeOnError); + return signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType, enclosingDeclaration, flags); } } @@ -2435,12 +2452,12 @@ namespace ts { function createTypeQueryNodeFromType(type: Type) { const symbol = type.symbol; if (symbol) { - const entityName = symbolToName(symbol, enclosingDeclaration); + const entityName = symbolToName(symbol, enclosingDeclaration, /*expectsIdentifier*/ false, flags); return createTypeQueryNode(entityName); } } - function typeReferenceToTypeReferenceNode(type: TypeReference) { + function typeReferenceToTypeNode(type: TypeReference) { const typeArguments: Type[] = type.typeArguments || emptyArray; if (type.target === globalArrayType) { 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 // the default outer type arguments), we don't show the group. if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) { - const qualifiedNamePart = symbolToName(parent, enclosingDeclaration, /*mustBeIdentifier*/ true); + const qualifiedNamePart = symbolToName(parent, enclosingDeclaration, /*expectsIdentifier*/ true, flags); if (!qualifiedName) { qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined); } @@ -2478,7 +2495,7 @@ namespace ts { } } let entityName: EntityName = undefined; - const nameIdentifier = symbolToName(type.symbol, enclosingDeclaration, /*mustBeIdentifier*/ true); + const nameIdentifier = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ true, flags); if (qualifiedName) { Debug.assert(!qualifiedName.right); qualifiedName.right = nameIdentifier; @@ -2496,16 +2513,16 @@ namespace ts { function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] { const typeElements: TypeElement[] = []; for (const signature of resolvedType.callSignatures) { - typeElements.push(signatureToSignatureDeclaration(signature, SyntaxKind.CallSignature, enclosingDeclaration, emitNodeOnError)); + typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature, enclosingDeclaration, flags)); } for (const signature of resolvedType.constructSignatures) { - typeElements.push(signatureToSignatureDeclaration(signature, SyntaxKind.ConstructSignature, enclosingDeclaration, emitNodeOnError)); + typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature, enclosingDeclaration, flags)); } if (resolvedType.stringIndexInfo) { - typeElements.push(indexInfoToIndexSignatureDeclaration(resolvedType.stringIndexInfo, IndexKind.String, enclosingDeclaration, emitNodeOnError)); + typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.stringIndexInfo, IndexKind.String, enclosingDeclaration, flags)); } 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; @@ -2524,17 +2541,20 @@ namespace ts { if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) { const signatures = getSignaturesOfType(propertyType, SignatureKind.Call); for (const signature of signatures) { - const methodDeclaration = signatureToSignatureDeclaration(signature, SyntaxKind.MethodSignature, enclosingDeclaration, emitNodeOnError); + const methodDeclaration = signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, enclosingDeclaration, flags); methodDeclaration.name = propertyName; methodDeclaration.questionToken = optionalToken; typeElements.push(methodDeclaration); } } else { + + // TODO(aozgaa): should we create a node with explicit or implict any? + const propertyTypeNode = propertyType ? typeToTypeNodeWorker(propertyType) : createKeywordTypeNode(SyntaxKind.AnyKeyword); typeElements.push(createPropertySignature( propertyName, optionalToken, - typeToTypeNodeWorker(propertyType), + propertyTypeNode, /*initializer*/undefined)); } } @@ -2543,10 +2563,7 @@ namespace ts { } } - function indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node, emitNodeOnError?: boolean): IndexSignatureDeclaration { - const encounteredErrorCache = encounteredError; - encounteredError = false; - + function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node, flags: NodeBuilderFlags): IndexSignatureDeclaration { const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword); const name = getNameFromIndexInfo(indexInfo); @@ -2558,55 +2575,46 @@ namespace ts { /*questionToken*/ undefined, indexerTypeNode, /*initializer*/ undefined); - const typeNode = typeToTypeNode(indexInfo.type, enclosingDeclaration, emitNodeOnError); - const result = !encounteredError || emitNodeOnError ? createIndexSignatureDeclaration( + const typeNode = typeToTypeNodeHelper(indexInfo.type, enclosingDeclaration, flags); + return createIndexSignatureDeclaration( [indexingParameter], typeNode, /*decorators*/ undefined, - indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined) - : undefined; - encounteredError = encounteredErrorCache; - return result; + indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined); } - function signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, emitNodeOnError?: boolean): SignatureDeclaration { - const encounteredErrorCache = encounteredError; - encounteredError = false; + function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind, enclosingDeclaration: Node, flags: NodeBuilderFlags): SignatureDeclaration { - const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, enclosingDeclaration)); - const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter, enclosingDeclaration)); + const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, enclosingDeclaration, flags)); + const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter, enclosingDeclaration, flags)); const type = typeToTypeNodeExceptAny(getReturnTypeOfSignature(signature)); - const result = !encounteredError || emitNodeOnError ? createSignatureDeclaration(kind, typeParameters, parameters, type) : undefined; - encounteredError = encounteredErrorCache; - return result; + return createSignatureDeclaration(kind, typeParameters, parameters, type); 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; } } - 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)) { return undefined; } - const constraint = typeToTypeNode(getConstraintFromTypeParameter(type), enclosingDeclaration); - const defaultParameter = typeToTypeNode(getDefaultFromTypeParameter(type), enclosingDeclaration); - - let toNodeEncounteredErrorCache = encounteredError; - encounteredError = false; - const name = symbolToName(type.symbol, enclosingDeclaration, /*mustBeIdentifier*/ true); - let result = encounteredError && !returnNodeOnError ? undefined : createTypeParameterDeclaration(name, constraint, defaultParameter); - encounteredError = toNodeEncounteredErrorCache; - return result; + const constraint = getConstraintFromTypeParameter(type); + const constraintNode = constraint && typeToTypeNodeHelper(constraint, enclosingDeclaration, flags); + const defaultParameter = getDefaultFromTypeParameter(type); + const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter, enclosingDeclaration, flags); + const name = symbolToName(type.symbol, enclosingDeclaration, /*expectsIdentifier*/ true, flags); + return createTypeParameterDeclaration(name, constraintNode, defaultParameterNode); } - function symbolToParameterDeclaration(parameterSymbol: Symbol, enclosingDeclaration?: Node): ParameterDeclaration { + function symbolToParameterDeclaration(parameterSymbol: Symbol, enclosingDeclaration: Node, flags: NodeBuilderFlags): ParameterDeclaration { const parameterDeclaration = parameterSymbol.declarations[0] as ParameterDeclaration; const parameterType = getTypeOfSymbol(parameterSymbol); - const parameterTypeNode = typeToTypeNode(parameterType, enclosingDeclaration); + const parameterTypeNode = typeToTypeNodeHelper(parameterType, enclosingDeclaration, flags); // TODO(aozgaa): check initializer accessibility correctly. const parameterNode = createParameter( parameterDeclaration.decorators, @@ -2620,19 +2628,17 @@ namespace ts { return parameterNode; } - function symbolToName(symbol: Symbol, enclosingDeclaration: Node | undefined, mustBeIdentifier: true): Identifier; - function symbolToName(symbol: Symbol, enclosingDeclaration?: Node, mustBeIdentifier?: false): EntityName; - function symbolToName(symbol: Symbol, enclosingDeclaration: Node | undefined, mustBeIdentifier: boolean | undefined): EntityName { + function symbolToName(symbol: Symbol, enclosingDeclaration: Node | undefined, expectsIdentifier: true, flags: NodeBuilderFlags): Identifier; + function symbolToName(symbol: Symbol, enclosingDeclaration: Node | undefined, expectsIdentifier: false, flags: NodeBuilderFlags): EntityName; + function symbolToName(symbol: Symbol, enclosingDeclaration: Node | undefined, expectsIdentifier: boolean, flags: NodeBuilderFlags): EntityName { let parentSymbol: Symbol; let meaning: SymbolFlags; - // 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[]; const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter; if (!isTypeParameter && enclosingDeclaration) { 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); } else { @@ -2640,10 +2646,9 @@ namespace ts { } parentSymbol = undefined; - if (mustBeIdentifier && chain.length !== 1) { - encounteredError = true; - // TODO: failing to get an identifier when we expect one generates an unprintable node. - // Should error handling be more severe? + + if (expectsIdentifier && chain.length !== 1) { + encounteredError = encounteredError || !(flags & NodeBuilderFlags.allowQualifedNameInPlaceOfIdentifier); } return createEntityNameFromSymbolChain(chain, chain.length - 1); @@ -2653,7 +2658,7 @@ namespace ts { const symbol = chain[index]; let typeParameterString = ""; if (index > 0) { - // TODO: is the parentSymbol wrong? + const parentSymbol = chain[index - 1]; let typeParameters: TypeParameter[]; if (getCheckFlags(symbol) & CheckFlags.Instantiated) { @@ -2666,7 +2671,8 @@ namespace ts { } } if (typeParameters && typeParameters.length > 0) { - encounteredError = true; + encounteredError = encounteredError || !(flags & NodeBuilderFlags.allowTypeParameterInQualifiedName);; + const writer = getSingleLineStringWriter(); const displayBuilder = getSymbolDisplayBuilder(); displayBuilder.buildDisplayForTypeParametersAndDelimiters(typeParameters, writer, enclosingDeclaration, 0); @@ -2724,7 +2730,7 @@ namespace ts { if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) { return declarationNameToString((declaration.parent).name); } - encounteredError = true; + encounteredError = encounteredError || !(flags & NodeBuilderFlags.allowAnonymousIdentifier); switch (declaration.kind) { case SyntaxKind.ClassExpression: return "(Anonymous class)"; diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 0ae42459709..0d2dee8cfdc 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -378,28 +378,65 @@ namespace ts { } // TODO: Split according to AST nodes. - export function createSignatureDeclaration(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined): T; - export function createSignatureDeclaration(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined): T; - export function createSignatureDeclaration(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, name?: string | PropertyName, questionToken?: QuestionToken): T { - const signatureDeclaration = createSynthesizedNode(kind) as T; + export function createSignatureDeclaration(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined) { + const signatureDeclaration = createSynthesizedNode(kind) as SignatureDeclaration; signatureDeclaration.typeParameters = asNodeArray(typeParameters); signatureDeclaration.parameters = asNodeArray(parameters); signatureDeclaration.type = type; - signatureDeclaration.name = asName(name); - signatureDeclaration.questionToken = questionToken; return signatureDeclaration; } - // TODO: figure out right type annotation for this function. - export function updateSignatureDeclaration(node: T, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined): T; - export function updateSignatureDeclaration(node: T, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined, name: PropertyName, questionToken: QuestionToken | undefined): T; - export function updateSignatureDeclaration(node: T, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined, name?: PropertyName, questionToken?: QuestionToken): T { + export function updateSignatureDeclaration(node: SignatureDeclaration, typeParameters: NodeArray | undefined, parameters: NodeArray, type: TypeNode | undefined) { + return node.typeParameters !== typeParameters + || node.parameters !== parameters + || 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 | undefined, parameters: NodeArray, type: TypeNode | undefined): FunctionTypeNode { + return 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 | undefined, parameters: NodeArray, type: TypeNode | undefined): ConstructorTypeNode { + return 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 | undefined, parameters: NodeArray, type: TypeNode | undefined): CallSignatureDeclaration { + return 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 | undefined, parameters: NodeArray, type: TypeNode | undefined): ConstructSignatureDeclaration { + return 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 | undefined, parameters: NodeArray, type: TypeNode | undefined, name?: PropertyName, questionToken?: QuestionToken): MethodSignature { return node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type || node.name !== name || node.questionToken !== questionToken - ? updateNode(createSignatureDeclaration(node.kind, typeParameters, parameters, type, name, questionToken), node) + ? updateNode(createMethodSignature(typeParameters, parameters, type, name, questionToken), node) : node; } @@ -502,7 +539,7 @@ namespace ts { : 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 = createSynthesizedNode(SyntaxKind.MethodDeclaration); node.decorators = asNodeArray(decorators); node.modifiers = asNodeArray(modifiers); @@ -525,7 +562,7 @@ namespace ts { || node.parameters !== parameters || node.type !== type || 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; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 288d0942b78..f07338503e0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2473,11 +2473,12 @@ namespace ts { getNonNullableType(type: Type): Type; /** 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. */ - 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. */ - 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[]; getSymbolAtLocation(node: Node): Symbol; @@ -2530,18 +2531,20 @@ namespace ts { /* @internal */ getTypeCount(): number; } - /** Note that the resulting nodes cannot be checked. */ + /** Note that any resulting nodes cannot be checked. */ /* @internal */ export interface NodeBuilder { - typeToTypeNode(type: Type, enclosingDeclaration?: Node, returnNodeOnError?: boolean): NodeBuilderResult; - signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node): NodeBuilderResult; - indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node): NodeBuilderResult; + typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode; + signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration; + indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration; } - /* @internal */ - export interface NodeBuilderResult { - value: T; - error?: boolean; + export enum NodeBuilderFlags { + None = 0, + allowThisInObjectLiteral = 1 << 0, + allowQualifedNameInPlaceOfIdentifier = 1 << 1, + allowTypeParameterInQualifiedName = 1 << 2, + allowAnonymousIdentifier = 1 << 3 } export interface SymbolDisplayBuilder { diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 57de104b0ca..e6df9c211e7 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -260,21 +260,36 @@ namespace ts { // Signatures and Signature Elements case SyntaxKind.FunctionType: + return updateFunctionTypeNode(node, + nodesVisitor((node).typeParameters, visitor, isTypeParameter), + visitParameterList((node).parameters, visitor, context, nodesVisitor), + visitNode((node).type, visitor, isTypeNode)); + case SyntaxKind.ConstructorType: + return updateConstructorTypeNode(node, + nodesVisitor((node).typeParameters, visitor, isTypeParameter), + visitParameterList((node).parameters, visitor, context, nodesVisitor), + visitNode((node).type, visitor, isTypeNode)); + case SyntaxKind.CallSignature: + return updateCallSignatureDeclaration(node, + nodesVisitor((node).typeParameters, visitor, isTypeParameter), + visitParameterList((node).parameters, visitor, context, nodesVisitor), + visitNode((node).type, visitor, isTypeNode)); + case SyntaxKind.ConstructSignature: - return updateSignatureDeclaration(node, - nodesVisitor((node).typeParameters, visitor, isTypeParameter), - visitParameterList((node).parameters, visitor, context, nodesVisitor), - visitNode((node).type, visitor, isTypeNode)); + return updateConstructSignatureDeclaration(node, + nodesVisitor((node).typeParameters, visitor, isTypeParameter), + visitParameterList((node).parameters, visitor, context, nodesVisitor), + visitNode((node).type, visitor, isTypeNode)); case SyntaxKind.MethodSignature: - return updateSignatureDeclaration(node, - nodesVisitor((node).typeParameters, visitor, isTypeParameter), - visitParameterList((node).parameters, visitor, context, nodesVisitor), - visitNode((node).type, visitor, isTypeNode), - visitNode((node).name, visitor, isPropertyName), - visitNode((node).questionToken, tokenVisitor, isToken)); + return updateMethodSignature(node, + nodesVisitor((node).typeParameters, visitor, isTypeParameter), + visitParameterList((node).parameters, visitor, context, nodesVisitor), + visitNode((node).type, visitor, isTypeNode), + visitNode((node).name, visitor, isPropertyName), + visitNode((node).questionToken, tokenVisitor, isToken)); case SyntaxKind.IndexSignature: return updateIndexSignatureDeclaration(node, diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index da729215087..0000bd97c56 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -100,7 +100,7 @@ namespace ts.codefix { if (declarations.length === 1) { Debug.assert(signatures.length === 1); const signature = signatures[0]; - const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration) as MethodDeclaration; + const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration); signatureDeclaration.modifiers = modifiers; signatureDeclaration.name = name; signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined; @@ -111,7 +111,7 @@ namespace ts.codefix { let signatureDeclarations = []; for (let i = 0; i < signatures.length; i++) { const signature = signatures[i]; - const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration) as MethodDeclaration; + const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration); signatureDeclaration.modifiers = modifiers; signatureDeclaration.name = name; signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined; @@ -120,7 +120,7 @@ namespace ts.codefix { if (declarations.length > signatures.length) { let signature = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration); - const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration) as MethodDeclaration; + const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration); signatureDeclaration.modifiers = modifiers; signatureDeclaration.name = name; 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) { - return createMethod( + return createMethodDeclaration( /*decorators*/ undefined, modifiers, /*asteriskToken*/ undefined,