Use heuristics for capitalization warning in suggestions
This commit is contained in:
parent
4bb771615e
commit
6dd718ca79
13 changed files with 37 additions and 24 deletions
|
@ -13,7 +13,7 @@ use syntax_pos::{SourceFile, Span, MultiSpan};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Level, CodeSuggestion, Diagnostic, SubDiagnostic,
|
Level, CodeSuggestion, Diagnostic, SubDiagnostic,
|
||||||
SuggestionStyle, SourceMapperDyn, DiagnosticId,
|
SuggestionStyle, SourceMapper, SourceMapperDyn, DiagnosticId,
|
||||||
};
|
};
|
||||||
use crate::Level::Error;
|
use crate::Level::Error;
|
||||||
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style};
|
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style};
|
||||||
|
@ -239,11 +239,11 @@ pub trait Emitter {
|
||||||
format!(
|
format!(
|
||||||
"help: {}{}: `{}`",
|
"help: {}{}: `{}`",
|
||||||
sugg.msg,
|
sugg.msg,
|
||||||
if self.source_map().as_ref().map(|sm| substitution.to_lowercase() == sm
|
if self.source_map().map(|sm| is_case_difference(
|
||||||
.span_to_snippet(sugg.substitutions[0].parts[0].span)
|
&**sm,
|
||||||
.unwrap()
|
substitution,
|
||||||
.to_lowercase()).unwrap_or(false)
|
sugg.substitutions[0].parts[0].span,
|
||||||
{
|
)).unwrap_or(false) {
|
||||||
" (notice the capitalization)"
|
" (notice the capitalization)"
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
|
@ -2058,3 +2058,18 @@ impl<'a> Drop for WritableDst<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the original and suggested code are visually similar enough to warrant extra wording.
|
||||||
|
pub fn is_case_difference(sm: &dyn SourceMapper, suggested: &str, sp: Span) -> bool {
|
||||||
|
// FIXME: this should probably be extended to also account for `FO0` → `FOO` and unicode.
|
||||||
|
let found = sm.span_to_snippet(sp).unwrap();
|
||||||
|
let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z'];
|
||||||
|
// There are ASCII chars that are confusable (above) and differ in capitalization:
|
||||||
|
let confusable = found.chars().zip(suggested.chars()).any(|(f, s)| {
|
||||||
|
(ascii_confusables.contains(&f) || ascii_confusables.contains(&s)) && f != s
|
||||||
|
});
|
||||||
|
confusable && found.to_lowercase() == suggested.to_lowercase()
|
||||||
|
// FIXME: We sometimes suggest the same thing we already have, which is a
|
||||||
|
// bug, but be defensive against that here.
|
||||||
|
&& found != suggested
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ pub use emitter::ColorConfig;
|
||||||
|
|
||||||
use Level::*;
|
use Level::*;
|
||||||
|
|
||||||
use emitter::{Emitter, EmitterWriter};
|
use emitter::{Emitter, EmitterWriter, is_case_difference};
|
||||||
use registry::Registry;
|
use registry::Registry;
|
||||||
|
|
||||||
use rustc_data_structures::sync::{self, Lrc, Lock};
|
use rustc_data_structures::sync::{self, Lrc, Lock};
|
||||||
|
@ -239,8 +239,7 @@ impl CodeSuggestion {
|
||||||
prev_hi = cm.lookup_char_pos(part.span.hi());
|
prev_hi = cm.lookup_char_pos(part.span.hi());
|
||||||
prev_line = fm.get_line(prev_hi.line - 1);
|
prev_line = fm.get_line(prev_hi.line - 1);
|
||||||
}
|
}
|
||||||
let only_capitalization = buf.clone().to_lowercase()
|
let only_capitalization = is_case_difference(cm, &buf, bounding_span);
|
||||||
== cm.span_to_snippet(bounding_span).unwrap().to_lowercase();
|
|
||||||
// if the replacement already ends with a newline, don't print the next line
|
// if the replacement already ends with a newline, don't print the next line
|
||||||
if !buf.ends_with('\n') {
|
if !buf.ends_with('\n') {
|
||||||
push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
|
push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
|
||||||
|
@ -250,7 +249,6 @@ impl CodeSuggestion {
|
||||||
buf.pop();
|
buf.pop();
|
||||||
}
|
}
|
||||||
(buf, substitution.parts, only_capitalization)
|
(buf, substitution.parts, only_capitalization)
|
||||||
|
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ LL | use my_core;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
| |
|
| |
|
||||||
| no `my_core` in the root
|
| no `my_core` in the root
|
||||||
| help: a similar name exists in the module (notice the capitalization): `my_core`
|
| help: a similar name exists in the module: `my_core`
|
||||||
|
|
||||||
error[E0432]: unresolved import `my_core`
|
error[E0432]: unresolved import `my_core`
|
||||||
--> $DIR/extern-prelude-from-opaque-fail.rs:7:13
|
--> $DIR/extern-prelude-from-opaque-fail.rs:7:13
|
||||||
|
|
|
@ -41,7 +41,7 @@ error: static variable `bad` should have an upper case name
|
||||||
--> $DIR/lint-group-nonstandard-style.rs:14:16
|
--> $DIR/lint-group-nonstandard-style.rs:14:16
|
||||||
|
|
|
|
||||||
LL | static bad: isize = 1;
|
LL | static bad: isize = 1;
|
||||||
| ^^^ help: convert the identifier to upper case (notice the capitalization): `BAD`
|
| ^^^ help: convert the identifier to upper case: `BAD`
|
||||||
|
|
|
|
||||||
note: lint level defined here
|
note: lint level defined here
|
||||||
--> $DIR/lint-group-nonstandard-style.rs:10:14
|
--> $DIR/lint-group-nonstandard-style.rs:10:14
|
||||||
|
|
|
@ -2,7 +2,7 @@ error: constant in pattern `a` should have an upper case name
|
||||||
--> $DIR/lint-lowercase-static-const-pattern.rs:11:13
|
--> $DIR/lint-lowercase-static-const-pattern.rs:11:13
|
||||||
|
|
|
|
||||||
LL | (0, a) => 0,
|
LL | (0, a) => 0,
|
||||||
| ^ help: convert the identifier to upper case (notice the capitalization): `A`
|
| ^ help: convert the identifier to upper case: `A`
|
||||||
|
|
|
|
||||||
note: lint level defined here
|
note: lint level defined here
|
||||||
--> $DIR/lint-lowercase-static-const-pattern.rs:4:9
|
--> $DIR/lint-lowercase-static-const-pattern.rs:4:9
|
||||||
|
@ -14,7 +14,7 @@ error: constant in pattern `aha` should have an upper case name
|
||||||
--> $DIR/lint-lowercase-static-const-pattern.rs:26:13
|
--> $DIR/lint-lowercase-static-const-pattern.rs:26:13
|
||||||
|
|
|
|
||||||
LL | (0, aha) => 0,
|
LL | (0, aha) => 0,
|
||||||
| ^^^ help: convert the identifier to upper case (notice the capitalization): `AHA`
|
| ^^^ help: convert the identifier to upper case: `AHA`
|
||||||
|
|
||||||
error: constant in pattern `not_okay` should have an upper case name
|
error: constant in pattern `not_okay` should have an upper case name
|
||||||
--> $DIR/lint-lowercase-static-const-pattern.rs:40:13
|
--> $DIR/lint-lowercase-static-const-pattern.rs:40:13
|
||||||
|
|
|
@ -38,7 +38,7 @@ error: variant `bar` should have an upper camel case name
|
||||||
--> $DIR/lint-non-camel-case-types.rs:22:5
|
--> $DIR/lint-non-camel-case-types.rs:22:5
|
||||||
|
|
|
|
||||||
LL | bar
|
LL | bar
|
||||||
| ^^^ help: convert the identifier to upper camel case (notice the capitalization): `Bar`
|
| ^^^ help: convert the identifier to upper camel case: `Bar`
|
||||||
|
|
||||||
error: trait `foo6` should have an upper camel case name
|
error: trait `foo6` should have an upper camel case name
|
||||||
--> $DIR/lint-non-camel-case-types.rs:25:7
|
--> $DIR/lint-non-camel-case-types.rs:25:7
|
||||||
|
@ -50,7 +50,7 @@ error: type parameter `ty` should have an upper camel case name
|
||||||
--> $DIR/lint-non-camel-case-types.rs:29:6
|
--> $DIR/lint-non-camel-case-types.rs:29:6
|
||||||
|
|
|
|
||||||
LL | fn f<ty>(_: ty) {}
|
LL | fn f<ty>(_: ty) {}
|
||||||
| ^^ help: convert the identifier to upper camel case (notice the capitalization): `Ty`
|
| ^^ help: convert the identifier to upper camel case: `Ty`
|
||||||
|
|
||||||
error: aborting due to 8 previous errors
|
error: aborting due to 8 previous errors
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ error: method `render_HTML` should have a snake case name
|
||||||
--> $DIR/lint-non-snake-case-functions.rs:17:8
|
--> $DIR/lint-non-snake-case-functions.rs:17:8
|
||||||
|
|
|
|
||||||
LL | fn render_HTML() {}
|
LL | fn render_HTML() {}
|
||||||
| ^^^^^^^^^^^ help: convert the identifier to snake case (notice the capitalization): `render_html`
|
| ^^^^^^^^^^^ help: convert the identifier to snake case: `render_html`
|
||||||
|
|
||||||
error: trait method `ABC` should have a snake case name
|
error: trait method `ABC` should have a snake case name
|
||||||
--> $DIR/lint-non-snake-case-functions.rs:22:8
|
--> $DIR/lint-non-snake-case-functions.rs:22:8
|
||||||
|
|
|
@ -14,7 +14,7 @@ error: static variable `bar` should have an upper case name
|
||||||
--> $DIR/lint-non-uppercase-statics.rs:6:12
|
--> $DIR/lint-non-uppercase-statics.rs:6:12
|
||||||
|
|
|
|
||||||
LL | static mut bar: isize = 1;
|
LL | static mut bar: isize = 1;
|
||||||
| ^^^ help: convert the identifier to upper case (notice the capitalization): `BAR`
|
| ^^^ help: convert the identifier to upper case: `BAR`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ error: variable `Test` should have a snake case name
|
||||||
--> $DIR/lint-uppercase-variables.rs:18:9
|
--> $DIR/lint-uppercase-variables.rs:18:9
|
||||||
|
|
|
|
||||||
LL | let Test: usize = 0;
|
LL | let Test: usize = 0;
|
||||||
| ^^^^ help: convert the identifier to snake case (notice the capitalization): `test`
|
| ^^^^ help: convert the identifier to snake case: `test`
|
||||||
|
|
||||||
error: variable `Foo` should have a snake case name
|
error: variable `Foo` should have a snake case name
|
||||||
--> $DIR/lint-uppercase-variables.rs:22:9
|
--> $DIR/lint-uppercase-variables.rs:22:9
|
||||||
|
|
|
@ -8,7 +8,7 @@ LL | handle: Handle
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
| |
|
| |
|
||||||
| did you mean `Handle { /* fields */ }`?
|
| did you mean `Handle { /* fields */ }`?
|
||||||
| help: a local variable with a similar name exists (notice the capitalization): `handle`
|
| help: a local variable with a similar name exists: `handle`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ LL | use main as x;
|
||||||
| ----^^^^^
|
| ----^^^^^
|
||||||
| |
|
| |
|
||||||
| no `main` in the root
|
| no `main` in the root
|
||||||
| help: a similar name exists in the module (notice the capitalization): `main`
|
| help: a similar name exists in the module: `main`
|
||||||
|
|
||||||
error[E0432]: unresolved import `test`
|
error[E0432]: unresolved import `test`
|
||||||
--> $DIR/inaccessible-test-modules.rs:6:5
|
--> $DIR/inaccessible-test-modules.rs:6:5
|
||||||
|
@ -14,7 +14,7 @@ LL | use test as y;
|
||||||
| ----^^^^^
|
| ----^^^^^
|
||||||
| |
|
| |
|
||||||
| no `test` in the root
|
| no `test` in the root
|
||||||
| help: a similar name exists in the module (notice the capitalization): `test`
|
| help: a similar name exists in the module: `test`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ error[E0573]: expected type, found module `a`
|
||||||
--> $DIR/trait-impl-for-module.rs:7:12
|
--> $DIR/trait-impl-for-module.rs:7:12
|
||||||
|
|
|
|
||||||
LL | impl A for a {
|
LL | impl A for a {
|
||||||
| ^ help: a trait with a similar name exists (notice the capitalization): `A`
|
| ^ help: a trait with a similar name exists: `A`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ warning: type parameter `γ` should have an upper camel case name
|
||||||
--> $DIR/utf8_idents.rs:3:5
|
--> $DIR/utf8_idents.rs:3:5
|
||||||
|
|
|
|
||||||
LL | γ
|
LL | γ
|
||||||
| ^ help: convert the identifier to upper camel case (notice the capitalization): `Γ`
|
| ^ help: convert the identifier to upper camel case: `Γ`
|
||||||
|
|
|
|
||||||
= note: `#[warn(non_camel_case_types)]` on by default
|
= note: `#[warn(non_camel_case_types)]` on by default
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue