Skip to content

Commit 420279b

Browse files
author
Arthur Ozga
committed
add missing method
1 parent 7adfa8d commit 420279b

File tree

3 files changed

+64
-9
lines changed

3 files changed

+64
-9
lines changed

src/compiler/diagnosticMessages.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3583,7 +3583,11 @@
35833583
"category": "Message",
35843584
"code": 90022
35853585
},
3586-
3586+
"Add declaration for missing method '{0}'.": {
3587+
"category": "Message",
3588+
"code": 90023
3589+
},
3590+
35873591
"Convert function to an ES2015 class": {
35883592
"category": "Message",
35893593
"code": 95001

src/services/codefixes/fixAddMissingMember.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
namespace ts.codefix {
33
registerCodeFix({
44
errorCodes: [Diagnostics.Property_0_does_not_exist_on_type_1.code,
5-
Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2.code],
5+
Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2.code],
66
getCodeActions: getActionsForAddMissingMember
77
});
88

@@ -79,20 +79,31 @@ namespace ts.codefix {
7979
}
8080

8181
function getActionsForAddMissingMemberInTypeScriptFile(): CodeAction[] | undefined {
82-
let typeNode: TypeNode;
82+
const openBrace = getOpenBraceOfClassLike(classDeclaration, sourceFile);
83+
const tokenName = token.getText(sourceFile);
84+
let actions: CodeAction[];
85+
86+
if (token.parent.parent.kind === SyntaxKind.CallExpression) {
87+
const callExpression = <CallExpression>token.parent.parent;
88+
const methodDeclaration = createMethodFromCallExpression(callExpression, tokenName);
89+
90+
const methodDeclarationChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
91+
methodDeclarationChangeTracker.insertNodeAfter(sourceFile, openBrace, methodDeclaration, { suffix: context.newLineCharacter });
92+
actions = [{
93+
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_method_0), [tokenName]),
94+
changes: methodDeclarationChangeTracker.getChanges()
95+
}];
96+
}
8397

98+
let typeNode: TypeNode;
8499
if (token.parent.parent.kind === SyntaxKind.BinaryExpression) {
85100
const binaryExpression = token.parent.parent as BinaryExpression;
86-
87101
const checker = context.program.getTypeChecker();
88102
const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right)));
89103
typeNode = checker.typeToTypeNode(widenedType, classDeclaration);
90104
}
91-
92105
typeNode = typeNode || createKeywordTypeNode(SyntaxKind.AnyKeyword);
93106

94-
const openBrace = getOpenBraceOfClassLike(classDeclaration, sourceFile);
95-
96107
const property = createProperty(
97108
/*decorators*/undefined,
98109
/*modifiers*/ isStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined,
@@ -103,10 +114,10 @@ namespace ts.codefix {
103114
const propertyChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
104115
propertyChangeTracker.insertNodeAfter(sourceFile, openBrace, property, { suffix: context.newLineCharacter });
105116

106-
const actions = [{
117+
(actions || (actions = [])).push({
107118
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]),
108119
changes: propertyChangeTracker.getChanges()
109-
}];
120+
});
110121

111122
if (!isStatic) {
112123
const stringTypeNode = createKeywordTypeNode(SyntaxKind.StringKeyword);

src/services/codefixes/helpers.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,46 @@ namespace ts.codefix {
142142
}
143143
}
144144

145+
export function createMethodFromCallExpression(callExpression: CallExpression, methodName: string): MethodDeclaration {
146+
const argCount = callExpression.arguments.length;
147+
const parameters: ParameterDeclaration[] = [];
148+
for (let i = 0; i < argCount; i++) {
149+
const typeNode = createKeywordTypeNode(SyntaxKind.AnyKeyword);
150+
const newParameter = createParameter(
151+
/*decorators*/ undefined,
152+
/*modifiers*/ undefined,
153+
/*dotDotDotToken*/ undefined,
154+
`arg${i}`,
155+
/*questionToken*/ undefined,
156+
typeNode,
157+
/*initializer*/ undefined);
158+
parameters.push(newParameter);
159+
}
160+
161+
const typeArgCount = callExpression.typeArguments ? callExpression.typeArguments.length : 0;
162+
let typeParameters: TypeParameterDeclaration[];
163+
for (let i = 0; i < typeArgCount; i++) {
164+
const name = typeArgCount < 8 ? String.fromCharCode(CharacterCodes.T + i) : `T${i}`;
165+
const typeParameter = createTypeParameterDeclaration(name, /*constraint*/ undefined, /*defaultType*/ undefined);
166+
167+
(typeParameters ? typeParameters : typeParameters = []).push(typeParameter);
168+
}
169+
170+
const newMethod = createMethod(
171+
/*decorators*/ undefined,
172+
/*modifiers*/ undefined,
173+
/*asteriskToken*/ undefined,
174+
methodName,
175+
/*questionToken*/ undefined,
176+
typeParameters,
177+
parameters,
178+
/*type*/ undefined,
179+
createStubbedMethodBody()
180+
)
181+
182+
return newMethod;
183+
}
184+
145185
function createMethodImplementingSignatures(signatures: Signature[], name: PropertyName, optional: boolean, modifiers: Modifier[] | undefined): MethodDeclaration {
146186
/** This is *a* signature with the maximal number of arguments,
147187
* such that if there is a "maximal" signature without rest arguments,

0 commit comments

Comments
 (0)