]> git.lizzy.rs Git - rust.git/blobdiff - src/librustdoc/clean/types.rs
Rollup merge of #84442 - jyn514:doc-cfg, r=petrochenkov
[rust.git] / src / librustdoc / clean / types.rs
index a2a03dfd15b7c02764807e9c7b5d5daf475929d4..9861e838e33f1c95a03b16dc92da73e472257899 100644 (file)
@@ -1,9 +1,9 @@
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
 use std::default::Default;
-use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::iter::FromIterator;
 use std::lazy::SyncOnceCell as OnceCell;
+use std::path::PathBuf;
 use std::rc::Rc;
 use std::sync::Arc;
 use std::{slice, vec};
@@ -18,7 +18,7 @@
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{BodyId, Mutability};
 use rustc_index::vec::IndexVec;
 use self::SelfTy::*;
 use self::Type::*;
 
-thread_local!(crate static MAX_DEF_IDX: RefCell<FxHashMap<CrateNum, DefIndex>> = Default::default());
+crate type FakeDefIdSet = FxHashSet<FakeDefId>;
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
+crate enum FakeDefId {
+    Real(DefId),
+    Fake(DefIndex, CrateNum),
+}
+
+impl FakeDefId {
+    #[cfg(parallel_compiler)]
+    crate fn new_fake(crate: CrateNum) -> Self {
+        unimplemented!("")
+    }
+
+    #[cfg(not(parallel_compiler))]
+    crate fn new_fake(krate: CrateNum) -> Self {
+        thread_local!(static FAKE_DEF_ID_COUNTER: Cell<usize> = Cell::new(0));
+        let id = FAKE_DEF_ID_COUNTER.with(|id| {
+            let tmp = id.get();
+            id.set(tmp + 1);
+            tmp
+        });
+        Self::Fake(DefIndex::from(id), krate)
+    }
+
+    crate fn new_real(id: DefId) -> Self {
+        Self::Real(id)
+    }
+
+    #[inline]
+    crate fn is_local(self) -> bool {
+        match self {
+            FakeDefId::Real(id) => id.is_local(),
+            FakeDefId::Fake(_, krate) => krate == LOCAL_CRATE,
+        }
+    }
+
+    #[inline]
+    crate fn as_local(self) -> Option<LocalDefId> {
+        match self {
+            FakeDefId::Real(id) => id.as_local(),
+            FakeDefId::Fake(idx, krate) => {
+                (krate == LOCAL_CRATE).then(|| LocalDefId { local_def_index: idx })
+            }
+        }
+    }
+
+    #[inline]
+    crate fn expect_local(self) -> LocalDefId {
+        self.as_local()
+            .unwrap_or_else(|| panic!("FakeDefId::expect_local: `{:?}` isn't local", self))
+    }
+
+    #[inline]
+    crate fn expect_real(self) -> rustc_hir::def_id::DefId {
+        self.as_real().unwrap_or_else(|| panic!("FakeDefId::expect_real: `{:?}` isn't real", self))
+    }
+
+    #[inline]
+    crate fn as_real(self) -> Option<DefId> {
+        match self {
+            FakeDefId::Real(id) => Some(id),
+            FakeDefId::Fake(_, _) => None,
+        }
+    }
+
+    #[inline]
+    crate fn krate(self) -> CrateNum {
+        match self {
+            FakeDefId::Real(id) => id.krate,
+            FakeDefId::Fake(_, krate) => krate,
+        }
+    }
+
+    #[inline]
+    crate fn index(self) -> Option<DefIndex> {
+        match self {
+            FakeDefId::Real(id) => Some(id.index),
+            FakeDefId::Fake(_, _) => None,
+        }
+    }
+}
+
+impl From<DefId> for FakeDefId {
+    fn from(id: DefId) -> Self {
+        Self::Real(id)
+    }
+}
 
 #[derive(Clone, Debug)]
 crate struct Crate {
@@ -90,6 +177,58 @@ fn def_id(&self) -> DefId {
         tcx.crate_name(self.crate_num)
     }
 
+    crate fn src_root(&self, tcx: TyCtxt<'_>) -> PathBuf {
+        match self.src(tcx) {
+            FileName::Real(ref p) => match p.local_path().parent() {
+                Some(p) => p.to_path_buf(),
+                None => PathBuf::new(),
+            },
+            _ => PathBuf::new(),
+        }
+    }
+
+    /// Attempts to find where an external crate is located, given that we're
+    /// rendering in to the specified source destination.
+    crate fn location(
+        &self,
+        extern_url: Option<&str>,
+        dst: &std::path::Path,
+        tcx: TyCtxt<'_>,
+    ) -> ExternalLocation {
+        use ExternalLocation::*;
+
+        fn to_remote(url: impl ToString) -> ExternalLocation {
+            let mut url = url.to_string();
+            if !url.ends_with('/') {
+                url.push('/');
+            }
+            Remote(url)
+        }
+
+        // See if there's documentation generated into the local directory
+        // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts.
+        // Make sure to call `location()` by that time.
+        let local_location = dst.join(&*self.name(tcx).as_str());
+        if local_location.is_dir() {
+            return Local;
+        }
+
+        if let Some(url) = extern_url {
+            return to_remote(url);
+        }
+
+        // Failing that, see if there's an attribute specifying where to find this
+        // external crate
+        let did = DefId { krate: self.crate_num, index: CRATE_DEF_INDEX };
+        tcx.get_attrs(did)
+            .lists(sym::doc)
+            .filter(|a| a.has_name(sym::html_root_url))
+            .filter_map(|a| a.value_str())
+            .map(to_remote)
+            .next()
+            .unwrap_or(Unknown) // Well, at least we tried.
+    }
+
     crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
         let root = self.def_id();
 
@@ -208,7 +347,7 @@ fn def_id(&self) -> DefId {
 /// Anything with a source location and set of attributes and, optionally, a
 /// name. That is, anything that can be documented. This doesn't correspond
 /// directly to the AST's concept of an item; it's a strict superset.
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 crate struct Item {
     /// The name of this item.
     /// Optional because not every item has a name, e.g. impls.
@@ -218,7 +357,7 @@ fn def_id(&self) -> DefId {
     /// Information about this item that is specific to what kind of item it is.
     /// E.g., struct vs enum vs function.
     crate kind: Box<ItemKind>,
-    crate def_id: DefId,
+    crate def_id: FakeDefId,
 
     crate cfg: Option<Arc<Cfg>>,
 }
@@ -227,21 +366,6 @@ fn def_id(&self) -> DefId {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Item, 48);
 
-impl fmt::Debug for Item {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let def_id: &dyn fmt::Debug = if self.is_fake() { &"**FAKE**" } else { &self.def_id };
-
-        fmt.debug_struct("Item")
-            .field("name", &self.name)
-            .field("attrs", &self.attrs)
-            .field("kind", &self.kind)
-            .field("visibility", &self.visibility)
-            .field("def_id", def_id)
-            .field("cfg", &self.cfg)
-            .finish()
-    }
-}
-
 crate fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
     Span::from_rustc_span(def_id.as_local().map_or_else(
         || tcx.def_span(def_id),
@@ -254,19 +378,19 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 impl Item {
     crate fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx Stability> {
-        if self.is_fake() { None } else { tcx.lookup_stability(self.def_id) }
+        if self.is_fake() { None } else { tcx.lookup_stability(self.def_id.expect_real()) }
     }
 
     crate fn const_stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ConstStability> {
-        if self.is_fake() { None } else { tcx.lookup_const_stability(self.def_id) }
+        if self.is_fake() { None } else { tcx.lookup_const_stability(self.def_id.expect_real()) }
     }
 
     crate fn deprecation(&self, tcx: TyCtxt<'_>) -> Option<Deprecation> {
-        if self.is_fake() { None } else { tcx.lookup_deprecation(self.def_id) }
+        if self.is_fake() { None } else { tcx.lookup_deprecation(self.def_id.expect_real()) }
     }
 
     crate fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
-        if self.is_fake() { false } else { tcx.get_attrs(self.def_id).inner_docs() }
+        if self.is_fake() { false } else { tcx.get_attrs(self.def_id.expect_real()).inner_docs() }
     }
 
     crate fn span(&self, tcx: TyCtxt<'_>) -> Span {
@@ -281,7 +405,7 @@ impl Item {
         } else if self.is_fake() {
             Span::dummy()
         } else {
-            rustc_span(self.def_id, tcx)
+            rustc_span(self.def_id.expect_real(), tcx)
         }
     }
 
@@ -335,7 +459,7 @@ pub fn from_def_id_and_attrs_and_parts(
         trace!("name={:?}, def_id={:?}", name, def_id);
 
         Item {
-            def_id,
+            def_id: def_id.into(),
             kind: box kind,
             name,
             attrs,
@@ -359,9 +483,9 @@ pub fn from_def_id_and_attrs_and_parts(
             .map_or(&[][..], |v| v.as_slice())
             .iter()
             .filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
-                match *did {
+                match did {
                     Some(did) => {
-                        if let Some((mut href, ..)) = href(did, cx) {
+                        if let Some((mut href, ..)) = href(did.expect_real(), cx) {
                             if let Some(ref fragment) = *fragment {
                                 href.push('#');
                                 href.push_str(fragment);
@@ -380,8 +504,8 @@ pub fn from_def_id_and_attrs_and_parts(
                     None => {
                         let relative_to = &cx.current;
                         if let Some(ref fragment) = *fragment {
-                            let url = match cx.cache().extern_locations.get(&self.def_id.krate) {
-                                Some(&(_, _, ExternalLocation::Local)) => {
+                            let url = match cx.cache().extern_locations.get(&self.def_id.krate()) {
+                                Some(&ExternalLocation::Local) => {
                                     if relative_to[0] == "std" {
                                         let depth = relative_to.len() - 1;
                                         "../".repeat(depth)
@@ -390,13 +514,12 @@ pub fn from_def_id_and_attrs_and_parts(
                                         format!("{}std/", "../".repeat(depth))
                                     }
                                 }
-                                Some(&(_, _, ExternalLocation::Remote(ref s))) => {
+                                Some(ExternalLocation::Remote(ref s)) => {
                                     format!("{}/std/", s.trim_end_matches('/'))
                                 }
-                                Some(&(_, _, ExternalLocation::Unknown)) | None => format!(
-                                    "https://doc.rust-lang.org/{}/std/",
-                                    crate::doc_rust_lang_org_channel(),
-                                ),
+                                Some(ExternalLocation::Unknown) | None => {
+                                    "https://doc.rust-lang.org/nightly/std/".to_string()
+                                }
                             };
                             // This is a primitive so the url is done "by hand".
                             let tail = fragment.find('#').unwrap_or_else(|| fragment.len());
@@ -420,7 +543,7 @@ pub fn from_def_id_and_attrs_and_parts(
     }
 
     crate fn is_crate(&self) -> bool {
-        self.is_mod() && self.def_id.index == CRATE_DEF_INDEX
+        self.is_mod() && self.def_id.as_real().map_or(false, |did| did.index == CRATE_DEF_INDEX)
     }
 
     crate fn is_mod(&self) -> bool {
@@ -533,13 +656,8 @@ pub fn from_def_id_and_attrs_and_parts(
         }
     }
 
-    /// See the documentation for [`next_def_id()`].
-    ///
-    /// [`next_def_id()`]: DocContext::next_def_id()
     crate fn is_fake(&self) -> bool {
-        MAX_DEF_IDX.with(|m| {
-            m.borrow().get(&self.def_id.krate).map(|&idx| idx <= self.def_id.index).unwrap_or(false)
-        })
+        matches!(self.def_id, FakeDefId::Fake(_, _))
     }
 }
 
@@ -625,10 +743,6 @@ impl ItemKind {
             | KeywordItem(_) => [].iter(),
         }
     }
-
-    crate fn is_type_alias(&self) -> bool {
-        matches!(self, ItemKind::TypedefItem(..) | ItemKind::AssocTypeItem(..))
-    }
 }
 
 #[derive(Clone, Debug)]
@@ -873,7 +987,7 @@ fn from_iter<T>(iter: T) -> Self
     /// This may not be the same as `link` if there was a disambiguator
     /// in an intra-doc link (e.g. \[`fn@f`\])
     pub(crate) link_text: String,
-    pub(crate) did: Option<DefId>,
+    pub(crate) did: Option<FakeDefId>,
     /// The url fragment to append to the link
     pub(crate) fragment: Option<String>,
 }
@@ -971,7 +1085,7 @@ fn update_need_backline(doc_strings: &mut Vec<DocFragment>, frag: &DocFragment)
             }
         }
 
-        let clean_attr = |(attr, parent_module): (&ast::Attribute, _)| {
+        let clean_attr = |(attr, parent_module): (&ast::Attribute, Option<DefId>)| {
             if let Some(value) = attr.doc_str() {
                 trace!("got doc_str={:?}", value);
                 let value = beautify_doc_string(value);
@@ -1591,7 +1705,7 @@ impl Type {
 impl Type {
     fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
         let t: PrimitiveType = match *self {
-            ResolvedPath { did, .. } => return Some(did),
+            ResolvedPath { did, .. } => return Some(did.into()),
             Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
             BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
             BorrowedRef { ref type_, .. } => return type_.inner_def_id(cache),
@@ -2138,7 +2252,6 @@ impl Constant {
     crate span: Span,
     crate unsafety: hir::Unsafety,
     crate generics: Generics,
-    crate provided_trait_methods: FxHashSet<Symbol>,
     crate trait_: Option<Type>,
     crate for_: Type,
     crate items: Vec<Item>,
@@ -2147,6 +2260,15 @@ impl Constant {
     crate blanket_impl: Option<Type>,
 }
 
+impl Impl {
+    crate fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxHashSet<Symbol> {
+        self.trait_
+            .def_id()
+            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
+            .unwrap_or_default()
+    }
+}
+
 #[derive(Clone, Debug)]
 crate struct Import {
     crate kind: ImportKind,