diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts index 49298f9058053..535a03526367c 100644 --- a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts +++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts @@ -5,7 +5,6 @@ import { createMissingMemberNodes, getNoopSymbolTrackerWithResolver, registerCodeFix, - TypeConstructionContext, } from "../_namespaces/ts.codefix.js"; import { addToSeen, @@ -13,8 +12,10 @@ import { ClassElement, ClassLikeDeclaration, CodeFixAction, + CodeFixContextBase, createSymbolTable, Debug, + Diagnostic, Diagnostics, ExpressionWithTypeArguments, find, @@ -30,6 +31,7 @@ import { isConstructorDeclaration, mapDefined, ModifierFlags, + Node, SourceFile, Symbol, SymbolTable, @@ -76,7 +78,7 @@ function symbolPointsToNonPrivateMember(symbol: Symbol) { } function addMissingDeclarations( - context: TypeConstructionContext, + context: CodeFixContextBase, implementedTypeNode: ExpressionWithTypeArguments, sourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, @@ -90,6 +92,13 @@ function addMissingDeclarations( const implementedType = checker.getTypeAtLocation(implementedTypeNode) as InterfaceType; const implementedTypeSymbols = checker.getPropertiesOfType(implementedType); const nonPrivateAndNotExistedInHeritageClauseMembers = implementedTypeSymbols.filter(and(symbolPointsToNonPrivateMember, symbol => !maybeHeritageClauseSymbol.has(symbol.escapedName))); + const semanticDiagnostics = new Map(); + if ( + hasBlockingSemanticError(context, semanticDiagnostics, implementedTypeNode) || + nonPrivateAndNotExistedInHeritageClauseMembers.some(symbol => symbol.getDeclarations()?.some(declaration => hasBlockingSemanticError(context, semanticDiagnostics, declaration))) + ) { + return; + } const classType = checker.getTypeAtLocation(classDeclaration); const constructor = find(classDeclaration.members, m => isConstructorDeclaration(m)); @@ -123,6 +132,22 @@ function addMissingDeclarations( } } +function hasBlockingSemanticError(context: CodeFixContextBase, semanticDiagnostics: Map, node: Node): boolean { + const sourceFile = node.getSourceFile(); + let diagnostics = semanticDiagnostics.get(sourceFile); + if (!diagnostics) { + diagnostics = context.program.getSemanticDiagnostics(sourceFile, context.cancellationToken); + semanticDiagnostics.set(sourceFile, diagnostics); + } + return diagnostics.some(diagnostic => + diagnostic.start !== undefined && + diagnostic.length !== undefined && + !errorCodes.includes(diagnostic.code) && + diagnostic.start >= node.pos && + diagnostic.start + diagnostic.length <= node.end + ); +} + function getHeritageClauseSymbolTable(classDeclaration: ClassLikeDeclaration, checker: TypeChecker): SymbolTable { const heritageClauseNode = getEffectiveBaseTypeNode(classDeclaration); if (!heritageClauseNode) return createSymbolTable(); diff --git a/tests/cases/fourslash/codeFixClassImplementInterfaceTypeParamInstantiateError.ts b/tests/cases/fourslash/codeFixClassImplementInterfaceTypeParamInstantiateError.ts index dc816ae86551b..cdc05c06abf3b 100644 --- a/tests/cases/fourslash/codeFixClassImplementInterfaceTypeParamInstantiateError.ts +++ b/tests/cases/fourslash/codeFixClassImplementInterfaceTypeParamInstantiateError.ts @@ -8,5 +8,4 @@ // TODO: (arozga) Don't know how to instantiate in codeFix // if instantiation is invalid. -// Should be verify.codeFixAvailable([]); -verify.codeFixAvailable([{ description: "Implement interface 'I'" }]); +verify.codeFixAvailable([]); diff --git a/tests/cases/fourslash/codeFixClassImplementInterfaceUndeclaredSymbol.ts b/tests/cases/fourslash/codeFixClassImplementInterfaceUndeclaredSymbol.ts index c5bb11e1b40b6..94c5f7c70fe57 100644 --- a/tests/cases/fourslash/codeFixClassImplementInterfaceUndeclaredSymbol.ts +++ b/tests/cases/fourslash/codeFixClassImplementInterfaceUndeclaredSymbol.ts @@ -15,5 +15,4 @@ // Since we can't guess the programmer's intent here, we do nothing. // TODO: (aozgaa) Acknowledge other errors on class/implemented interface/extended abstract class. -// Should be verify.codeFixAvailable([]); -verify.codeFixAvailable([{ description: "Implement interface 'I'" }]); +verify.codeFixAvailable([]);