Skip to content

Commit 8ce8c42

Browse files
committed
Do not underline suggestions for code that is already there
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. Fix clippy lint suggestion incorrectly treated as `span_help`.
1 parent e60ebb2 commit 8ce8c42

12 files changed

+75
-58
lines changed

compiler/rustc_errors/src/emitter.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -1767,7 +1767,10 @@ impl HumanEmitter {
17671767
debug!(?suggestions);
17681768

17691769
if suggestions.is_empty() {
1770-
// Suggestions coming from macros can have malformed spans. This is a heavy handed
1770+
// Here we check if there are suggestions that have actual code changes. We sometimes
1771+
// suggest the same code that is already there, instead of changing how we produce the
1772+
// suggestions and filtering there, we just don't emit the suggestion.
1773+
// Suggestions coming from macros can also have malformed spans. This is a heavy handed
17711774
// approach to avoid ICEs by ignoring the suggestion outright.
17721775
return Ok(());
17731776
}
@@ -2046,7 +2049,9 @@ impl HumanEmitter {
20462049
assert!(underline_start >= 0 && underline_end >= 0);
20472050
let padding: usize = max_line_num_len + 3;
20482051
for p in underline_start..underline_end {
2049-
if let DisplaySuggestion::Underline = show_code_change {
2052+
if let DisplaySuggestion::Underline = show_code_change
2053+
&& is_different(sm, &part.snippet, part.span)
2054+
{
20502055
// If this is a replacement, underline with `~`, if this is an addition
20512056
// underline with `+`.
20522057
buffer.putc(
@@ -2824,6 +2829,18 @@ impl Style {
28242829
}
28252830
}
28262831

2832+
/// Whether the original and suggested code are the same.
2833+
pub fn is_different(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
2834+
let found = match sm.span_to_snippet(sp) {
2835+
Ok(snippet) => snippet,
2836+
Err(e) => {
2837+
warn!(error = ?e, "Invalid span {:?}", sp);
2838+
return true;
2839+
}
2840+
};
2841+
found != suggested
2842+
}
2843+
28272844
/// Whether the original and suggested code are visually similar enough to warrant extra wording.
28282845
pub fn is_case_difference(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
28292846
// FIXME: this should probably be extended to also account for `FO0` → `FOO` and unicode.

compiler/rustc_errors/src/lib.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub use diagnostic_impls::{
5050
IndicateAnonymousLifetime, SingleLabelManySpans,
5151
};
5252
pub use emitter::ColorConfig;
53-
use emitter::{is_case_difference, DynEmitter, Emitter};
53+
use emitter::{is_case_difference, is_different, DynEmitter, Emitter};
5454
use registry::Registry;
5555
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
5656
use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
@@ -357,10 +357,16 @@ impl CodeSuggestion {
357357
_ => 1,
358358
})
359359
.sum();
360-
line_highlight.push(SubstitutionHighlight {
361-
start: (cur_lo.col.0 as isize + acc) as usize,
362-
end: (cur_lo.col.0 as isize + acc + len) as usize,
363-
});
360+
if !is_different(sm, &part.snippet, part.span) {
361+
// Account for cases where we are suggesting the same code that's already
362+
// there. This shouldn't happen often, but in some cases for multipart
363+
// suggestions it's much easier to handle it here than in the origin.
364+
} else {
365+
line_highlight.push(SubstitutionHighlight {
366+
start: (cur_lo.col.0 as isize + acc) as usize,
367+
end: (cur_lo.col.0 as isize + acc + len) as usize,
368+
});
369+
}
364370
buf.push_str(&part.snippet);
365371
let cur_hi = sm.lookup_char_pos(part.span.hi());
366372
// Account for the difference between the width of the current code and the
@@ -392,7 +398,11 @@ impl CodeSuggestion {
392398
while buf.ends_with('\n') {
393399
buf.pop();
394400
}
395-
Some((buf, substitution.parts, highlights, only_capitalization))
401+
if highlights.iter().all(|parts| parts.is_empty()) {
402+
None
403+
} else {
404+
Some((buf, substitution.parts, highlights, only_capitalization))
405+
}
396406
})
397407
.collect()
398408
}

src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
145145
(
146146
"this function's return value is unnecessary".to_string(),
147147
"remove the return type...".to_string(),
148-
snippet(cx, fn_decl.output.span(), "..").to_string(),
148+
// FIXME: we should instead get the span including the `->` and suggest an
149+
// empty string for this case.
150+
"()".to_string(),
149151
"...and then remove returned values",
150152
)
151153
} else {

src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ LL | let _val = None::<()>.expect("this always happens");
6363
help: remove the `None` and `expect()`
6464
|
6565
LL | let _val = panic!("this always happens");
66-
| ~~~~~~~ ~
66+
| ~~~~~~~
6767

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

139139
error: used `unwrap_or_default()` on `None` value
140140
--> tests/ui/unnecessary_literal_unwrap.rs:30:5

src/tools/clippy/tests/ui/unnecessary_wraps.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ LL | | }
118118
|
119119
help: remove the return type...
120120
|
121-
LL | fn issue_6640_1(a: bool, b: bool) -> Option<()> {
122-
| ~~~~~~~~~~
121+
LL | fn issue_6640_1(a: bool, b: bool) -> () {
122+
| ~~
123123
help: ...and then remove returned values
124124
|
125125
LL ~ return ;
@@ -145,8 +145,8 @@ LL | | }
145145
|
146146
help: remove the return type...
147147
|
148-
LL | fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> {
149-
| ~~~~~~~~~~~~~~~
148+
LL | fn issue_6640_2(a: bool, b: bool) -> () {
149+
| ~~
150150
help: ...and then remove returned values
151151
|
152152
LL ~ return ;

tests/ui/const-generics/generic_const_exprs/issue-105608.stderr

-4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@ error[E0282]: type annotations needed
44
LL | Combination::<0>.and::<_>().and::<_>();
55
| ^^^ cannot infer type of the type parameter `M` declared on the method `and`
66
|
7-
help: consider specifying the generic argument
8-
|
9-
LL | Combination::<0>.and::<_>().and::<_>();
10-
| ~~~~~
117

128
error: aborting due to 1 previous error
139

tests/ui/imports/issue-55884-2.stderr

-4
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@ note: ...and refers to the struct `ParseOptions` which is defined here
2424
|
2525
LL | pub struct ParseOptions {}
2626
| ^^^^^^^^^^^^^^^^^^^^^^^ you could import this directly
27-
help: import `ParseOptions` through the re-export
28-
|
29-
LL | pub use parser::ParseOptions;
30-
| ~~~~~~~~~~~~~~~~~~~~
3127

3228
error: aborting due to 1 previous error
3329

tests/ui/lint/wide_pointer_comparisons.stderr

+19-19
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ LL | let _ = PartialEq::eq(&a, &b);
7474
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
7575
|
7676
LL | let _ = std::ptr::addr_eq(a, b);
77-
| ~~~~~~~~~~~~~~~~~~ ~ ~
77+
| ~~~~~~~~~~~~~~~~~~ ~
7878

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

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

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

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

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

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

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

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

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

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

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

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

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

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

599599
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
600600
--> $DIR/wide_pointer_comparisons.rs:159:39

tests/ui/privacy/issue-75907.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ LL | let Bar(x, y, Foo(z)) = make_bar();
1414
help: consider making the fields publicly accessible
1515
|
1616
LL | pub(crate) struct Bar(pub u8, pub u8, pub Foo);
17-
| ~~~ ~~~ +++
17+
| ~~~ +++
1818

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

0 commit comments

Comments
 (0)