]> git.lizzy.rs Git - rust.git/blobdiff - src/librustdoc/clean/mod.rs
Rollup merge of #103709 - cuviper:netbsd-9, r=pietroalbini
[rust.git] / src / librustdoc / clean / mod.rs
index 16e2d9a3cfc3809363312223b769f794c4ec8b27..c2f78fd5950f7148417f6aaba58cdd30210413b5 100644 (file)
@@ -12,7 +12,7 @@
 
 use rustc_ast as ast;
 use rustc_attr as attr;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
@@ -182,10 +182,9 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
         .collect_referenced_late_bound_regions(&poly_trait_ref)
         .into_iter()
         .filter_map(|br| match br {
-            ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => Some(GenericParamDef {
-                name,
-                kind: GenericParamDefKind::Lifetime { outlives: vec![] },
-            }),
+            ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => {
+                Some(GenericParamDef::lifetime(name))
+            }
             _ => None,
         })
         .collect();
@@ -227,7 +226,7 @@ pub(crate) fn clean_middle_const<'tcx>(
     // FIXME: instead of storing the stringified expression, store `self` directly instead.
     Constant {
         type_: clean_middle_ty(constant.ty(), cx, None),
-        kind: ConstantKind::TyConst { expr: constant.to_string() },
+        kind: ConstantKind::TyConst { expr: constant.to_string().into() },
     }
 }
 
@@ -741,10 +740,7 @@ fn clean_ty_generics<'tcx>(
                             p.get_bound_params()
                                 .into_iter()
                                 .flatten()
-                                .map(|param| GenericParamDef {
-                                    name: param.0,
-                                    kind: GenericParamDefKind::Lifetime { outlives: Vec::new() },
-                                })
+                                .map(|param| GenericParamDef::lifetime(param.0))
                                 .collect(),
                         ));
                     }
@@ -957,12 +953,14 @@ fn clean_args_from_types_and_names<'tcx>(
         values: types
             .iter()
             .enumerate()
-            .map(|(i, ty)| {
-                let mut name = names.get(i).map_or(kw::Empty, |ident| ident.name);
-                if name.is_empty() {
-                    name = kw::Underscore;
-                }
-                Argument { name, type_: clean_ty(ty, cx), is_const: false }
+            .map(|(i, ty)| Argument {
+                type_: clean_ty(ty, cx),
+                name: names
+                    .get(i)
+                    .map(|ident| ident.name)
+                    .filter(|ident| !ident.is_empty())
+                    .unwrap_or(kw::Underscore),
+                is_const: false,
             })
             .collect(),
     }
@@ -1024,7 +1022,11 @@ fn clean_fn_decl_from_did_and_sig<'tcx>(
                 .iter()
                 .map(|t| Argument {
                     type_: clean_middle_ty(*t, cx, None),
-                    name: names.next().map_or(kw::Empty, |i| i.name),
+                    name: names
+                        .next()
+                        .map(|i| i.name)
+                        .filter(|i| !i.is_empty())
+                        .unwrap_or(kw::Underscore),
                     is_const: false,
                 })
                 .collect(),
@@ -1144,12 +1146,25 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
             }
         }
         ty::AssocKind::Fn => {
-            let generics = clean_ty_generics(
+            let sig = tcx.fn_sig(assoc_item.def_id);
+
+            let late_bound_regions = sig.bound_vars().into_iter().filter_map(|var| match var {
+                ty::BoundVariableKind::Region(ty::BrNamed(_, name))
+                    if name != kw::UnderscoreLifetime =>
+                {
+                    Some(GenericParamDef::lifetime(name))
+                }
+                _ => None,
+            });
+
+            let mut generics = clean_ty_generics(
                 cx,
                 tcx.generics_of(assoc_item.def_id),
                 tcx.explicit_predicates_of(assoc_item.def_id),
             );
-            let sig = tcx.fn_sig(assoc_item.def_id);
+            // FIXME: This does not place parameters in source order (late-bound ones come last)
+            generics.params.extend(late_bound_regions);
+
             let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(assoc_item.def_id), sig);
 
             if assoc_item.fn_has_self_parameter {
@@ -1200,7 +1215,7 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
                         true
                     }
                     (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &c.kind {
-                        ConstantKind::TyConst { expr } => expr == param.name.as_str(),
+                        ConstantKind::TyConst { expr } => **expr == *param.name.as_str(),
                         _ => false,
                     },
                     _ => false,
@@ -1281,7 +1296,16 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
                         ..
                     }) = generics.params.iter_mut().find(|param| &param.name == arg)
                     {
-                        param_bounds.extend(mem::take(bounds));
+                        param_bounds.append(bounds);
+                    } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
+                    && let Some(GenericParamDef {
+                        kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
+                        ..
+                    }) = generics.params.iter_mut().find(|param| &param.name == arg) {
+                        param_bounds.extend(bounds.drain(..).map(|bound| match bound {
+                            GenericBound::Outlives(lifetime) => lifetime,
+                            _ => unreachable!(),
+                        }));
                     } else {
                         where_predicates.push(pred);
                     }
@@ -1530,7 +1554,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
                 }
             };
 
