use crate::utils::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind, VisibilityKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { /// **What it does:** Checks for items declared `pub(crate)` that are not crate visible because they /// are inside a private module. /// /// **Why is this bad?** Writing `pub(crate)` is misleading when it's redundant due to the parent /// module's visibility. /// /// **Known problems:** None. /// /// **Example:** /// /// ```rust /// mod internal { /// pub(crate) fn internal_fn() { } /// } /// ``` /// This function is not visible outside the module and it can be declared with `pub` or /// private visibility /// ```rust /// mod internal { /// pub fn internal_fn() { } /// } /// ``` pub REDUNDANT_PUB_CRATE, nursery, "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them." } #[derive(Default)] pub struct RedundantPubCrate { is_exported: Vec, } impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantPubCrate { fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item<'tcx>) { if let VisibilityKind::Crate { .. } = item.vis.node { if !cx.access_levels.is_exported(item.hir_id) { if let Some(false) = self.is_exported.last() { let span = item.span.with_hi(item.ident.span.hi()); span_lint_and_then( cx, REDUNDANT_PUB_CRATE, span, &format!("pub(crate) {} inside private module", item.kind.descr()), |diag| { diag.span_suggestion( item.vis.span, "consider using", "pub".to_string(), Applicability::MachineApplicable, ); }, ) } } } if let ItemKind::Mod { .. } = item.kind { self.is_exported.push(cx.access_levels.is_exported(item.hir_id)); } } fn check_item_post(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx Item<'tcx>) { if let ItemKind::Mod { .. } = item.kind { self.is_exported.pop().expect("unbalanced check_item/check_item_post"); } } }