rustdoc/passes/
check_doc_cfg.rs1use rustc_hir::HirId;
2use rustc_hir::def_id::LocalDefId;
3use rustc_middle::ty::TyCtxt;
4use rustc_span::sym;
5
6use super::Pass;
7use crate::clean::{Attributes, Crate, Item};
8use crate::core::DocContext;
9use crate::visit::DocVisitor;
10
11pub(crate) const CHECK_DOC_CFG: Pass = Pass {
12 name: "check-doc-cfg",
13 run: Some(check_doc_cfg),
14 description: "checks `#[doc(cfg(...))]` for stability feature and unexpected cfgs",
15};
16
17pub(crate) fn check_doc_cfg(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
18 let mut checker = DocCfgChecker { cx };
19 checker.visit_crate(&krate);
20 krate
21}
22
23struct RustdocCfgMatchesLintEmitter<'a>(TyCtxt<'a>, HirId);
24
25impl<'a> rustc_attr_parsing::CfgMatchesLintEmitter for RustdocCfgMatchesLintEmitter<'a> {
26 fn emit_span_lint(
27 &self,
28 sess: &rustc_session::Session,
29 lint: &'static rustc_lint::Lint,
30 sp: rustc_span::Span,
31 builtin_diag: rustc_lint_defs::BuiltinLintDiag,
32 ) {
33 self.0.node_span_lint(lint, self.1, sp, |diag| {
34 rustc_lint::decorate_builtin_lint(sess, Some(self.0), builtin_diag, diag)
35 });
36 }
37}
38
39struct DocCfgChecker<'a, 'tcx> {
40 cx: &'a mut DocContext<'tcx>,
41}
42
43impl DocCfgChecker<'_, '_> {
44 fn check_attrs(&mut self, attrs: &Attributes, did: LocalDefId) {
45 let doc_cfgs = attrs
46 .other_attrs
47 .iter()
48 .filter(|attr| attr.has_name(sym::doc))
49 .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
50 .filter(|attr| attr.has_name(sym::cfg));
51
52 for doc_cfg in doc_cfgs {
53 if let Some([cfg_mi]) = doc_cfg.meta_item_list() {
54 let _ = rustc_attr_parsing::cfg_matches(
55 cfg_mi,
56 &self.cx.tcx.sess,
57 RustdocCfgMatchesLintEmitter(
58 self.cx.tcx,
59 self.cx.tcx.local_def_id_to_hir_id(did),
60 ),
61 Some(self.cx.tcx.features()),
62 );
63 }
64 }
65 }
66}
67
68impl DocVisitor<'_> for DocCfgChecker<'_, '_> {
69 fn visit_item(&mut self, item: &'_ Item) {
70 if let Some(Some(local_did)) = item.def_id().map(|did| did.as_local()) {
71 self.check_attrs(&item.attrs, local_did);
72 }
73
74 self.visit_item_recur(item);
75 }
76}