-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New lint [min_ident_chars
]
#10916
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
New lint [min_ident_chars
]
#10916
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
52cfc99
Add lint `single_letter_idents`
Centri3 e2ecb13
rename the lint
Centri3 03c8db0
make cargo test pass + example
Centri3 7cdd87c
ignore generics and allow arbitrary threshold
Centri3 243943f
make it work for locals as well
Centri3 95d1bff
add to tests and configuration
Centri3 203e875
`cargo collect-metadata`
Centri3 29c1c6e
refactor and add link to issue
Centri3 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
use clippy_utils::{diagnostics::span_lint, is_from_proc_macro}; | ||
use rustc_data_structures::fx::FxHashSet; | ||
use rustc_hir::{ | ||
def::{DefKind, Res}, | ||
intravisit::{walk_item, Visitor}, | ||
GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind, | ||
}; | ||
use rustc_lint::{LateContext, LateLintPass, LintContext}; | ||
use rustc_middle::lint::in_external_macro; | ||
use rustc_session::{declare_tool_lint, impl_lint_pass}; | ||
use rustc_span::Span; | ||
use std::borrow::Cow; | ||
|
||
declare_clippy_lint! { | ||
/// ### What it does | ||
/// Checks for idents which comprise of a single letter. | ||
/// | ||
/// Note: This lint can be very noisy when enabled; it may be desirable to only enable it | ||
/// temporarily. | ||
/// | ||
/// ### Why is this bad? | ||
/// In many cases it's not, but at times it can severely hinder readability. Some codebases may | ||
/// wish to disallow this to improve readability. | ||
/// | ||
/// ### Example | ||
/// ```rust,ignore | ||
/// for m in movies { | ||
/// let title = m.t; | ||
/// } | ||
/// ``` | ||
/// Use instead: | ||
/// ```rust,ignore | ||
/// for movie in movies { | ||
/// let title = movie.title; | ||
/// } | ||
/// ``` | ||
#[clippy::version = "1.72.0"] | ||
pub MIN_IDENT_CHARS, | ||
restriction, | ||
"disallows idents that are too short" | ||
} | ||
impl_lint_pass!(MinIdentChars => [MIN_IDENT_CHARS]); | ||
|
||
#[derive(Clone)] | ||
pub struct MinIdentChars { | ||
pub allowed_idents_below_min_chars: FxHashSet<String>, | ||
pub min_ident_chars_threshold: u64, | ||
} | ||
|
||
impl MinIdentChars { | ||
#[expect(clippy::cast_possible_truncation)] | ||
fn is_ident_too_short(&self, cx: &LateContext<'_>, str: &str, span: Span) -> bool { | ||
!in_external_macro(cx.sess(), span) | ||
&& str.len() <= self.min_ident_chars_threshold as usize | ||
&& !str.starts_with('_') | ||
&& !str.is_empty() | ||
&& self.allowed_idents_below_min_chars.get(&str.to_owned()).is_none() | ||
} | ||
} | ||
|
||
impl LateLintPass<'_> for MinIdentChars { | ||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { | ||
if self.min_ident_chars_threshold == 0 { | ||
return; | ||
} | ||
|
||
walk_item(&mut IdentVisitor { conf: self, cx }, item); | ||
} | ||
|
||
// This is necessary as `Node::Pat`s are not visited in `visit_id`. :/ | ||
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) { | ||
if let PatKind::Binding(_, _, ident, ..) = pat.kind | ||
&& let str = ident.as_str() | ||
&& self.is_ident_too_short(cx, str, ident.span) | ||
{ | ||
emit_min_ident_chars(self, cx, str, ident.span); | ||
} | ||
} | ||
} | ||
|
||
struct IdentVisitor<'cx, 'tcx> { | ||
conf: &'cx MinIdentChars, | ||
cx: &'cx LateContext<'tcx>, | ||
} | ||
|
||
impl Visitor<'_> for IdentVisitor<'_, '_> { | ||
fn visit_id(&mut self, hir_id: HirId) { | ||
let Self { conf, cx } = *self; | ||
// FIXME(#112534) Reimplementation of `find`, as it uses indexing, which can (and will in | ||
// async functions, or really anything async) panic. This should probably be fixed on the | ||
// rustc side, this is just a temporary workaround. | ||
let node = if hir_id.local_id == ItemLocalId::from_u32(0) { | ||
// In this case, we can just use `find`, `Owner`'s `node` field is private anyway so we can't | ||
// reimplement it even if we wanted to | ||
cx.tcx.hir().find(hir_id) | ||
} else { | ||
let Some(owner) = cx.tcx.hir_owner_nodes(hir_id.owner).as_owner() else { | ||
return; | ||
}; | ||
owner.nodes.get(hir_id.local_id).copied().flatten().map(|p| p.node) | ||
}; | ||
let Some(node) = node else { | ||
return; | ||
}; | ||
let Some(ident) = node.ident() else { | ||
return; | ||
}; | ||
|
||
let str = ident.as_str(); | ||
if conf.is_ident_too_short(cx, str, ident.span) { | ||
if let Node::Item(item) = node && let ItemKind::Use(..) = item.kind { | ||
return; | ||
} | ||
// `struct Awa<T>(T)` | ||
// ^ | ||
if let Node::PathSegment(path) = node { | ||
if let Res::Def(def_kind, ..) = path.res && let DefKind::TyParam = def_kind { | ||
return; | ||
} | ||
if matches!(path.res, Res::PrimTy(..)) || path.res.opt_def_id().is_some_and(|def_id| !def_id.is_local()) | ||
{ | ||
return; | ||
} | ||
} | ||
// `struct Awa<T>(T)` | ||
// ^ | ||
if let Node::GenericParam(generic_param) = node | ||
&& let GenericParamKind::Type { .. } = generic_param.kind | ||
{ | ||
return; | ||
} | ||
|
||
if is_from_proc_macro(cx, &ident) { | ||
return; | ||
} | ||
|
||
emit_min_ident_chars(conf, cx, str, ident.span); | ||
} | ||
} | ||
} | ||
|
||
fn emit_min_ident_chars(conf: &MinIdentChars, cx: &impl LintContext, ident: &str, span: Span) { | ||
let help = if conf.min_ident_chars_threshold == 1 { | ||
Cow::Borrowed("this ident consists of a single char") | ||
} else { | ||
Cow::Owned(format!( | ||
"this ident is too short ({} <= {})", | ||
ident.len(), | ||
conf.min_ident_chars_threshold, | ||
)) | ||
}; | ||
span_lint(cx, MIN_IDENT_CHARS, span, &help); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#![allow(nonstandard_style, unused)] | ||
|
||
pub struct Aaa; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
allowed-idents-below-min-chars = ["Owo", "Uwu", "wha", "t_e", "lse", "_do", "_i_", "put", "her", "_e"] | ||
Centri3 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
min-ident-chars-threshold = 3 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
//@aux-build:extern_types.rs | ||
#![allow(nonstandard_style, unused)] | ||
#![warn(clippy::min_ident_chars)] | ||
|
||
extern crate extern_types; | ||
use extern_types::Aaa; | ||
|
||
struct Owo { | ||
Uwu: u128, | ||
aaa: Aaa, | ||
} | ||
|
||
fn main() { | ||
let wha = 1; | ||
let vvv = 1; | ||
let uuu = 1; | ||
let (mut a, mut b) = (1, 2); | ||
for i in 0..1000 {} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.