add new lint, pub_underscore_fields
- add a new late pass lint, with config options - add ui tests for both variations of config option - update CHANGELOG.md github feedback bump version to 1.77 and run cargo collect-metadata Change `,` to `;` in `conf.rs`
This commit is contained in:
parent
7343db9ce3
commit
fa7dd1c4e0
13 changed files with 257 additions and 1 deletions
|
|
@ -576,6 +576,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::ptr::MUT_FROM_REF_INFO,
|
||||
crate::ptr::PTR_ARG_INFO,
|
||||
crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
|
||||
crate::pub_underscore_fields::PUB_UNDERSCORE_FIELDS_INFO,
|
||||
crate::pub_use::PUB_USE_INFO,
|
||||
crate::question_mark::QUESTION_MARK_INFO,
|
||||
crate::question_mark_used::QUESTION_MARK_USED_INFO,
|
||||
|
|
|
|||
|
|
@ -272,6 +272,7 @@ mod permissions_set_readonly_false;
|
|||
mod precedence;
|
||||
mod ptr;
|
||||
mod ptr_offset_with_cast;
|
||||
mod pub_underscore_fields;
|
||||
mod pub_use;
|
||||
mod question_mark;
|
||||
mod question_mark_used;
|
||||
|
|
@ -571,6 +572,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
verbose_bit_mask_threshold,
|
||||
warn_on_all_wildcard_imports,
|
||||
check_private_items,
|
||||
pub_underscore_fields_behavior,
|
||||
|
||||
blacklisted_names: _,
|
||||
cyclomatic_complexity_threshold: _,
|
||||
|
|
@ -1081,6 +1083,11 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences));
|
||||
store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions));
|
||||
store.register_late_pass(|_| Box::new(unconditional_recursion::UnconditionalRecursion));
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(pub_underscore_fields::PubUnderscoreFields {
|
||||
behavior: pub_underscore_fields_behavior,
|
||||
})
|
||||
});
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
|
|
|||
83
clippy_lints/src/pub_underscore_fields.rs
Normal file
83
clippy_lints/src/pub_underscore_fields.rs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
use clippy_config::types::PubUnderscoreFieldsBehaviour;
|
||||
use clippy_utils::attrs::is_doc_hidden;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_path_lang_item;
|
||||
use rustc_hir::{FieldDef, Item, ItemKind, LangItem};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks whether any field of the struct is prefixed with an `_` (underscore) and also marked
|
||||
/// `pub` (public)
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Fields prefixed with an `_` are inferred as unused, which suggests it should not be marked
|
||||
/// as `pub`, because marking it as `pub` infers it will be used.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// struct FileHandle {
|
||||
/// pub _descriptor: usize,
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// struct FileHandle {
|
||||
/// _descriptor: usize,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// OR
|
||||
///
|
||||
/// ```rust
|
||||
/// struct FileHandle {
|
||||
/// pub descriptor: usize,
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.77.0"]
|
||||
pub PUB_UNDERSCORE_FIELDS,
|
||||
pedantic,
|
||||
"struct field prefixed with underscore and marked public"
|
||||
}
|
||||
|
||||
pub struct PubUnderscoreFields {
|
||||
pub behavior: PubUnderscoreFieldsBehaviour,
|
||||
}
|
||||
impl_lint_pass!(PubUnderscoreFields => [PUB_UNDERSCORE_FIELDS]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for PubUnderscoreFields {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
// This lint only pertains to structs.
|
||||
let ItemKind::Struct(variant_data, _) = &item.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
let is_visible = |field: &FieldDef<'_>| match self.behavior {
|
||||
PubUnderscoreFieldsBehaviour::PublicallyExported => cx.effective_visibilities.is_reachable(field.def_id),
|
||||
PubUnderscoreFieldsBehaviour::AllPubFields => {
|
||||
// If there is a visibility span then the field is marked pub in some way.
|
||||
!field.vis_span.is_empty()
|
||||
},
|
||||
};
|
||||
|
||||
for field in variant_data.fields() {
|
||||
// Only pertains to fields that start with an underscore, and are public.
|
||||
if field.ident.as_str().starts_with('_') && is_visible(field)
|
||||
// We ignore fields that have `#[doc(hidden)]`.
|
||||
&& !is_doc_hidden(cx.tcx.hir().attrs(field.hir_id))
|
||||
// We ignore fields that are `PhantomData`.
|
||||
&& !is_path_lang_item(cx, field.ty, LangItem::PhantomData)
|
||||
{
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
PUB_UNDERSCORE_FIELDS,
|
||||
field.vis_span.to(field.ident.span),
|
||||
"field marked as public but also inferred as unused because it's prefixed with `_`",
|
||||
None,
|
||||
"consider removing the underscore, or making the field private",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue