2022-10-16 03:02:23 -05:00
|
|
|
|
use clippy_utils::diagnostics::span_lint_and_help;
|
2022-10-16 03:21:48 -05:00
|
|
|
|
use rustc_ast::ast::{Item, ItemKind};
|
2022-10-16 03:02:23 -05:00
|
|
|
|
use rustc_lint::{EarlyContext, EarlyLintPass};
|
|
|
|
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
/// ```rust
|
|
|
|
|
/// pub struct Color {
|
2022-10-16 04:10:27 -05:00
|
|
|
|
/// pub r: u8,
|
|
|
|
|
/// pub g: u8,
|
|
|
|
|
/// b: u8,
|
2022-10-16 03:02:23 -05:00
|
|
|
|
/// }
|
|
|
|
|
/// ```
|
|
|
|
|
/// Use instead:
|
|
|
|
|
/// ```rust
|
|
|
|
|
/// pub struct Color {
|
2022-10-16 04:10:27 -05:00
|
|
|
|
/// pub r: u8,
|
|
|
|
|
/// pub g: u8,
|
|
|
|
|
/// pub b: u8,
|
2022-10-16 03:02:23 -05:00
|
|
|
|
/// }
|
|
|
|
|
/// ```
|
|
|
|
|
#[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,
|
2022-10-16 03:21:48 -05:00
|
|
|
|
PARTIAL_PUB_FIELDS,
|
2022-10-16 03:02:23 -05:00
|
|
|
|
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,
|
2022-10-16 03:21:48 -05:00
|
|
|
|
PARTIAL_PUB_FIELDS,
|
2022-10-16 03:02:23 -05:00
|
|
|
|
field.vis.span,
|
|
|
|
|
msg,
|
|
|
|
|
None,
|
|
|
|
|
"consider using public field here",
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|