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

Much better comment preservation #22141

Merged

Conversation

weswigham
Copy link
Member

@weswigham weswigham commented Feb 23, 2018

This clears out some large swaths of #17689 (which is now much more precise now that I've taken an initial look on what should/should not be functioning right now), specifically:

  • YieldExpression
  • AwaitExpression
  • DeleteExpression
  • TypeOfExpression
  • VoidExpression
  • NewExpression
  • ElementAccessExpression
  • PropertyAccessExpression
  • Block-level statements where the comments need to be considered attached to a parenthesis token (all of them)
  • VariableDeclaration
  • All import and export kinds

should now all preserve any comments of any kind between any of their tokens, regardless of if the token is actually in the AST, so long as the node is sufficiently similar to its original form.

Just a reminder: Comment preservation is important for tools based on TS (like our own quickfixes) which expect to be able to extract, transform, and insert arbitrary ranges without modification. You can actually see improvements in our own organizeImports baseline. 😄

Things that might still not preserve comments correctly include any multitoken type nodes, and some TS-specific constructs (like namespaces and casts). I'm choosing to tackle those later (if at all) in a separate PR, since they need to be tested in a separate harness (as we have no transform-less emit option). Additionally, I am aware of a bug preventing multiline object literals from preserving comments after non-final commas (#10385). I'm leaving a fix for that out of this PR, since fixing it may end up requiring reworking emitList a bit more than I want to when there's already a lot else going on.

I don't think I have an exhaustive list, but I know this:
Fixes #11755
Fixes #2546 (all cases mentioned in the thread)
Fixes #17606
Fixes #6069 probably (provided I understand the original issue correctly)
Fixes #9873 (Which is actually a collection of issues)

Side note on why the changeset is so big: The sourcemap changes should be from changing emitTokenWithComment to no longer add an extra sourcemap entry for the token we're emitting comments for. Baselines were captured when this was used for return statements, and while the baselines were technically "more precise" insofar as there were more mapping entries, typically the extra entries were for equal width spans (as a token always mapped to itself) making the extra entry rather pointless. That alone wouldn't usually be enough for me to care, but we actually have some places where the token does map to more text (when you consider non-return tokens), and the sourcemaps for those locations were always inaccurate (as the transformers hadn't setup corrected ones). So in lieu of updating the transformers to add mappings for all these tokens, I'm just leaving them all mapped as they are today, and reverting return to how it was more simply mapped in the past. If it'd help, I can extract that change into a separate PR so this one's easier to review once it's merged.

@DanielRosenwasser
Copy link
Member

(Psst, @evmar)

@@ -2399,7 +2399,7 @@ namespace ts {

function emitEnumMember(node: EnumMember) {
emit(node.name);
emitInitializer(node.initializer);
emitInitializer(node.initializer, node.name.end + 1, node);
Copy link
Member

Choose a reason for hiding this comment

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

Why are these all plus one? Shouldn't the start position be the end of the name?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep. This one (and like one other?) were the first ones I wrote and for some reason thought that I needed to skip the length the token in question. Thanks for reminding me that I still hadn't gone back and changed them.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe that's a good indicator that we need tests for cases where trivia comes immediately after:

enum E {
  A/*what sick person even writes comments like this?*/=0
}

@rbuckton
Copy link
Member

Have you run a benchmark for these changes against master? I want to be sure these changes don't cause a dramatic slowdown.

@weswigham
Copy link
Member Author

image
I did an unscientific 10/10 comparison yesterday, actually. I'm not sure what our limit here is, but the difference doesn't seem terribly outlandish.

}

function emitCaseOrDefaultClauseStatements(parentNode: Node, statements: NodeArray<Statement>) {
function emitCaseOrDefaultClauseStatements(parentNode: Node, statements: NodeArray<Statement>, colonPos: number) {
// This also handles the colon token from the preceeding clause, as weather comments must be emitted for it depends on
Copy link
Member

Choose a reason for hiding this comment

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

nit: This comment is hard to read and has misspellings ('whether' not 'weather'), can you rephrase it?

Copy link
Member

Choose a reason for hiding this comment

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

You can probably just remove the comment entirely if you rename the function to emitCaseOrDefaultClauseRest (as it no longer would imply only emitting the statements).

@rbuckton
Copy link
Member

rbuckton commented Mar 2, 2018

Can you address the merge conflict?

@weswigham weswigham merged commit 1c93744 into microsoft:master Mar 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
3 participants