-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Duplicated functionnality for parsing comments #9701
Comments
|
flip1995
pushed a commit
to flip1995/rust
that referenced
this issue
Dec 29, 2022
…Jarcho Improve `possible_borrower` This PR makes several improvements to `clippy_uitls::mir::possible_borrower`. These changes benefit both `needless_borrow` and `redundant clone`. 1. **Use the compiler's `MaybeStorageLive` analysis** I could spot not functional differences between the one in the compiler and the one in Clippy's repository. So, I removed the latter in favor of the the former. 2. **Make `PossibleBorrower` a dataflow analysis instead of a visitor** The main benefit of this change is that allows `possible_borrower` to take advantage of statements' relative locations, which is easier to do in an analysis than in a visitor. This is easier to illustrate with an example, so consider this one: ```rust fn foo(cx: &LateContext<'_>, lint: &'static Lint) { cx.struct_span_lint(lint, rustc_span::Span::default(), "", |diag| diag.note(&String::new())); // ^ } ``` We would like to flag the `&` pointed to by the `^` for removal. `foo`'s MIR begins like this: ```rust fn span_lint::foo::{closure#0}(_1: [closure@$DIR/needless_borrow.rs:396:68: 396:74], _2: &mut rustc_errors::diagnostic_builder::DiagnosticBuilder<'_, ()>) -> &mut rustc_errors::diagnostic_builder::DiagnosticBuilder<'_, ()> { debug diag => _2; // in scope 0 at $DIR/needless_borrow.rs:396:69: 396:73 let mut _0: &mut rustc_errors::diagnostic_builder::DiagnosticBuilder<'_, ()>; // return place in scope 0 at $DIR/needless_borrow.rs:396:75: 396:75 let mut _3: &mut rustc_errors::diagnostic_builder::DiagnosticBuilder<'_, ()>; // in scope 0 at $DIR/needless_borrow.rs:396:75: 396:100 let mut _4: &mut rustc_errors::diagnostic_builder::DiagnosticBuilder<'_, ()>; // in scope 0 at $DIR/needless_borrow.rs:396:75: 396:100 let mut _5: &std::string::String; // in scope 0 at $DIR/needless_borrow.rs:396:85: 396:99 let _6: std::string::String; // in scope 0 at $DIR/needless_borrow.rs:396:86: 396:99 bb0: { StorageLive(_3); // scope 0 at $DIR/needless_borrow.rs:396:75: 396:100 StorageLive(_4); // scope 0 at $DIR/needless_borrow.rs:396:75: 396:100 _4 = &mut (*_2); // scope 0 at $DIR/needless_borrow.rs:396:75: 396:100 StorageLive(_5); // scope 0 at $DIR/needless_borrow.rs:396:85: 396:99 StorageLive(_6); // scope 0 at $DIR/needless_borrow.rs:396:86: 396:99 _6 = std::string::String::new() -> bb1; // scope 0 at $DIR/needless_borrow.rs:396:86: 396:99 // mir::Constant // + span: $DIR/needless_borrow.rs:396:86: 396:97 // + literal: Const { ty: fn() -> std::string::String {std::string::String::new}, val: Value(<ZST>) } } bb1: { _5 = &_6; // scope 0 at $DIR/needless_borrow.rs:396:85: 396:99 _3 = rustc_errors::diagnostic_builder::DiagnosticBuilder::<'_, ()>::note::<&std::string::String>(move _4, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/needless_borrow.rs:396:75: 396:100 // mir::Constant // + span: $DIR/needless_borrow.rs:396:80: 396:84 // + literal: Const { ty: for<'a> fn(&'a mut rustc_errors::diagnostic_builder::DiagnosticBuilder<'_, ()>, &std::string::String) -> &'a mut rustc_errors::diagnostic_builder::DiagnosticBuilder<'_, ()> {rustc_errors::diagnostic_builder::DiagnosticBuilder::<'_, ()>::note::<&std::string::String>}, val: Value(<ZST>) } } ``` The call to `diag.note` appears in `bb1` on the line beginning with `_3 =`. The `String` is owned by `_6`. So, in the call to `diag.note`, we would like to know whether there are any references to `_6` besides `_5`. The old, visitor approach did not consider the relative locations of statements. So all borrows were treated the same, *even if they occurred after the location of interest*. For example, before the `_3 = ...` call, the possible borrowers of `_6` would be just `_5`. But after the call, the possible borrowers would include `_2`, `_3`, and `_4`. So, in a sense, the call from which we are try to remove the needless borrow is trying to prevent us from removing the needless borrow(!). With an analysis, things do not get so muddled. We can determine the set of possible borrowers at any specific location, e.g., using a `ResultsCursor`. 3. **Change `only_borrowers` to `at_most_borrowers`** `possible_borrowers` exposed a function `only_borrowers` that determined whether the borrowers of some local were *exactly* some set `S`. But, from what I can tell, this was overkill. For the lints that currently use `possible_borrower` (`needless_borrow` and `redundant_clone`), all we really want to know is whether there are borrowers *other than* those in `S`. (Put another way, we only care about the subset relation in one direction.) The new function `at_most_borrowers` takes this more tailored approach. 4. **Compute relations "on the fly" rather than using `transitive_relation`** The visitor would compute and store the transitive closure of the possible borrower relation for an entire MIR body. But with an analysis, there is effectively a different possible borrower relation at each location in the body. Computing and storing a transitive closure at each location would not be practical. So the new approach is to compute the transitive closure on the fly, as needed. But the new approach might actually be more efficient, as I now explain. In all current uses of `at_most_borrowers` (previously `only_borrowers`), the size of the set of borrowers `S` is at most 2. So you need only check at most three borrowers to determine whether the subset relation holds. That is, once you have found a third borrower, you can stop, since you know the relation cannot hold. Note that `transitive_relation` is still used by `clippy_uitls::mir::possible_origin` (a kind of "subroutine" of `possible_borrower`). cc: `@Jarcho` --- changelog: [`needless_borrow`], [`redundant_clone`]: Now track references better and detect more cases [rust-lang#9701](rust-lang/rust-clippy#9701) <!-- changelog_checked -->
flip1995
pushed a commit
to flip1995/rust
that referenced
this issue
Jan 12, 2023
Partially revert rust-lang#9701 This partially reverts rust-lang#9701 due to rust-lang#10134 r? `@flip1995` changelog: None
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey there
Reading the parsing code to try to fix #9468, I noticed there was some redundancies in the code.
The logic for parsing comments is fully implemented in
libsyntax/parse/comments.rs
, but doesn't seem to be used out of the pretty printer (https://github.com/mozilla/rust/blob/master/src/libsyntax/parse/comments.rs#L344).The same logic is also implemented in
libsyntax/parse/lexer.rs
. The implementations don't seem to share code, and have some different features (comments.rs supports nested block comments while lexer.rs does not).They probably should be merged.
I'm new to rust, and I'm a little afraid to touch this problem. The two implementations looks like they have different goals, and I fear I might not have the kind of insight required to that kind of refactoring.
The text was updated successfully, but these errors were encountered: