add missing method

This commit is contained in:
Arthur Ozga 2017-05-23 11:34:37 -07:00
parent 7adfa8d854
commit 420279b99d
3 changed files with 64 additions and 9 deletions

View file

@ -3583,7 +3583,11 @@
"category": "Message", "category": "Message",
"code": 90022 "code": 90022
}, },
"Add declaration for missing method '{0}'.": {
"category": "Message",
"code": 90023
},
"Convert function to an ES2015 class": { "Convert function to an ES2015 class": {
"category": "Message", "category": "Message",
"code": 95001 "code": 95001

View file

@ -2,7 +2,7 @@
namespace ts.codefix { namespace ts.codefix {
registerCodeFix({ registerCodeFix({
errorCodes: [Diagnostics.Property_0_does_not_exist_on_type_1.code, errorCodes: [Diagnostics.Property_0_does_not_exist_on_type_1.code,
Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2.code], Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2.code],
getCodeActions: getActionsForAddMissingMember getCodeActions: getActionsForAddMissingMember
}); });
@ -79,20 +79,31 @@ namespace ts.codefix {
} }
function getActionsForAddMissingMemberInTypeScriptFile(): CodeAction[] | undefined { function getActionsForAddMissingMemberInTypeScriptFile(): CodeAction[] | undefined {
let typeNode: TypeNode; const openBrace = getOpenBraceOfClassLike(classDeclaration, sourceFile);
const tokenName = token.getText(sourceFile);
let actions: CodeAction[];
if (token.parent.parent.kind === SyntaxKind.CallExpression) {
const callExpression = <CallExpression>token.parent.parent;
const methodDeclaration = createMethodFromCallExpression(callExpression, tokenName);
const methodDeclarationChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
methodDeclarationChangeTracker.insertNodeAfter(sourceFile, openBrace, methodDeclaration, { suffix: context.newLineCharacter });
actions = [{
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_method_0), [tokenName]),
changes: methodDeclarationChangeTracker.getChanges()
}];
}
let typeNode: TypeNode;
if (token.parent.parent.kind === SyntaxKind.BinaryExpression) { if (token.parent.parent.kind === SyntaxKind.BinaryExpression) {
const binaryExpression = token.parent.parent as BinaryExpression; const binaryExpression = token.parent.parent as BinaryExpression;
const checker = context.program.getTypeChecker(); const checker = context.program.getTypeChecker();
const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right))); const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right)));
typeNode = checker.typeToTypeNode(widenedType, classDeclaration); typeNode = checker.typeToTypeNode(widenedType, classDeclaration);
} }
typeNode = typeNode || createKeywordTypeNode(SyntaxKind.AnyKeyword); typeNode = typeNode || createKeywordTypeNode(SyntaxKind.AnyKeyword);
const openBrace = getOpenBraceOfClassLike(classDeclaration, sourceFile);
const property = createProperty( const property = createProperty(
/*decorators*/undefined, /*decorators*/undefined,
/*modifiers*/ isStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined, /*modifiers*/ isStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined,
@ -103,10 +114,10 @@ namespace ts.codefix {
const propertyChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); const propertyChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
propertyChangeTracker.insertNodeAfter(sourceFile, openBrace, property, { suffix: context.newLineCharacter }); propertyChangeTracker.insertNodeAfter(sourceFile, openBrace, property, { suffix: context.newLineCharacter });
const actions = [{ (actions || (actions = [])).push({
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]), description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]),
changes: propertyChangeTracker.getChanges() changes: propertyChangeTracker.getChanges()
}]; });
if (!isStatic) { if (!isStatic) {
const stringTypeNode = createKeywordTypeNode(SyntaxKind.StringKeyword); const stringTypeNode = createKeywordTypeNode(SyntaxKind.StringKeyword);

View file

@ -142,6 +142,46 @@ namespace ts.codefix {
} }
} }
export function createMethodFromCallExpression(callExpression: CallExpression, methodName: string): MethodDeclaration {
const argCount = callExpression.arguments.length;
const parameters: ParameterDeclaration[] = [];
for (let i = 0; i < argCount; i++) {
const typeNode = createKeywordTypeNode(SyntaxKind.AnyKeyword);
const newParameter = createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
`arg${i}`,
/*questionToken*/ undefined,
typeNode,
/*initializer*/ undefined);
parameters.push(newParameter);
}
const typeArgCount = callExpression.typeArguments ? callExpression.typeArguments.length : 0;
let typeParameters: TypeParameterDeclaration[];
for (let i = 0; i < typeArgCount; i++) {
const name = typeArgCount < 8 ? String.fromCharCode(CharacterCodes.T + i) : `T${i}`;
const typeParameter = createTypeParameterDeclaration(name, /*constraint*/ undefined, /*defaultType*/ undefined);
(typeParameters ? typeParameters : typeParameters = []).push(typeParameter);
}
const newMethod = createMethod(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
methodName,
/*questionToken*/ undefined,
typeParameters,
parameters,
/*type*/ undefined,
createStubbedMethodBody()
)
return newMethod;
}
function createMethodImplementingSignatures(signatures: Signature[], name: PropertyName, optional: boolean, modifiers: Modifier[] | undefined): MethodDeclaration { function createMethodImplementingSignatures(signatures: Signature[], name: PropertyName, optional: boolean, modifiers: Modifier[] | undefined): MethodDeclaration {
/** This is *a* signature with the maximal number of arguments, /** This is *a* signature with the maximal number of arguments,
* such that if there is a "maximal" signature without rest arguments, * such that if there is a "maximal" signature without rest arguments,