]> git.lizzy.rs Git - rust.git/commitdiff
Teach tools that macros are now HIR items
authorinquisitivecrystal <22333129+inquisitivecrystal@users.noreply.github.com>
Thu, 5 Aug 2021 23:58:46 +0000 (16:58 -0700)
committerinquisitivecrystal <22333129+inquisitivecrystal@users.noreply.github.com>
Sat, 28 Aug 2021 07:24:39 +0000 (00:24 -0700)
src/librustdoc/clean/mod.rs
src/librustdoc/doctest.rs
src/librustdoc/doctree.rs
src/librustdoc/visit_ast.rs
src/tools/clippy/clippy_lints/src/missing_doc.rs
src/tools/clippy/clippy_lints/src/missing_inline.rs
src/tools/clippy/clippy_lints/src/utils/inspector.rs

index b6ff3890c584edf4268078af879d13d6d75627d7..640acffb114d945de22d1324f2bce214fec84637 100644 (file)
@@ -91,7 +91,6 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
         items.extend(self.mods.iter().map(|x| x.clean(cx)));
         items.extend(self.items.iter().map(|x| x.clean(cx)).flatten());
-        items.extend(self.macros.iter().map(|x| x.clean(cx)));
 
         // determine if we should display the inner contents or
         // the outer `mod` item for the source code.
@@ -1861,6 +1860,10 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Vec<Item> {
                 ItemKind::Fn(ref sig, ref generics, body_id) => {
                     clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
                 }
+                ItemKind::Macro(ref macro_def) => MacroItem(Macro {
+                    source: display_macro_source(cx, name, &macro_def, def_id, &item.vis),
+                    imported_from: None,
+                }),
                 ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
                     let items = item_ids
                         .iter()
@@ -2138,24 +2141,6 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
     }
 }
 
-impl Clean<Item> for (&hir::MacroDef<'_>, Option<Symbol>) {
-    fn clean(&self, cx: &mut DocContext<'_>) -> Item {
-        let (item, renamed) = self;
-        let name = renamed.unwrap_or(item.ident.name);
-        let def_id = item.def_id.to_def_id();
-
-        Item::from_hir_id_and_parts(
-            item.hir_id(),
-            Some(name),
-            MacroItem(Macro {
-                source: display_macro_source(cx, name, &item.ast, def_id, &item.vis),
-                imported_from: None,
-            }),
-            cx,
-        )
-    }
-}
-
 impl Clean<TypeBinding> for hir::TypeBinding<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> TypeBinding {
         TypeBinding { name: self.ident.name, kind: self.kind.clean(cx) }
index 083d82cb414d85fca06758a4618e4144e8fbeb3d..bf14a17c0769355f33f36dbad24dcede2b495ea0 100644 (file)
@@ -1171,10 +1171,21 @@ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
     }
 
     fn visit_item(&mut self, item: &'hir hir::Item<'_>) {
-        let name = if let hir::ItemKind::Impl(impl_) = &item.kind {
-            rustc_hir_pretty::id_to_string(&self.map, impl_.self_ty.hir_id)
-        } else {
-            item.ident.to_string()
+        let name = match &item.kind {
+            hir::ItemKind::Macro(ref macro_def) => {
+                // FIXME(#88038): Non exported macros have historically not been tested,
+                // but we really ought to start testing them.
+                let def_id = item.def_id.to_def_id();
+                if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) {
+                    intravisit::walk_item(self, item);
+                    return;
+                }
+                item.ident.to_string()
+            }
+            hir::ItemKind::Impl(impl_) => {
+                rustc_hir_pretty::id_to_string(&self.map, impl_.self_ty.hir_id)
+            }
+            _ => item.ident.to_string(),
         };
 
         self.visit_testable(name, item.hir_id(), item.span, |this| {
@@ -1216,15 +1227,6 @@ fn visit_field_def(&mut self, f: &'hir hir::FieldDef<'_>) {
             intravisit::walk_field_def(this, f);
         });
     }
-
-    fn visit_macro_def(&mut self, macro_def: &'hir hir::MacroDef<'_>) {
-        self.visit_testable(
-            macro_def.ident.to_string(),
-            macro_def.hir_id(),
-            macro_def.span,
-            |_| (),
-        );
-    }
 }
 
 #[cfg(test)]
index eadac89f79ef22e0abcb25e6ae19d3d57cd37d14..8f1e8f277c5fe8795a7a7d8ca98471cf3e8df29c 100644 (file)
@@ -5,6 +5,7 @@
 
 use rustc_hir as hir;
 
