Skip to content

Commit 4c32a55

Browse files
committed
New internal lint: unusual_names
This lint aims at detecting unusual names used in Clippy source code, such as `appl` or `application` for a `rustc_errors::Applicability` variable, instead of `app` and `applicability` which are commonly used throughout Clippy. This helps maintaining the consistency of the Clippy source code.
1 parent 344589f commit 4c32a55

File tree

5 files changed

+117
-0
lines changed

5 files changed

+117
-0
lines changed

clippy_lints_internal/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = "2024"
66
[dependencies]
77
clippy_config = { path = "../clippy_config" }
88
clippy_utils = { path = "../clippy_utils" }
9+
itertools = "0.12"
910
regex = { version = "1.5" }
1011
rustc-semver = "1.1"
1112

clippy_lints_internal/src/internal_paths.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@ use clippy_utils::paths::{PathLookup, PathNS};
22
use clippy_utils::{sym, type_path, value_path};
33

44
// Paths inside rustc
5+
pub static APPLICABILITY: PathLookup = type_path!(rustc_errors::Applicability);
6+
pub static EARLY_CONTEXT: PathLookup = type_path!(rustc_lint::EarlyContext);
57
pub static EARLY_LINT_PASS: PathLookup = type_path!(rustc_lint::passes::EarlyLintPass);
68
pub static KW_MODULE: PathLookup = type_path!(rustc_span::symbol::kw);
9+
pub static LATE_CONTEXT: PathLookup = type_path!(rustc_lint::LateContext);
710
pub static LINT: PathLookup = type_path!(rustc_lint_defs::Lint);
811
pub static SYMBOL: PathLookup = type_path!(rustc_span::symbol::Symbol);
912
pub static SYMBOL_AS_STR: PathLookup = value_path!(rustc_span::symbol::Symbol::as_str);
1013
pub static SYM_MODULE: PathLookup = type_path!(rustc_span::symbol::sym);
1114
pub static SYNTAX_CONTEXT: PathLookup = type_path!(rustc_span::hygiene::SyntaxContext);
15+
#[expect(clippy::unnecessary_def_path, reason = "for uniform checking in internal lint")]
16+
pub static TY_CTXT: PathLookup = type_path!(rustc_middle::ty::TyCtxt);
1217

1318
// Paths in clippy itself
1419
pub static CLIPPY_SYM_MODULE: PathLookup = type_path!(clippy_utils::sym);

clippy_lints_internal/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ mod produce_ice;
4141
mod symbols;
4242
mod unnecessary_def_path;
4343
mod unsorted_clippy_utils_paths;
44+
mod unusual_names;
4445

4546
use rustc_lint::{Lint, LintStore};
4647

@@ -59,6 +60,7 @@ static LINTS: &[&Lint] = &[
5960
symbols::SYMBOL_AS_STR,
6061
unnecessary_def_path::UNNECESSARY_DEF_PATH,
6162
unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS,
63+
unusual_names::UNUSUAL_NAMES,
6264
];
6365

