This commit is contained in:
Arthur Ozga
2017-02-13 11:18:56 -08:00
parent f4175c0184
commit 9897c69492
4 changed files with 100 additions and 4 deletions

View File

@@ -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.<thing>.
// Want to infer type of x when possible. ie:
// * assignment,
// * function call argument: foo<T>(this.x) where foo(x: SomeType<T>)
// * 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;
// // }
// // }

View File

@@ -1,4 +1,5 @@
/// <reference path="fixClassIncorrectlyImplementsInterface.ts" />
/// <reference path="fixAddMissingMember.ts" />
/// <reference path="fixClassDoesntImplementInheritedAbstractMember.ts" />
/// <reference path="fixClassSuperMustPrecedeThisAccess.ts" />
/// <reference path="fixConstructorForDerivedNeedSuperCall.ts" />

View File

@@ -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 ";
}

View File

@@ -0,0 +1,17 @@
/// <reference path='fourslash.ts' />
//// [|class A {
//// constructor() {
//// this.x = 10;
//// }
//// }|]
verify.rangeAfterCodeFix(`
class A {
x: number;
constructor() {
this.x = 10;
}
}
`);