blob: 8abcc964b890c1d515e73cffe712e85eae292716 [file] [log] [blame]
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, declare_tool_lint};
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<T> = Option<Box<T>>;
/// ```
/// Use instead:
/// ```rust,ignore
/// type OptBox<T> = Option<Box<T>>;
/// ```
#[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(<loc>)` 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<T> = Option<Box<T>>;
/// ```
/// Use instead:
/// ```rust,ignore
/// pub(in super) type OptBox<T> = Option<Box<T>>;
/// ```
#[clippy::version = "1.72.0"]
pub PUB_WITH_SHORTHAND,
restriction,
"disallows usage of `pub(<loc>)`, without `in`"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `pub(<loc>)` without `in`.
///
/// Note: As you cannot write a module's path in `pub(<loc>)`, 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<T> = Option<Box<T>>;
/// ```
/// Use instead:
/// ```rust,ignore
/// pub(super) type OptBox<T> = Option<Box<T>>;
/// ```
#[clippy::version = "1.72.0"]
pub PUB_WITHOUT_SHORTHAND,
restriction,
"disallows usage of `pub(in <loc>)` 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<bool> {
snippet_opt(cx, span).map(|s| !s.starts_with("pub"))
}