From 9897c6949256a6281326b87746d4933a437dad12 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Mon, 13 Feb 2017 11:18:56 -0800 Subject: [PATCH] wip --- src/services/codefixes/fixAddMissingMember.ts | 74 +++++++++++++++++++ src/services/codefixes/fixes.ts | 1 + src/services/codefixes/helpers.ts | 12 ++- ...codeFixUndeclaredPropertyNumericLiteral.ts | 17 +++++ 4 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 src/services/codefixes/fixAddMissingMember.ts create mode 100644 tests/cases/fourslash/codeFixUndeclaredPropertyNumericLiteral.ts diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts new file mode 100644 index 00000000000..c51c63bdc27 --- /dev/null +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -0,0 +1,74 @@ +/* @internal */ +namespace ts.codefix { + registerCodeFix({ + errorCodes: [Diagnostics.Property_0_does_not_exist_on_type_1.code], + getCodeActions: getActionsForAddMissingMember + }); + + function getActionsForAddMissingMember(context: CodeFixContext): CodeAction[] | undefined { + + const sourceFile = context.sourceFile; + const start = context.span.start; + // This is the identifier in the case of a class declaration + // or the class keyword token in the case of a class expression. + const token = getTokenAtPosition(sourceFile, start); + const checker = context.program.getTypeChecker(); + + if(!(token.parent && token.parent.kind === SyntaxKind.PropertyAccessExpression)) { + return undefined; + } + + if((token.parent as PropertyAccessExpression).expression.kind !== SyntaxKind.ThisKeyword) { + return undefined; + } + 1 + 1; + + let typeString: string = 'any'; + // if binary expression, try to infer type for LHS, else use any + if(token.parent.parent.kind === SyntaxKind.BinaryExpression) + { + const binaryExpression = token.parent.parent as BinaryExpression; + binaryExpression.operatorToken; + + const type = checker.getTypeAtLocation(binaryExpression.right); + typeString = checker.typeToString(type); + } + + const classDeclaration = getContainingClass(token); + const startPos = classDeclaration.members.pos; + return [{ + description: getLocaleSpecificMessage(Diagnostics.Implement_inherited_abstract_class), + changes: [{ + fileName: sourceFile.fileName, + textChanges: [{ + span: { start: startPos, length: 0 }, + newText: `${token.getFullText(sourceFile)}: ${typeString};` + }] + }] + }]; + } + + + + + // x needs to be a `this` construct. ie + // this.. + // Want to infer type of x when possible. ie: + // * assignment, + // * function call argument: foo(this.x) where foo(x: SomeType) + // * expression with a type assertion: this.x as MyFavoriteType + // * access expression: this.x.push("asdf") ... probably an array? + // * + // What if there are multiple usages of this.x? Create intersection over all usages? + + // needs to be in a class + // inferred type might be error. then add any. + // either make indexable of the inferred type + // add named member of the inferred type. +} + +// // class C { +// // constructor() { +// // this.x = 1; +// // } +// // } \ No newline at end of file diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts index 3bd173e04f6..76be34c67cd 100644 --- a/src/services/codefixes/fixes.ts +++ b/src/services/codefixes/fixes.ts @@ -1,4 +1,5 @@ /// +/// /// /// /// diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 7bee4f5a0ed..60efdef1e81 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -32,7 +32,7 @@ namespace ts.codefix { const declaration = declarations[0] as Declaration; const name = declaration.name ? declaration.name.getText() : undefined; - const visibility = getVisibilityPrefix(getModifierFlags(declaration)); + const visibility = getVisibilityPrefixWithSpace(getModifierFlags(declaration)); switch (declaration.kind) { case SyntaxKind.GetAccessor: @@ -138,11 +138,15 @@ namespace ts.codefix { } } - function getMethodBodyStub(newLineChar: string) { - return ` {${newLineChar}throw new Error('Method not implemented.');${newLineChar}}${newLineChar}`; + export function getStubbedMethod(visibility: string, name: string, signature: string = '()', newlineChar: string): string { + return `${visibility}${name}${signature}${getMethodBodyStub(newlineChar)}`; } - function getVisibilityPrefix(flags: ModifierFlags): string { + function getMethodBodyStub(newlineChar: string) { + return ` {${newlineChar}throw new Error('Method not implemented.');${newlineChar}}${newlineChar}`; + } + + function getVisibilityPrefixWithSpace(flags: ModifierFlags): string { if (flags & ModifierFlags.Public) { return "public "; } diff --git a/tests/cases/fourslash/codeFixUndeclaredPropertyNumericLiteral.ts b/tests/cases/fourslash/codeFixUndeclaredPropertyNumericLiteral.ts new file mode 100644 index 00000000000..bb11d9e76e1 --- /dev/null +++ b/tests/cases/fourslash/codeFixUndeclaredPropertyNumericLiteral.ts @@ -0,0 +1,17 @@ +/// + +//// [|class A { +//// constructor() { +//// this.x = 10; +//// } +//// }|] + +verify.rangeAfterCodeFix(` +class A { + x: number; + + constructor() { + this.x = 10; + } +} +`); \ No newline at end of file