Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lint for pub(crate) items that are not crate visible due to the visibility of the module that contains them #5319

Merged
merged 3 commits into from
Mar 23, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,7 @@ Released 2018-09-13
[`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
[`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
[`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
[`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.

[There are 361 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
[There are 362 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)

We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:

Expand Down
4 changes: 4 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ pub mod ranges;
pub mod redundant_clone;
pub mod redundant_field_names;
pub mod redundant_pattern_matching;
pub mod redundant_pub_crate;
pub mod redundant_static_lifetimes;
pub mod reference;
pub mod regex;
Expand Down Expand Up @@ -744,6 +745,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&redundant_clone::REDUNDANT_CLONE,
&redundant_field_names::REDUNDANT_FIELD_NAMES,
&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING,
&redundant_pub_crate::REDUNDANT_PUB_CRATE,
&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
&reference::DEREF_ADDROF,
&reference::REF_IN_DEREF,
Expand Down Expand Up @@ -1020,6 +1022,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box wildcard_imports::WildcardImports);
store.register_early_pass(|| box macro_use::MacroUseImports);
store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());

store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
Expand Down Expand Up @@ -1669,6 +1672,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&mutex_atomic::MUTEX_INTEGER),
LintId::of(&needless_borrow::NEEDLESS_BORROW),
LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE),
LintId::of(&use_self::USE_SELF),
]);
}
Expand Down
76 changes: 76 additions & 0 deletions clippy_lints/src/redundant_pub_crate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can put it in the style group.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have to run cargo dev update_lints after changing the group.

"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<bool>,
}

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()),
|db| {
db.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");
}
}
}
9 changes: 8 additions & 1 deletion src/lintlist/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub use lint::Lint;
pub use lint::LINT_LEVELS;

// begin lint list, do not remove this comment, it’s used in `update_lints`
pub const ALL_LINTS: [Lint; 361] = [
pub const ALL_LINTS: [Lint; 362] = [
Lint {
name: "absurd_extreme_comparisons",
group: "correctness",
Expand Down Expand Up @@ -1764,6 +1764,13 @@ pub const ALL_LINTS: [Lint; 361] = [
deprecation: None,
module: "redundant_pattern_matching",
},
Lint {
name: "redundant_pub_crate",
group: "nursery",
desc: "Using `pub(crate)` visibility on items that are not crate visible due to the visibility of the module that contains them.",
deprecation: None,
module: "redundant_pub_crate",
},
Lint {
name: "redundant_static_lifetimes",
group: "style",
Expand Down
107 changes: 107 additions & 0 deletions tests/ui/redundant_pub_crate.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// run-rustfix
#![allow(dead_code)]
#![warn(clippy::redundant_pub_crate)]

mod m1 {
fn f() {}
pub fn g() {} // private due to m1
pub fn h() {}

mod m1_1 {
fn f() {}
pub fn g() {} // private due to m1_1 and m1
pub fn h() {}
}

pub mod m1_2 {
// ^ private due to m1
fn f() {}
pub fn g() {} // private due to m1_2 and m1
pub fn h() {}
}

pub mod m1_3 {
fn f() {}
pub fn g() {} // private due to m1
pub fn h() {}
}
}

pub(crate) mod m2 {
fn f() {}
pub fn g() {} // already crate visible due to m2
pub fn h() {}

mod m2_1 {
fn f() {}
pub fn g() {} // private due to m2_1
pub fn h() {}
}

pub mod m2_2 {
// ^ already crate visible due to m2
fn f() {}
pub fn g() {} // already crate visible due to m2_2 and m2
pub fn h() {}
}

pub mod m2_3 {
fn f() {}
pub fn g() {} // already crate visible due to m2
pub fn h() {}
}
}

pub mod m3 {
fn f() {}
pub(crate) fn g() {} // ok: m3 is exported
pub fn h() {}

mod m3_1 {
fn f() {}
pub fn g() {} // private due to m3_1
pub fn h() {}
}

pub(crate) mod m3_2 {
// ^ ok
fn f() {}
pub fn g() {} // already crate visible due to m3_2
pub fn h() {}
}

pub mod m3_3 {
fn f() {}
pub(crate) fn g() {} // ok: m3 and m3_3 are exported
pub fn h() {}
}
}

mod m4 {
fn f() {}
pub fn g() {} // private: not re-exported by `pub use m4::*`
pub fn h() {}

mod m4_1 {
fn f() {}
pub fn g() {} // private due to m4_1
pub fn h() {}
}

pub mod m4_2 {
// ^ private: not re-exported by `pub use m4::*`
fn f() {}
pub fn g() {} // private due to m4_2
pub fn h() {}
}

pub mod m4_3 {
fn f() {}
pub(crate) fn g() {} // ok: m4_3 is re-exported by `pub use m4::*`
pub fn h() {}
}
}

pub use m4::*;

fn main() {}
107 changes: 107 additions & 0 deletions tests/ui/redundant_pub_crate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// run-rustfix
#![allow(dead_code)]
#![warn(clippy::redundant_pub_crate)]

mod m1 {
fn f() {}
pub(crate) fn g() {} // private due to m1
pub fn h() {}

mod m1_1 {
fn f() {}
pub(crate) fn g() {} // private due to m1_1 and m1
pub fn h() {}
}

pub(crate) mod m1_2 {
// ^ private due to m1
fn f() {}
pub(crate) fn g() {} // private due to m1_2 and m1
pub fn h() {}
}

pub mod m1_3 {
fn f() {}
pub(crate) fn g() {} // private due to m1
pub fn h() {}
}
}

pub(crate) mod m2 {
fn f() {}
pub(crate) fn g() {} // already crate visible due to m2
pub fn h() {}

mod m2_1 {
fn f() {}
pub(crate) fn g() {} // private due to m2_1
pub fn h() {}
}

pub(crate) mod m2_2 {
// ^ already crate visible due to m2
fn f() {}
pub(crate) fn g() {} // already crate visible due to m2_2 and m2
pub fn h() {}
}

pub mod m2_3 {
fn f() {}
pub(crate) fn g() {} // already crate visible due to m2
pub fn h() {}
}
}

pub mod m3 {
fn f() {}
pub(crate) fn g() {} // ok: m3 is exported
pub fn h() {}

mod m3_1 {
fn f() {}
pub(crate) fn g() {} // private due to m3_1
pub fn h() {}
}

pub(crate) mod m3_2 {
// ^ ok
fn f() {}
pub(crate) fn g() {} // already crate visible due to m3_2
pub fn h() {}
}

pub mod m3_3 {
fn f() {}
pub(crate) fn g() {} // ok: m3 and m3_3 are exported
pub fn h() {}
}
}

mod m4 {
fn f() {}
pub(crate) fn g() {} // private: not re-exported by `pub use m4::*`
pub fn h() {}

mod m4_1 {
fn f() {}
pub(crate) fn g() {} // private due to m4_1
pub fn h() {}
}

pub(crate) mod m4_2 {
// ^ private: not re-exported by `pub use m4::*`
fn f() {}
pub(crate) fn g() {} // private due to m4_2
pub fn h() {}
}

pub mod m4_3 {
fn f() {}
pub(crate) fn g() {} // ok: m4_3 is re-exported by `pub use m4::*`
pub fn h() {}
}
}

pub use m4::*;

fn main() {}
Loading