fix: Fix runnables trying to add doc tests in the crate root from #[macro_export] macros

This commit is contained in:
Lukas Wirth 2022-03-18 11:55:53 +01:00
parent bd17933c31
commit 828196be3b
6 changed files with 98 additions and 3 deletions

View file

@ -570,6 +570,12 @@ impl Module {
.collect() .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> { pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> {
let def_map = self.id.def_map(db.upcast()); let def_map = self.id.def_map(db.upcast());
def_map[self.id.local_id].scope.impls().map(Impl::from).collect() def_map[self.id.local_id].scope.impls().map(Impl::from).collect()
@ -1789,6 +1795,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 { pub fn kind(&self, db: &dyn HirDatabase) -> MacroKind {
match self.id { match self.id {
MacroId::Macro2Id(it) => match it.lookup(db.upcast()).expander { MacroId::Macro2Id(it) => match it.lookup(db.upcast()).expander {

View file

@ -315,6 +315,7 @@ impl Macro2Data {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct MacroRulesData { pub struct MacroRulesData {
pub name: Name, pub name: Name,
pub macro_export: bool,
} }
impl MacroRulesData { impl MacroRulesData {
@ -326,7 +327,12 @@ impl MacroRulesData {
let item_tree = loc.id.item_tree(db); let item_tree = loc.id.item_tree(db);
let makro = &item_tree[loc.id.value]; 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)] #[derive(Debug, Clone, PartialEq, Eq)]

View file

@ -63,6 +63,7 @@ pub struct ItemScope {
// FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will // 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. // be all resolved to the last one defined if shadowing happens.
legacy_macros: FxHashMap<Name, MacroRulesId>, legacy_macros: FxHashMap<Name, MacroRulesId>,
/// The derive macro invocations in this scope.
attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>, attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
/// The derive macro invocations in this scope, keyed by the owner item over the actual derive attributes /// 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. /// paired with the derive macro invocations for the specific attribute.

View file

@ -157,7 +157,13 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
Definition::SelfType(impl_) => runnable_impl(&sema, &impl_), Definition::SelfType(impl_) => runnable_impl(&sema, &impl_),
_ => None, _ => 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 { if let Definition::SelfType(impl_) = def {
impl_.items(db).into_iter().for_each(|assoc| { impl_.items(db).into_iter().for_each(|assoc| {
let runnable = match 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,
},
]
"#]],
);
}
} }

View file

@ -447,7 +447,7 @@ impl NameRefClass {
impl_from!( impl_from!(
Field, Module, Function, Adt, Variant, Const, Static, Trait, TypeAlias, BuiltinType, Local, Field, Module, Function, Adt, Variant, Const, Static, Trait, TypeAlias, BuiltinType, Local,
GenericParam, Label GenericParam, Label, Macro
for Definition for Definition
); );

View file

@ -76,6 +76,14 @@ pub fn visit_file_defs(
cb(def.into()); cb(def.into());
} }
module.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.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. /// Checks if the given lint is equal or is contained by the other lint which may or may not be a group.