Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir/src/lib.rs10
-rw-r--r--crates/hir_def/src/data.rs8
-rw-r--r--crates/hir_def/src/item_scope.rs1
-rw-r--r--crates/ide/src/runnables.rs72
-rw-r--r--crates/ide_db/src/defs.rs2
-rw-r--r--crates/ide_db/src/helpers.rs8
6 files changed, 98 insertions, 3 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 8121b27dcb..56832d6f8b 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -570,6 +570,12 @@ impl Module {
.collect()
}
+ pub fn legacy_macros(self, db: &dyn HirDatabase) -> Vec<Macro> {
+ let def_map = self.id.def_map(db.upcast());
+ let scope = &def_map[self.id.local_id].scope;
+ scope.legacy_macros().map(|(_, it)| MacroId::from(it).into()).collect()
+ }
+
pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> {
let def_map = self.id.def_map(db.upcast());
def_map[self.id.local_id].scope.impls().map(Impl::from).collect()
@@ -1785,6 +1791,10 @@ impl Macro {
}
}
+ pub fn is_macro_export(self, db: &dyn HirDatabase) -> bool {
+ matches!(self.id, MacroId::MacroRulesId(id) if db.macro_rules_data(id).macro_export)
+ }
+
pub fn kind(&self, db: &dyn HirDatabase) -> MacroKind {
match self.id {
MacroId::Macro2Id(it) => match it.lookup(db.upcast()).expander {
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index 456ed9e610..ffb733c2b9 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -315,6 +315,7 @@ impl Macro2Data {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MacroRulesData {
pub name: Name,
+ pub macro_export: bool,
}
impl MacroRulesData {
@@ -326,7 +327,12 @@ impl MacroRulesData {
let item_tree = loc.id.item_tree(db);
let makro = &item_tree[loc.id.value];
- Arc::new(MacroRulesData { name: makro.name.clone() })
+ let macro_export = item_tree
+ .attrs(db, loc.container.krate(), ModItem::from(loc.id.value).into())
+ .by_key("macro_export")
+ .exists();
+
+ Arc::new(MacroRulesData { name: makro.name.clone(), macro_export })
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index e6fdd41bd8..f1330b34d1 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -63,6 +63,7 @@ pub struct ItemScope {
// FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
// be all resolved to the last one defined if shadowing happens.
legacy_macros: FxHashMap<Name, MacroRulesId>,
+ /// The derive macro invocations in this scope.
attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
/// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes
/// paired with the derive macro invocations for the specific attribute.
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 1507e7cdd0..2c8e898d72 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -157,7 +157,13 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
Definition::SelfType(impl_) => runnable_impl(&sema, &impl_),
_ => None,
};
- add_opt(runnable.or_else(|| module_def_doctest(sema.db, def)), Some(def));
+ add_opt(
+ runnable
+ .or_else(|| module_def_doctest(sema.db, def))
+ // #[macro_export] mbe macros are declared in the root, while their definition may reside in a different module
+ .filter(|it| it.nav.file_id == file_id),
+ Some(def),
+ );
if let Definition::SelfType(impl_) = def {
impl_.items(db).into_iter().for_each(|assoc| {
let runnable = match assoc {
@@ -2074,4 +2080,68 @@ impl<T, U> Foo<T, U> {
"#]],
);
}
+
+ #[test]
+ fn doc_test_macro_export_mbe() {
+ check(
+ r#"
+//- /lib.rs
+$0
+mod foo;
+
+//- /foo.rs
+/// ```
+/// fn foo() {
+/// }
+/// ```
+#[macro_export]
+macro_rules! foo {
+ () => {
+
+ };
+}
+"#,
+ &[],
+ expect![[r#"
+ []
+ "#]],
+ );
+ check(
+ r#"
+//- /lib.rs
+$0
+/// ```
+/// fn foo() {
+/// }
+/// ```
+#[macro_export]
+macro_rules! foo {
+ () => {
+
+ };
+}
+"#,
+ &[DocTest],
+ expect![[r#"
+ [
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 1..94,
+ name: "foo",
+ },
+ kind: DocTest {
+ test_id: Path(
+ "foo",
+ ),
+ },
+ cfg: None,
+ },
+ ]
+ "#]],
+ );
+ }
}
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index e60c3b04e8..36457a5364 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -447,7 +447,7 @@ impl NameRefClass {
impl_from!(
Field, Module, Function, Adt, Variant, Const, Static, Trait, TypeAlias, BuiltinType, Local,
- GenericParam, Label
+ GenericParam, Label, Macro
for Definition
);
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs
index 4046c2febb..d4fda397d6 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -76,6 +76,14 @@ pub fn visit_file_defs(
cb(def.into());
}
module.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into()));
+
+ let is_root = module.is_crate_root(db);
+ module
+ .legacy_macros(db)
+ .into_iter()
+ // don't show legacy macros declared in the crate-root that were already covered in declarations earlier
+ .filter(|it| !(is_root && it.is_macro_export(db)))
+ .for_each(|mac| cb(mac.into()));
}
/// Checks if the given lint is equal or is contained by the other lint which may or may not be a group.