Skip to content

Commit 5991695

Browse files
committed
Auto merge of #8236 - PatchMixolydic:single_char_lifetime_names, r=llogiq
new lint: `single_char_lifetime_names` This pull request adds a lint against single character lifetime names, as they might not divulge enough information about the purpose of the lifetime. This can make code harder to understand. I placed this in `restriction` rather than `pedantic` (as suggested in #8233) since most of the Rust ecosystem already uses single character lifetime names (to my knowledge, at least) and since single character lifetime names aren't incorrect. I'd be happy to change this upon request, however. Fixes #8233. - [x] Followed lint naming conventions - [x] Added passing UI tests (including committed `.stderr` file) - [x] `cargo test` passes locally - [x] Executed `cargo dev update_lints` - [x] Added lint documentation - [x] Run `cargo dev fmt` changelog: new lint: [`single_char_lifetime_names`]
2 parents 83a9f68 + a6f80fc commit 5991695

File tree

7 files changed

+154
-0
lines changed

7 files changed

+154
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3253,6 +3253,7 @@ Released 2018-09-13
32533253
[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
32543254
[`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
32553255
[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
3256+
[`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names
32563257
[`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
32573258
[`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
32583259
[`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ store.register_lints(&[
435435
shadow::SHADOW_REUSE,
436436
shadow::SHADOW_SAME,
437437
shadow::SHADOW_UNRELATED,
438+
single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES,
438439
single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
439440
size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
440441
slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,

clippy_lints/src/lib.register_restriction.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
5454
LintId::of(shadow::SHADOW_REUSE),
5555
LintId::of(shadow::SHADOW_SAME),
5656
LintId::of(shadow::SHADOW_UNRELATED),
57+
LintId::of(single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES),
5758
LintId::of(strings::STRING_ADD),
5859
LintId::of(strings::STRING_SLICE),
5960
LintId::of(strings::STRING_TO_STRING),

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ mod self_named_constructors;
351351
mod semicolon_if_nothing_returned;
352352
mod serde_api;
353353
mod shadow;
354+
mod single_char_lifetime_names;
354355
mod single_component_path_imports;
355356
mod size_of_in_element_count;
356357
mod slow_vector_initialization;
@@ -858,6 +859,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
858859
store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit));
859860
store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
860861
store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields));
862+
store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
861863
// add lints here, do not remove this comment, it's used in `new_lint`
862864
}
863865

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use clippy_utils::diagnostics::span_lint_and_help;
2+
use rustc_ast::ast::{GenericParam, GenericParamKind};
3+
use rustc_lint::{EarlyContext, EarlyLintPass};
4+
use rustc_middle::lint::in_external_macro;
5+
use rustc_session::{declare_lint_pass, declare_tool_lint};
6+
7+
declare_clippy_lint! {
8+
/// ### What it does
9+
/// Checks for lifetimes with names which are one character
10+
/// long.
11+
///
12+
/// ### Why is this bad?
13+
/// A single character is likely not enough to express the
14+
/// purpose of a lifetime. Using a longer name can make code
15+
/// easier to understand, especially for those who are new to
16+
/// Rust.
17+
///
18+
/// ### Known problems
19+
/// Rust programmers and learning resources tend to use single
20+
/// character lifetimes, so this lint is at odds with the
21+
/// ecosystem at large. In addition, the lifetime's purpose may
22+
/// be obvious or, rarely, expressible in one character.
23+
///
24+
/// ### Example
25+
/// ```rust
26+
/// struct DiagnosticCtx<'a> {
27+
/// source: &'a str,
28+
/// }
29+
/// ```
30+
/// Use instead:
31+
/// ```rust
32+
/// struct DiagnosticCtx<'src> {
33+
/// source: &'src str,
34+
/// }
35+
/// ```
36+
#[clippy::version = "1.59.0"]
37+
pub SINGLE_CHAR_LIFETIME_NAMES,
38+
restriction,
39+
"warns against single-character lifetime names"
40+
}
41+
42+
declare_lint_pass!(SingleCharLifetimeNames => [SINGLE_CHAR_LIFETIME_NAMES]);
43+
44+
impl EarlyLintPass for SingleCharLifetimeNames {
45+
fn check_generic_param(&mut self, ctx: &EarlyContext<'_>, param: &GenericParam) {
46+
if in_external_macro(ctx.sess, param.ident.span) {
47+
return;
48+
}
49+
50+
if let GenericParamKind::Lifetime = param.kind {
51+
if !param.is_placeholder && param.ident.as_str().len() <= 2 {
52+
span_lint_and_help(
53+
ctx,
54+
SINGLE_CHAR_LIFETIME_NAMES,
55+
param.ident.span,
56+
"single-character lifetime names are likely uninformative",
57+
None,
58+
"use a more informative name",
59+
);
60+
}
61+
}
62+
}
63+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#![warn(clippy::single_char_lifetime_names)]
2+
3+
// Lifetimes should only be linted when they're introduced
4+
struct DiagnosticCtx<'a, 'b>
5+
where
6+
'a: 'b,
7+
{
8+
_source: &'a str,
9+
_unit: &'b (),
10+
}
11+
12+
// Only the lifetimes on the `impl`'s generics should be linted
13+
impl<'a, 'b> DiagnosticCtx<'a, 'b> {
14+
fn new(source: &'a str, unit: &'b ()) -> DiagnosticCtx<'a, 'b> {
15+
Self {
16+
_source: source,
17+
_unit: unit,
18+
}
19+
}
20+
}
21+
22+
// No lifetimes should be linted here
23+
impl<'src, 'unit> DiagnosticCtx<'src, 'unit> {
24+
fn new_pass(source: &'src str, unit: &'unit ()) -> DiagnosticCtx<'src, 'unit> {
25+
Self {
26+
_source: source,
27+
_unit: unit,
28+
}
29+
}
30+
}
31+
32+
// Only 'a should be linted here
33+
fn split_once<'a>(base: &'a str, other: &'_ str) -> (&'a str, Option<&'a str>) {
34+
base.split_once(other)
35+
.map(|(left, right)| (left, Some(right)))
36+
.unwrap_or((base, None))
37+
}
38+
39+
fn main() {
40+
let src = "loop {}";
41+
let unit = ();
42+
DiagnosticCtx::new(src, &unit);
43+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error: single-character lifetime names are likely uninformative
2+
--> $DIR/single_char_lifetime_names.rs:4:22
3+
|
4+
LL | struct DiagnosticCtx<'a, 'b>
5+
| ^^
6+
|
7+
= note: `-D clippy::single-char-lifetime-names` implied by `-D warnings`
8+
= help: use a more informative name
9+
10+
error: single-character lifetime names are likely uninformative
11+
--> $DIR/single_char_lifetime_names.rs:4:26
12+
|
13+
LL | struct DiagnosticCtx<'a, 'b>
14+
| ^^
15+
|
16+
= help: use a more informative name
17+
18+
error: single-character lifetime names are likely uninformative
19+
--> $DIR/single_char_lifetime_names.rs:13:6
20+
|
21+
LL | impl<'a, 'b> DiagnosticCtx<'a, 'b> {
22+
| ^^
23+
|
24+
= help: use a more informative name
25+
26+
error: single-character lifetime names are likely uninformative
27+
--> $DIR/single_char_lifetime_names.rs:13:10
28+
|
29+
LL | impl<'a, 'b> DiagnosticCtx<'a, 'b> {
30+
| ^^
31+
|
32+
= help: use a more informative name
33+
34+
error: single-character lifetime names are likely uninformative
35+
--> $DIR/single_char_lifetime_names.rs:33:15
36+
|
37+
LL | fn split_once<'a>(base: &'a str, other: &'_ str) -> (&'a str, Option<&'a str>) {
38+
| ^^
39+
|
40+
= help: use a more informative name
41+
42+
error: aborting due to 5 previous errors
43+

0 commit comments

Comments
 (0)