From f9a55beec57663c99c88faf24271f2c4ec240483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=96=87=E7=92=90?= Date: Mon, 28 May 2018 18:38:07 +0800 Subject: [PATCH] add lookup for extends class when implement interface --- src/services/codefixes/helpers.ts | 13 ++++++- ...nterfaceHeritageClauseAlreadyHaveMember.ts | 39 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/codeFixClassImplementInterfaceHeritageClauseAlreadyHaveMember.ts diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 5d033a82cb3..a22f8dfbcc6 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -7,14 +7,25 @@ namespace ts.codefix { * @returns Empty string iff there are no member insertions. */ export function createMissingMemberNodes(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: ReadonlyArray, checker: TypeChecker, preferences: UserPreferences, out: (node: ClassElement) => void): void { + const heritageClauseSymbolTable = getHeritageClauseSymbolTable(classDeclaration, checker); + const classMembers = classDeclaration.symbol.members!; for (const symbol of possiblyMissingSymbols) { - if (!classMembers.has(symbol.escapedName)) { + if (!classMembers.has(symbol.escapedName) && !(heritageClauseSymbolTable && heritageClauseSymbolTable.has(symbol.escapedName))) { addNewNodeForMemberSymbol(symbol, classDeclaration, checker, preferences, out); } } } + function getHeritageClauseSymbolTable (classDeclaration: ClassLikeDeclaration, checker: TypeChecker): SymbolTable | undefined { + const heritageClauseNode = getClassExtendsHeritageClauseElement(classDeclaration); + if (!heritageClauseNode) return undefined; + const heritageClauseType = checker.getTypeAtLocation(heritageClauseNode) as InterfaceType; + const heritageClauseTypeSymbols = checker.getPropertiesOfType(heritageClauseType); + const nonPrivateMembers = heritageClauseTypeSymbols.filter(symbol => !(getModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private)); + return createSymbolTable(nonPrivateMembers); + } + /** * @returns Empty string iff there we can't figure out a representation for `symbol` in `enclosingDeclaration`. */ diff --git a/tests/cases/fourslash/codeFixClassImplementInterfaceHeritageClauseAlreadyHaveMember.ts b/tests/cases/fourslash/codeFixClassImplementInterfaceHeritageClauseAlreadyHaveMember.ts new file mode 100644 index 00000000000..b67bd966f9e --- /dev/null +++ b/tests/cases/fourslash/codeFixClassImplementInterfaceHeritageClauseAlreadyHaveMember.ts @@ -0,0 +1,39 @@ +/// + +//// class Base { +//// foo: number; +//// } +//// +//// class D extends Base { +//// bar: number; +//// } +//// +//// interface I { +//// foo: number; +//// bar: number; +//// baz: number; +//// } +//// +//// class C extends D implements I { } + +verify.codeFix({ + description: "Implement interface 'I'", + newFileContent: +`class Base { + foo: number; +} + +class D extends Base { + bar: number; +} + +interface I { + foo: number; + bar: number; + baz: number; +} + +class C extends D implements I { + baz: number; +}`, +});