+#[derive(Debug)]
 crate struct Module<'hir> {
     crate name: Symbol,
     crate where_inner: Span,
     // (item, renamed)
     crate items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>)>,
     crate foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>,
-    crate macros: Vec<(&'hir hir::MacroDef<'hir>, Option<Symbol>)>,
 }
 
 impl Module<'hir> {
     crate fn new(name: Symbol, id: hir::HirId, where_inner: Span) -> Module<'hir> {
-        Module {
-            name,
-            id,
-            where_inner,
-            mods: Vec::new(),
-            items: Vec::new(),
-            foreigns: Vec::new(),
-            macros: Vec::new(),
-        }
+        Module { name, id, where_inner, mods: Vec::new(), items: Vec::new(), foreigns: Vec::new() }
     }
 
     crate fn where_outer(&self, tcx: TyCtxt<'_>) -> Span {
index e28910355357b29b50eb9c69fcbab79ee60b743c..897b9140fc8bcc6dfdc6aef07198cd5abd59908d 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_middle::middle::privacy::AccessLevel;
 use rustc_middle::ty::TyCtxt;
 use rustc_span;
-use rustc_span::def_id::LOCAL_CRATE;
+use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Symbol};
 
@@ -79,49 +79,23 @@ fn store_path(&mut self, did: DefId) {
             &krate.module(),
             self.cx.tcx.crate_name(LOCAL_CRATE),
         );
