Skip to content

Commit a715ae4

Browse files
committed
branch start, add new lint pub_underscore_fields, add ui tests
1 parent 8a98609 commit a715ae4

File tree

6 files changed

+176
-0
lines changed

6 files changed

+176
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4673,6 +4673,7 @@ Released 2018-09-13
46734673
[`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
46744674
[`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
46754675
[`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
4676+
[`pub_underscore_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields
46764677
[`pub_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_use
46774678
[`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark
46784679
[`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
504504
crate::ptr::MUT_FROM_REF_INFO,
505505
crate::ptr::PTR_ARG_INFO,
506506
crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
507+
crate::pub_underscore_fields::PUB_UNDERSCORE_FIELDS_INFO,
507508
crate::pub_use::PUB_USE_INFO,
508509
crate::question_mark::QUESTION_MARK_INFO,
509510
crate::ranges::MANUAL_RANGE_CONTAINS_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ mod permissions_set_readonly_false;
241241
mod precedence;
242242
mod ptr;
243243
mod ptr_offset_with_cast;
244+
mod pub_underscore_fields;
244245
mod pub_use;
245246
mod question_mark;
246247
mod ranges;
@@ -912,6 +913,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
912913
store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
913914
store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock));
914915
store.register_late_pass(|_| Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters));
916+
store.register_early_pass(|| Box::new(pub_underscore_fields::PubUnderscoreFields));
915917
// add lints here, do not remove this comment, it's used in `new_lint`
916918
}
917919

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use clippy_utils::diagnostics::span_lint_and_help;
2+
use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
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 any field of the struct is prefixed with an `_` (underscore) and also marked
9+
/// `pub` (public)
10+
///
11+
/// ### Why is this bad?
12+
/// Fields prefixed with an `_` are inferred as unused, which suggests it should not be marked
13+
/// as `pub`, because marking it as `pub` infers it will be used.
14+
///
15+
/// ### Example
16+
/// ```rust
17+
/// struct FileHandle {
18+
/// pub _descriptor: usize,
19+
/// }
20+
/// ```
21+
/// Use instead:
22+
/// ```rust
23+
/// struct FileHandle {
24+
/// _descriptor: usize,
25+
/// }
26+
/// ```
27+
#[clippy::version = "1.69.0"]
28+
pub PUB_UNDERSCORE_FIELDS,
29+
pedantic,
30+
"struct field prefixed with underscore and marked public"
31+
}
32+
declare_lint_pass!(PubUnderscoreFields => [PUB_UNDERSCORE_FIELDS]);
33+
34+
impl EarlyLintPass for PubUnderscoreFields {
35+
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
36+
// this only pertains to structs
37+
let ItemKind::Struct(ref st, _) = item.kind else {
38+
return;
39+
};
40+
41+
let msg = "field marked as public but also inferred as unused because it's prefixed with `_`";
42+
for field in st.fields().iter() {
43+
if let Some(ident) = field.ident.as_ref()
44+
&& ident.as_str().starts_with('_')
45+
&& !matches!(field.vis.kind, VisibilityKind::Inherited) {
46+
span_lint_and_help(
47+
cx,
48+
PUB_UNDERSCORE_FIELDS,
49+
field.vis.span.to(ident.span),
50+
msg,
51+
None,
52+
"consider removing the underscore, or making the field private",
53+
);
54+
}
55+
}
56+
}
57+
}

tests/ui/pub_underscore_fields.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#![allow(unused)]
2+
#![warn(clippy::pub_underscore_fields)]
3+
4+
fn main() {
5+
pub struct StructWithOneViolation {
6+
pub _a: usize,
7+
}
8+
9+
// should handle structs with multiple violations
10+
pub struct StructWithMultipleViolations {
11+
a: u8,
12+
_b: usize,
13+
pub _c: i64,
14+
pub d: String,
15+
pub _e: Option<u8>,
16+
}
17+
18+
// shouldn't warn on anonymous fields
19+
pub struct AnonymousFields(pub usize, i32);
20+
21+
// don't warn on empty structs
22+
pub struct Empty1;
23+
pub struct Empty2();
24+
pub struct Empty3 {};
25+
26+
pub struct PubCrate {
27+
pub(crate) a: String,
28+
pub(crate) _b: Option<String>,
29+
}
30+
31+
// shouldn't warn on fields named pub
32+
pub struct NamedPub {
33+
r#pub: bool,
34+
_pub: String,
35+
}
36+
37+
mod inner {
38+
pub struct PubSuper {
39+
pub(super) a: usize,
40+
pub(super) _b: u8,
41+
_c: i32,
42+
}
43+
}
44+
45+
mod inner2 {
46+
pub struct PubModVisibility {
47+
pub(in super::inner) e: bool,
48+
pub(in super::inner) _f: Option<()>,
49+
}
50+
}
51+
}

tests/ui/pub_underscore_fields.stderr

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
error[E0433]: failed to resolve: could not find `inner` in the crate root
2+
--> $DIR/pub_underscore_fields.rs:47:27
3+
|
4+
LL | pub(in super::inner) e: bool,
5+
| ^^^^^ could not find `inner` in the crate root
6+
7+
error[E0433]: failed to resolve: could not find `inner` in the crate root
8+
--> $DIR/pub_underscore_fields.rs:48:27
9+
|
10+
LL | pub(in super::inner) _f: Option<()>,
11+
| ^^^^^ could not find `inner` in the crate root
12+
13+
error: field marked as public but also inferred as unused because it's prefixed with `_`
14+
--> $DIR/pub_underscore_fields.rs:6:9
15+
|
16+
LL | pub _a: usize,
17+
| ^^^^^^
18+
|
19+
= help: consider removing the underscore, or making the field private
20+
= note: `-D clippy::pub-underscore-fields` implied by `-D warnings`
21+
22+
error: field marked as public but also inferred as unused because it's prefixed with `_`
23+
--> $DIR/pub_underscore_fields.rs:13:9
24+
|
25+
LL | pub _c: i64,
26+
| ^^^^^^
27+
|
28+
= help: consider removing the underscore, or making the field private
29+
30+
error: field marked as public but also inferred as unused because it's prefixed with `_`
31+
--> $DIR/pub_underscore_fields.rs:15:9
32+
|
33+
LL | pub _e: Option<u8>,
34+
| ^^^^^^
35+
|
36+
= help: consider removing the underscore, or making the field private
37+
38+
error: field marked as public but also inferred as unused because it's prefixed with `_`
39+
--> $DIR/pub_underscore_fields.rs:28:9
40+
|
41+
LL | pub(crate) _b: Option<String>,
42+
| ^^^^^^^^^^^^^
43+
|
44+
= help: consider removing the underscore, or making the field private
45+
46+
error: field marked as public but also inferred as unused because it's prefixed with `_`
47+
--> $DIR/pub_underscore_fields.rs:40:13
48+
|
49+
LL | pub(super) _b: u8,
50+
| ^^^^^^^^^^^^^
51+
|
52+
= help: consider removing the underscore, or making the field private
53+
54+
error: field marked as public but also inferred as unused because it's prefixed with `_`
55+
--> $DIR/pub_underscore_fields.rs:48:13
56+
|
57+
LL | pub(in super::inner) _f: Option<()>,
58+
| ^^^^^^^^^^^^^^^^^^^^^^^
59+
|
60+
= help: consider removing the underscore, or making the field private
61+
62+
error: aborting due to 8 previous errors
63+
64+
For more information about this error, try `rustc --explain E0433`.

0 commit comments

Comments
 (0)