about summary refs log tree commit diff
path: root/src/librustc_errors
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-10-14 14:30:59 -0700
committerEsteban Küber <esteban@kuber.com.ar>2019-10-14 14:32:10 -0700
commit6dd718ca7937fc1a769d65b06396cf64f45f94ba (patch)
tree08b198ddeab20cb3d535877236d48a8a83f7deed /src/librustc_errors
parent4bb771615e194e64d0fc9cd97c1cdcc4972a1771 (diff)
downloadrust-6dd718ca7937fc1a769d65b06396cf64f45f94ba.tar.gz
rust-6dd718ca7937fc1a769d65b06396cf64f45f94ba.zip
Use heuristics for capitalization warning in suggestions
Diffstat (limited to 'src/librustc_errors')
-rw-r--r--src/librustc_errors/emitter.rs27
-rw-r--r--src/librustc_errors/lib.rs6
2 files changed, 23 insertions, 10 deletions
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs
index 04084453768..d02201d5321 100644
--- a/src/librustc_errors/emitter.rs
+++ b/src/librustc_errors/emitter.rs
@@ -13,7 +13,7 @@ use syntax_pos::{SourceFile, Span, MultiSpan};
 
 use crate::{
     Level, CodeSuggestion, Diagnostic, SubDiagnostic,
-    SuggestionStyle, SourceMapperDyn, DiagnosticId,
+    SuggestionStyle, SourceMapper, SourceMapperDyn, DiagnosticId,
 };
 use crate::Level::Error;
 use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style};
@@ -239,11 +239,11 @@ pub trait Emitter {
                     format!(
                         "help: {}{}: `{}`",
                         sugg.msg,
-                        if self.source_map().as_ref().map(|sm| substitution.to_lowercase() == sm
-                            .span_to_snippet(sugg.substitutions[0].parts[0].span)
-                            .unwrap()
-                            .to_lowercase()).unwrap_or(false)
-                        {
+                        if self.source_map().map(|sm| is_case_difference(
+                            &**sm,
+                            substitution,
+                            sugg.substitutions[0].parts[0].span,
+                        )).unwrap_or(false) {
                             " (notice the capitalization)"
                         } 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
+}
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index babaeb7e532..63df052a225 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -13,7 +13,7 @@ pub use emitter::ColorConfig;
 
 use Level::*;
 
-use emitter::{Emitter, EmitterWriter};
+use emitter::{Emitter, EmitterWriter, is_case_difference};
 use registry::Registry;
 
 use rustc_data_structures::sync::{self, Lrc, Lock};
@@ -239,8 +239,7 @@ impl CodeSuggestion {
                 prev_hi = cm.lookup_char_pos(part.span.hi());
                 prev_line = fm.get_line(prev_hi.line - 1);
             }
-            let only_capitalization = buf.clone().to_lowercase()
-                == cm.span_to_snippet(bounding_span).unwrap().to_lowercase();
+            let only_capitalization = is_case_difference(cm, &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);
@@ -250,7 +249,6 @@ impl CodeSuggestion {
                 buf.pop();
             }
             (buf, substitution.parts, only_capitalization)
-            
         }).collect()
     }
 }