| use rustc_hir::HirId; |
| use rustc_hir::def_id::LocalDefId; |
| use rustc_middle::ty::TyCtxt; |
| use rustc_span::sym; |
| |
| use super::Pass; |
| use crate::clean::{Attributes, Crate, Item}; |
| use crate::core::DocContext; |
| use crate::visit::DocVisitor; |
| |
| pub(crate) const CHECK_DOC_CFG: Pass = Pass { |
| name: "check-doc-cfg", |
| run: Some(check_doc_cfg), |
| description: "checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs", |
| }; |
| |
| pub(crate) fn check_doc_cfg(krate: Crate, cx: &mut DocContext<'_>) -> Crate { |
| let mut checker = DocCfgChecker { cx }; |
| checker.visit_crate(&krate); |
| krate |
| } |
| |
| struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, HirId); |
| |
| impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> { |
| fn emit_span_lint( |
| &self, |
| sess: &rustc_session::Session, |
| lint: &'static rustc_lint::Lint, |
| sp: rustc_span::Span, |
| builtin_diag: rustc_lint_defs::BuiltinLintDiag, |
| ) { |
| self.0.node_span_lint(lint, self.1, sp, |diag| { |
| rustc_lint::decorate_builtin_lint(sess, Some(self.0), builtin_diag, diag) |
| }); |
| } |
| } |
| |
| struct DocCfgChecker<'a, 'tcx> { |
| cx: &'a mut DocContext<'tcx>, |
| } |
| |
| impl DocCfgChecker<'_, '_> { |
| fn check_attrs(&mut self, attrs: &Attributes, did: LocalDefId) { |
| let doc_cfgs = attrs |
| .other_attrs |
| .iter() |
| .filter(|attr| attr.has_name(sym::doc)) |
| .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) |
| .filter(|attr| attr.has_name(sym::cfg)); |
| |
| for doc_cfg in doc_cfgs { |
| if let Some([cfg_mi]) = doc_cfg.meta_item_list() { |
| let _ = rustc_attr_parsing::cfg_matches( |
| cfg_mi, |
| &self.cx.tcx.sess, |
| RustdocCfgMatchesLintEmitter( |
| self.cx.tcx, |
| self.cx.tcx.local_def_id_to_hir_id(did), |
| ), |
| Some(self.cx.tcx.features()), |
| ); |
| } |
| } |
| } |
| } |
| |
| impl DocVisitor<'_> for DocCfgChecker<'_, '_> { |
| fn visit_item(&mut self, item: &'_ Item) { |
| if let Some(Some(local_did)) = item.def_id().map(|did| did.as_local()) { |
| self.check_attrs(&item.attrs, local_did); |
| } |
| |
| self.visit_item_recur(item); |
| } |
| } |