]> git.lizzy.rs Git - rust.git/commitdiff
Add suggestion of similar macro names to `macro undefined` error message
authorFlorian Hartwig <florian.j.hartwig@gmail.com>
Wed, 25 Nov 2015 23:21:38 +0000 (00:21 +0100)
committerFlorian Hartwig <florian.j.hartwig@gmail.com>
Wed, 25 Nov 2015 23:21:38 +0000 (00:21 +0100)
src/librustc/lib.rs
src/librustc/util/lev_distance.rs [deleted file]
src/librustc_resolve/lib.rs
src/librustc_typeck/check/mod.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs
src/libsyntax/lib.rs
src/libsyntax/util/lev_distance.rs [new file with mode: 0644]

index 393329b42147c770975746d5667d0dc221495fc0..454b70da8f20976516b4b9ecd0536974b69209a0 100644 (file)
@@ -152,7 +152,6 @@ pub mod util {
     pub mod common;
     pub mod ppaux;
     pub mod nodemap;
-    pub mod lev_distance;
     pub mod num;
     pub mod fs;
 }
diff --git a/src/librustc/util/lev_distance.rs b/src/librustc/util/lev_distance.rs
deleted file mode 100644 (file)
index 28f8510..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::cmp;
-
-pub fn lev_distance(me: &str, t: &str) -> usize {
-    if me.is_empty() { return t.chars().count(); }
-    if t.is_empty() { return me.chars().count(); }
-
-    let mut dcol: Vec<_> = (0..t.len() + 1).collect();
-    let mut t_last = 0;
-
-    for (i, sc) in me.chars().enumerate() {
-
-        let mut current = i;
-        dcol[0] = current + 1;
-
-        for (j, tc) in t.chars().enumerate() {
-
-            let next = dcol[j + 1];
-
-            if sc == tc {
-                dcol[j + 1] = current;
-            } else {
-                dcol[j + 1] = cmp::min(current, next);
-                dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1;
-            }
-
-            current = next;
-            t_last = j;
-        }
-    }
-
-    dcol[t_last + 1]
-}
-
-#[test]
-fn test_lev_distance() {
-    use std::char::{ from_u32, MAX };
-    // Test bytelength agnosticity
-    for c in (0..MAX as u32)
-             .filter_map(|i| from_u32(i))
-             .map(|i| i.to_string()) {
-        assert_eq!(lev_distance(&c[..], &c[..]), 0);
-    }
-
-    let a = "\nMäry häd ä little lämb\n\nLittle lämb\n";
-    let b = "\nMary häd ä little lämb\n\nLittle lämb\n";
-    let c = "Mary häd ä little lämb\n\nLittle lämb\n";
-    assert_eq!(lev_distance(a, b), 1);
-    assert_eq!(lev_distance(b, a), 1);
-    assert_eq!(lev_distance(a, c), 2);
-    assert_eq!(lev_distance(c, a), 2);
-    assert_eq!(lev_distance(b, c), 1);
-    assert_eq!(lev_distance(c, b), 1);
-}
index 51d7ceb946dae2920d2a3307c42093e7de7aa1cf..5cdce22d82644cffa614a5375c2776a672a97d5b 100644 (file)
@@ -63,7 +63,6 @@
 use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace};
 use rustc::middle::ty::{Freevar, FreevarMap, TraitMap, GlobMap};
 use rustc::util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
-use rustc::util::lev_distance::lev_distance;
 
 use syntax::ast;
 use syntax::ast::{CRATE_NODE_ID, Ident, Name, NodeId, CrateNum, TyIs, TyI8, TyI16, TyI32, TyI64};
@@ -73,6 +72,7 @@
 use syntax::parse::token::{self, special_names, special_idents};
 use syntax::ptr::P;
 use syntax::codemap::{self, Span, Pos};
+use syntax::util::lev_distance::lev_distance;
 
 use rustc_front::intravisit::{self, FnKind, Visitor};
 use rustc_front::hir;
index bac85e4b7001e13d8cf90e5d34efa766739635d3..df91db3608932c579e4ba962699ce1fe225633b6 100644 (file)
 use lint;
 use util::common::{block_query, ErrorReported, indenter, loop_query};
 use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
-use util::lev_distance::lev_distance;
 
 use std::cell::{Cell, Ref, RefCell};
 use std::collections::{HashSet};
 use syntax::owned_slice::OwnedSlice;
 use syntax::parse::token::{self, InternedString};
 use syntax::ptr::P;
