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

Fix: Check division operator in astUtils.canTokensBeAdjacent #12879

Merged
merged 3 commits into from Mar 9, 2020

Conversation

mdjermanovic
Copy link
Member

@mdjermanovic mdjermanovic commented Feb 6, 2020

Prerequisites checklist

  • I have read the contributing guidelines.
  • The team has reached consensus on the changes proposed in this pull request. If not, I understand that the evaluation process will begin with this pull request and won't be merged until the team has reached consensus.

What is the purpose of this pull request? (put an "X" next to an item)

[X] Bug fix

Tell us about your environment

  • ESLint Version: 7.0.0-alpha.0
  • Node Version: v12.14.0
  • npm Version: v6.13.4

What parser (default, Babel-ESLint, etc.) are you using?

default

Please show your full configuration:

Configuration
module.exports = {
    parserOptions: {
        ecmaVersion: 2015
    },
};

What did you do? Please include the actual source code causing the issue.

/* eslint no-extra-parens: ["error"] */
/* eslint operator-assignment: ["error", "never"] */

a/(/**/b);

a/(//
  b);

a/(/regex/);

a/=/**/b;

Online Demo Link (v6.8.0 actual)

What did you expect to happen?

4 errors and auto-fix that would not comment out some code.

What actually happened? Please include the actual, raw output from ESLint.

4 errors and auto-fix to:

/* eslint no-extra-parens: ["error"] */
/* eslint operator-assignment: ["error", "never"] */

a//**/b;

a///
  b;

a//regex/;

a= a//**/b;

In all 4 lines / becomes start of a line comment.

What changes did you make? (Give an overview)

  • Fixed astUtils.canTokensBeAdjacent to account for the / operator on the left side and block comment, line comment or regex on the right side.
  • Fixed no-extra-parens and operator-assignment rules to get and pass possible comment tokens as well.
  • Since there are now rules that can pass comment tokens to astUtils.canTokensBeAdjacent, had to also add the logic for comments (I believe they can be adjacent with everything except for / on the left side).
  • Fixed part of the code in astUtils.canTokensBeAdjacent that deals with string input (using espree.tokenize) to handle comments as well. I don't think this will affect the rules that are using this feature at the moment, but it should be a correct change and it also allowed testing this function with comments (all tests actually pass strings, maybe we should add some tests with tokens at some point since it's the most common case).
  • Also upgraded espree in order to pass espree.latestEcmaVersion instead of a hard-coded version to espree.tokenize(), and added try-catch around espree.tokenize(). This should fix partially or entirely astUtils.canTokensBeAdjacent hardcoded espree.tokenize #12291 (edited to prevent auto-closing astUtils.canTokensBeAdjacent hardcoded espree.tokenize #12291),

Is there anything you'd like reviewers to focus on?

  • Is this the correct way to get comments from espree.tokenize?

This can also happen in operator-linebreak in some edge cases. That rule has its own code to handle adjacent tokens, I'll see if it is possible to switch to astUtils.canTokensBeAdjacent (or fix the same issue there if it isn't) in a follow-up PR.

Marked as accepted since it's an obvious autofix bug.

@mdjermanovic mdjermanovic added bug ESLint is working incorrectly rule Relates to ESLint's core rules accepted There is consensus among the team that this change meets the criteria for inclusion autofix This change is related to ESLint's autofixing capabilities labels Feb 6, 2020
let leftToken;

if (typeof leftValue === "string") {
const leftTokens = espree.tokenize(leftValue, { ecmaVersion: 2015 });
const tokens = espree.tokenize(leftValue, espreeOptions);
Copy link
Member

@kaicataldo kaicataldo Feb 6, 2020

Choose a reason for hiding this comment

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

Do you mind adding a test for when a Shebang comment token is given as the left value? I don't think this could ever be a real world use case (since another token can't be on the same line as the shebang), but I do think we should make sure that this won't crash the process when Espree tries to tokenize this.

For reference, we mutate the text input to make the shebang a regular JS line comment before we parse in lib/linter/linter.js and then transform the token post-parse to a Shebang comment token.

Copy link
Member Author

Choose a reason for hiding this comment

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

You're right, that would crash! Maybe we could already add try-catch as suggested in #12291 (comment) and also close #12291 with this PR?

Copy link
Member Author

Choose a reason for hiding this comment

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

canTokensBeAdjacent also didn't assume it could get a code (as a string argument) without any tokens, so it doesn't support a comment-only code. This isn't changed with this PR, it would still crash, so it isn't possible to call it with e.g.,:

astUtils.canTokensBeAdjacent(someToken, "/* comment */");

Then, it might also make sense to support empty code as well, and maybe even to account for spaces at the start/end of the code (e.g., canTokensBeAdjacent("a ", "b") would return true).

Maybe we could do that as well in this PR?

Copy link
Member

@kaicataldo kaicataldo Feb 7, 2020

Choose a reason for hiding this comment

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

That sounds good to me! I guess another option (or something we could do additionally) is to short circuit it and add an early return of false if the left value token is of type Shebang. That would save the process from having to run the tokenizing at all.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, interesting! Since this is already an improvement over the existing code, I would be fine with splitting these bug fixes over multiple PRs to keep them manageable. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

