82 lines
2.4 KiB
Rust
82 lines
2.4 KiB
Rust
use clippy_utils::diagnostics::span_lint_and_help;
|
||
use rustc_ast::ast::{Item, ItemKind};
|
||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||
use rustc_session::declare_lint_pass;
|
||
|
||
declare_clippy_lint! {
|
||
/// ### What it does
|
||
/// Checks whether partial fields of a struct are public.
|
||
///
|
||
/// Either make all fields of a type public, or make none of them public
|
||
///
|
||
/// ### Why is this bad?
|
||
/// Most types should either be:
|
||
/// * Abstract data types: complex objects with opaque implementation which guard
|
||
/// interior invariants and expose intentionally limited API to the outside world.
|
||
/// * Data: relatively simple objects which group a bunch of related attributes together.
|
||
///
|
||
/// ### Example
|
||
/// ```no_run
|
||
/// pub struct Color {
|
||
/// pub r: u8,
|
||
/// pub g: u8,
|
||
/// b: u8,
|
||
/// }
|
||
/// ```
|
||
/// Use instead:
|
||
/// ```no_run
|
||
/// pub struct Color {
|
||
/// pub r: u8,
|
||
/// pub g: u8,
|
||
/// pub b: u8,
|
||
/// }
|
||
/// ```
|
||
#[clippy::version = "1.66.0"]
|
||
pub PARTIAL_PUB_FIELDS,
|
||
restriction,
|
||
"partial fields of a struct are public"
|
||
}
|
||
declare_lint_pass!(PartialPubFields => [PARTIAL_PUB_FIELDS]);
|
||
|
||
impl EarlyLintPass for PartialPubFields {
|
||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
|
||
let ItemKind::Struct(ref st, _) = item.kind else {
|
||
return;
|
||
};
|
||
|
||
let mut fields = st.fields().iter();
|
||
let Some(first_field) = fields.next() else {
|
||
// Empty struct.
|
||
return;
|
||
};
|
||
let all_pub = first_field.vis.kind.is_pub();
|
||
let all_priv = !all_pub;
|
||
|
||
let msg = "mixed usage of pub and non-pub fields";
|
||
|
||
for field in fields {
|
||
if all_priv && field.vis.kind.is_pub() {
|
||
span_lint_and_help(
|
||
cx,
|
||
PARTIAL_PUB_FIELDS,
|
||
field.vis.span,
|
||
msg,
|
||
None,
|
||
"consider using private field here",
|
||
);
|
||
return;
|
||
} else if all_pub && !field.vis.kind.is_pub() {
|
||
span_lint_and_help(
|
||
cx,
|
||
PARTIAL_PUB_FIELDS,
|
||
field.vis.span,
|
||
msg,
|
||
None,
|
||
"consider using public field here",
|
||
);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
}
|