diff --git a/Jakefile.js b/Jakefile.js index 95027e07ed3..0ed65abf263 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -176,6 +176,9 @@ var servicesSources = [ "codefixes/fixClassDoesntImplementInheritedAbstractMember.ts", "codefixes/fixClassSuperMustPrecedeThisAccess.ts", "codefixes/fixConstructorForDerivedNeedSuperCall.ts", + "codefixes/helpers.ts", + "codefixes/importFixes.ts", + "codefixes/unusedIdentifierFixes.ts" ].map(function (f) { return path.join(servicesDirectory, f); })); diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 41167058578..6b83cf249a7 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -74,13 +74,18 @@ "../services/formatting/rulesProvider.ts", "../services/formatting/smartIndenter.ts", "../services/formatting/tokenRange.ts", - "../services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts", - "../services/codefixes/fixClassIncorrectlyImplementsInterface.ts", - "../services/codefixes/fixClassSuperMustPrecedeThisAccess.ts", - "../services/codefixes/fixConstructorForDerivedNeedSuperCall.ts", + "../services/codeFixProvider.ts", "../services/codefixes/fixes.ts", "../services/codefixes/fixExtendsInterfaceBecomesImplements.ts", - "harness.ts", + "../services/codefixes/fixClassIncorrectlyImplementsInterface.ts", + "../services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts", + "../services/codefixes/fixClassSuperMustPrecedeThisAccess.ts", + "../services/codefixes/fixConstructorForDerivedNeedSuperCall.ts", + "../services/codefixes/helpers.ts", + "../services/codefixes/importFixes.ts", + "../services/codefixes/unusedIdentifierFixes.ts", + "../services/harness.ts", + "sourceMapRecorder.ts", "harnessLanguageService.ts", "fourslash.ts", diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts index da6dcde16c3..10d6fa50158 100644 --- a/src/services/codefixes/fixes.ts +++ b/src/services/codefixes/fixes.ts @@ -5,4 +5,5 @@ /// /// /// +/// diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts new file mode 100644 index 00000000000..5ad99e7b389 --- /dev/null +++ b/src/services/codefixes/helpers.ts @@ -0,0 +1,65 @@ +/* @internal */ +namespace ts.codefix { + + /** + * Finds members of the resolved type that are missing in the class pointed to by class decl + * and generates source code for the missing members. + * @param possiblyMissingSymbols The collection of symbols to filter and then get insertions for. + * @returns undefined iff there is no insertion available. + */ + export function getMissingMembersInsertion(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: Symbol[], checker: TypeChecker, newlineChar: string): string { + const classMembers = classDeclaration.symbol.members; + const missingMembers = possiblyMissingSymbols.filter(symbol => !(symbol.getName() in classMembers)); + + let insertion = ""; + + for (const symbol of missingMembers) { + insertion = insertion.concat(getInsertionForMemberSymbol(symbol, classDeclaration, checker, newlineChar)); + } + return insertion.length > 0 ? insertion : undefined; + } + + function getInsertionForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker, newlineChar: string): string { + const name = symbol.getName(); + const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration); + const declarations = symbol.getDeclarations(); + if (!(declarations && declarations.length)) { + return ""; + } + const node = declarations[0]; + const visibility = getVisibilityPrefix(getModifierFlags(node)); + switch (node.kind) { + case SyntaxKind.PropertySignature: + case SyntaxKind.PropertyDeclaration: + const typeString = checker.typeToString(type, enclosingDeclaration, TypeFormatFlags.None); + return `${visibility}${name}: ${typeString};${newlineChar}`; + + case SyntaxKind.MethodSignature: + case SyntaxKind.MethodDeclaration: + const signatures = checker.getSignaturesOfType(type, SignatureKind.Call); + if (!(signatures && signatures.length > 0)) { + return ""; + } + // TODO: (arozga) Deal with multiple signatures. + const sigString = checker.signatureToString(signatures[0], enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call); + + return `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`; + default: + return ""; + } + } + + function getMethodBodyStub(newLineChar: string) { + return `{${newLineChar}throw new Error('Method not Implemented');${newLineChar}}${newLineChar}`; + } + + function getVisibilityPrefix(flags: ModifierFlags): string { + if (flags & ModifierFlags.Public) { + return "public "; + } + else if (flags & ModifierFlags.Protected) { + return "protected "; + } + return ""; + } +} \ No newline at end of file diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 9966c83f4cd..921ee7762f8 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -88,11 +88,14 @@ "formatting/smartIndenter.ts", "formatting/tokenRange.ts", "codeFixProvider.ts", - "codeFixes/fixes.ts", - "codeFixes/fixExtendsInterfaceBecomesImplements.ts", - "codeFixes/fixClassIncorrectlyImplementsInterface.ts", - "codeFixes/fixClassDoesntImplementInheritedAbstractMember.ts", - "codeFixes/fixClassSuperMustPrecedeThisAccess.ts", - "codeFixes/fixConstructorForDerivedNeedSuperCall.ts" + "codefixes/fixExtendsInterfaceBecomesImplements.ts", + "codefixes/fixClassIncorrectlyImplementsInterface.ts", + "codefixes/fixClassDoesntImplementInheritedAbstractMember.ts", + "codefixes/fixClassSuperMustPrecedeThisAccess.ts", + "codefixes/fixConstructorForDerivedNeedSuperCall.ts", + "codefixes/fixes.ts", + "codefixes/helpers.ts", + "codefixes/importFixes.ts", + "codefixes/unusedIdentifierFixes.ts" ] -} +} \ No newline at end of file diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 947222cba3c..7542fd86dac 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1359,68 +1359,6 @@ namespace ts { }; } - /** - * Finds members of the resolved type that are missing in the class pointed to by class decl - * and generates source code for the missing members. - * @param possiblyMissingSymbols The collection of symbols to filter and then get insertions for. - * @returns undefined iff there is no insertion available. - */ - export function getMissingMembersInsertion(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: Symbol[], checker: TypeChecker, newlineChar: string): string { - const classMembers = classDeclaration.symbol.members; - const missingMembers = possiblyMissingSymbols.filter(symbol => !(symbol.getName() in classMembers)); - - let insertion = ""; - - for (const symbol of missingMembers) { - insertion = insertion.concat(getInsertionForMemberSymbol(symbol, classDeclaration, checker, newlineChar)); - } - return insertion.length > 0 ? insertion : undefined; - } - - function getInsertionForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker, newlineChar: string): string { - const name = symbol.getName(); - const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration); - const declarations = symbol.getDeclarations(); - if (!(declarations && declarations.length)) { - return ""; - } - const node = declarations[0]; - const visibility = getVisibilityPrefix(getModifierFlags(node)); - switch (node.kind) { - case SyntaxKind.PropertySignature: - case SyntaxKind.PropertyDeclaration: - const typeString = checker.typeToString(type, enclosingDeclaration, TypeFormatFlags.None); - return `${visibility}${name}: ${typeString};${newlineChar}`; - - case SyntaxKind.MethodSignature: - case SyntaxKind.MethodDeclaration: - const signatures = checker.getSignaturesOfType(type, SignatureKind.Call); - if (!(signatures && signatures.length > 0)) { - return ""; - } - // TODO: (arozga) Deal with multiple signatures. - const sigString = checker.signatureToString(signatures[0], enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call); - - return `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`; - default: - return ""; - } - } - - function getMethodBodyStub(newLineChar: string) { - return `{${newLineChar}throw new Error('Method not Implemented');${newLineChar}}${newLineChar}`; - } - - function getVisibilityPrefix(flags: ModifierFlags): string { - if (flags & ModifierFlags.Public) { - return "public "; - } - else if (flags & ModifierFlags.Protected) { - return "protected "; - } - return ""; - } - export function getOpenBraceEnd(constructor: ConstructorDeclaration, sourceFile: SourceFile) { // First token is the open curly, this is where we want to put the 'super' call. return constructor.body.getFirstToken(sourceFile).getEnd();