]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/redundant_pub_crate.rs
Auto merge of #8738 - tamaroning:fix_wrong_self_convention, r=xFrednet
[rust.git] / clippy_lints / src / redundant_pub_crate.rs
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, VisibilityKind};
5 use rustc_lint::{LateContext, LateLintPass};
6 use rustc_session::{declare_tool_lint, impl_lint_pass};
7 use rustc_span::hygiene::MacroKind;
8
9 declare_clippy_lint! {
10     /// ### What it does
11     /// Checks for items declared `pub(crate)` that are not crate visible because they
12     /// are inside a private module.
13     ///
14     /// ### Why is this bad?
15     /// Writing `pub(crate)` is misleading when it's redundant due to the parent
16     /// module's visibility.
17     ///
18     /// ### Example
19     /// ```rust
20     /// mod internal {
21     ///     pub(crate) fn internal_fn() { }
22     /// }
23     /// ```
24     /// This function is not visible outside the module and it can be declared with `pub` or
25     /// private visibility
26     /// ```rust
27     /// mod internal {
28     ///     pub fn internal_fn() { }
29     /// }
30     /// ```
31     #[clippy::version = "1.44.0"]
32     pub REDUNDANT_PUB_CRATE,
33     nursery,
34     "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them."
35 }
36
37 #[derive(Default)]
38 pub struct RedundantPubCrate {
39     is_exported: Vec<bool>,
40 }
41
42 impl_lint_pass!(RedundantPubCrate => [REDUNDANT_PUB_CRATE]);
43
44 impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
45     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
46         if_chain! {
47             if let VisibilityKind::Crate { .. } = item.vis.node;
48             if !cx.access_levels.is_exported(item.def_id) && self.is_exported.last() == Some(&false);
49             if is_not_macro_export(item);
50             then {
51                 let span = item.span.with_hi(item.ident.span.hi());
52                 let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id());
53                 span_lint_and_then(
54                     cx,
55                     REDUNDANT_PUB_CRATE,
56                     span,
57                     &format!("pub(crate) {} inside private module", descr),
58                     |diag| {
59                         diag.span_suggestion(
60                             item.vis.span,
61                             "consider using",
62                             "pub".to_string(),
63                             Applicability::MachineApplicable,
64                         );
65                     },
66                 );
67             }
68         }
69
70         if let ItemKind::Mod { .. } = item.kind {
71             self.is_exported.push(cx.access_levels.is_exported(item.def_id));
72         }
73     }
74
75     fn check_item_post(&mut self, _cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
76         if let ItemKind::Mod { .. } = item.kind {
77             self.is_exported.pop().expect("unbalanced check_item/check_item_post");
78         }
79     }
80 }
81
82 fn is_not_macro_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
83     if let ItemKind::Use(path, _) = item.kind {
84         if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = path.res {
85             return false;
86         }
87     }
88
89     true
90 }