use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use rustc_ast::ast::{Item, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::symbol::kw; use rustc_span::Span; declare_clippy_lint! { /// ### What it does /// Checks for usage of `pub(self)` and `pub(in self)`. /// /// ### Why is this bad? /// It's unnecessary, omitting the `pub` entirely will give the same results. /// /// ### Example /// ```rust,ignore /// pub(self) type OptBox = Option>; /// ``` /// Use instead: /// ```rust,ignore /// type OptBox = Option>; /// ``` #[clippy::version = "1.72.0"] pub NEEDLESS_PUB_SELF, style, "checks for usage of `pub(self)` and `pub(in self)`." } declare_clippy_lint! { /// ### What it does /// Checks for usage of `pub()` with `in`. /// /// ### Why is this bad? /// Consistency. Use it or don't, just be consistent about it. /// /// Also see the `pub_without_shorthand` lint for an alternative. /// /// ### Example /// ```rust,ignore /// pub(super) type OptBox = Option>; /// ``` /// Use instead: /// ```rust,ignore /// pub(in super) type OptBox = Option>; /// ``` #[clippy::version = "1.72.0"] pub PUB_WITH_SHORTHAND, restriction, "disallows usage of `pub()`, without `in`" } declare_clippy_lint! { /// ### What it does /// Checks for usage of `pub()` without `in`. /// /// Note: As you cannot write a module's path in `pub()`, this will only trigger on /// `pub(super)` and the like. /// /// ### Why is this bad? /// Consistency. Use it or don't, just be consistent about it. /// /// Also see the `pub_with_shorthand` lint for an alternative. /// /// ### Example /// ```rust,ignore /// pub(in super) type OptBox = Option>; /// ``` /// Use instead: /// ```rust,ignore /// pub(super) type OptBox = Option>; /// ``` #[clippy::version = "1.72.0"] pub PUB_WITHOUT_SHORTHAND, restriction, "disallows usage of `pub(in )` with `in`" } declare_lint_pass!(Visibility => [NEEDLESS_PUB_SELF, PUB_WITH_SHORTHAND, PUB_WITHOUT_SHORTHAND]); impl EarlyLintPass for Visibility { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { if !in_external_macro(cx.sess(), item.span) && let VisibilityKind::Restricted { path, shorthand, .. } = &item.vis.kind { if **path == kw::SelfLower && let Some(false) = is_from_proc_macro(cx, item.vis.span) { span_lint_and_sugg( cx, NEEDLESS_PUB_SELF, item.vis.span, &format!("unnecessary `pub({}self)`", if *shorthand { "" } else { "in " }), "remove it", String::new(), Applicability::MachineApplicable, ); } if (**path == kw::Super || **path == kw::SelfLower || **path == kw::Crate) && !*shorthand && let [.., last] = &*path.segments && let Some(false) = is_from_proc_macro(cx, item.vis.span) { span_lint_and_sugg( cx, PUB_WITHOUT_SHORTHAND, item.vis.span, "usage of `pub` with `in`", "remove it", format!("pub({})", last.ident), Applicability::MachineApplicable, ); } if *shorthand && let [.., last] = &*path.segments && let Some(false) = is_from_proc_macro(cx, item.vis.span) { span_lint_and_sugg( cx, PUB_WITH_SHORTHAND, item.vis.span, "usage of `pub` without `in`", "add it", format!("pub(in {})", last.ident), Applicability::MachineApplicable, ); } } } } fn is_from_proc_macro(cx: &EarlyContext<'_>, span: Span) -> Option { snippet_opt(cx, span).map(|s| !s.starts_with("pub")) }