6466
pub fn register_lints(store: &mut LintStore) {
@@ -74,4 +76,5 @@ pub fn register_lints(store: &mut LintStore) {
7476
store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass));
7577
store.register_late_pass(|_| Box::new(msrv_attr_impl::MsrvAttrImpl));
7678
store.register_late_pass(|_| Box::new(almost_standard_lint_formulation::AlmostStandardFormulation::new()));
79+
store.register_late_pass(|_| Box::new(unusual_names::UnusualNames));
7780
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
use clippy_utils::diagnostics::span_lint_and_help;
2+
use clippy_utils::paths::PathLookup;
3+
use clippy_utils::sym;
4+
use itertools::Itertools;
5+
use rustc_hir::def_id::LocalDefId;
6+
use rustc_hir::intravisit::FnKind;
7+
use rustc_hir::{Body, FnDecl, Pat, PatKind, Stmt, StmtKind};
8+
use rustc_lint::{LateContext, LateLintPass};
9+
use rustc_middle::ty::Ty;
10+
use rustc_session::{declare_lint_pass, declare_tool_lint};
11+
use rustc_span::symbol::kw;
12+
use rustc_span::{Span, Symbol};
13+
14+
use crate::internal_paths::{APPLICABILITY, EARLY_CONTEXT, LATE_CONTEXT, TY_CTXT};
15+
16+
declare_tool_lint! {
17+
/// ### What it does
18+
/// Checks if variables of some types use the usual name.
19+
///
20+
/// ### Why is this bad?
21+
/// Restricting the identifiers used for common things in
22+
/// Clippy sources increases consistency.
23+
///
24+
/// ### Example
25+
/// Check that an `rustc_errors::Applicability` variable is
26+
/// named either `app` or `applicability`, and not
27+
/// `a` or `appl`.
28+
pub clippy::UNUSUAL_NAMES,
29+
Warn,
30+
"commonly used concepts should use usual same variable name.",
31+
report_in_external_macro: true
32+
}
33+
34+
declare_lint_pass!(UnusualNames => [UNUSUAL_NAMES]);
35+
36+
const USUAL_NAMES: [(&PathLookup, &str, &[Symbol]); 4] = [
37+
(
38+
&APPLICABILITY,
39+
"rustc_errors::Applicability",
40+
&[sym::app, sym::applicability],
41+
),
42+
(&EARLY_CONTEXT, "rustc_lint::EarlyContext", &[sym::cx]),
43+
(&LATE_CONTEXT, "rustc_lint::LateContext", &[sym::cx]),
44+
(&TY_CTXT, "rustc_middle::ty::TyCtxt", &[sym::tcx]),
45+
];
46+
47+
impl<'tcx> LateLintPass<'tcx> for UnusualNames {
48+
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
49+
if let StmtKind::Let(let_stmt) = stmt.kind
50+
&& let Some(init_expr) = let_stmt.init
51+
{
52+
check_pat_name_for_ty(cx, let_stmt.pat, cx.typeck_results().expr_ty(init_expr), "variable");
53+
}
54+
}
55+
56+
fn check_fn(
57+
&mut self,
58+
cx: &LateContext<'tcx>,
59+
kind: FnKind<'tcx>,
60+
_decl: &'tcx FnDecl<'_>,
61+
body: &'tcx Body<'_>,
62+
_span: Span,
63+
def_id: LocalDefId,
64+
) {
65+
if matches!(kind, FnKind::Closure) {
66+
return;
67+
}
68+
for (param, ty) in body
69+
.params
70+
.iter()
71+
.zip(cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder().inputs())
72+
{
73+
check_pat_name_for_ty(cx, param.pat, *ty, "parameter");
74+
}
75+
}
76+
}
77+
78+
fn check_pat_name_for_ty(cx: &LateContext<'_>, pat: &Pat<'_>, ty: Ty<'_>, kind: &str) {
79+
if let PatKind::Binding(_, _, ident, _) = pat.kind {
80+
let ty = ty.peel_refs();
81+
for (usual_ty, ty_str, usual_names) in USUAL_NAMES {
82+
if usual_ty.matches_ty(cx, ty)
83+
&& !usual_names.contains(&ident.name)
84+
&& ident.name != kw::SelfLower
85+
&& !ident.name.as_str().starts_with('_')
86+
{
87+
let usual_names = usual_names.iter().map(|name| format!("`{name}`")).join(" or ");
88+
span_lint_and_help(
89+
cx,
90+
UNUSUAL_NAMES,
91+
ident.span,
92+
format!("unusual name for a {kind} of type `{ty_str}`"),
93+
None,
94+
format!("prefer using {usual_names}"),
95+
);
96+
}
97+
}
98+
}
99+
}

clippy_utils/src/sym.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ macro_rules! generate {
3434
//
3535
// `cargo dev fmt` ensures that the content of the `generate!()` macro call stays sorted.
3636
generate! {
37+
Applicability,
3738
AsyncReadExt,
3839
AsyncWriteExt,
3940
BACKSLASH_SINGLE_QUOTE: r"\'",
@@ -45,10 +46,12 @@ generate! {
4546
Current,
4647
DOUBLE_QUOTE: "\"",
4748
Deserialize,
49+
EarlyContext,
4850
EarlyLintPass,
4951
IntoIter,
5052
Itertools,
5153
LF: "\n",
54+
LateContext,
5255
Lazy,
5356
Lint,
5457
LowerExp,
@@ -75,7 +78,9 @@ generate! {
7578
Weak,
7679
abs,
7780
ambiguous_glob_reexports,
81+
app,
7882
append,
83+
applicability,
7984
arg,
8085
as_bytes,
8186
as_deref,
@@ -125,6 +130,7 @@ generate! {
125130
count_ones,
126131
create,
127132
create_new,
133+
cx,
128134
cycle,
129135
cyclomatic_complexity,
130136
de,
@@ -287,8 +293,10 @@ generate! {
287293
rsplit_terminator,
288294
rsplitn,
289295
rsplitn_mut,
296+
rustc_errors,
290297
rustc_lint,
291298
rustc_lint_defs,
299+
rustc_middle,
292300
rustc_span,
293301
rustfmt_skip,
294302
rwlock,
@@ -331,6 +339,7 @@ generate! {
331339
symbol,
332340
take,
333341
take_while,
342+
tcx,
334343
then,
335344
then_some,
336345
to_ascii_lowercase,

0 commit comments

Comments
 (0)