Skip to content

Commit e74d5ee

Browse files
author
Andy Hanson
committed
Code review
1 parent 8ae463f commit e74d5ee

7 files changed

+39
-10
lines changed

Diff for: src/services/codefixes/fixImplicitThis.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace ts.codefix {
3030
const { name } = fn;
3131
const body = Debug.assertDefined(fn.body); // Should be defined because the function contained a 'this' expression
3232
if (isFunctionExpression(fn)) {
33-
if (fn.name && FindAllReferences.Core.isSymbolReferencedInFile(fn.name, checker, sourceFile, body)) {
33+
if (name && FindAllReferences.Core.isSymbolReferencedInFile(name, checker, sourceFile, body)) {
3434
// Function expression references itself. To fix we would have to extract it to a const.
3535
return undefined;
3636
}
@@ -41,7 +41,7 @@ namespace ts.codefix {
4141
changes.delete(sourceFile, name);
4242
}
4343
changes.insertText(sourceFile, body.pos, " =>");
44-
return [Diagnostics.Convert_function_expression_0_to_arrow_function, name ? name.text : "<anonymous>"];
44+
return [Diagnostics.Convert_function_expression_0_to_arrow_function, name ? name.text : ANONYMOUS];
4545
}
4646
else {
4747
// `function f() {}` => `const f = () => {}`
@@ -52,14 +52,14 @@ namespace ts.codefix {
5252
return [Diagnostics.Convert_function_declaration_0_to_arrow_function, name!.text];
5353
}
5454
}
55-
else { // No outer 'this', must add an annotation
55+
else { // No outer 'this', must add a jsdoc tag / parameter
5656
if (isSourceFileJS(sourceFile)) {
5757
const addClassTag = isPropertyAccessExpression(token.parent) && isAssignmentExpression(token.parent.parent);
5858
addJSDocTags(changes, sourceFile, fn, [addClassTag ? createJSDocClassTag() : createJSDocThisTag(createKeywordTypeNode(SyntaxKind.AnyKeyword))]);
5959
return addClassTag ? Diagnostics.Add_class_tag : Diagnostics.Add_this_tag;
6060
}
6161
else {
62-
changes.insertNodeAt(sourceFile, fn.parameters.pos, makeParameter("this", createKeywordTypeNode(SyntaxKind.AnyKeyword)));
62+
changes.insertFirstParameter(sourceFile, fn.parameters, makeParameter("this", createKeywordTypeNode(SyntaxKind.AnyKeyword)));
6363
return Diagnostics.Add_this_parameter;
6464
}
6565
}

Diff for: src/services/codefixes/generateTypes.ts

+1
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ namespace ts {
191191
];
192192
return { parameters, returnType: hasReturn ? anyType() : createKeywordTypeNode(SyntaxKind.VoidKeyword) };
193193
}
194+
/* @internal */
194195
export function makeParameter(name: string, type: TypeNode): ParameterDeclaration {
195196
return createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name, /*questionToken*/ undefined, type);
196197
}

Diff for: src/services/refactors/extractSymbol.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ namespace ts.refactor.extractSymbol {
673673
case SyntaxKind.FunctionDeclaration:
674674
return scope.name
675675
? `function '${scope.name.text}'`
676-
: "anonymous function";
676+
: ANONYMOUS;
677677
case SyntaxKind.ArrowFunction:
678678
return "arrow function";
679679
case SyntaxKind.MethodDeclaration:

Diff for: src/services/textChanges.ts

+14-4
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,18 @@ namespace ts.textChanges {
310310
});
311311
}
312312

313+
public insertFirstParameter(sourceFile: SourceFile, parameters: NodeArray<ParameterDeclaration>, newParam: ParameterDeclaration): void {
314+
const p0 = firstOrUndefined(parameters);
315+
if (p0) {
316+
this.insertNodeBefore(sourceFile, p0, newParam);
317+
}
318+
else {
319+
this.insertNodeAt(sourceFile, parameters.pos, newParam);
320+
}
321+
}
322+
313323
public insertNodeBefore(sourceFile: SourceFile, before: Node, newNode: Node, blankLineBetween = false) {
314-
this.insertNodeAt(sourceFile, getAdjustedStartPosition(sourceFile, before, {}, Position.Start), newNode, this.getOptionsForInsertNodeBefore(before, blankLineBetween));
324+
this.insertNodeAt(sourceFile, getAdjustedStartPosition(sourceFile, before, {}, Position.Start), newNode, this.getOptionsForInsertNodeBefore(before, newNode, blankLineBetween));
315325
}
316326

317327
public insertModifierBefore(sourceFile: SourceFile, modifier: SyntaxKind, before: Node): void {
@@ -390,15 +400,15 @@ namespace ts.textChanges {
390400
this.insertNodesAt(sourceFile, start, typeParameters, { prefix: "<", suffix: ">" });
391401
}
392402

393-
private getOptionsForInsertNodeBefore(before: Node, doubleNewlines: boolean): InsertNodeOptions {
403+
private getOptionsForInsertNodeBefore(before: Node, inserted: Node, doubleNewlines: boolean): InsertNodeOptions {
394404
if (isStatement(before) || isClassElement(before)) {
395405
return { suffix: doubleNewlines ? this.newLineCharacter + this.newLineCharacter : this.newLineCharacter };
396406
}
397407
else if (isVariableDeclaration(before)) { // insert `x = 1, ` into `const x = 1, y = 2;
398408
return { suffix: ", " };
399409
}
400410
else if (isParameter(before)) {
401-
return {};
411+
return isParameter(inserted) ? { suffix: ", " } : {};
402412
}
403413
else if (isStringLiteral(before) && isImportDeclaration(before.parent) || isNamedImports(before)) {
404414
return { suffix: ", " };
@@ -807,7 +817,7 @@ namespace ts.textChanges {
807817
}
808818

809819
/** Note: this may mutate `nodeIn`. */
810-
export function getFormattedTextOfNode(nodeIn: Node, sourceFile: SourceFile, pos: number, { indentation, prefix, delta }: InsertNodeOptions, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): string {
820+
function getFormattedTextOfNode(nodeIn: Node, sourceFile: SourceFile, pos: number, { indentation, prefix, delta }: InsertNodeOptions, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): string {
811821
// Emitter doesn't handle JSDoc, so generate that here.
812822
if (isJSDocTag(nodeIn)) {
813823
switch (nodeIn.kind) {

Diff for: src/services/utilities.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1908,4 +1908,6 @@ namespace ts {
19081908
export function getSwitchedType(caseClause: CaseClause, checker: TypeChecker): Type | undefined {
19091909
return checker.getTypeAtLocation(caseClause.parent.parent.expression);
19101910
}
1911+
1912+
export const ANONYMOUS = "anonymous function";
19111913
}

Diff for: tests/cases/fourslash/codeFixImplicitThis_ts_functionExpression_noName.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
////}
1212

1313
verify.codeFix({
14-
description: "Convert function expression '<anonymous>' to arrow function",
14+
description: "Convert function expression 'anonymous function' to arrow function",
1515
index: 0,
1616
newFileContent:
1717
`class C {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @noImplicitThis: true
4+
5+
////function f(x: number) {
6+
//// this;
7+
////}
8+
9+
verify.codeFix({
10+
description: "Add 'this' parameter.",
11+
index: 0,
12+
newFileContent:
13+
`function f(this: any, x: number) {
14+
this;
15+
}`,
16+
});

0 commit comments

Comments
 (0)