+use syntax::util::lev_distance::lev_distance;
 
 use rustc_front::intravisit::{self, Visitor};
 use rustc_front::hir;
index 55f0fa5675ac84d10250bb82b27f5c2698c73d01..7db9dd9fbeedb8ef48a2a57c593c944e080ea9c7 100644 (file)
@@ -24,6 +24,7 @@
 use parse::token::{InternedString, intern, str_to_ident};
 use ptr::P;
 use util::small_vector::SmallVector;
+use util::lev_distance::lev_distance;
 use ext::mtwt;
 use fold::Folder;
 
@@ -776,6 +777,22 @@ pub fn std_path(&self, components: &[&str]) -> Vec<ast::Ident> {
     pub fn name_of(&self, st: &str) -> ast::Name {
         token::intern(st)
     }
+
+    pub fn suggest_macro_name(&mut self, name: &str, span: Span) {
+        use std::cmp::max;
+
+        let mut min: Option<(Name, usize)> = None;
+        let max_dist = max(name.len() / 3, 1);
+        for macro_name in self.syntax_env.names.iter() {
+            let dist = lev_distance(name, &macro_name.as_str());
+            if dist <= max_dist && (min.is_none() || min.unwrap().1 > dist) {
+                min = Some((*macro_name, dist));
+            }
+        }
+        if let Some((suggestion, _)) = min {
+            self.span_help(span, &format!("did you mean `{}`?", suggestion));
+        }
+    }
 }
 
 /// Extract a string literal from the macro expanded version of `expr`,
index 9b1a7a50201b022aee19c636107c7dc3acf0b27a..01e72cf2a8d849f7352235ca14f8ad4c153abe9e 100644 (file)
@@ -191,6 +191,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
                 pth.span,
                 &format!("macro undefined: '{}!'",
                         &extname));
+            fld.cx.suggest_macro_name(&extname.as_str(), pth.span);
 
             // let compilation continue
             None
index 59cc380b0ec2967876404a61fad88b23def304ab..d245599592108eef5a5fda30bfdd24de9fdc7bb8 100644 (file)
@@ -65,6 +65,7 @@ macro_rules! panictry {
 
 pub mod util {
     pub mod interner;
+    pub mod lev_distance;
     pub mod node_count;
     pub mod parser;
     #[cfg(test)]
diff --git a/src/libsyntax/util/lev_distance.rs b/src/libsyntax/util/lev_distance.rs
new file mode 100644 (file)
index 0000000..28f8510
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cmp;
+
+pub fn lev_distance(me: &str, t: &str) -> usize {
+    if me.is_empty() { return t.chars().count(); }
+    if t.is_empty() { return me.chars().count(); }
+
+    let mut dcol: Vec<_> = (0..t.len() + 1).collect();
+    let mut t_last = 0;
+
+    for (i, sc) in me.chars().enumerate() {
+
+        let mut current = i;
+        dcol[0] = current + 1;
+
+        for (j, tc) in t.chars().enumerate() {
+
+            let next = dcol[j + 1];
+
+            if sc == tc {
+                dcol[j + 1] = current;
+            } else {
+                dcol[j + 1] = cmp::min(current, next);
+                dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1;
+            }
+
+            current = next;
+            t_last = j;
+        }
+    }
+
+    dcol[t_last + 1]
+}
+
+#[test]
+fn test_lev_distance() {
+    use std::char::{ from_u32, MAX };
+    // Test bytelength agnosticity
+    for c in (0..MAX as u32)
+             .filter_map(|i| from_u32(i))
+             .map(|i| i.to_string()) {
+        assert_eq!(lev_distance(&c[..], &c[..]), 0);
+    }
+
+    let a = "\nMäry häd ä little lämb\n\nLittle lämb\n";
+    let b = "\nMary häd ä little lämb\n\nLittle lämb\n";
+    let c = "Mary häd ä little lämb\n\nLittle lämb\n";
+    assert_eq!(lev_distance(a, b), 1);
+    assert_eq!(lev_distance(b, a), 1);
+    assert_eq!(lev_distance(a, c), 2);
+    assert_eq!(lev_distance(c, a), 2);
+    assert_eq!(lev_distance(b, c), 1);
+    assert_eq!(lev_distance(c, b), 1);
+}