-        // Attach the crate's exported macros to the top-level module.
-        // In the case of macros 2.0 (`pub macro`), and for built-in `derive`s or attributes as
-        // well (_e.g._, `Copy`), these are wrongly bundled in there too, so we need to fix that by
-        // moving them back to their correct locations.
-        'exported_macros: for def in krate.exported_macros() {
-            // The `def` of a macro in `exported_macros` should correspond to either:
-            //  - a `#[macro_export] macro_rules!` macro,
-            //  - a built-in `derive` (or attribute) macro such as the ones in `::core`,
-            //  - a `pub macro`.
-            // Only the last two need to be fixed, thus:
-            if def.ast.macro_rules {
-                top_level_module.macros.push((def, None));
-                continue 'exported_macros;
-            }
-            let tcx = self.cx.tcx;
-            // Note: this is not the same as `.parent_module()`. Indeed, the latter looks
-            // for the closest module _ancestor_, which is not necessarily a direct parent
-            // (since a direct parent isn't necessarily a module, c.f. #77828).
-            let macro_parent_def_id = {
-                use rustc_middle::ty::DefIdTree;
-                tcx.parent(def.def_id.to_def_id()).unwrap()
-            };
-            let macro_parent_path = tcx.def_path(macro_parent_def_id);
-            // HACK: rustdoc has no way to lookup `doctree::Module`s by their HirId. Instead,
-            // lookup the module by its name, by looking at each path segment one at a time.
-            let mut cur_mod = &mut top_level_module;
-            for path_segment in macro_parent_path.data {
-                // Path segments may refer to a module (in which case they belong to the type
-                // namespace), which is _necessary_ for the macro to be accessible outside it
-                // (no "associated macros" as of yet). Else we bail with an outer `continue`.
-                let path_segment_ty_ns = match path_segment.data {
-                    rustc_hir::definitions::DefPathData::TypeNs(symbol) => symbol,
-                    _ => continue 'exported_macros,
-                };
-                // Descend into the child module that matches this path segment (if any).
-                match cur_mod.mods.iter_mut().find(|child| child.name == path_segment_ty_ns) {
-                    Some(child_mod) => cur_mod = &mut *child_mod,
-                    None => continue 'exported_macros,
+
+        // `#[macro_export] macro_rules!` items are reexported at the top level of the
+        // crate, regardless of where they're defined. We want to document the
+        // top level rexport of the macro, not its original definition, since
+        // the rexport defines the path that a user will actually see. Accordingly,
+        // we add the rexport as an item here, and then skip over the original
+        // definition in `visit_item()` below.
+        for export in self.cx.tcx.module_exports(CRATE_DEF_ID).unwrap_or(&[]) {
+            if let Res::Def(DefKind::Macro(_), def_id) = export.res {
+                if let Some(local_def_id) = def_id.as_local() {
+                    if self.cx.tcx.has_attr(def_id, sym::macro_export) {
+                        let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
+                        let item = self.cx.tcx.hir().expect_item(hir_id);
+                        top_level_module.items.push((item, None));
+                    }
                 }
             }
-            let cur_mod_def_id = tcx.hir().local_def_id(cur_mod.id).to_def_id();
-            assert_eq!(cur_mod_def_id, macro_parent_def_id);
-            cur_mod.macros.push((def, None));
         }
         self.cx.cache.exact_paths = self.exact_paths;
         top_level_module
@@ -238,10 +212,6 @@ fn maybe_inline_local(
                 self.inlining = prev;
                 true
             }
-            Node::MacroDef(def) if !glob => {
-                om.macros.push((def, renamed));
-                true
-            }
             _ => false,
         };
         self.view_item_stack.remove(&res_hir_id);
@@ -257,7 +227,10 @@ fn visit_item(
         debug!("visiting item {:?}", item);
         let name = renamed.unwrap_or(item.ident.name);
 
-        if item.vis.node.is_pub() {
+        let def_id = item.def_id.to_def_id();
+        let is_pub = item.vis.node.is_pub() || self.cx.tcx.has_attr(def_id, sym::macro_export);
+
+        if is_pub {
             self.store_path(item.def_id.to_def_id());
         }
 
@@ -269,7 +242,7 @@ fn visit_item(
                 }
             }
             // If we're inlining, skip private items.
-            _ if self.inlining && !item.vis.node.is_pub() => {}
+            _ if self.inlining && !is_pub => {}
             hir::ItemKind::GlobalAsm(..) => {}
             hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
             hir::ItemKind::Use(ref path, kind) => {
@@ -285,7 +258,7 @@ fn visit_item(
 
                 // If there was a private module in the current path then don't bother inlining
                 // anything as it will probably be stripped anyway.
-                if item.vis.node.is_pub() && self.inside_public_path {
+                if is_pub && self.inside_public_path {
                     let please_inline = attrs.iter().any(|item| match item.meta_item_list() {
                         Some(ref list) if item.has_name(sym::doc) => {
                             list.iter().any(|i| i.has_name(sym::inline))
@@ -307,6 +280,26 @@ fn visit_item(
 
                 om.items.push((item, renamed))
             }
+            hir::ItemKind::Macro(ref macro_def) => {
+                // `#[macro_export] macro_rules!` items are handled seperately in `visit()`,
+                // above, since they need to be documented at the module top level. Accordingly,
+                // we only want to handle macros if one of three conditions holds:
+                //
+                // 1. This macro was defined by `macro`, and thus isn't covered by the case
+                //    above.
+                // 2. This macro isn't marked with `#[macro_export]`, and thus isn't covered
+                //    by the case above.
+                // 3. We're inlining, since a reexport where inlining has been requested
+                //    should be inlined even if it is also documented at the top level.
+
+                let def_id = item.def_id.to_def_id();
+                let is_macro_2_0 = !macro_def.macro_rules;
+                let nonexported = !self.cx.tcx.has_attr(def_id, sym::macro_export);
+
+                if is_macro_2_0 || nonexported || self.inlining {
+                    om.items.push((item, renamed));
+                }
+            }
             hir::ItemKind::Mod(ref m) => {
                 om.mods.push(self.visit_mod_contents(&item.vis, item.hir_id(), m, name));
             }
index da86d28ee0b2d6f5f8ef288514ed4ace70de2d86..940eee7a78897131d0ced058361e5dd3a87454e3 100644 (file)
@@ -122,8 +122,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
             },
             hir::ItemKind::Const(..)
             | hir::ItemKind::Enum(..)
-            | hir::ItemKind::Mod(..)
             | hir::ItemKind::Macro(..)
+            | hir::ItemKind::Mod(..)
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Struct(..)
             | hir::ItemKind::Trait(..)
index 977e6d966e873779cd4d72e909278e2cbced50ea..667cdd8302528caec005ef878d7a8f2087d50e70 100644 (file)
@@ -118,6 +118,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
             },
             hir::ItemKind::Const(..)
             | hir::ItemKind::Enum(..)
+            | hir::ItemKind::Macro(..)
             | hir::ItemKind::Mod(..)
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Struct(..)
index 6bf216cec1670f1011e1806d653dfd48cd5af4ca..e97983a2e1451d373e77609e8f13f456f7dbbfde 100644 (file)
@@ -381,6 +381,13 @@ fn print_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
             let item_ty = cx.tcx.type_of(did);
             println!("function of type {:#?}", item_ty);
         },
+        hir::ItemKind::Macro(ref macro_def) => {
+            if macro_def.macro_rules {
+                println!("macro introduced by `macro_rules!`");
+            } else {
+                println!("macro introduced by `macro`");
+            }
+        },
         hir::ItemKind::Mod(..) => println!("module"),
         hir::ItemKind::ForeignMod { abi, .. } => println!("foreign module with abi: {}", abi),
         hir::ItemKind::GlobalAsm(asm) => println!("global asm: {:?}", asm),