From 7c34f1a8d8bf45b7c0e4197f642d757b4e01ce01 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 15 Jul 2023 16:43:45 +0000 Subject: [PATCH] Make MissingDoc a module lint. --- compiler/rustc_interface/src/passes.rs | 4 +- compiler/rustc_lint/src/builtin.rs | 35 +--------------- compiler/rustc_lint/src/late.rs | 42 ++++++++++--------- compiler/rustc_lint/src/levels.rs | 11 +++++ compiler/rustc_lint/src/lib.rs | 21 ++-------- src/librustdoc/core.rs | 7 ++-- .../ui/lint/lint-attr-everywhere-late.stderr | 36 ++++++++-------- tests/ui/lint/lint-missing-doc.stderr | 36 ++++++++-------- .../ui/lint/missing-doc-private-macro.stderr | 12 +++--- 9 files changed, 84 insertions(+), 120 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 7355136aae5..a34fdf4ecc9 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -846,9 +846,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { }, { sess.time("lint_checking", || { - rustc_lint::check_crate(tcx, || { - rustc_lint::BuiltinCombinedLateLintPass::new() - }); + rustc_lint::check_crate(tcx); }); }, { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 3dfe84dcccc..310e542e5a5 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -457,10 +457,7 @@ declare_lint! { report_in_external_macro } -pub struct MissingDoc { - /// Stack of whether `#[doc(hidden)]` is set at each level which has lint attributes. - doc_hidden_stack: Vec, -} +pub struct MissingDoc; impl_lint_pass!(MissingDoc => [MISSING_DOCS]); @@ -489,14 +486,6 @@ fn has_doc(attr: &ast::Attribute) -> bool { } impl MissingDoc { - pub fn new() -> MissingDoc { - MissingDoc { doc_hidden_stack: vec![false] } - } - - fn doc_hidden(&self) -> bool { - *self.doc_hidden_stack.last().expect("empty doc_hidden_stack") - } - fn check_missing_docs_attrs( &self, cx: &LateContext<'_>, @@ -510,11 +499,6 @@ impl MissingDoc { return; } - // `#[doc(hidden)]` disables missing_docs check. - if self.doc_hidden() { - return; - } - // Only check publicly-visible items, using the result from the privacy pass. // It's an option so the crate root can also use this function (it doesn't // have a `NodeId`). @@ -537,23 +521,6 @@ impl MissingDoc { } impl<'tcx> LateLintPass<'tcx> for MissingDoc { - #[inline] - fn enter_lint_attrs(&mut self, _cx: &LateContext<'_>, attrs: &[ast::Attribute]) { - let doc_hidden = self.doc_hidden() - || attrs.iter().any(|attr| { - attr.has_name(sym::doc) - && match attr.meta_item_list() { - None => false, - Some(l) => attr::list_contains_name(&l, sym::hidden), - } - }); - self.doc_hidden_stack.push(doc_hidden); - } - - fn exit_lint_attrs(&mut self, _: &LateContext<'_>, _attrs: &[ast::Attribute]) { - self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); - } - fn check_crate(&mut self, cx: &LateContext<'_>) { self.check_missing_docs_attrs(cx, CRATE_DEF_ID, "the", "crate"); } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index fb12ded71d6..3331dbad4a9 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -17,7 +17,7 @@ use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore}; use rustc_ast as ast; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_data_structures::sync::{join, DynSend}; +use rustc_data_structures::sync::join; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit as hir_visit; @@ -336,7 +336,7 @@ macro_rules! impl_late_lint_pass { crate::late_lint_methods!(impl_late_lint_pass, []); -pub(super) fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( +pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( tcx: TyCtxt<'tcx>, module_def_id: LocalDefId, builtin_lints: T, @@ -376,6 +376,12 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>( let mut cx = LateContextAndPass { context, pass }; let (module, _span, hir_id) = tcx.hir().get_module(module_def_id); + + // There is no module lint that will have the crate itself as an item, so check it here. + if hir_id == hir::CRATE_HIR_ID { + lint_callback!(cx, check_crate,); + } + cx.process_mod(module, hir_id); // Visit the crate attributes @@ -383,10 +389,19 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>( for attr in tcx.hir().attrs(hir::CRATE_HIR_ID).iter() { cx.visit_attribute(attr) } + lint_callback!(cx, check_crate_post,); } } -fn late_lint_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(tcx: TyCtxt<'tcx>, builtin_lints: T) { +fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) { + // Note: `passes` is often empty. + let mut passes: Vec<_> = + unerased_lint_store(tcx).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); + + if passes.is_empty() { + return; + } + let context = LateContext { tcx, enclosing_body: None, @@ -399,18 +414,8 @@ fn late_lint_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(tcx: TyCtxt<'tcx>, builti only_module: false, }; - // Note: `passes` is often empty. In that case, it's faster to run - // `builtin_lints` directly rather than bundling it up into the - // `RuntimeCombinedLateLintPass`. - let mut passes: Vec<_> = - unerased_lint_store(tcx).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect(); - if passes.is_empty() { - late_lint_crate_inner(tcx, context, builtin_lints); - } else { - passes.push(Box::new(builtin_lints)); - let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] }; - late_lint_crate_inner(tcx, context, pass); - } + let pass = RuntimeCombinedLateLintPass { passes: &mut passes[..] }; + late_lint_crate_inner(tcx, context, pass); } fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>( @@ -432,15 +437,12 @@ fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>( } /// Performs lint checking on a crate. -pub fn check_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>( - tcx: TyCtxt<'tcx>, - builtin_lints: impl FnOnce() -> T + Send + DynSend, -) { +pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) { join( || { tcx.sess.time("crate_lints", || { // Run whole crate non-incremental lints - late_lint_crate(tcx, builtin_lints()); + late_lint_crate(tcx); }); }, || { diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index fb407be1f02..18b178d8882 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -1,4 +1,5 @@ use crate::{ + builtin::MISSING_DOCS, context::{CheckLintNameResult, LintStore}, fluent_generated as fluent, late::unerased_lint_store, @@ -667,6 +668,16 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { continue; } + // `#[doc(hidden)]` disables missing_docs check. + if attr.has_name(sym::doc) + && attr + .meta_item_list() + .map_or(false, |l| ast::attr::list_contains_name(&l, sym::hidden)) + { + self.insert(LintId::of(MISSING_DOCS), (Level::Allow, LintLevelSource::Default)); + continue; + } + let level = match Level::from_attr(attr) { None => continue, // This is the only lint level with a `LintExpectationId` that can be created from an attribute diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 8ae0c9ba3fe..67823a2dcc2 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -126,11 +126,11 @@ use types::*; use unused::*; /// Useful for other parts of the compiler / Clippy. -pub use builtin::SoftLints; +pub use builtin::{MissingDoc, SoftLints}; pub use context::{CheckLintNameResult, FindLintError, LintStore}; pub use context::{EarlyContext, LateContext, LintContext}; pub use early::{check_ast_node, EarlyCheckNode}; -pub use late::{check_crate, unerased_lint_store}; +pub use late::{check_crate, late_lint_mod, unerased_lint_store}; pub use passes::{EarlyLintPass, LateLintPass}; pub use rustc_session::lint::Level::{self, *}; pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId}; @@ -146,7 +146,7 @@ pub fn provide(providers: &mut Providers) { } fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - late::late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new()); + late_lint_mod(tcx, module_def_id, BuiltinCombinedModuleLateLintPass::new()); } early_lint_methods!( @@ -184,19 +184,6 @@ early_lint_methods!( ] ); -// FIXME: Make a separate lint type which does not require typeck tables. - -late_lint_methods!( - declare_combined_late_lint_pass, - [ - pub BuiltinCombinedLateLintPass, - [ - // Tracks attributes of parents - MissingDoc: MissingDoc::new(), - ] - ] -); - late_lint_methods!( declare_combined_late_lint_pass, [ @@ -250,6 +237,7 @@ late_lint_methods!( MultipleSupertraitUpcastable: MultipleSupertraitUpcastable, MapUnitFn: MapUnitFn, MissingDebugImplementations: MissingDebugImplementations, + MissingDoc: MissingDoc, ] ] ); @@ -278,7 +266,6 @@ fn register_builtins(store: &mut LintStore) { store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints()); store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints()); store.register_lints(&BuiltinCombinedModuleLateLintPass::get_lints()); - store.register_lints(&BuiltinCombinedLateLintPass::get_lints()); store.register_lints(&foreign_modules::get_lints()); add_lint_group!( diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 6f791aec3f2..ceee6274ea5 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -10,6 +10,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{HirId, Path}; use rustc_interface::interface; +use rustc_lint::{late_lint_mod, MissingDoc}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks}; @@ -269,7 +270,7 @@ pub(crate) fn create_config( register_lints: Some(Box::new(crate::lint::register_lints)), override_queries: Some(|_sess, providers, _external_providers| { // Most lints will require typechecking, so just don't run them. - providers.lint_mod = |_, _| {}; + providers.lint_mod = |tcx, module_def_id| late_lint_mod(tcx, module_def_id, MissingDoc); // hack so that `used_trait_imports` won't try to call typeck providers.used_trait_imports = |_, _| { static EMPTY_SET: LazyLock> = LazyLock::new(UnordSet::default); @@ -323,9 +324,7 @@ pub(crate) fn run_global_ctxt( tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) }); tcx.sess.abort_if_errors(); - tcx.sess.time("missing_docs", || { - rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new); - }); + tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx)); tcx.sess.time("check_mod_attrs", || { tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module)) }); diff --git a/tests/ui/lint/lint-attr-everywhere-late.stderr b/tests/ui/lint/lint-attr-everywhere-late.stderr index be4368c5cc3..7fe078068fe 100644 --- a/tests/ui/lint/lint-attr-everywhere-late.stderr +++ b/tests/ui/lint/lint-attr-everywhere-late.stderr @@ -34,12 +34,6 @@ note: the lint level is defined here LL | #![deny(missing_docs)] | ^^^^^^^^^^^^ -error: missing documentation for a function - --> $DIR/lint-attr-everywhere-late.rs:47:5 - | -LL | pub fn missing_inner() {} - | ^^^^^^^^^^^^^^^^^^^^^^ - error: missing documentation for an associated function --> $DIR/lint-attr-everywhere-late.rs:54:5 | @@ -142,18 +136,6 @@ note: the lint level is defined here LL | #[deny(missing_docs)] | ^^^^^^^^^^^^ -error: missing documentation for a variant - --> $DIR/lint-attr-everywhere-late.rs:112:5 - | -LL | Variant1, - | ^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/lint-attr-everywhere-late.rs:111:12 - | -LL | #[deny(missing_docs)] - | ^^^^^^^^^^^^ - error: types that do not implement `Drop` can still have drop glue, consider instead using `std::mem::needs_drop` to detect whether a type is trivially dropped --> $DIR/lint-attr-everywhere-late.rs:93:38 | @@ -196,6 +178,18 @@ note: the lint level is defined here LL | #[deny(overflowing_literals)] const ASSOC_CONST: u8 = 1000; | ^^^^^^^^^^^^^^^^^^^^ +error: missing documentation for a variant + --> $DIR/lint-attr-everywhere-late.rs:112:5 + | +LL | Variant1, + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-attr-everywhere-late.rs:111:12 + | +LL | #[deny(missing_docs)] + | ^^^^^^^^^^^^ + error: variable `PARAM` should have a snake case name --> $DIR/lint-attr-everywhere-late.rs:131:37 | @@ -402,6 +396,12 @@ note: the lint level is defined here LL | TupleStruct(#[deny(enum_intrinsics_non_enums)] discriminant::(&123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^ +error: missing documentation for a function + --> $DIR/lint-attr-everywhere-late.rs:47:5 + | +LL | pub fn missing_inner() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + error: `clashing1` redeclared with a different signature --> $DIR/lint-attr-everywhere-late.rs:123:5 | diff --git a/tests/ui/lint/lint-missing-doc.stderr b/tests/ui/lint/lint-missing-doc.stderr index adcc21c44b2..4e9ee4f2769 100644 --- a/tests/ui/lint/lint-missing-doc.stderr +++ b/tests/ui/lint/lint-missing-doc.stderr @@ -112,24 +112,6 @@ error: missing documentation for a static LL | pub static BAR4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^ -error: missing documentation for a function - --> $DIR/lint-missing-doc.rs:174:5 - | -LL | pub fn undocumented1() {} - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a function - --> $DIR/lint-missing-doc.rs:175:5 - | -LL | pub fn undocumented2() {} - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: missing documentation for a function - --> $DIR/lint-missing-doc.rs:181:9 - | -LL | pub fn also_undocumented1() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: missing documentation for a function --> $DIR/lint-missing-doc.rs:196:5 | @@ -154,5 +136,23 @@ error: missing documentation for a trait alias LL | pub trait T = Sync; | ^^^^^^^^^^^ +error: missing documentation for a function + --> $DIR/lint-missing-doc.rs:174:5 + | +LL | pub fn undocumented1() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a function + --> $DIR/lint-missing-doc.rs:175:5 + | +LL | pub fn undocumented2() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a function + --> $DIR/lint-missing-doc.rs:181:9 + | +LL | pub fn also_undocumented1() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 25 previous errors diff --git a/tests/ui/lint/missing-doc-private-macro.stderr b/tests/ui/lint/missing-doc-private-macro.stderr index 979b007d0ec..18c8ad2de6b 100644 --- a/tests/ui/lint/missing-doc-private-macro.stderr +++ b/tests/ui/lint/missing-doc-private-macro.stderr @@ -1,8 +1,8 @@ error: missing documentation for a macro - --> $DIR/missing-doc-private-macro.rs:31:5 + --> $DIR/missing-doc-private-macro.rs:37:1 | -LL | macro_rules! exported_to_top_level { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub macro top_level_pub_macro { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/missing-doc-private-macro.rs:5:9 @@ -11,10 +11,10 @@ LL | #![deny(missing_docs)] | ^^^^^^^^^^^^ error: missing documentation for a macro - --> $DIR/missing-doc-private-macro.rs:37:1 + --> $DIR/missing-doc-private-macro.rs:31:5 | -LL | pub macro top_level_pub_macro { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | macro_rules! exported_to_top_level { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors