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

Implement RUF028 to detect useless formatter suppression comments #9899

Merged
merged 13 commits into from
Feb 28, 2024

Conversation

snowsignal
Copy link
Contributor

@snowsignal snowsignal commented Feb 8, 2024

Fixes #6611

Summary

This lint rule spots comments that are intended to suppress or enable the formatter, but will be ignored by the Ruff formatter.

We borrow some functions the formatter uses for determining comment placement / putting them in context within an AST.

The analysis function uses an AST visitor to visit each comment and attach it to the AST. It then uses that context to check:

  1. Is this comment in an expression?
  2. Does this comment have bad placement? (e.g. a # fmt: skip above a function instead of at the end of a line)
  3. Is this comment redundant?
  4. Does this comment actually suppress any code?
  5. Does this comment have ambiguous placement? (e.g. a # fmt: off above an else: block)

If any of these are true, a violation is thrown. The reported reason depends on the order of the above check-list: in other words, a # fmt: skip comment on its own line within a list expression will be reported as being in an expression, since that reason takes priority.

The lint suggests removing the comment as an unsafe fix, regardless of the reason.

Test Plan

A snapshot test has been created.

@snowsignal
Copy link
Contributor Author

snowsignal commented Feb 8, 2024

Draft Checklist

  • Snapshot test output isn't totally correct yet. We need to correctly resolving dangling comments at the end of indented bodies.
  • A few more edge cases need to be added to ensure that all permutations are accounted for.
  • We need to check if there's any other scenarios to report, and whether those need new error messages.

Copy link

codspeed-hq bot commented Feb 14, 2024

CodSpeed Performance Report

Merging #9899 will not alter performance

Comparing jane/formatter/useless-noqa (8fc186e) with main (36bc725)

Summary

✅ 30 untouched benchmarks

@snowsignal snowsignal marked this pull request as ready for review February 14, 2024 22:53
Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

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

Uhh, it seems there are many failing tests. I'm not sure what happened. It doesn't seem like you changed much on the formatter side.

@MichaReiser MichaReiser added rule Implementing or modifying a lint rule preview Related to preview mode features labels Feb 15, 2024
Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

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

Nice work. You make it look less complicated than it is. There are some perf opportunities and simplifications that we can do to the code. But there are also still a few cases that are not handled correctly which make it difficult to assess if other cases are handled correctly. We should have a look at those.

I played around with it in the playground and found a few cases that need improvement:

def body():
    # fmt: off
    test
    # fmt: on

    test2

The rule reports that the last fmt: on comment is unnecessary because formatting is already enabled. This is not the case, formatting was disabled

The rule reports that the `fmt: off` in the `if True` body is unused but that's a valid use. 

One check the rule doesn't cover today but I'm okay leaving to an extension is missing fmt: on comments to re-enable formatting without relying on the automatic re-enabling at the end of a block.

crates/ruff_linter/src/checkers/ast/analyze/module.rs Outdated Show resolved Hide resolved
crates/ruff_linter/src/checkers/noqa.rs Outdated Show resolved Hide resolved
crates/ruff_python_formatter/src/lib.rs Outdated Show resolved Hide resolved
crates/ruff_python_trivia/src/suppression.rs Outdated Show resolved Hide resolved
crates/ruff_python_trivia/src/suppression.rs Outdated Show resolved Hide resolved
Copy link
Contributor

github-actions bot commented Feb 23, 2024

ruff-ecosystem results

Linter (stable)

ℹ️ ecosystem check encountered linter errors. (no lint changes; 1 project error)

indico/indico (error)

ruff failed
  Cause: Rule `S410` was removed and cannot be selected.

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+2 -0 violations, +0 -0 fixes in 1 projects; 1 project error; 41 projects unchanged)

DisnakeDev/disnake (+2 -0 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

+ disnake/ext/commands/params.py:481:9: RUF028 This suppression comment is invalid because it cannot be in an expression, pattern, argument list, or other non-statement
+ disnake/ext/commands/params.py:498:9: RUF028 This suppression comment is invalid because it cannot be in an expression, pattern, argument list, or other non-statement

indico/indico (error)

ruff check --no-cache --exit-zero --ignore RUF9 --output-format concise --preview

ruff failed
  Cause: Rule `S410` was removed and cannot be selected.

Changes by rule (1 rules affected)

code total + violation - violation + fix - fix
RUF028 2 2 0 0 0

Formatter (stable)

ℹ️ ecosystem check encountered format errors. (no format changes; 2 project errors)

indico/indico (error)

ruff failed
  Cause: Rule `S410` was removed and cannot be selected.

openai/openai-cookbook (error)

warning: Detected debug build without --no-cache.
error: Failed to read examples/How_to_handle_rate_limits.ipynb: Expected a Jupyter Notebook, which must be internally stored as JSON, but this file isn't valid JSON: trailing comma at line 47 column 4

Formatter (preview)

ℹ️ ecosystem check encountered format errors. (no format changes; 2 project errors)

indico/indico (error)

ruff format --preview

ruff failed
  Cause: Rule `S410` was removed and cannot be selected.

openai/openai-cookbook (error)

ruff format --preview

warning: Detected debug build without --no-cache.
error: Failed to read examples/How_to_handle_rate_limits.ipynb: Expected a Jupyter Notebook, which must be internally stored as JSON, but this file isn't valid JSON: trailing comma at line 47 column 4

Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

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

I really like how you narrowed down the scope of the rule. This looks good to me. There's one issue around suppression comments in nodes that aren't expressions that we need solving but this is ready otherwise

@MichaReiser MichaReiser added this to the v0.3.0 milestone Feb 27, 2024
@snowsignal snowsignal enabled auto-merge (squash) February 28, 2024 19:15
@snowsignal snowsignal merged commit 0293908 into main Feb 28, 2024
17 checks passed
@snowsignal snowsignal deleted the jane/formatter/useless-noqa branch February 28, 2024 19:21
nkxxll pushed a commit to nkxxll/ruff that referenced this pull request Mar 10, 2024
…tral-sh#9899)

<!--
Thank you for contributing to Ruff! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->
Fixes astral-sh#6611

## Summary

This lint rule spots comments that are _intended_ to suppress or enable
the formatter, but will be ignored by the Ruff formatter.

We borrow some functions the formatter uses for determining comment
placement / putting them in context within an AST.

The analysis function uses an AST visitor to visit each comment and
attach it to the AST. It then uses that context to check:
1. Is this comment in an expression?
2. Does this comment have bad placement? (e.g. a `# fmt: skip` above a
function instead of at the end of a line)
3. Is this comment redundant?
4. Does this comment actually suppress any code?
5. Does this comment have ambiguous placement? (e.g. a `# fmt: off`
above an `else:` block)

If any of these are true, a violation is thrown. The reported reason
depends on the order of the above check-list: in other words, a `# fmt:
skip` comment on its own line within a list expression will be reported
as being in an expression, since that reason takes priority.

The lint suggests removing the comment as an unsafe fix, regardless of
the reason.

## Test Plan

A snapshot test has been created.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
preview Related to preview mode features rule Implementing or modifying a lint rule
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Warn about incorrect formatter suppression comments
2 participants