Skip to content

Didyoumean #12979

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
131 changes: 110 additions & 21 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use driver::session::Session;
use metadata::csearch;
use metadata::cstore;
use metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
use middle::lang_items::LanguageItems;
use middle::lint::{UnnecessaryQualification, UnusedImports};
Expand All @@ -33,6 +34,7 @@ use syntax::visit::Visitor;

use std::cell::{Cell, RefCell};
use std::uint;
use std::cmp;
use std::mem::replace;
use std::vec_ng::Vec;
use collections::{HashMap, HashSet};
Expand Down Expand Up @@ -788,8 +790,9 @@ fn namespace_error_to_str(ns: NamespaceError) -> &'static str {
}

fn Resolver<'a>(session: &'a Session,
lang_items: @LanguageItems,
crate_span: Span) -> Resolver<'a> {
lang_items: @LanguageItems,
crate_span: Span,
krate:&'a ast::Crate) -> Resolver<'a> {
let graph_root = @NameBindings();

graph_root.define_module(NoParentLink,
Expand All @@ -809,6 +812,7 @@ fn Resolver<'a>(session: &'a Session,
// AST.

graph_root: graph_root,
resolver_krate:krate,

method_map: @RefCell::new(HashMap::new()),
structs: HashSet::new(),
Expand Down Expand Up @@ -852,6 +856,8 @@ struct Resolver<'a> {
method_map: @RefCell<HashMap<Name, HashSet<DefId>>>,
structs: HashSet<DefId>,

resolver_krate: &'a ast::Crate, // for error message search-"did you mean..."

// The number of imports that are currently unresolved.
unresolved_imports: uint,

Expand Down Expand Up @@ -939,7 +945,8 @@ impl<'a, 'b> Visitor<()> for UnusedImportCheckVisitor<'a, 'b> {

impl<'a> Resolver<'a> {
/// The main name resolution procedure.
fn resolve(&mut self, krate: &ast::Crate) {
fn resolve(&mut self, krate: &'a ast::Crate) {
self.resolver_krate = krate;
self.build_reduced_graph(krate);
self.session.abort_if_errors();

Expand Down Expand Up @@ -2860,7 +2867,7 @@ impl<'a> Resolver<'a> {
}
UseLexicalScope => {
// This is not a crate-relative path. We resolve the
// first component of the path in the current lexical
// first component of the path in the current lexical
// scope and then proceed to resolve below that.
let result = self.resolve_module_in_lexical_scope(
module_,
Expand Down Expand Up @@ -5157,22 +5164,25 @@ impl<'a> Resolver<'a> {
wrong_name));

}
_ =>
// limit search to 5 to reduce the number
// of stupid suggestions
match self.find_best_match_for_name(wrong_name, 5) {
Some(m) => {
self.resolve_error(expr.span,
format!("unresolved name `{}`. \
Did you mean `{}`?",
wrong_name, m));
}
None => {
self.resolve_error(expr.span,
format!("unresolved name `{}`.",
wrong_name));
}
}
_ => {
// limit search to 5 to reduce the number
// of stupid suggestions
match self.find_best_match_for_name(wrong_name, 5) {
Some(m) => {
self.resolve_error(expr.span,
format!("unresolved name `{}`. \
Did you mean `{}`?",
wrong_name, m));
}
None => {
self.resolve_error(expr.span,
format!("unresolved name `{}`.",
wrong_name));
}
}
// additionally display exact symbol matches from other scopes.
self.show_suggestions_from_other_scopes(path);
}
}
}
}
Expand Down Expand Up @@ -5560,8 +5570,87 @@ impl<'a> Resolver<'a> {
debug!("* {}:{}{}", token::get_name(name), value_repr, type_repr);
}
}

// Search other modules for this ident, and advise possible module paths
fn show_suggestions_from_other_scopes(&self, path:&Path) {

let suggestions = self.find_suggestions_from_other_scopes(path);

if suggestions.len()>0 {
let mut note=~"did you mean:-\n";
for &(ref name,_) in suggestions.iter() {
note.push_str(
"\t\t\t"+ "::"+
name.map(
|i|{token::get_ident(*i).get().to_str()})
.connect("::")+"\n"
);
}
self.session.span_note(path.span, note);
}
}

fn find_suggestions_from_other_scopes(&self, path:&Path)->Vec<(Vec<Ident>,uint)> {
let mut finder_visitor= FindSymbolVisitor{
cstore:&self.session.cstore,
curr_path_idents: Vec::new(),
path_to_find:path,
suggestions: Vec::new(),
max_suggestions: 5,
};
visit::walk_crate(&mut finder_visitor, self.resolver_krate, ());
finder_visitor.suggestions
}
}

struct FindSymbolVisitor<'a>{
cstore:&'a cstore::CStore,
curr_path_idents: Vec<Ident>,
path_to_find:&'a Path,
suggestions: Vec<(Vec<Ident>,uint)>,
max_suggestions: uint,
}

impl<'a,'r> Visitor<()> for FindSymbolVisitor<'a> {
fn visit_item<'a>(&mut self, item:&Item, e: ()) {
let find_path_last_seg:&PathSegment = self.path_to_find.segments.last().unwrap();

self.curr_path_idents.push(item.ident);

//todo: compare with current 'use' and uprate suggestions with more segs in scope.
if find_path_last_seg.identifier.name== item.ident.name &&
self.suggestions.len() <= (self.max_suggestions) {

let mut score=0;
let mut segs_found=0;
for ref find_seg in self.path_to_find.segments.iter() {
for (ref index,ref ident) in self.curr_path_idents.iter().enumerate() {
if ident.name==find_seg.identifier.name {score+=*index;segs_found+=1;}
}
}
if segs_found >=self.path_to_find.segments.len() {
// sort such that highscore is first.
self.suggestions.push((self.curr_path_idents.clone(),score));
self.suggestions.sort_by(
|&(_,ref score1),&(_,ref score2)|
if score1<score2 {cmp::Greater}else {cmp::Less});

if self.suggestions.len() > self.max_suggestions {self.suggestions.pop();}
}
}
// visit sub nodes..

visit::walk_item(self,item,e);
self.curr_path_idents.pop();
}

fn visit_mod(&mut self, m: &Mod, _s: Span, _n: NodeId, e: ()) {
visit::walk_mod(self, m, e) ;
}
}



pub struct CrateMap {
def_map: DefMap,
exp_map2: ExportMap2,
Expand All @@ -5575,7 +5664,7 @@ pub fn resolve_crate(session: &Session,
lang_items: @LanguageItems,
krate: &Crate)
-> CrateMap {
let mut resolver = Resolver(session, lang_items, krate.span);
let mut resolver = Resolver(session, lang_items, krate.span, krate);
resolver.resolve(krate);
let Resolver { def_map, export_map2, trait_map, last_private,
external_exports, .. } = resolver;
Expand Down