That sounds good to me! I guess another option (or something we could do additionally) is to short circuit it and add an early return of false if the left value token is of type Shebang. That would save the process from having to run the tokenizing at all.

Maybe I didn't understand, but I think it isn't possible to check if the token is Shebang before tokenizing, because we don't have the token yet?

Copy link
Member

@kaicataldo kaicataldo Feb 7, 2020

Choose a reason for hiding this comment

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

Oh, I see, I missed that it could be a string or a token. Yes, if the left value is a string that won't work. I think the approach you suggested sounds good 👍

@mdjermanovic mdjermanovic changed the title Fix: Check division operator in astUtils.canTokensBeAdjacent [WIP] Fix: Check division operator in astUtils.canTokensBeAdjacent Feb 7, 2020
@mdjermanovic mdjermanovic added the do not merge This pull request should not be merged yet label Feb 7, 2020
@@ -1357,17 +1357,43 @@ module.exports = {
* next to each other, behavior is undefined (although it should return `true` in most cases).
*/
canTokensBeAdjacent(leftValue, rightValue) {
const espreeOptions = { ecmaVersion: 2020, comment: true, range: true };
Copy link
Member

Choose a reason for hiding this comment

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

Non-blocker for this PR, but it could be nice to add the ability to specify “latest” somehow, so that this never gets out of date.

Copy link
Member Author

Choose a reason for hiding this comment

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

That would be great! But, I'm not sure if there is a way to do that at the moment? Does espree support something like "latest" or provides a list of available versions?

Copy link
Member

Choose a reason for hiding this comment

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

v/_ \ I don't think espree has such a thing.

Copy link
Member

Choose a reason for hiding this comment

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

It doesn’t, no! Definitely not a blocker for this - just an idea I had and wanted to write down for posterity 😄

Copy link
Member Author

Choose a reason for hiding this comment

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

A list of all versions could be also useful for the online demo, it's hard-coded there and has to be updated manually.

Copy link
Member

Choose a reason for hiding this comment

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

PR/proposal here: eslint/espree#430

let leftToken;

if (typeof leftValue === "string") {
const leftTokens = espree.tokenize(leftValue, { ecmaVersion: 2015 });
const tokens = espree.tokenize(leftValue, espreeOptions);
Copy link
Member

Choose a reason for hiding this comment

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

Oh, interesting! Since this is already an improvement over the existing code, I would be fine with splitting these bug fixes over multiple PRs to keep them manageable. What do you think?

@kaicataldo
Copy link
Member

Sorry, meant to submit those two comments yesterday.

@mdjermanovic mdjermanovic removed the do not merge This pull request should not be merged yet label Feb 8, 2020
@mdjermanovic mdjermanovic changed the title [WIP] Fix: Check division operator in astUtils.canTokensBeAdjacent Fix: Check division operator in astUtils.canTokensBeAdjacent Feb 8, 2020
@mdjermanovic
Copy link
Member Author

Since this is already an improvement over the existing code, I would be fine with splitting these bug fixes over multiple PRs to keep them manageable. What do you think?

Agreed! Just added try-catch and explicit check for Shebang (test with the "token" returns false because of the condition, test with the string return false on tokenizing).

This PR is now ready for review since it fixes some issues and (I believe) doesn't add any new ones.

@nzakas
Copy link
Member

nzakas commented Feb 28, 2020

What are next steps here? Are we waiting for the Espree change?

@kaicataldo
Copy link
Member

I can run an Espree release tomorrow as well. It would be good to get the updated API in before we run the next major release with eslint/espree#429.

@mdjermanovic
Copy link
Member Author

If it would be easier for reviewing, I can add a note in #12291 and update canTokensBeAdjacent with the new Espree interface in another PR when the new Espree version gets published.

@kaicataldo
Copy link
Member

espree@6.2.0 has been released. latestEcmaVersion is now available for this PR!

@mdjermanovic mdjermanovic added the upgrade This change is related to a dependency upgrade label Mar 3, 2020
@mdjermanovic
Copy link
Member Author

espree@6.2.0 has been released. latestEcmaVersion is now available for this PR!

Done!

@nzakas nzakas merged commit 6cef0d5 into master Mar 9, 2020
@nzakas nzakas deleted the adjacent-division branch March 9, 2020 23:43
anikethsaha pushed a commit to anikethsaha/eslint that referenced this pull request Mar 11, 2020
…12879)

* Fix: Check division operator in astUtils.canTokensBeAdjacent

* Add try-catch and Shebang check

* Upgrade espree, use latestEcmaVersion
@eslint-deprecated eslint-deprecated bot locked and limited conversation to collaborators Sep 7, 2020
@eslint-deprecated eslint-deprecated bot added the archived due to age This issue has been archived; please open a new issue for any further discussion label Sep 7, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion archived due to age This issue has been archived; please open a new issue for any further discussion autofix This change is related to ESLint's autofixing capabilities bug ESLint is working incorrectly rule Relates to ESLint's core rules upgrade This change is related to a dependency upgrade
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants