]> git.lizzy.rs Git - rust.git/commitdiff
librustc: hint close matches on accessing nonexisting fields
authorOliver Schneider <git1984941651981@oli-obk.de>
Tue, 20 Jan 2015 09:58:06 +0000 (10:58 +0100)
committerOliver Schneider <git1984941651981@oli-obk.de>
Tue, 20 Jan 2015 09:58:06 +0000 (10:58 +0100)
src/librustc_typeck/check/mod.rs
src/test/compile-fail/struct-fields-hints-no-dupe.rs [new file with mode: 0644]
src/test/compile-fail/struct-fields-hints.rs [new file with mode: 0644]
src/test/compile-fail/struct-fields-typo.rs [new file with mode: 0644]

index f610456f73cf103dfdc63cbdc33e897df79f65ff..df9d54ccd8a3e68bd43aae2fe5b910e7a0cc5dc8 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
 use util::common::{block_query, indenter, loop_query};
 use util::ppaux::{self, Repr};
 use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
+use util::lev_distance::lev_distance;
 
 use std::cell::{Cell, Ref, RefCell};
 use std::mem::replace;
@@ -3074,11 +3075,43 @@ fn check_field(fcx: &FnCtxt,
                             actual)
                 },
                 expr_t, None);
+            if let Some(t) = ty::ty_to_def_id(expr_t) {
+                suggest_field_names(t, field, tcx, vec![]);
+            }
         }
 
         fcx.write_error(expr.id);
     }
 
+    // displays hints about the closest matches in field names
+    fn suggest_field_names<'tcx>(id : DefId,
+                                 field : &ast::SpannedIdent,
+                                 tcx : &ty::ctxt<'tcx>,
+                                 skip : Vec<&str>) {
+        let ident = token::get_ident(field.node);
+        let name = ident.get();
+        // only find fits with at least one matching letter
+        let mut best_dist = name.len();
+        let mut best = None;
+        let fields = ty::lookup_struct_fields(tcx, id);
+        for elem in fields.iter() {
+            let n = elem.name.as_str();
+            // ignore already set fields
+            if skip.iter().any(|&x| x == n) {
+                continue;
+            }
+            let dist = lev_distance(n, name);
+            if dist < best_dist {
+                best = Some(n);
+                best_dist = dist;
+            }
+        }
+        if let Some(n) = best {
+            tcx.sess.span_help(field.span,
+                format!("did you mean `{}`?", n).as_slice());
+        }
+    }
+
     // Check tuple index expressions
     fn check_tup_field(fcx: &FnCtxt,
                        expr: &ast::Expr,
@@ -3186,6 +3219,13 @@ fn check_struct_or_variant_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                         },
                         struct_ty,
                         None);
+                    // prevent all specified fields from being suggested
+                    let skip_fields = ast_fields.iter().map(|ref x| x.ident.node.name.as_str());
+                    let actual_id = match enum_id_opt {
+                        Some(_) => class_id,
+                        None => ty::ty_to_def_id(struct_ty).unwrap()
+                    };
+                    suggest_field_names(actual_id, &field.ident, tcx, skip_fields.collect());
                     error_happened = true;
                 }
                 Some((_, true)) => {
diff --git a/src/test/compile-fail/struct-fields-hints-no-dupe.rs b/src/test/compile-fail/struct-fields-hints-no-dupe.rs
new file mode 100644 (file)
index 0000000..8df9ffd
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2015 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.
+
+struct A {
+    foo : i32,
+    car : i32,
+    barr : i32
+}
+
+fn main() {
+    let a = A {
+        foo : 5,
+        bar : 42,//~ ERROR structure `A` has no field named `bar`
+        //~^ HELP did you mean `barr`?
+        car : 9,
+    };
+}
diff --git a/src/test/compile-fail/struct-fields-hints.rs b/src/test/compile-fail/struct-fields-hints.rs
new file mode 100644 (file)
index 0000000..37001f1
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+struct A {
+    foo : i32,
+    car : i32,
+    barr : i32
+}
+
+fn main() {
+    let a = A {
+        foo : 5,
+        bar : 42,//~ ERROR structure `A` has no field named `bar`
+        //~^ HELP did you mean `car`?
+    };
+}
diff --git a/src/test/compile-fail/struct-fields-typo.rs b/src/test/compile-fail/struct-fields-typo.rs
new file mode 100644 (file)
index 0000000..c897dc5
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2012 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.
+
+struct BuildData {
+    foo: isize,
+    bar: f32
+}
+
+fn main() {
+    let foo = BuildData {
+        foo: 0,
+        bar: 0.5,
+    };
+    let x = foo.baa;//~ ERROR attempted access of field `baa` on type `BuildData`
+    //~^ HELP did you mean `bar`?
+    println!("{}", x);
+}