diff --git a/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts b/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts
index 692eeedbdb6..307939785be 100644
--- a/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts
+++ b/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts
@@ -6,43 +6,36 @@ namespace ts.codefix {
const sourceFile = context.sourceFile;
const start = context.span.start;
const token = getTokenAtPosition(sourceFile, start);
-
- if (!(token.kind === SyntaxKind.Identifier && token.parent.parent.parent.kind === SyntaxKind.ClassDeclaration)) {
+ const classDeclNode = getAncestor(token, SyntaxKind.ClassDeclaration) as ClassDeclaration;
+ if (!(token.kind === SyntaxKind.Identifier && classDeclNode && classDeclNode.kind === SyntaxKind.ClassDeclaration)) {
return undefined;
}
- const extendsNode = (token.parent.parent as HeritageClause).getChildren()[0];
+ const heritageClauses = classDeclNode.heritageClauses;
+ if (!(heritageClauses && heritageClauses.length > 0)) {
+ return undefined;
+ }
+
+ const extendsToken = heritageClauses[0].getFirstToken();
+ if (!(extendsToken && extendsToken.kind === SyntaxKind.ExtendsKeyword)) {
+ return undefined;
+ }
const result = [{
description: getLocaleSpecificMessage(Diagnostics.Change_extends_to_implements),
changes: [{
fileName: sourceFile.fileName,
- textChanges: [{ newText: " implements", span: { start: extendsNode.pos, length: extendsNode.end - extendsNode.pos } }]
+ textChanges: [{ newText: " implements", span: { start: extendsToken.pos, length: extendsToken.end - extendsToken.pos } }]
}]
}];
// We check if the implements keyword is present and replace it with a comma if so.
- const classDeclNode = getAncestor(token, SyntaxKind.ClassDeclaration);
- if (!classDeclNode) {
- return result;
+ for (let i = 1; i < heritageClauses.length; i++) {
+ const keywordToken = heritageClauses[i].getFirstToken();
+ if (keywordToken) {
+ result[0].changes[0].textChanges.push({ newText: ",", span: { start: keywordToken.pos, length: keywordToken.end - keywordToken.pos } });
+ }
}
- const classDeclChildren = classDeclNode.getChildren();
- if (classDeclChildren.length < 3) {
- return result;
- }
-
- let classSyntaxListChildren: Node[];
- if (classDeclChildren[2].kind !== SyntaxKind.SyntaxList || (classSyntaxListChildren = classDeclChildren[2].getChildren()).length < 2) {
- return result;
- }
-
- let implementsTokenChildren: Node[];
- if ((classSyntaxListChildren[1] as HeritageClause).token !== SyntaxKind.ImplementsKeyword || (implementsTokenChildren = classSyntaxListChildren[1].getChildren()).length === 0) {
- return result;
- }
-
- const implementsNode = implementsTokenChildren[0];
- result[0].changes[0].textChanges.push({ newText: ",", span: { start: implementsNode.pos, length: implementsNode.end - implementsNode.pos } });
return result;
}
diff --git a/tests/cases/fourslash/codeFixChangeExtendsToImplementsAbstractModifier.ts b/tests/cases/fourslash/codeFixChangeExtendsToImplementsAbstractModifier.ts
new file mode 100644
index 00000000000..5f5ca93c28f
--- /dev/null
+++ b/tests/cases/fourslash/codeFixChangeExtendsToImplementsAbstractModifier.ts
@@ -0,0 +1,8 @@
+///
+
+//// interface I1 { }
+//// interface I2 { }
+
+//// [|abstract class A extends I1 implements I2|] { }
+
+verify.rangeAfterCodeFix("abstract class A implements I1, I2");
\ No newline at end of file
diff --git a/tests/cases/fourslash/codeFixChangeExtendsToImplementsWithDecorator.ts b/tests/cases/fourslash/codeFixChangeExtendsToImplementsWithDecorator.ts
new file mode 100644
index 00000000000..9671f41def3
--- /dev/null
+++ b/tests/cases/fourslash/codeFixChangeExtendsToImplementsWithDecorator.ts
@@ -0,0 +1,13 @@
+///
+
+//// interface I1 { }
+//// interface I2 { }
+
+//// function sealed(constructor: Function) {
+//// Object.seal(constructor);
+//// Object.seal(constructor.prototype);
+//// }
+
+//// @sealed
+//// [|class A extends I1 implements I2 { }|]
+verify.rangeAfterCodeFix("class A implements I1, I2 { }");
\ No newline at end of file