let krate = self.file_to_def(file_id)?.krate;
let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
let ast_id = Some(AstId::new(src.file_id, file_ast_id));
- Some(MacroDefId { krate: Some(krate), ast_id, kind })
+ Some(MacroDefId { krate: Some(krate), ast_id, kind, local_inner: false })
}
pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
krate: Some(self.expander.module.krate),
ast_id: Some(self.expander.ast_id(&e)),
kind: MacroDefKind::Declarative,
+ local_inner: false,
};
self.body.item_scope.define_legacy_macro(name, mac);
ast_id: None,
krate: Some(krate),
kind: MacroDefKind::CustomDerive(expander),
+ local_inner: false,
};
self.define_proc_macro(name.clone(), macro_id);
ast_id: Some(ast_id.ast_id),
krate: Some(self.def_collector.def_map.krate),
kind: MacroDefKind::Declarative,
+ local_inner: mac.local_inner,
};
self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export);
}
pub(super) path: ModPath,
pub(super) name: Option<Name>,
pub(super) export: bool,
+ pub(super) local_inner: bool,
pub(super) builtin: bool,
}
let name = m.name().map(|it| it.as_name());
let ast_id = self.source_ast_id_map.ast_id(&m);
- // FIXME: cfg_attr
- let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export");
// FIXME: cfg_attr
- let builtin =
- m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "rustc_builtin_macro");
-
- let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export, builtin });
+ let export = attrs.by_key("macro_export").exists();
+ let local_inner =
+ attrs.by_key("macro_export").tt_values().map(|it| &it.token_trees).flatten().any(
+ |it| match it {
+ tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
+ ident.text.contains("local_inner_macros")
+ }
+ _ => false,
+ },
+ );
+ let builtin = attrs.by_key("rustc_builtin_macro").exists();
+
+ let m = self.raw_items.macros.alloc(MacroData {
+ ast_id,
+ path,
+ name,
+ export,
+ local_inner,
+ builtin,
+ });
self.push_item(current_module, attrs, RawItemKind::Macro(m));
}
hygiene::Hygiene,
name::{name, AsName},
};
-use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner};
+use ra_syntax::{
+ ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner},
+ T,
+};
use super::AssociatedTypeBinding;
use crate::{
}
segments.reverse();
generic_args.reverse();
+
+ // handle local_inner_macros :
+ // Basically, even in rustc it is quite hacky:
+ // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456
+ // We follow what it did anyway :)
+ if segments.len() == 1 && kind == PathKind::Plain {
+ let next = path.syntax().last_token().and_then(|it| it.next_token());
+ if next.map_or(false, |it| it.kind() == T![!]) {
+ if let Some(crate_id) = hygiene.local_inner_macros() {
+ kind = PathKind::DollarCrate(crate_id);
+ }
+ }
+ }
+
let mod_path = ModPath { kind, segments };
return Some(Path { type_anchor, mod_path, generic_args });
_ => return None,
};
- Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind) })
+ Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind),local_inner:false })
}
};
}
krate: Some(krate),
ast_id: Some(ast_id),
kind: MacroDefKind::BuiltIn(kind),
+ local_inner: false,
}),
Either::Right(kind) => Some(MacroDefId {
krate: Some(krate),
ast_id: Some(ast_id),
kind: MacroDefKind::BuiltInEager(kind),
+ local_inner: false,
}),
}
}
krate: Some(CrateId(0)),
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))),
kind: MacroDefKind::BuiltIn(expander),
+ local_inner: false,
};
let loc = MacroCallLoc {
krate: Some(CrateId(0)),
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))),
kind: MacroDefKind::BuiltInEager(expander),
+ local_inner: false,
};
let args = macro_calls[1].token_tree().unwrap();
pub struct Hygiene {
// This is what `$crate` expands to
def_crate: Option<CrateId>,
+
+ // Indiciate this is a local inner macro
+ local_inner: bool,
}
impl Hygiene {
pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene {
- let def_crate = match file_id.0 {
- HirFileIdRepr::FileId(_) => None,
+ let (def_crate, local_inner) = match file_id.0 {
+ HirFileIdRepr::FileId(_) => (None, false),
HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id {
MacroCallId::LazyMacro(id) => {
let loc = db.lookup_intern_macro(id);
match loc.def.kind {
- MacroDefKind::Declarative => loc.def.krate,
- MacroDefKind::BuiltIn(_) => None,
- MacroDefKind::BuiltInDerive(_) => None,
- MacroDefKind::BuiltInEager(_) => None,
- MacroDefKind::CustomDerive(_) => None,
+ MacroDefKind::Declarative => (loc.def.krate, loc.def.local_inner),
+ MacroDefKind::BuiltIn(_) => (None, false),
+ MacroDefKind::BuiltInDerive(_) => (None, false),
+ MacroDefKind::BuiltInEager(_) => (None, false),
+ MacroDefKind::CustomDerive(_) => (None, false),
}
}
- MacroCallId::EagerMacro(_id) => None,
+ MacroCallId::EagerMacro(_id) => (None, false),
},
};
- Hygiene { def_crate }
+ Hygiene { def_crate, local_inner }
}
pub fn new_unhygienic() -> Hygiene {
- Hygiene { def_crate: None }
+ Hygiene { def_crate: None, local_inner: false }
}
// FIXME: this should just return name
}
Either::Left(name_ref.as_name())
}
+
+ pub fn local_inner_macros(&self) -> Option<CrateId> {
+ if self.local_inner {
+ self.def_crate
+ } else {
+ None
+ }
+ }
}
pub krate: Option<CrateId>,
pub ast_id: Option<AstId<ast::MacroCall>>,
pub kind: MacroDefKind,
+
+ pub local_inner: bool,
}
impl MacroDefId {
);
}
+#[test]
+fn infer_local_inner_macros() {
+ let (db, pos) = TestDB::with_position(
+ r#"
+//- /main.rs crate:main deps:foo
+fn test() {
+ let x = foo::foo!(1);
+ x<|>;
+}
+
+//- /lib.rs crate:foo
+#[macro_export(local_inner_macros)]
+macro_rules! foo {
+ (1) => { bar!() };
+}
+
+#[macro_export]
+macro_rules! bar {
+ () => { 42 }
+}
+
+"#,
+ );
+ assert_eq!("i32", type_at_pos(&db, pos));
+}
+
#[test]
fn infer_builtin_macros_line() {
assert_snapshot!(