diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ee999b3fe10..ea7c01b9735 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2211,7 +2211,10 @@ namespace ts { let inObjectTypeLiteral = false; let checkAlias = true; - return createTypeNodeWorker(type); + let result = createTypeNodeWorker(type); + (result).__type_source = type; + (result).__type_source_str = typeToString(type); + return result; function createTypeNodeWorker(type: Type): TypeNode { if (!type) { @@ -2221,12 +2224,6 @@ namespace ts { const typeString = typeToString(type); typeString; // TODO: remove. - if (checkAlias && type.aliasSymbol) { - const name = getNameOfSymbol(type.aliasSymbol); - const typeArguments = mapToTypeNodeArray(type.aliasTypeArguments); - return createTypeReferenceNode(createIdentifier(name), typeArguments); - } - checkAlias = false; if (type.flags & TypeFlags.Any) { // TODO: add other case where type ends up being `any`. @@ -2271,14 +2268,14 @@ namespace ts { if (type.flags & TypeFlags.ESSymbol) { throw new Error("ESSymbol not implemented"); } - if (type.flags & TypeFlags.TypeParameter) { - if ((type).isThisType) { - if (inObjectTypeLiteral) { - encounteredError = true; - } - return createThis(); + if (type.flags & TypeFlags.NonPrimitive) { + throw new Error("Non primitive not implemented"); + } + if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) { + if (inObjectTypeLiteral) { + encounteredError = true; } - throw new Error("Type Parameter declarations only handled in other worker."); + return createThis(); } const objectFlags = getObjectFlags(type); @@ -2291,64 +2288,35 @@ namespace ts { return createTypeReferenceNodeFromType(type); } + if (type.flags & TypeFlags.EnumLiteral) { + throw new Error("Enum literal not implemented"); + } + if (objectFlags & ObjectFlags.ClassOrInterface) { + Debug.assert(!!(type.flags & TypeFlags.Object)); + const name = getNameOfSymbol(type.symbol); + // TODO: handle type arguments. + // TODO: handle anonymous classes. + return createTypeReferenceNode(name, /*typeParameters*/undefined); + } + if (type.flags & TypeFlags.TypeParameter) { + throw new Error("Type Parameter declarations only handled in other worker."); + } + + // accessible type aliasSymbol + // TODO: move back up later on? + if (checkAlias && type.aliasSymbol) { + const name = getNameOfSymbol(type.aliasSymbol); + const typeArgumentNodes = mapToTypeNodeArray(type.aliasTypeArguments); + return createTypeReferenceNode(createIdentifier(name), typeArgumentNodes); + } + checkAlias = false; + if (type.flags & TypeFlags.Union) { return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, mapToTypeNodeArray((type as UnionType).types)); } if (type.flags & TypeFlags.Intersection) { return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, mapToTypeNodeArray((type as UnionType).types)); } - if (type.flags & TypeFlags.Index) { - throw new Error("index not implemented"); - } - if (type.flags & TypeFlags.IndexedAccess) { - throw new Error("indexed access not implemented"); - } - - if (objectFlags & ObjectFlags.ClassOrInterface) { - Debug.assert(!!(type.flags & TypeFlags.Object)); - const name = getNameOfSymbol(type.symbol); - // TODO: handle type arguments. - // TODO: handle anonymous classes. - return createTypeReferenceNode(name); - } - - // keyword types - // this type node - // function type node - // constructor type node - // type reference node - // type predicate node - is Foo (for return types) - // type query node -- typeof number - // type literal node (like object literal) - // array type - // tuple type - // union type - // might need parens - // intersection type - // Type operator node (eg (ie?): keyof T) - // IndexedAccess Type Node - // mapped type node - // literal type node - - // if (inTypeAlias && type.aliasSymbol) { - // return isSymbolAccessible(type.aliasSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/false).accessibility === SymbolAccessibility.Accessible - // && (!type.aliasTypeArguments || allTypesVisible(type.aliasTypeArguments)); - // } - // const typeSymbolAccessibility = type.symbol && isSymbolAccessible(type.symbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility; - // if (type.flags & TypeFlags.TypeParameter) { - // if (inObjectLiteral && (type as TypeParameter).isThisType) { - // return false; - // } - // const constraint = getConstraintFromTypeParameter((type)); - // return typeSymbolAccessibility === SymbolAccessibility.Accessible - // && (!constraint || isTypeAccessibleWorker(constraint, inObjectLiteral, /*inTypeAlias*/false)); - // } - // const objectFlags = getObjectFlags(type); - // if (objectFlags & ObjectFlags.ClassOrInterface) { - // // If type is a class or interface type that wasn't hit by the isSymbolAccessible check above, - // // type must be an anonymous class or interface. - // return false; - // } if (objectFlags & ObjectFlags.Mapped) { Debug.assert(!!(type.flags & TypeFlags.Object)); @@ -2370,6 +2338,15 @@ namespace ts { return createTypeLiteralNodeFromType(type); } + // TODO: string or number literal here or above? + + if (type.flags & TypeFlags.Index) { + throw new Error("index not implemented"); + } + if (type.flags & TypeFlags.IndexedAccess) { + throw new Error("indexed access not implemented"); + } + Debug.fail("Should be unreachable."); /** Note that mapToTypeNodeArray(undefined) === undefined. */ @@ -2476,7 +2453,8 @@ namespace ts { typeElements.push(createPropertySignature( createIdentifier(memberName) , optional ? createToken(SyntaxKind.QuestionToken) : undefined - , createTypeNode(typeOfOldMember))); + , createTypeNode(typeOfOldMember) + , /*initializer*/undefined)); break; case SyntaxKind.MethodSignature: case SyntaxKind.CallSignature: diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 14af23e95b5..7eb44f93bc5 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -248,30 +248,30 @@ namespace ts { : node; } - // TODO: handle qualified names, ie EntityName's. - export function createTypeReferenceNode(typeName: string | EntityName, typeArguments?: NodeArray) { + export function createTypeReferenceNode(typeName: string | EntityName, typeArguments: NodeArray | undefined) { const typeReference = createSynthesizedNode(SyntaxKind.TypeReference) as TypeReferenceNode; - + typeReference.typeName = isQualifiedName(typeName) ? typeName : asName(typeName); typeReference.typeArguments = typeArguments; return typeReference; } + export function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray | undefined) { + return node.typeName !== typeName + || node.typeArguments !== typeArguments + ? updateNode(createTypeReferenceNode(typeName, typeArguments), node) + : node; + } + export function createArrayTypeNode(elementType: TypeNode): ArrayTypeNode { const arrayTypeNode = createSynthesizedNode(SyntaxKind.ArrayType) as ArrayTypeNode; arrayTypeNode.elementType = elementType; return arrayTypeNode; } - + export function updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode { return node.elementType !== elementType - ? updateNode(createArrayTypeNode(elementType), node) - : node; - } - export function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments?: NodeArray) { - return node.typeName !== typeName - || node.typeArguments !== typeArguments - ? updateNode(createTypeReferenceNode(typeName, typeArguments), node) + ? updateNode(createArrayTypeNode(elementType), node) : node; } @@ -316,7 +316,7 @@ namespace ts { // Type Declarations - export function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultParameter?: TypeNode) { + export function createTypeParameterDeclaration(name: string | Identifier, constraint: TypeNode | undefined, defaultParameter: TypeNode | undefined) { const typeParameter = createSynthesizedNode(SyntaxKind.TypeParameter) as TypeParameterDeclaration; typeParameter.name = asName(name); typeParameter.constraint = constraint; @@ -325,7 +325,7 @@ namespace ts { return typeParameter; } - export function updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint?: TypeNode, defaultParameter?: TypeNode) { + export function updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultParameter: TypeNode | undefined) { return node.name !== name || node.constraint !== constraint || node.default !== defaultParameter @@ -335,7 +335,7 @@ namespace ts { // Signature elements - export function createPropertySignature(name: PropertyName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression): PropertySignature { + export function createPropertySignature(name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertySignature { const propertySignature = createSynthesizedNode(SyntaxKind.PropertySignature) as PropertySignature; propertySignature.name = name; propertySignature.questionToken = questionToken; @@ -344,7 +344,7 @@ namespace ts { return propertySignature; } - export function updatePropertySignature(node: PropertySignature, name: PropertyName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression) { + export function updatePropertySignature(node: PropertySignature, name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) { return node.name !== name || node.questionToken !== questionToken || node.type !== type @@ -353,18 +353,7 @@ namespace ts { : node; } - export function createSignature(kind: SyntaxKind, parameters: NodeArray, name?: PropertyName, typeParameters?: NodeArray, returnType?: TypeNode): SignatureDeclaration { - const signature = createSynthesizedNode(kind) as SignatureDeclaration; - signature.parameters = parameters; - signature.name = name; - signature.typeParameters = typeParameters; - signature.type = returnType; - return signature; - } - - // TODO: check usage of name... - // TODO: create entry in visitor.ts - export function createIndexSignatureDeclaration(parameters: ParameterDeclaration[], type: TypeNode, decorators?: Decorator[], modifiers?: Modifier[]): IndexSignatureDeclaration { + export function createIndexSignatureDeclaration(parameters: ParameterDeclaration[], type: TypeNode, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined): IndexSignatureDeclaration { const indexSignature = createSynthesizedNode(SyntaxKind.IndexSignature) as IndexSignatureDeclaration; // indexSignature.name = asName(name); // type parameters @@ -375,7 +364,7 @@ namespace ts { return indexSignature; } - export function updateIndexSignatureDeclaration(node: IndexSignatureDeclaration, parameters: ParameterDeclaration[], type: TypeNode, decorators?: Decorator[], modifiers?: Modifier[]) { + export function updateIndexSignatureDeclaration(node: IndexSignatureDeclaration, parameters: ParameterDeclaration[], type: TypeNode, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined) { return node.parameters !== parameters || node.type !== type || node.decorators !== decorators diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 547178e3b7f..3b75e072a57 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -302,8 +302,8 @@ namespace ts { case SyntaxKind.TypeReference: return updateTypeReferenceNode(node , visitNode((node).typeName, visitor, isEntityName) - , nodesVisitor((node).typeArguments, visitor, isTypeNode) - ); + , nodesVisitor((node).typeArguments, visitor, isTypeNode)); + case SyntaxKind.FunctionType: throw new Error("reached unsupported type in visitor."); case SyntaxKind.ConstructorType: @@ -347,7 +347,8 @@ namespace ts { return updatePropertySignature((node) , visitNode((node).name, visitor, isPropertyName) , visitNode((node).questionToken, visitor, isToken) - , visitNode((node).type, visitor, isTypeNode)); + , visitNode((node).type, visitor, isTypeNode) + , visitNode((node).initializer, visitor, isExpression)); case SyntaxKind.IndexSignature: return updateIndexSignatureDeclaration(node diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index fe12249f176..2403c0adbe0 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -62,7 +62,11 @@ namespace ts.codefix { , "x" , /*questionToken*/ undefined , stringTypeNode); - const indexSignature = createIndexSignatureDeclaration([indexingParameter], typeNode); + const indexSignature = createIndexSignatureDeclaration( + [indexingParameter] + , typeNode + , /*decorators*/undefined + , /*modifiers*/ undefined); const indexSignatureChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); indexSignatureChangeTracker.insertNodeAfter(sourceFile, openBrace, indexSignature, { insertTrailingNewLine: true }); diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts index f653d21e02b..220cea55d6f 100644 --- a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts +++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts @@ -62,7 +62,9 @@ namespace ts.codefix { , getNameFromIndexInfo(indexInfoOfKind) , /*questionToken*/ undefined , kind === IndexKind.String ? createKeywordTypeNode(SyntaxKind.StringKeyword) : createKeywordTypeNode(SyntaxKind.NumberKeyword))] - , typeNode); + , typeNode + , /*decorators*/undefined + , /*modifiers*/ undefined); newNodes.push(newIndexSignatureDeclaration); } diff --git a/tests/cases/fourslash/codeFixClassExtendAbstractMethod.ts b/tests/cases/fourslash/codeFixClassExtendAbstractMethod.ts index b6b408cf5ff..7e51e2216dc 100644 --- a/tests/cases/fourslash/codeFixClassExtendAbstractMethod.ts +++ b/tests/cases/fourslash/codeFixClassExtendAbstractMethod.ts @@ -5,6 +5,7 @@ //// abstract f(a: number, b: string): this; //// abstract f(a: string, b: number): Function; //// abstract f(a: string): Function; +//// abstract foo(): number; //// } //// //// class C extends A {[| |]} @@ -17,4 +18,7 @@ verify.rangeAfterCodeFix(` f(a: any, b?: any) { throw new Error("Method not implemented."); } + foo(): number { + throw new Error("Method not implemented."); + } `); diff --git a/tests/cases/fourslash/codeFixClassExtendAbstractProperty.ts b/tests/cases/fourslash/codeFixClassExtendAbstractProperty.ts index 83f770b5553..701903d6770 100644 --- a/tests/cases/fourslash/codeFixClassExtendAbstractProperty.ts +++ b/tests/cases/fourslash/codeFixClassExtendAbstractProperty.ts @@ -4,7 +4,6 @@ //// abstract x: number; //// abstract y: this; //// abstract z: A; -//// abstract foo(): number; //// } //// //// class C extends A {[| |]} @@ -13,7 +12,4 @@ verify.rangeAfterCodeFix(` x: number; y: this; z: A; - foo(): number { - throw new Error("Method not implemented."); - } `);