-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[perflint] Implement fix for manual-dict-comprehension (PERF403)
#16719
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
Merged
Merged
Changes from 15 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
8e5f474
add fix
w0nder1ng 170715f
finalize fix for PERF403 manual dict comprehension
w0nder1ng 97296f0
merge with main
w0nder1ng 874d7b5
fix test output
w0nder1ng 1b441a3
update PERF403 and PERF401 to work with `value = dict()` and `list()`
w0nder1ng 07753ff
update test output
w0nder1ng 720ff33
Merge remote-tracking branch 'origin' into perf403_fix
w0nder1ng 836d1c7
empty commit to rerun CI
w0nder1ng 3de805e
fix nits
w0nder1ng 791cae8
increase scope of feature gate
w0nder1ng 2c30bdf
modify comment ordering for both PERF401 and PERF403
w0nder1ng 8611782
add tests for relevant constraints
w0nder1ng 60dddb5
remove a `.expect()` and use Diagnostic::with_fix
w0nder1ng 6077aa3
Merge branch 'main' into perf403_fix
w0nder1ng 7085ea5
add debug_assert that target variable binding exists
w0nder1ng d3b7068
make fix return an Option
w0nder1ng 30bb035
remove unused anyhow import
w0nder1ng 22ab9c1
remove check that was affecting ecosystem results
w0nder1ng File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| use ruff_python_trivia::{ | ||
| BackwardsTokenizer, PythonWhitespace, SimpleToken, SimpleTokenKind, SimpleTokenizer, | ||
| }; | ||
| use ruff_source_file::LineRanges; | ||
| use ruff_text_size::{Ranged, TextRange}; | ||
|
|
||
| use crate::checkers::ast::Checker; | ||
|
|
||
| pub(super) fn comment_strings_in_range<'a>( | ||
| checker: &'a Checker, | ||
| range: TextRange, | ||
| ranges_to_ignore: &[TextRange], | ||
| ) -> Vec<&'a str> { | ||
| checker | ||
| .comment_ranges() | ||
| .comments_in_range(range) | ||
| .iter() | ||
| // Ignore comments inside of the append or iterator, since these are preserved | ||
| .filter(|comment| { | ||
| !ranges_to_ignore | ||
| .iter() | ||
| .any(|to_ignore| to_ignore.contains_range(**comment)) | ||
| }) | ||
| .map(|range| checker.locator().slice(range).trim_whitespace_start()) | ||
| .collect() | ||
| } | ||
|
|
||
| fn semicolon_before_and_after( | ||
| checker: &Checker, | ||
| statement: TextRange, | ||
| ) -> (Option<SimpleToken>, Option<SimpleToken>) { | ||
| // determine whether there's a semicolon either before or after the binding statement. | ||
| // Since it's a binding statement, we can just check whether there's a semicolon immediately | ||
| // after the whitespace in front of or behind it | ||
| let mut after_tokenizer = | ||
| SimpleTokenizer::starts_at(statement.end(), checker.locator().contents()).skip_trivia(); | ||
|
|
||
| let after_semicolon = if after_tokenizer | ||
| .next() | ||
| .is_some_and(|token| token.kind() == SimpleTokenKind::Semi) | ||
| { | ||
| after_tokenizer.next() | ||
| } else { | ||
| None | ||
| }; | ||
|
|
||
| let semicolon_before = BackwardsTokenizer::up_to( | ||
| statement.start(), | ||
| checker.locator().contents(), | ||
| checker.comment_ranges(), | ||
| ) | ||
| .skip_trivia() | ||
| .next() | ||
| .filter(|token| token.kind() == SimpleTokenKind::Semi); | ||
|
|
||
| (semicolon_before, after_semicolon) | ||
| } | ||
|
|
||
| /// Finds the range necessary to delete a statement (including any semicolons around it). | ||
| /// Returns the range and whether there were multiple statements on the line | ||
| pub(super) fn statement_deletion_range( | ||
| checker: &Checker, | ||
| statement_range: TextRange, | ||
| ) -> (TextRange, bool) { | ||
| let locator = checker.locator(); | ||
| // If the binding has multiple statements on its line, the fix would be substantially more complicated | ||
| let (semicolon_before, after_semicolon) = semicolon_before_and_after(checker, statement_range); | ||
|
|
||
| // If there are multiple binding statements in one line, we don't want to accidentally delete them | ||
| // Instead, we just delete the binding statement and leave any comments where they are | ||
|
|
||
| match (semicolon_before, after_semicolon) { | ||
| // ```python | ||
| // a = [] | ||
| // ``` | ||
| (None, None) => (locator.full_lines_range(statement_range), false), | ||
|
|
||
| // ```python | ||
| // a = 1; b = [] | ||
| // ^^^^^^^^ | ||
| // a = 1; b = []; c = 3 | ||
| // ^^^^^^^^ | ||
| // ``` | ||
| (Some(semicolon_before), Some(_) | None) => ( | ||
| TextRange::new(semicolon_before.start(), statement_range.end()), | ||
| true, | ||
| ), | ||
|
|
||
| // ```python | ||
| // a = []; b = 3 | ||
| // ^^^^^^^ | ||
| // ``` | ||
| (None, Some(after_semicolon)) => ( | ||
| TextRange::new(statement_range.start(), after_semicolon.start()), | ||
| true, | ||
| ), | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.