]> git.lizzy.rs Git - rust.git/blobdiff - src/librustdoc/clean/types.rs
Clean up code a bit:
[rust.git] / src / librustdoc / clean / types.rs
index 0e78fe7aec357f001ff0900d79ef75c3df4c3268..09cb99dbf223df922ed140767e5ee9079effab2d 100644 (file)
@@ -421,7 +421,7 @@ pub fn from_def_id_and_parts(
             kind,
             box ast_attrs.clean(cx),
             cx,
-            ast_attrs.cfg(cx.sess()),
+            ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
         )
     }
 
@@ -747,7 +747,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 
     fn other_attrs(&self) -> Vec<ast::Attribute>;
 
-    fn cfg(&self, sess: &Session) -> Option<Arc<Cfg>>;
+    fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>>;
 }
 
 impl AttributesExt for [ast::Attribute] {
@@ -772,8 +772,58 @@ fn other_attrs(&self) -> Vec<ast::Attribute> {
         self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect()
     }
 
-    fn cfg(&self, sess: &Session) -> Option<Arc<Cfg>> {
-        let mut cfg = Cfg::True;
+    fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
+        let sess = tcx.sess;
+        let doc_cfg_active = tcx.features().doc_cfg;
+
+        trait SingleExt {
+            type Item;
+            fn single(self) -> Option<Self::Item>;
+        }
+
+        impl<T: IntoIterator> SingleExt for T {
+            type Item = T::Item;
+            fn single(self) -> Option<Self::Item> {
+                let mut iter = self.into_iter();
+                let item = iter.next()?;
+                if iter.next().is_some() {
+                    return None;
+                }
+                Some(item)
+            }
+        }
+
+        let mut cfg = if doc_cfg_active {
+            let mut doc_cfg = self
+                .iter()
+                .filter(|attr| attr.has_name(sym::doc))
+                .filter_map(|attr| Some(attr.meta_item_list()?.single()?))
+                .filter(|attr| attr.has_name(sym::cfg))
+                .filter_map(|attr| Some(attr.meta_item_list()?.single()?.meta_item()?.clone()))
+                .peekable();
+            if doc_cfg.peek().is_some() {
+                doc_cfg
+                    .filter_map(|attr| {
+                        Cfg::parse(&attr)
+                            .map_err(|e| sess.diagnostic().span_err(e.span, e.msg))
+                            .ok()
+                    })
+                    .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
+            } else {
+                self.iter()
+                    .filter(|attr| attr.has_name(sym::cfg))
+                    .filter_map(|attr| Some(attr.meta_item_list()?.single()?.meta_item()?.clone()))
+                    .filter_map(|attr| {
+                        Cfg::parse(&attr)
+                            .map_err(|e| sess.diagnostic().span_err(e.span, e.msg))
+                            .ok()
+                    })
+                    .filter(|cfg| !hidden_cfg.contains(cfg))
+                    .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
+            }
+        } else {
+            Cfg::True
+        };
 
         for attr in self.iter() {
             // #[doc]
@@ -800,6 +850,8 @@ fn cfg(&self, sess: &Session) -> Option<Arc<Cfg>> {
             }
         }
 
+        // treat #[target_feature(enable = "feat")] attributes as if they were
+        // #[doc(cfg(target_feature = "feat"))] attributes as well
         for attr in self.lists(sym::target_feature) {
             if attr.has_name(sym::enable) {
                 if let Some(feat) = attr.value_str() {