Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add codefix for --noImplicitThis #27565

Merged
merged 10 commits into from
Mar 17, 2020
Merged

Add codefix for --noImplicitThis #27565

merged 10 commits into from
Mar 17, 2020

Conversation

ghost
Copy link

@ghost ghost commented Oct 5, 2018

  • If there's no containing function, no fix.
  • If this is defined outside the containing function, convert the containing function to an arrow function, since that's the most likely error.
  • If not, inside a JS function:
    • Tag as a @class if this is an assignment.

Edit by @sandersn:

  • Removed features that are redundant with inferFromUsage now.

@ghost ghost force-pushed the fixImplicitThis branch 2 times, most recently from 3748c71 to ddc7797 Compare October 8, 2018 18:00
@ghost ghost force-pushed the fixImplicitThis branch from ddc7797 to cb30622 Compare October 8, 2018 18:08
@ghost ghost requested review from amcasey, DanielRosenwasser and sandersn October 8, 2018 18:40
const { name } = fn;
const body = Debug.assertDefined(fn.body); // Should be defined because the function contained a 'this' expression
if (isFunctionExpression(fn)) {
if (fn.name && FindAllReferences.Core.isSymbolReferencedInFile(fn.name, checker, sourceFile, body)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's kind of confusing to refer to the same property as both name and fn.name in this function.

@sandersn sandersn self-assigned this Oct 8, 2018
@@ -339,6 +339,22 @@ namespace ts.textChanges {
this.insertText(sourceFile, token.getStart(sourceFile), text);
}

public insertJsdocCommentBefore(sourceFile: SourceFile, fn: FunctionDeclaration | FunctionExpression, tag: JSDocTag): void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will work right for function expressions immediately preceded by text.

: formatting.SmartIndenter.getIndentation(pos, sourceFile, formatOptions, prefix === newLineCharacter || getLineStartPositionForPosition(pos, sourceFile) === pos);
if (delta === undefined) {
delta = formatting.SmartIndenter.shouldIndentChildNode(formatContext.options, nodeIn) ? (formatOptions.indentSize || 0) : 0;
export function getFormattedTextOfNode(nodeIn: Node, sourceFile: SourceFile, pos: number, { indentation, prefix, delta }: InsertNodeOptions, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this used now that there is an export here?

Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the emit is correct for FunctionExpressions that are preceded by non-whitespace text on their line. Probably you should use code from #27610 and then I can grab it from master after this goes in and use it there.

@@ -1103,15 +1138,23 @@ namespace ts.textChanges {
deleteImportBinding(changes, sourceFile, node as NamespaceImport);
break;

case SyntaxKind.SemicolonToken:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could be miscounting the scopes, but why would deleteDeclaration be called on a semicolon?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

convertToEs6Module deletes semicolons when changing an assignment statement to a function declaration.

const token = getTokenAtPosition(sourceFile, pos);
Debug.assert(token.kind === SyntaxKind.ThisKeyword);

const fn = getThisContainer(token, /*includeArrowFunctions*/ false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we be in a default argument of the function? Does that matter?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a parameter initializer, 'this' refers to the same 'this' as inside the body of the function, not to 'this' of an outer function. So this will work just as well in that case.

changes.delete(sourceFile, name);
}
changes.insertText(sourceFile, body.pos, " =>");
return [Diagnostics.Convert_function_expression_0_to_arrow_function, name ? name.text : "<anonymous>"];
Copy link
Member

@amcasey amcasey Oct 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a constant for "<anonymous>" somewhere? It seems unlikely that this is the first time we've had to name an anonymous symbol.

if (name) {
changes.delete(sourceFile, name);
}
changes.insertText(sourceFile, body.pos, " =>");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't there a code fix or refactoring for converting a function to an error function? Can/should we share code?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There will be in #28250, we can combine these then.

return [Diagnostics.Convert_function_declaration_0_to_arrow_function, name!.text];
}
}
else { // No outer 'this', must add an annotation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or a parameter?

@ghost ghost force-pushed the fixImplicitThis branch from d5cdff9 to e74d5ee Compare November 13, 2018 22:12
@sandersn sandersn added For Milestone Bug PRs that fix a bug with a specific milestone For Backlog Bug PRs that fix a backlog bug and removed For Milestone Bug PRs that fix a bug with a specific milestone labels Feb 1, 2020
DOES NOT BUILD, because I only fixed the conflicts, not the build
errors. I'm going to push this up and sync on my desktop machine because
it's so much easier to work there.
@sandersn
Copy link
Member

This PR is old enough that it's taking a while to bring up-to-date. Currently:

  • Merged from master.
  • Builds.
  • All tests passes except for the newly added test, plus a test for another codefix (infer from usage) that now interferes with it.

Infer-from-usage also inserts `this: any` parameters when needed, so I
removed that from fixImplicitThis.

Otherwise, fixImplicitThis has better suggestions than inferFromUsage,
so I moved inferFromUsage later in the suggestion order.
Don't need to add `@this` anymore either since inferFromUsage will do
that.
From moving inferFromUsage down in priority I think?
@sandersn sandersn merged commit b0450ae into master Mar 17, 2020
@sandersn sandersn deleted the fixImplicitThis branch March 17, 2020 20:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Backlog Bug PRs that fix a backlog bug
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

2 participants