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

Add field_scoped_visibility_modifiers lint #12893

Merged
merged 1 commit into from
Jun 16, 2024
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -5362,6 +5362,7 @@ Released 2018-09-13
[`extra_unused_type_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_type_parameters
[`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from
[`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
[`field_scoped_visibility_modifiers`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_scoped_visibility_modifiers
[`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
[`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map
[`filter_map_bool_then`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_bool_then
Expand Down
1 change: 1 addition & 0 deletions clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::explicit_write::EXPLICIT_WRITE_INFO,
crate::extra_unused_type_parameters::EXTRA_UNUSED_TYPE_PARAMETERS_INFO,
crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO,
crate::field_scoped_visibility_modifiers::FIELD_SCOPED_VISIBILITY_MODIFIERS_INFO,
crate::float_literal::EXCESSIVE_PRECISION_INFO,
crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
crate::floating_point_arithmetic::IMPRECISE_FLOPS_INFO,
Expand Down
75 changes: 75 additions & 0 deletions clippy_lints/src/field_scoped_visibility_modifiers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::declare_lint_pass;

declare_clippy_lint! {
/// ### What it does
/// Checks for usage of scoped visibility modifiers, like `pub(crate)`, on fields. These
/// make a field visible within a scope between public and private.
///
/// ### Why restrict this?
/// Scoped visibility modifiers cause a field to be accessible within some scope between
/// public and private, potentially within an entire crate. This allows for fields to be
/// non-private while upholding internal invariants, but can be a code smell. Scoped visibility
/// requires checking a greater area, potentially an entire crate, to verify that an invariant
/// is upheld, and global analysis requires a lot of effort.
///
/// ### Example
/// ```no_run
/// pub mod public_module {
/// struct MyStruct {
/// pub(crate) first_field: bool,
/// pub(super) second_field: bool
/// }
/// }
/// ```
/// Use instead:
/// ```no_run
/// pub mod public_module {
/// struct MyStruct {
/// first_field: bool,
/// second_field: bool
/// }
/// impl MyStruct {
/// pub(crate) fn get_first_field(&self) -> bool {
/// self.first_field
/// }
/// pub(super) fn get_second_field(&self) -> bool {
/// self.second_field
/// }
/// }
/// }
/// ```
#[clippy::version = "1.78.0"]
pub FIELD_SCOPED_VISIBILITY_MODIFIERS,
restriction,
"checks for usage of a scoped visibility modifier, like `pub(crate)`, on fields"
}

declare_lint_pass!(FieldScopedVisibilityModifiers => [FIELD_SCOPED_VISIBILITY_MODIFIERS]);

impl EarlyLintPass for FieldScopedVisibilityModifiers {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
let ItemKind::Struct(ref st, _) = item.kind else {
return;
};
for field in st.fields() {
let VisibilityKind::Restricted { path, .. } = &field.vis.kind else {
continue;
};
if !path.segments.is_empty() && path.segments[0].ident.name == rustc_span::symbol::kw::SelfLower {
// pub(self) is equivalent to not using pub at all, so we ignore it
continue;
}
span_lint_and_help(
cx,
FIELD_SCOPED_VISIBILITY_MODIFIERS,
field.vis.span,
"scoped visibility modifier on a field",
None,
"consider making the field private and adding a scoped visibility method for it",
);
}
}
}
2 changes: 2 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ mod exit;
mod explicit_write;
mod extra_unused_type_parameters;
mod fallible_impl_from;
mod field_scoped_visibility_modifiers;
mod float_literal;
mod floating_point_arithmetic;
mod format;
Expand Down Expand Up @@ -1169,6 +1170,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
})
});
store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv())));
store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers));
// add lints here, do not remove this comment, it's used in `new_lint`
}

Expand Down
21 changes: 21 additions & 0 deletions tests/ui/field_scoped_visibility_modifiers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#![warn(clippy::field_scoped_visibility_modifiers)]

pub mod pub_module {
pub(in crate::pub_module) mod pub_in_path_module {}
pub(super) mod pub_super_module {}
struct MyStruct {
private_field: bool,
pub pub_field: bool,
pub(crate) pub_crate_field: bool,
pub(in crate::pub_module) pub_in_path_field: bool,
pub(super) pub_super_field: bool,
#[allow(clippy::needless_pub_self)]
pub(self) pub_self_field: bool,
}
}
pub(crate) mod pub_crate_module {}

#[allow(clippy::needless_pub_self)]
pub(self) mod pub_self_module {}

fn main() {}
28 changes: 28 additions & 0 deletions tests/ui/field_scoped_visibility_modifiers.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
error: scoped visibility modifier on a field
--> tests/ui/field_scoped_visibility_modifiers.rs:9:9
|
LL | pub(crate) pub_crate_field: bool,
| ^^^^^^^^^^
|
= help: consider making the field private and adding a scoped visibility method for it
= note: `-D clippy::field-scoped-visibility-modifiers` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::field_scoped_visibility_modifiers)]`

error: scoped visibility modifier on a field
--> tests/ui/field_scoped_visibility_modifiers.rs:10:9
|
LL | pub(in crate::pub_module) pub_in_path_field: bool,
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider making the field private and adding a scoped visibility method for it

error: scoped visibility modifier on a field
--> tests/ui/field_scoped_visibility_modifiers.rs:11:9
|
LL | pub(super) pub_super_field: bool,
| ^^^^^^^^^^
|
= help: consider making the field private and adding a scoped visibility method for it

error: aborting due to 3 previous errors

Loading