Skip to content

Refine extends-to-implements code fix#20991

Merged
amcasey merged 2 commits into
microsoft:masterfrom
amcasey:GH18794
Jan 6, 2018
Merged

Refine extends-to-implements code fix#20991
amcasey merged 2 commits into
microsoft:masterfrom
amcasey:GH18794

Conversation

@amcasey
Copy link
Copy Markdown
Member

@amcasey amcasey commented Jan 3, 2018

  1. Retain surrounding trivia when swapping the keyword.
  2. Insert commas at the full-starts, rather than starts, of existing
    keywords when merging with existing implements clauses.

Fixes #18794

@amcasey amcasey requested review from a user and sandersn January 3, 2018 23:04
@amcasey
Copy link
Copy Markdown
Member Author

amcasey commented Jan 3, 2018

FYI @sandersn who periodically has to deal with trivia issues in code fixes and refactorings.

Copy link
Copy Markdown

@ghost ghost left a comment

Choose a reason for hiding this comment

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

You could try something like this to avoid dealing directly with positions:

if (heritageClauses.length === 1) {
    changes.replaceNode(sourceFile, extendsToken, createToken(SyntaxKind.ImplementsKeyword));
}
else {
    changes.deleteNode(sourceFile, heritageClauses[0]);
    // Move types from 'extends' to 'implements' clause
    for (let i = heritageClauses[0].types.length - 1; i >= 0; i--) {
        changes.insertNodeBefore(sourceFile, first(heritageClauses[1].types), heritageClauses[0].types[i]);
    }
}

(and in textChanges.ts add || isExpressionWithTypeArguments(before) to the else if in getOptionsForInsertNodeBefore)

changes.replaceNode(sourceFile, extendsToken, createToken(SyntaxKind.ImplementsKeyword));
changes.replaceRange(sourceFile, { pos: extendsToken.getStart(), end: extendsToken.end }, createToken(SyntaxKind.ImplementsKeyword));
// We replace existing keywords with commas.
for (let i = 1; i < heritageClauses.length; i++) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It was this way before, but shouldn't this only apply to heritageClauses[1] since the others will have commas already?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I thought that implements I1, I2 counted as a single heritage clause (and that, in correct code, heritageClauses would have 0, 1, or 2 elements).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

OK, but then we don't need the loop, just an if.

changes.replaceRange(sourceFile, { pos: extendsToken.getStart(), end: extendsToken.end }, createToken(SyntaxKind.ImplementsKeyword));
// We replace existing keywords with commas.
for (let i = 1; i < heritageClauses.length; i++) {
const keywordToken = heritageClauses[i].getFirstToken()!;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Might want to assert that this is SyntaxKind.ImplementsKeyword.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

My thinking was that that assertion would fail in invalid code (e.g. multiple extends clauses or an out-of-order extends clause). I'm not convinced it's worthwhile to harden a best-effort code fix against that sort of bad code (the user will already be getting a diagnostic and the change is undoable), but I don't feel strongly about it. However, I'd only add the assert if we were also adding actual checks.

@amcasey
Copy link
Copy Markdown
Member Author

amcasey commented Jan 4, 2018

@Andy-MS I don't think I can use the replaceNode call you suggest because it will clobber the trivia of the replaced keyword. I did consider updating the list of types in the existing implements clause, but it wasn't clear where all the trivia would go in that case. @sandersn and I discussed it offline (before I implemented it) and concluded that this was the closest to what a user would do by hand.

 1. Retain surrounding trivia when swapping the keyword.
 2. Insert commas at the full-starts, rather than starts, of existing
 keywords when merging with existing implements clauses.

Fixes microsoft#18794
@amcasey
Copy link
Copy Markdown
Member Author

amcasey commented Jan 5, 2018

Good to go?

@amcasey amcasey merged commit 1957dfe into microsoft:master Jan 6, 2018
@amcasey amcasey deleted the GH18794 branch January 6, 2018 01:52
@microsoft microsoft locked and limited conversation to collaborators Jul 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant