Skip to content

Commit d917590

Browse files
committed
Auto merge of #9658 - TennyZhuang:partial-pub-fields, r=llogiq
Add new lint `partial_pub_fields` Signed-off-by: TennyZhuang <[email protected]> *Please write a short comment explaining your change (or "none" for internal only changes)* changelog: `partial_pub_fields`: new lint to disallow partial fields of a struct be pub Resolve #9604
2 parents 332b5b3 + 360b48b commit d917590

9 files changed

+189
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -4134,6 +4134,7 @@ Released 2018-09-13
41344134
[`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
41354135
[`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
41364136
[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
4137+
[`partial_pub_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#partial_pub_fields
41374138
[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
41384139
[`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
41394140
[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite

clippy_lints/src/lib.register_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ store.register_lints(&[
479479
panic_unimplemented::TODO,
480480
panic_unimplemented::UNIMPLEMENTED,
481481
panic_unimplemented::UNREACHABLE,
482+
partial_pub_fields::PARTIAL_PUB_FIELDS,
482483
partialeq_ne_impl::PARTIALEQ_NE_IMPL,
483484
partialeq_to_none::PARTIALEQ_TO_NONE,
484485
pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,

clippy_lints/src/lib.register_restriction.rs

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
6161
LintId::of(panic_unimplemented::TODO),
6262
LintId::of(panic_unimplemented::UNIMPLEMENTED),
6363
LintId::of(panic_unimplemented::UNREACHABLE),
64+
LintId::of(partial_pub_fields::PARTIAL_PUB_FIELDS),
6465
LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
6566
LintId::of(pub_use::PUB_USE),
6667
LintId::of(redundant_slicing::DEREF_BY_SLICING),

clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ mod option_if_let_else;
324324
mod overflow_check_conditional;
325325
mod panic_in_result_fn;
326326
mod panic_unimplemented;
327+
mod partial_pub_fields;
327328
mod partialeq_ne_impl;
328329
mod partialeq_to_none;
329330
mod pass_by_ref_or_value;
@@ -914,6 +915,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
914915
store.register_late_pass(|_| Box::new(bool_to_int_with_if::BoolToIntWithIf));
915916
store.register_late_pass(|_| Box::new(box_default::BoxDefault));
916917
store.register_late_pass(|_| Box::new(implicit_saturating_add::ImplicitSaturatingAdd));
918+
store.register_early_pass(|| Box::new(partial_pub_fields::PartialPubFields));
917919
// add lints here, do not remove this comment, it's used in `new_lint`
918920
}
919921

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use clippy_utils::diagnostics::span_lint_and_help;
2+
use rustc_ast::ast::{Item, ItemKind};
3+
use rustc_lint::{EarlyContext, EarlyLintPass};
4+
use rustc_session::{declare_lint_pass, declare_tool_lint};
5+
6+
declare_clippy_lint! {
7+
/// ### What it does
8+
/// Checks whether partial fields of a struct are public.
9+
///
10+
/// Either make all fields of a type public, or make none of them public
11+
///
12+
/// ### Why is this bad?
13+
/// Most types should either be:
14+
/// * Abstract data types: complex objects with opaque implementation which guard
15+
/// interior invariants and expose intentionally limited API to the outside world.
16+
/// * Data: relatively simple objects which group a bunch of related attributes together.
17+
///
18+
/// ### Example
19+
/// ```rust
20+
/// pub struct Color {
21+
/// pub r: u8,
22+
/// pub g: u8,
23+
/// b: u8,
24+
/// }
25+
/// ```
26+
/// Use instead:
27+
/// ```rust
28+
/// pub struct Color {
29+
/// pub r: u8,
30+
/// pub g: u8,
31+
/// pub b: u8,
32+
/// }
33+
/// ```
34+
#[clippy::version = "1.66.0"]
35+
pub PARTIAL_PUB_FIELDS,
36+
restriction,
37+
"partial fields of a struct are public"
38+
}
39+
declare_lint_pass!(PartialPubFields => [PARTIAL_PUB_FIELDS]);
40+
41+
impl EarlyLintPass for PartialPubFields {
42+
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
43+
let ItemKind::Struct(ref st, _) = item.kind else {
44+
return;
45+
};
46+
47+
let mut fields = st.fields().iter();
48+
let Some(first_field) = fields.next() else {
49+
// Empty struct.
50+
return;
51+
};
52+
let all_pub = first_field.vis.kind.is_pub();
53+
let all_priv = !all_pub;
54+
55+
let msg = "mixed usage of pub and non-pub fields";
56+
57+
for field in fields {
58+
if all_priv && field.vis.kind.is_pub() {
59+
span_lint_and_help(
60+
cx,
61+
PARTIAL_PUB_FIELDS,
62+
field.vis.span,
63+
msg,
64+
None,
65+
"consider using private field here",
66+
);
67+
return;
68+
} else if all_pub && !field.vis.kind.is_pub() {
69+
span_lint_and_help(
70+
cx,
71+
PARTIAL_PUB_FIELDS,
72+
field.vis.span,
73+
msg,
74+
None,
75+
"consider using public field here",
76+
);
77+
return;
78+
}
79+
}
80+
}
81+
}

src/docs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ docs! {
395395
"panic",
396396
"panic_in_result_fn",
397397
"panicking_unwrap",
398+
"partial_pub_fields",
398399
"partialeq_ne_impl",
399400
"partialeq_to_none",
400401
"path_buf_push_overwrite",

src/docs/partial_pub_fields.txt

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
### What it does
2+
Checks whether partial fields of a struct are public.
3+
4+
Either make all fields of a type public, or make none of them public
5+
6+
### Why is this bad?
7+
Most types should either be:
8+
* Abstract data types: complex objects with opaque implementation which guard
9+
interior invariants and expose intentionally limited API to the outside world.
10+
* Data: relatively simple objects which group a bunch of related attributes together.
11+
12+
### Example
13+
```
14+
pub struct Color {
15+
pub r: u8,
16+
pub g: u8,
17+
b: u8,
18+
}
19+
```
20+
Use instead:
21+
```
22+
pub struct Color {
23+
pub r: u8,
24+
pub g: u8,
25+
pub b: u8,
26+
}
27+
```

tests/ui/partial_pub_fields.rs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#![allow(unused)]
2+
#![warn(clippy::partial_pub_fields)]
3+
4+
fn main() {
5+
use std::collections::HashMap;
6+
7+
#[derive(Default)]
8+
pub struct FileSet {
9+
files: HashMap<String, u32>,
10+
pub paths: HashMap<u32, String>,
11+
}
12+
13+
pub struct Color {
14+
pub r: u8,
15+
pub g: u8,
16+
b: u8,
17+
}
18+
19+
pub struct Point(i32, pub i32);
20+
21+
pub struct Visibility {
22+
r#pub: bool,
23+
pub pos: u32,
24+
}
25+
26+
// Don't lint on empty structs;
27+
pub struct Empty1;
28+
pub struct Empty2();
29+
pub struct Empty3 {};
30+
31+
// Don't lint on structs with one field.
32+
pub struct Single1(i32);
33+
pub struct Single2(pub i32);
34+
pub struct Single3 {
35+
v1: i32,
36+
}
37+
pub struct Single4 {
38+
pub v1: i32,
39+
}
40+
}

tests/ui/partial_pub_fields.stderr

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error: mixed usage of pub and non-pub fields
2+
--> $DIR/partial_pub_fields.rs:10:9
3+
|
4+
LL | pub paths: HashMap<u32, String>,
5+
| ^^^
6+
|
7+
= help: consider using private field here
8+
= note: `-D clippy::partial-pub-fields` implied by `-D warnings`
9+
10+
error: mixed usage of pub and non-pub fields
11+
--> $DIR/partial_pub_fields.rs:16:9
12+
|
13+
LL | b: u8,
14+
| ^
15+
|
16+
= help: consider using public field here
17+
18+
error: mixed usage of pub and non-pub fields
19+
--> $DIR/partial_pub_fields.rs:19:27
20+
|
21+
LL | pub struct Point(i32, pub i32);
22+
| ^^^
23+
|
24+
= help: consider using private field here
25+
26+
error: mixed usage of pub and non-pub fields
27+
--> $DIR/partial_pub_fields.rs:23:9
28+
|
29+
LL | pub pos: u32,
30+
| ^^^
31+
|
32+
= help: consider using private field here
33+
34+
error: aborting due to 4 previous errors
35+

0 commit comments

Comments
 (0)