-            Array(Box::new(clean_ty(ty, cx)), length)
+            Array(Box::new(clean_ty(ty, cx)), length.into())
         }
         TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
         TyKind::OpaqueDef(item_id, _, _) => {
@@ -1602,7 +1626,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
         ty::Array(ty, mut n) => {
             n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
             let n = print_const(cx, n);
-            Array(Box::new(clean_middle_ty(ty, cx, None)), n)
+            Array(Box::new(clean_middle_ty(ty, cx, None)), n.into())
         }
         ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(clean_middle_ty(mt.ty, cx, None))),
         ty::Ref(r, ty, mutbl) => BorrowedRef {
@@ -1653,6 +1677,9 @@ pub(crate) fn clean_middle_ty<'tcx>(
 
             inline::record_extern_fqn(cx, did, ItemType::Trait);
 
+            // FIXME(fmease): Hide the trait-object lifetime bound if it coincides with its default
+            // to partially address #44306. Follow the rules outlined at
+            // https://doc.rust-lang.org/reference/lifetime-elision.html#default-trait-object-lifetimes
             let lifetime = clean_middle_region(*reg);
             let mut bounds = dids
                 .map(|did| {
@@ -1680,8 +1707,22 @@ pub(crate) fn clean_middle_ty<'tcx>(
                 })
                 .collect();
 
+            let late_bound_regions: FxIndexSet<_> = obj
+                .iter()
+                .flat_map(|pb| pb.bound_vars())
+                .filter_map(|br| match br {
+                    ty::BoundVariableKind::Region(ty::BrNamed(_, name))
+                        if name != kw::UnderscoreLifetime =>
+                    {
+                        Some(GenericParamDef::lifetime(name))
+                    }
+                    _ => None,
+                })
+                .collect();
+            let late_bound_regions = late_bound_regions.into_iter().collect();
+
             let path = external_path(cx, did, false, bindings, substs);
-            bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
+            bounds.insert(0, PolyTrait { trait_: path, generic_params: late_bound_regions });
 
             DynTrait(bounds, lifetime)
         }
@@ -1901,6 +1942,79 @@ fn clean_bare_fn_ty<'tcx>(
     BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params }
 }
 
+/// This visitor is used to go through only the "top level" of a item and not enter any sub
+/// item while looking for a given `Ident` which is stored into `item` if found.
+struct OneLevelVisitor<'hir> {
+    map: rustc_middle::hir::map::Map<'hir>,
+    item: Option<&'hir hir::Item<'hir>>,
+    looking_for: Ident,
+    target_hir_id: hir::HirId,
+}
+
+impl<'hir> OneLevelVisitor<'hir> {
+    fn new(map: rustc_middle::hir::map::Map<'hir>, target_hir_id: hir::HirId) -> Self {
+        Self { map, item: None, looking_for: Ident::empty(), target_hir_id }
+    }
+
+    fn reset(&mut self, looking_for: Ident) {
+        self.looking_for = looking_for;
+        self.item = None;
+    }
+}
+
+impl<'hir> hir::intravisit::Visitor<'hir> for OneLevelVisitor<'hir> {
+    type NestedFilter = rustc_middle::hir::nested_filter::All;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.map
+    }
+
+    fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
+        if self.item.is_none()
+            && item.ident == self.looking_for
+            && matches!(item.kind, hir::ItemKind::Use(_, _))
+            || item.hir_id() == self.target_hir_id
+        {
+            self.item = Some(item);
+        }
+    }
+}
+
+/// Because a `Use` item directly links to the imported item, we need to manually go through each
+/// import one by one. To do so, we go to the parent item and look for the `Ident` into it. Then,
+/// if we found the "end item" (the imported one), we stop there because we don't need its
+/// documentation. Otherwise, we repeat the same operation until we find the "end item".
+fn get_all_import_attributes<'hir>(
+    mut item: &hir::Item<'hir>,
+    tcx: TyCtxt<'hir>,
+    target_hir_id: hir::HirId,
+    attributes: &mut Vec<ast::Attribute>,
+) {
+    let hir_map = tcx.hir();
+    let mut visitor = OneLevelVisitor::new(hir_map, target_hir_id);
+    // If the item is an import and has at least a path with two parts, we go into it.
+    while let hir::ItemKind::Use(path, _) = item.kind &&
+        path.segments.len() > 1 &&
+        let hir::def::Res::Def(_, def_id) = path.segments[path.segments.len() - 2].res
+    {
+        if let Some(hir::Node::Item(parent_item)) = hir_map.get_if_local(def_id) {
+            // We add the attributes from this import into the list.
+            attributes.extend_from_slice(hir_map.attrs(item.hir_id()));
+            // We get the `Ident` we will be looking for into `item`.
+            let looking_for = path.segments[path.segments.len() - 1].ident;
+            visitor.reset(looking_for);
+            hir::intravisit::walk_item(&mut visitor, parent_item);
+            if let Some(i) = visitor.item {
+                item = i;
+            } else {
+                break;
+            }
+        } else {
+            break;
+        }
+    }
+}
+
 fn clean_maybe_renamed_item<'tcx>(
     cx: &mut DocContext<'tcx>,
     item: &hir::Item<'tcx>,
@@ -1982,13 +2096,20 @@ fn clean_maybe_renamed_item<'tcx>(
             }
             _ => unreachable!("not yet converted"),
         };
-        if let Some(import_id) = import_id {
-            let (attrs, cfg) = inline::merge_attrs(
-                cx,
-                Some(cx.tcx.parent_module(import_id).to_def_id()),
-                inline::load_attrs(cx, def_id),
-                Some(inline::load_attrs(cx, cx.tcx.hir().local_def_id(import_id).to_def_id())),
-            );
+
+        let mut extra_attrs = Vec::new();
+        if let Some(hir::Node::Item(use_node)) =
+            import_id.and_then(|hir_id| cx.tcx.hir().find(hir_id))
+        {
+            // We get all the various imports' attributes.
+            get_all_import_attributes(use_node, cx.tcx, item.hir_id(), &mut extra_attrs);
+        }
+
+        if !extra_attrs.is_empty() {
+            extra_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
+            let attrs = Attributes::from_ast(&extra_attrs);
+            let cfg = extra_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
+
             vec![Item::from_def_id_and_attrs_and_parts(
                 def_id,
                 Some(name),