From 8d4d572e4d8e41f9963dad997214a54df05baabf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 14 Feb 2024 19:18:28 +0000 Subject: [PATCH] Fix msg for verbose suggestions with confusable capitalization When encountering a verbose/multipart suggestion that has changes that are only caused by different capitalization of ASCII letters that have little differenciation, expand the message to highlight that fact (like we already do for inline suggestions). The logic to do this was already present, but implemented incorrectly. --- compiler/rustc_errors/src/emitter.rs | 19 ++++++++++--------- compiler/rustc_errors/src/lib.rs | 3 ++- .../tests/ui/match_str_case_mismatch.stderr | 2 +- tests/ui/error-codes/E0423.stderr | 2 +- tests/ui/parser/kw-in-trait-bounds.stderr | 8 ++++---- .../recover-fn-trait-from-fn-kw.stderr | 4 ++-- .../typod-const-in-const-param-def.stderr | 8 ++++---- .../assoc-ct-for-assoc-method.stderr | 2 +- .../suggestions/bool_typo_err_suggest.stderr | 2 +- 9 files changed, 26 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index b9e92dbb31c64..edcc23db6de35 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1742,9 +1742,17 @@ impl HumanEmitter { buffer.append(0, level.to_str(), Style::Level(*level)); buffer.append(0, ": ", Style::HeaderMsg); + let mut msg = vec![(suggestion.msg.to_owned(), Style::NoStyle)]; + if suggestions + .iter() + .take(MAX_SUGGESTIONS) + .any(|(_, _, _, only_capitalization)| *only_capitalization) + { + msg.push((" (notice the capitalization difference)".into(), Style::NoStyle)); + } self.msgs_to_buffer( &mut buffer, - &[(suggestion.msg.to_owned(), Style::NoStyle)], + &msg, args, max_line_num_len, "suggestion", @@ -1753,12 +1761,8 @@ impl HumanEmitter { let mut row_num = 2; draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1); - let mut notice_capitalization = false; - for (complete, parts, highlights, only_capitalization) in - suggestions.iter().take(MAX_SUGGESTIONS) - { + for (complete, parts, highlights, _) in suggestions.iter().take(MAX_SUGGESTIONS) { debug!(?complete, ?parts, ?highlights); - notice_capitalization |= only_capitalization; let has_deletion = parts.iter().any(|p| p.is_deletion(sm)); let is_multiline = complete.lines().count() > 1; @@ -2057,9 +2061,6 @@ impl HumanEmitter { let others = suggestions.len() - MAX_SUGGESTIONS; let msg = format!("and {} other candidate{}", others, pluralize!(others)); buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle); - } else if notice_capitalization { - let msg = "notice the capitalization difference"; - buffer.puts(row_num, max_line_num_len + 3, msg, Style::NoStyle); } emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; Ok(()) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index da9ef6627beae..2a0eddf6a0f32 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -319,7 +319,9 @@ impl CodeSuggestion { // We need to keep track of the difference between the existing code and the added // or deleted code in order to point at the correct column *after* substitution. let mut acc = 0; + let mut only_capitalization = false; for part in &substitution.parts { + only_capitalization |= is_case_difference(sm, &part.snippet, part.span); let cur_lo = sm.lookup_char_pos(part.span.lo()); if prev_hi.line == cur_lo.line { let mut count = @@ -392,7 +394,6 @@ impl CodeSuggestion { } } highlights.push(std::mem::take(&mut line_highlight)); - let only_capitalization = is_case_difference(sm, &buf, bounding_span); // if the replacement already ends with a newline, don't print the next line if !buf.ends_with('\n') { push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None); diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr index f799a4698b943..b178fb7512cdb 100644 --- a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr +++ b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr @@ -17,7 +17,7 @@ error: this `match` arm has a differing case than its expression LL | "~!@#$%^&*()-_=+Foo" => {}, | ^^^^^^^^^^^^^^^^^^^^ | -help: consider changing the case of this arm to respect `to_ascii_lowercase` +help: consider changing the case of this arm to respect `to_ascii_lowercase` (notice the capitalization difference) | LL | "~!@#$%^&*()-_=+foo" => {}, | ~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/ui/error-codes/E0423.stderr b/tests/ui/error-codes/E0423.stderr index ac70d905d353f..dd7a5b034c587 100644 --- a/tests/ui/error-codes/E0423.stderr +++ b/tests/ui/error-codes/E0423.stderr @@ -53,7 +53,7 @@ help: use struct literal syntax instead | LL | let f = Foo { a: val }; | ~~~~~~~~~~~~~~ -help: a function with a similar name exists +help: a function with a similar name exists (notice the capitalization difference) | LL | let f = foo(); | ~~~ diff --git a/tests/ui/parser/kw-in-trait-bounds.stderr b/tests/ui/parser/kw-in-trait-bounds.stderr index 2d3aad4d6baf4..3c54e03195031 100644 --- a/tests/ui/parser/kw-in-trait-bounds.stderr +++ b/tests/ui/parser/kw-in-trait-bounds.stderr @@ -4,7 +4,7 @@ error: expected identifier, found keyword `fn` LL | fn _f(_: impl fn(), _: &dyn fn()) | ^^ | -help: use `Fn` to refer to the trait +help: use `Fn` to refer to the trait (notice the capitalization difference) | LL | fn _f(_: impl fn(), _: &dyn fn()) | ~~ @@ -15,7 +15,7 @@ error: expected identifier, found keyword `fn` LL | fn _f(_: impl fn(), _: &dyn fn()) | ^^ | -help: use `Fn` to refer to the trait +help: use `Fn` to refer to the trait (notice the capitalization difference) | LL | fn _f(_: impl Fn(), _: &dyn fn()) | ~~ @@ -26,7 +26,7 @@ error: expected identifier, found keyword `fn` LL | fn _f(_: impl fn(), _: &dyn fn()) | ^^ | -help: use `Fn` to refer to the trait +help: use `Fn` to refer to the trait (notice the capitalization difference) | LL | fn _f(_: impl fn(), _: &dyn Fn()) | ~~ @@ -37,7 +37,7 @@ error: expected identifier, found keyword `fn` LL | G: fn(), | ^^ | -help: use `Fn` to refer to the trait +help: use `Fn` to refer to the trait (notice the capitalization difference) | LL | G: Fn(), | ~~ diff --git a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr index 17138a6f07921..aee31d08fe0ec 100644 --- a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr +++ b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr @@ -4,7 +4,7 @@ error: expected identifier, found keyword `fn` LL | fn foo(_: impl fn() -> i32) {} | ^^ | -help: use `Fn` to refer to the trait +help: use `Fn` to refer to the trait (notice the capitalization difference) | LL | fn foo(_: impl Fn() -> i32) {} | ~~ @@ -15,7 +15,7 @@ error: expected identifier, found keyword `fn` LL | fn foo2(_: T) {} | ^^ | -help: use `Fn` to refer to the trait +help: use `Fn` to refer to the trait (notice the capitalization difference) | LL | fn foo2(_: T) {} | ~~ diff --git a/tests/ui/parser/typod-const-in-const-param-def.stderr b/tests/ui/parser/typod-const-in-const-param-def.stderr index 75d73c6ea878a..80c0f1deae6fe 100644 --- a/tests/ui/parser/typod-const-in-const-param-def.stderr +++ b/tests/ui/parser/typod-const-in-const-param-def.stderr @@ -4,7 +4,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn foo() {} | ^^^^^ | -help: use the `const` keyword +help: use the `const` keyword (notice the capitalization difference) | LL | pub fn foo() {} | ~~~~~ @@ -15,7 +15,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn baz() {} | ^^^^^ | -help: use the `const` keyword +help: use the `const` keyword (notice the capitalization difference) | LL | pub fn baz() {} | ~~~~~ @@ -26,7 +26,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn qux() {} | ^^^^^ | -help: use the `const` keyword +help: use the `const` keyword (notice the capitalization difference) | LL | pub fn qux() {} | ~~~~~ @@ -37,7 +37,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn quux() {} | ^^^^^ | -help: use the `const` keyword +help: use the `const` keyword (notice the capitalization difference) | LL | pub fn quux() {} | ~~~~~ diff --git a/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr b/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr index 211cb1584ad7b..8f00a72f1e81a 100644 --- a/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr +++ b/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr @@ -8,7 +8,7 @@ LL | let x: i32 = MyS::foo; | = note: expected type `i32` found fn item `fn() -> MyS {MyS::foo}` -help: try referring to the associated const `FOO` instead +help: try referring to the associated const `FOO` instead (notice the capitalization difference) | LL | let x: i32 = MyS::FOO; | ~~~ diff --git a/tests/ui/suggestions/bool_typo_err_suggest.stderr b/tests/ui/suggestions/bool_typo_err_suggest.stderr index 52bde07ca0770..8d59ed63e5432 100644 --- a/tests/ui/suggestions/bool_typo_err_suggest.stderr +++ b/tests/ui/suggestions/bool_typo_err_suggest.stderr @@ -15,7 +15,7 @@ error[E0425]: cannot find value `False` in this scope LL | let y = False; | ^^^^^ not found in this scope | -help: you may want to use a bool value instead +help: you may want to use a bool value instead (notice the capitalization difference) | LL | let y = false; | ~~~~~