Add macro suggestions for macros imported with use

This commit searchs modules for macro suggestions.
It also removes imported macro_rules from macro_names,
and adds more corner case checks for which macros
should be suggested in specific contexts.
This commit is contained in:
Josh Driver 2017-02-23 20:18:20 +10:30
parent 4ecdc68153
commit da6dc5331f
4 changed files with 64 additions and 28 deletions

View File

@ -537,7 +537,6 @@ impl<'a> Resolver<'a> {
binding: &'a NameBinding<'a>,
span: Span,
allow_shadowing: bool) {
self.macro_names.insert(name);
if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing {
let msg = format!("`{}` is already in scope", name);
let note =

View File

@ -1264,7 +1264,7 @@ impl<'a> Resolver<'a> {
ribs: PerNS {
value_ns: vec![Rib::new(ModuleRibKind(graph_root))],
type_ns: vec![Rib::new(ModuleRibKind(graph_root))],
macro_ns: None,
macro_ns: Some(vec![Rib::new(ModuleRibKind(graph_root))]),
},
label_ribs: Vec::new(),
@ -2326,8 +2326,9 @@ impl<'a> Resolver<'a> {
};
}
}
if primary_ns != MacroNS && path.len() == 1 &&
self.macro_names.contains(&path[0].name) {
let is_builtin = self.builtin_macros.get(&path[0].name).cloned()
.map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false);
if primary_ns != MacroNS && (is_builtin || self.macro_names.contains(&path[0].name)) {
// Return some dummy definition, it's enough for error reporting.
return Some(
PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang))

View File

@ -23,7 +23,7 @@ use syntax::ast::{self, Name, Ident};
use syntax::attr;
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
use syntax::ext::base::{Resolver as SyntaxResolver, SyntaxExtension};
use syntax::ext::base::MacroKind;
use syntax::ext::expand::{Expansion, mark_tts};
use syntax::ext::hygiene::Mark;
@ -152,9 +152,6 @@ impl<'a> base::Resolver for Resolver<'a> {
}
fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
if let NormalTT(..) = *ext {
self.macro_names.insert(ident.name);
}
let def_id = DefId {
krate: BUILTIN_MACROS_CRATE,
index: DefIndex::new(self.macro_map.len()),
@ -466,24 +463,40 @@ impl<'a> Resolver<'a> {
fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
err: &mut DiagnosticBuilder<'a>) {
let suggestion = match kind {
MacroKind::Bang =>
find_best_match_for_name(self.macro_names.iter(), name, None),
MacroKind::Attr |
MacroKind::Derive => {
// Find a suggestion from the legacy namespace.
// FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
let builtin_macros = self.builtin_macros.clone();
let names = builtin_macros.iter().filter_map(|(name, binding)| {
if binding.get_macro(self).kind() == kind {
Some(name)
} else {
None
}
});
find_best_match_for_name(names, name, None)
// First check if this is a locally-defined bang macro.
let suggestion = if let MacroKind::Bang = kind {
find_best_match_for_name(self.macro_names.iter(), name, None)
} else {
None
// Then check builtin macros.
}.or_else(|| {
// FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
let builtin_macros = self.builtin_macros.clone();
let names = builtin_macros.iter().filter_map(|(name, binding)| {
if binding.get_macro(self).kind() == kind {
Some(name)
} else {
None
}
});
find_best_match_for_name(names, name, None)
// Then check modules.
}).or_else(|| {
if !self.use_extern_macros {
return None;
}
};
let is_macro = |def| {
if let Def::Macro(_, def_kind) = def {
def_kind == kind
} else {
false
}
};
let ident = Ident::from_str(name);
self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro)
.as_ref().map(|s| Symbol::intern(s))
});
if let Some(suggestion) = suggestion {
if suggestion != name {
if let MacroKind::Bang = kind {

View File

@ -22,15 +22,24 @@ extern crate attr_proc_macro;
use attr_proc_macro::attr_proc_macro;
#[derive(FooWithLongNam)]
//~^ ERROR cannot find derive macro `FooWithLongNam` in this scope
macro_rules! FooWithLongNam {
() => {}
}
#[derive(FooWithLongNan)]
//~^ ERROR cannot find derive macro `FooWithLongNan` in this scope
//~^^ HELP did you mean `FooWithLongName`?
struct Foo;
#[attr_proc_macra]
//~^ ERROR cannot find attribute macro `attr_proc_macra` in this scope
//~^^ HELP did you mean `attr_proc_macro`?
struct Bar;
#[FooWithLongNan]
//~^ ERROR cannot find attribute macro `FooWithLongNan` in this scope
struct Asdf;
#[derive(Dlone)]
//~^ ERROR cannot find derive macro `Dlone` in this scope
//~^^ HELP did you mean `Clone`?
@ -41,4 +50,18 @@ struct A;
//~^^ HELP did you mean `Clona`?
struct B;
fn main() {}
#[derive(attr_proc_macra)]
//~^ ERROR cannot find derive macro `attr_proc_macra` in this scope
struct C;
fn main() {
FooWithLongNama!();
//~^ ERROR cannot find macro `FooWithLongNama!` in this scope
//~^^ HELP did you mean `FooWithLongNam!`?
attr_proc_macra!();
//~^ ERROR cannot find macro `attr_proc_macra!` in this scope
Dlona!();
//~^ ERROR cannot find macro `Dlona!` in this scope
}