1 use clippy_utils
::diagnostics
::span_lint_and_then
;
2 use rustc_errors
::Applicability
;
3 use rustc_hir
::def
::{DefKind, Res}
;
4 use rustc_hir
::{Item, ItemKind}
;
5 use rustc_lint
::{LateContext, LateLintPass}
;
7 use rustc_session
::{declare_tool_lint, impl_lint_pass}
;
8 use rustc_span
::def_id
::CRATE_DEF_ID
;
9 use rustc_span
::hygiene
::MacroKind
;
11 declare_clippy_lint
! {
13 /// Checks for items declared `pub(crate)` that are not crate visible because they
14 /// are inside a private module.
16 /// ### Why is this bad?
17 /// Writing `pub(crate)` is misleading when it's redundant due to the parent
18 /// module's visibility.
23 /// pub(crate) fn internal_fn() { }
26 /// This function is not visible outside the module and it can be declared with `pub` or
27 /// private visibility
30 /// pub fn internal_fn() { }
33 #[clippy::version = "1.44.0"]
34 pub REDUNDANT_PUB_CRATE
,
36 "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them."
40 pub struct RedundantPubCrate
{
41 is_exported
: Vec
<bool
>,
44 impl_lint_pass
!(RedundantPubCrate
=> [REDUNDANT_PUB_CRATE
]);
46 impl<'tcx
> LateLintPass
<'tcx
> for RedundantPubCrate
{
47 fn check_item(&mut self, cx
: &LateContext
<'tcx
>, item
: &'tcx Item
<'tcx
>) {
49 if cx
.tcx
.visibility(item
.owner_id
.def_id
) == ty
::Visibility
::Restricted(CRATE_DEF_ID
.to_def_id());
50 if !cx
.effective_visibilities
.is_exported(item
.owner_id
.def_id
) && self.is_exported
.last() == Some(&false);
51 if is_not_macro_export(item
);
53 let span
= item
.span
.with_hi(item
.ident
.span
.hi());
54 let descr
= cx
.tcx
.def_kind(item
.owner_id
).descr(item
.owner_id
.to_def_id());
59 &format
!("pub(crate) {descr} inside private module"),
65 Applicability
::MachineApplicable
,
72 if let ItemKind
::Mod { .. }
= item
.kind
{
74 .push(cx
.effective_visibilities
.is_exported(item
.owner_id
.def_id
));
78 fn check_item_post(&mut self, _cx
: &LateContext
<'tcx
>, item
: &'tcx Item
<'tcx
>) {
79 if let ItemKind
::Mod { .. }
= item
.kind
{
80 self.is_exported
.pop().expect("unbalanced check_item/check_item_post");
85 fn is_not_macro_export
<'tcx
>(item
: &'tcx Item
<'tcx
>) -> bool
{
86 if let ItemKind
::Use(path
, _
) = item
.kind
{
90 .all(|res
| matches
!(res
, Res
::Def(DefKind
::Macro(MacroKind
::Bang
), _
)))
94 } else if let ItemKind
::Macro(..) = item
.kind
{