diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 73908e5808569..8963b009c31ec 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1767,7 +1767,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(()); } @@ -2046,7 +2049,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_different(sm, &part.snippet, part.span) + { // If this is a replacement, underline with `~`, if this is an addition // underline with `+`. buffer.putc( @@ -2824,6 +2829,18 @@ impl Style { } } +/// Whether the original and suggested code are the same. +pub fn is_different(sm: &SourceMap, suggested: &str, sp: Span) -> bool { + let found = match sm.span_to_snippet(sp) { + Ok(snippet) => snippet, + Err(e) => { + warn!(error = ?e, "Invalid span {:?}", sp); + return true; + } + }; + 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. diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 09855394cdb2b..ceebcd46a6f7f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -50,7 +50,7 @@ pub use diagnostic_impls::{ IndicateAnonymousLifetime, SingleLabelManySpans, }; pub use emitter::ColorConfig; -use emitter::{is_case_difference, DynEmitter, Emitter}; +use emitter::{is_case_difference, is_different, DynEmitter, Emitter}; use registry::Registry; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; @@ -357,10 +357,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_different(sm, &part.snippet, part.span) { + // Account for cases where we are suggesting the same code that's already + // there. This shouldn't happen often, but in some cases for multipart + // suggestions it's much 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 @@ -392,7 +398,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() } diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs index e4e7f7d06e706..080efe983c2a8 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -145,7 +145,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { ( "this function's return value is unnecessary".to_string(), "remove the return type...".to_string(), - snippet(cx, fn_decl.output.span(), "..").to_string(), + // FIXME: we should instead get the span including the `->` and suggest an + // empty string for this case. + "()".to_string(), "...and then remove returned values", ) } else { diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr index 15708090361ed..37ee9195fce66 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr @@ -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 @@ -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 diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr index a55a23d449f57..59986d895b30e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr @@ -118,8 +118,8 @@ LL | | } | help: remove the return type... | -LL | fn issue_6640_1(a: bool, b: bool) -> Option<()> { - | ~~~~~~~~~~ +LL | fn issue_6640_1(a: bool, b: bool) -> () { + | ~~ help: ...and then remove returned values | LL ~ return ; @@ -145,8 +145,8 @@ LL | | } | help: remove the return type... | -LL | fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> { - | ~~~~~~~~~~~~~~~ +LL | fn issue_6640_2(a: bool, b: bool) -> () { + | ~~ help: ...and then remove returned values | LL ~ return ; diff --git a/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr b/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr index 09b618fb3f050..1c97eaddfe1bb 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-105608.stderr @@ -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 diff --git a/tests/ui/imports/issue-55884-2.stderr b/tests/ui/imports/issue-55884-2.stderr index 8a9d5f2a6d8a6..0d4f01aeafc64 100644 --- a/tests/ui/imports/issue-55884-2.stderr +++ b/tests/ui/imports/issue-55884-2.stderr @@ -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 diff --git a/tests/ui/lint/wide_pointer_comparisons.stderr b/tests/ui/lint/wide_pointer_comparisons.stderr index 81a221c0ee640..7fe382393d7e1 100644 --- a/tests/ui/lint/wide_pointer_comparisons.stderr +++ b/tests/ui/lint/wide_pointer_comparisons.stderr @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/tests/ui/privacy/issue-75907.stderr b/tests/ui/privacy/issue-75907.stderr index f7cb874c2cc0d..3121cc04478a4 100644 --- a/tests/ui/privacy/issue-75907.stderr +++ b/tests/ui/privacy/issue-75907.stderr @@ -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 diff --git a/tests/ui/privacy/privacy5.stderr b/tests/ui/privacy/privacy5.stderr index 615b0af2762d3..ec3abe9b81629 100644 --- a/tests/ui/privacy/privacy5.stderr +++ b/tests/ui/privacy/privacy5.stderr @@ -53,7 +53,7 @@ LL | pub struct C(pub isize, isize); help: consider making the fields publicly accessible | LL | pub struct C(pub isize, pub isize); - | ~~~ +++ + | +++ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:56:12 @@ -262,7 +262,7 @@ LL | pub struct C(pub isize, isize); help: consider making the fields publicly accessible | LL | pub struct C(pub isize, pub isize); - | ~~~ +++ + | +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:69:12 @@ -281,7 +281,7 @@ LL | pub struct C(pub isize, isize); help: consider making the fields publicly accessible | LL | pub struct C(pub isize, pub isize); - | ~~~ +++ + | +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:70:12 @@ -300,7 +300,7 @@ LL | pub struct C(pub isize, isize); help: consider making the fields publicly accessible | LL | pub struct C(pub isize, pub isize); - | ~~~ +++ + | +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:71:12 @@ -319,7 +319,7 @@ LL | pub struct C(pub isize, isize); help: consider making the fields publicly accessible | LL | pub struct C(pub isize, pub isize); - | ~~~ +++ + | +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:72:18 @@ -338,7 +338,7 @@ LL | pub struct C(pub isize, isize); help: consider making the fields publicly accessible | LL | pub struct C(pub isize, pub isize); - | ~~~ +++ + | +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:73:18 @@ -357,7 +357,7 @@ LL | pub struct C(pub isize, isize); help: consider making the fields publicly accessible | LL | pub struct C(pub isize, pub isize); - | ~~~ +++ + | +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:74:18 @@ -376,7 +376,7 @@ LL | pub struct C(pub isize, isize); help: consider making the fields publicly accessible | LL | pub struct C(pub isize, pub isize); - | ~~~ +++ + | +++ error[E0603]: tuple struct constructor `C` is private --> $DIR/privacy5.rs:75:18 @@ -395,7 +395,7 @@ LL | pub struct C(pub isize, isize); help: consider making the fields publicly accessible | LL | pub struct C(pub isize, pub isize); - | ~~~ +++ + | +++ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:83:17 @@ -452,7 +452,7 @@ LL | pub struct C(pub isize, isize); help: consider making the fields publicly accessible | LL | pub struct C(pub isize, pub isize); - | ~~~ +++ + | +++ error[E0603]: tuple struct constructor `A` is private --> $DIR/privacy5.rs:90:20 diff --git a/tests/ui/span/issue-42234-unknown-receiver-type.full.stderr b/tests/ui/span/issue-42234-unknown-receiver-type.full.stderr index e01e1edab5aa6..6559845c23ec5 100644 --- a/tests/ui/span/issue-42234-unknown-receiver-type.full.stderr +++ b/tests/ui/span/issue-42234-unknown-receiver-type.full.stderr @@ -17,10 +17,6 @@ error[E0282]: type annotations needed LL | .sum::<_>() | ^^^ cannot infer type of the type parameter `S` declared on the method `sum` | -help: consider specifying the generic argument - | -LL | .sum::<_>() - | ~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/recover-missing-turbofish-surrounding-angle-braket.stderr b/tests/ui/suggestions/recover-missing-turbofish-surrounding-angle-braket.stderr index 618ccba0d3d12..dde6060c4334b 100644 --- a/tests/ui/suggestions/recover-missing-turbofish-surrounding-angle-braket.stderr +++ b/tests/ui/suggestions/recover-missing-turbofish-surrounding-angle-braket.stderr @@ -40,7 +40,7 @@ LL | let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>(); help: surround the type parameters with angle brackets | LL | let _ = vec![1, 2, 3].into_iter().collect::>(); - | + ~ + | + error: aborting due to 4 previous errors