Skip to content

Commit

Permalink
Do not underline suggestions for code that is already there
Browse files Browse the repository at this point in the history
When a suggestion part is for already present code, do not highlight it. If after that there are no highlights left, do not show the suggestion at all.
  • Loading branch information
estebank committed Jul 18, 2024
1 parent 5753b30 commit 90baa6a
Show file tree
Hide file tree
Showing 11 changed files with 69 additions and 61 deletions.
22 changes: 20 additions & 2 deletions compiler/rustc_errors/src/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1774,7 +1774,10 @@ impl HumanEmitter {
debug!(?suggestions);

if suggestions.is_empty() {
// Suggestions coming from macros can have malformed spans. This is a heavy handed
// Here we check if there are suggestions that have actual code changes. We sometimes
// suggest the same code that is already there, instead of changing how we produce the
// suggestions and filtering there, we just don't emit the suggestion.
// Suggestions coming from macros can also have malformed spans. This is a heavy handed
// approach to avoid ICEs by ignoring the suggestion outright.
return Ok(());
}
Expand Down Expand Up @@ -2053,7 +2056,9 @@ impl HumanEmitter {
assert!(underline_start >= 0 && underline_end >= 0);
let padding: usize = max_line_num_len + 3;
for p in underline_start..underline_end {
if let DisplaySuggestion::Underline = show_code_change {
if let DisplaySuggestion::Underline = show_code_change
&& !is_no_change(sm, &part.snippet, part.span)
{
// If this is a replacement, underline with `~`, if this is an addition
// underline with `+`.
buffer.putc(
Expand Down Expand Up @@ -2799,6 +2804,19 @@ impl Style {
}
}

/// Whether the original and suggested code are the same.
pub fn is_no_change(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
// FIXME: this should probably be extended to also account for `FO0` → `FOO` and unicode.
let found = match sm.span_to_snippet(sp) {
Ok(snippet) => snippet,
Err(e) => {
warn!(error = ?e, "Invalid span {:?}", sp);
return false;
}
};
found == suggested
}

/// Whether the original and suggested code are visually similar enough to warrant extra wording.
pub fn is_case_difference(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
// FIXME: this should probably be extended to also account for `FO0` → `FOO` and unicode.
Expand Down
22 changes: 16 additions & 6 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub use snippet::Style;
// See https://github.com/rust-lang/rust/pull/115393.
pub use termcolor::{Color, ColorSpec, WriteColor};

use emitter::{is_case_difference, DynEmitter, Emitter};
use emitter::{is_case_difference, is_no_change, DynEmitter, Emitter};
use registry::Registry;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
Expand Down Expand Up @@ -359,10 +359,16 @@ impl CodeSuggestion {
_ => 1,
})
.sum();
line_highlight.push(SubstitutionHighlight {
start: (cur_lo.col.0 as isize + acc) as usize,
end: (cur_lo.col.0 as isize + acc + len) as usize,
});
if is_no_change(sm, &part.snippet, part.span) {
// Account for cases where we are suggesting the same code that's already
// there. This should happen often, but in some cases for multipart
// suggestions it's mut easier to handle it here than in the origin.
} else {
line_highlight.push(SubstitutionHighlight {
start: (cur_lo.col.0 as isize + acc) as usize,
end: (cur_lo.col.0 as isize + acc + len) as usize,
});
}
buf.push_str(&part.snippet);
let cur_hi = sm.lookup_char_pos(part.span.hi());
// Account for the difference between the width of the current code and the
Expand Down Expand Up @@ -394,7 +400,11 @@ impl CodeSuggestion {
while buf.ends_with('\n') {
buf.pop();
}
Some((buf, substitution.parts, highlights, only_capitalization))
if highlights.iter().all(|parts| parts.is_empty()) {
None
} else {
Some((buf, substitution.parts, highlights, only_capitalization))
}
})
.collect()
}
Expand Down
4 changes: 2 additions & 2 deletions src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ LL | let _val = None::<()>.expect("this always happens");
help: remove the `None` and `expect()`
|
LL | let _val = panic!("this always happens");
| ~~~~~~~ ~
| ~~~~~~~

error: used `unwrap_or_default()` on `None` value
--> tests/ui/unnecessary_literal_unwrap.rs:22:24
Expand Down Expand Up @@ -134,7 +134,7 @@ LL | None::<()>.expect("this always happens");
help: remove the `None` and `expect()`
|
LL | panic!("this always happens");
| ~~~~~~~ ~
| ~~~~~~~

error: used `unwrap_or_default()` on `None` value
--> tests/ui/unnecessary_literal_unwrap.rs:30:5
Expand Down
8 changes: 0 additions & 8 deletions src/tools/clippy/tests/ui/unnecessary_wraps.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,6 @@ LL | | }
LL | | }
| |_^
|
help: remove the return type...
|
LL | fn issue_6640_1(a: bool, b: bool) -> Option<()> {
| ~~~~~~~~~~
help: ...and then remove returned values
|
LL ~ return ;
Expand All @@ -143,10 +139,6 @@ LL | | }
LL | | }
| |_^
|
help: remove the return type...
|
LL | fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> {
| ~~~~~~~~~~~~~~~
help: ...and then remove returned values
|
LL ~ return ;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ error[E0282]: type annotations needed
LL | Combination::<0>.and::<_>().and::<_>();
| ^^^ cannot infer type of the type parameter `M` declared on the method `and`
|
help: consider specifying the generic argument
|
LL | Combination::<0>.and::<_>().and::<_>();
| ~~~~~

error: aborting due to 1 previous error

Expand Down
4 changes: 0 additions & 4 deletions tests/ui/imports/issue-55884-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ note: ...and refers to the struct `ParseOptions` which is defined here
|
LL | pub struct ParseOptions {}
| ^^^^^^^^^^^^^^^^^^^^^^^ you could import this directly
help: import `ParseOptions` through the re-export
|
LL | pub use parser::ParseOptions;
| ~~~~~~~~~~~~~~~~~~~~

error: aborting due to 1 previous error

Expand Down
38 changes: 19 additions & 19 deletions tests/ui/lint/wide_pointer_comparisons.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ LL | let _ = PartialEq::eq(&a, &b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = std::ptr::addr_eq(a, b);
| ~~~~~~~~~~~~~~~~~~ ~ ~
| ~~~~~~~~~~~~~~~~~~ ~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:35:13
Expand All @@ -85,7 +85,7 @@ LL | let _ = PartialEq::ne(&a, &b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = !std::ptr::addr_eq(a, b);
| ~~~~~~~~~~~~~~~~~~~ ~ ~
| ~~~~~~~~~~~~~~~~~~~ ~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:37:13
Expand All @@ -96,7 +96,7 @@ LL | let _ = a.eq(&b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = std::ptr::addr_eq(a, b);
| ++++++++++++++++++ ~ ~
| ++++++++++++++++++ ~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:39:13
Expand All @@ -107,7 +107,7 @@ LL | let _ = a.ne(&b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = !std::ptr::addr_eq(a, b);
| +++++++++++++++++++ ~ ~
| +++++++++++++++++++ ~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:41:13
Expand Down Expand Up @@ -283,7 +283,7 @@ LL | let _ = PartialEq::eq(a, b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = std::ptr::addr_eq(*a, *b);
| ~~~~~~~~~~~~~~~~~~~ ~~~ ~
| ~~~~~~~~~~~~~~~~~~~ ~~~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:85:17
Expand All @@ -294,7 +294,7 @@ LL | let _ = PartialEq::ne(a, b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = !std::ptr::addr_eq(*a, *b);
| ~~~~~~~~~~~~~~~~~~~~ ~~~ ~
| ~~~~~~~~~~~~~~~~~~~~ ~~~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:87:17
Expand All @@ -305,7 +305,7 @@ LL | let _ = PartialEq::eq(&a, &b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = std::ptr::addr_eq(*a, *b);
| ~~~~~~~~~~~~~~~~~~~ ~~~ ~
| ~~~~~~~~~~~~~~~~~~~ ~~~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:89:17
Expand All @@ -316,7 +316,7 @@ LL | let _ = PartialEq::ne(&a, &b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = !std::ptr::addr_eq(*a, *b);
| ~~~~~~~~~~~~~~~~~~~~ ~~~ ~
| ~~~~~~~~~~~~~~~~~~~~ ~~~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:91:17
Expand All @@ -327,7 +327,7 @@ LL | let _ = a.eq(b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = std::ptr::addr_eq(*a, *b);
| +++++++++++++++++++ ~~~ ~
| +++++++++++++++++++ ~~~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:93:17
Expand All @@ -338,7 +338,7 @@ LL | let _ = a.ne(b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = !std::ptr::addr_eq(*a, *b);
| ++++++++++++++++++++ ~~~ ~
| ++++++++++++++++++++ ~~~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:95:17
Expand Down Expand Up @@ -519,11 +519,11 @@ LL | let _ = PartialEq::eq(&a, &b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = std::ptr::addr_eq(a, b);
| ~~~~~~~~~~~~~~~~~~ ~ ~
| ~~~~~~~~~~~~~~~~~~ ~
help: use explicit `std::ptr::eq` method to compare metadata and addresses
|
LL | let _ = std::ptr::eq(a, b);
| ~~~~~~~~~~~~~ ~ ~
| ~~~~~~~~~~~~~ ~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:133:17
Expand All @@ -534,11 +534,11 @@ LL | let _ = PartialEq::ne(&a, &b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = !std::ptr::addr_eq(a, b);
| ~~~~~~~~~~~~~~~~~~~ ~ ~
| ~~~~~~~~~~~~~~~~~~~ ~
help: use explicit `std::ptr::eq` method to compare metadata and addresses
|
LL | let _ = !std::ptr::eq(a, b);
| ~~~~~~~~~~~~~~ ~ ~
| ~~~~~~~~~~~~~~ ~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:135:17
Expand All @@ -549,11 +549,11 @@ LL | let _ = a.eq(&b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = std::ptr::addr_eq(a, b);
| ++++++++++++++++++ ~ ~
| ++++++++++++++++++ ~
help: use explicit `std::ptr::eq` method to compare metadata and addresses
|
LL | let _ = std::ptr::eq(a, b);
| +++++++++++++ ~ ~
| +++++++++++++ ~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:137:17
Expand All @@ -564,11 +564,11 @@ LL | let _ = a.ne(&b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | let _ = !std::ptr::addr_eq(a, b);
| +++++++++++++++++++ ~ ~
| +++++++++++++++++++ ~
help: use explicit `std::ptr::eq` method to compare metadata and addresses
|
LL | let _ = !std::ptr::eq(a, b);
| ++++++++++++++ ~ ~
| ++++++++++++++ ~

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:142:9
Expand All @@ -594,7 +594,7 @@ LL | cmp!(a, b);
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | cmp!(std::ptr::addr_eq(a, b));
| ++++++++++++++++++ ~ +
| ++++++++++++++++++ +

warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:159:39
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/privacy/issue-75907.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ LL | let Bar(x, y, Foo(z)) = make_bar();
help: consider making the fields publicly accessible
|
LL | pub(crate) struct Bar(pub u8, pub u8, pub Foo);
| ~~~ ~~~ +++
| ~~~ +++

error[E0532]: cannot match against a tuple struct which contains private fields
--> $DIR/issue-75907.rs:15:19
Expand Down
Loading

0 comments on commit 90baa6a

Please sign in to comment.