Skip to content

Commit 3ff4243

Browse files
committed
Add style configuration for unseparated_literal_suffix
This commit adds a configuration `literal-suffix-style` to enforce a specific style for unseparated_literal_suffix. The configuration accepts two values: - "separated" enforce all literals to be written separately (e.g. `123_i32`) - "unseparated" enforce all literals to be written as unseparated (e.g. `123i32`) Not specifying a value means that there is no preference on style and any style should not be warned.
1 parent 06ec1a3 commit 3ff4243

File tree

5 files changed

+115
-38
lines changed

5 files changed

+115
-38
lines changed

clippy_lints/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2043,7 +2043,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
20432043
store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
20442044
store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
20452045
store.register_early_pass(|| Box::new(formatting::Formatting));
2046-
store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints));
2046+
let literal_suffix_style = conf.literal_suffix_style.clone();
2047+
store.register_early_pass(move || Box::new(misc_early::MiscEarlyLints::new(literal_suffix_style.clone())));
20472048
store.register_early_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
20482049
store.register_late_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
20492050
store.register_early_pass(|| Box::new(unused_unit::UnusedUnit));
Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,18 @@
1-
use super::MiscEarlyLints;
21
use clippy_utils::diagnostics::span_lint;
32
use rustc_ast::ast::{Expr, ExprKind, UnOp};
43
use rustc_lint::EarlyContext;
54

65
use super::DOUBLE_NEG;
76

87
pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) {
9-
match expr.kind {
10-
ExprKind::Unary(UnOp::Neg, ref inner) => {
11-
if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
12-
span_lint(
13-
cx,
14-
DOUBLE_NEG,
15-
expr.span,
16-
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
17-
);
18-
}
19-
},
20-
ExprKind::Lit(ref lit) => MiscEarlyLints::check_lit(cx, lit),
21-
_ => (),
8+
if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind {
9+
if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
10+
span_lint(
11+
cx,
12+
DOUBLE_NEG,
13+
expr.span,
14+
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
15+
);
16+
}
2217
}
2318
}

clippy_lints/src/misc_early/mod.rs

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ mod zero_prefixed_literal;
99

1010
use clippy_utils::diagnostics::span_lint;
1111
use clippy_utils::source::snippet_opt;
12-
use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
12+
use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
1313
use rustc_ast::visit::FnKind;
1414
use rustc_data_structures::fx::FxHashMap;
1515
use rustc_lint::{EarlyContext, EarlyLintPass};
1616
use rustc_middle::lint::in_external_macro;
17-
use rustc_session::{declare_lint_pass, declare_tool_lint};
17+
use rustc_session::{declare_tool_lint, impl_lint_pass};
1818
use rustc_span::source_map::Span;
1919

2020
declare_clippy_lint! {
@@ -113,20 +113,35 @@ declare_clippy_lint! {
113113

114114
declare_clippy_lint! {
115115
/// ### What it does
116-
/// Warns if literal suffixes are not separated by an
117-
/// underscore.
116+
/// If `literal-suffix-stylle` = "separated", warns literal suffixes that are not separated by an
117+
/// underscore
118+
/// e.g `123i32`
118119
///
119-
/// ### Why is this bad?
120-
/// It is much less readable.
120+
/// If `literal-suffix-style` = "unseparated", warns literal suffixes that are separated by an
121+
/// underscore
122+
/// e.g. `123_i32`
123+
///
124+
/// else, any style of literal_suffix is allowed
121125
///
122126
/// ### Example
127+
///
128+
/// #### "separated"
123129
/// ```rust
124130
/// // Bad
125131
/// let y = 123832i32;
126132
///
127133
/// // Good
128134
/// let y = 123832_i32;
129135
/// ```
136+
///
137+
/// #### "unseparated"
138+
/// ```rust
139+
/// // Bad
140+
/// let y = 123832_i32;
141+
///
142+
/// // Good
143+
/// let y = 123832i32;
144+
/// ```
130145
pub UNSEPARATED_LITERAL_SUFFIX,
131146
restriction,
132147
"literals whose suffix is not separated by an underscore"
@@ -254,7 +269,12 @@ declare_clippy_lint! {
254269
"tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
255270
}
256271

257-
declare_lint_pass!(MiscEarlyLints => [
272+
#[allow(clippy::module_name_repetitions)]
273+
pub struct MiscEarlyLints {
274+
literal_suffix_style: Option<LiteralSuffixStyle>,
275+
}
276+
277+
impl_lint_pass!(MiscEarlyLints => [
258278
UNNEEDED_FIELD_PATTERN,
259279
DUPLICATE_UNDERSCORE_ARGUMENT,
260280
DOUBLE_NEG,
@@ -310,12 +330,29 @@ impl EarlyLintPass for MiscEarlyLints {
310330
if in_external_macro(cx.sess, expr.span) {
311331
return;
312332
}
333+
334+
if let ExprKind::Lit(ref lit) = expr.kind {
335+
self.check_lit(cx, lit);
336+
}
313337
double_neg::check(cx, expr);
314338
}
315339
}
316340

317341
impl MiscEarlyLints {
318-
fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
342+
pub fn new(suffix_style: Option<String>) -> Self {
343+
let literal_suffix_style = match suffix_style {
344+
Some(style) => match style.as_str() {
345+
"unseparated" => Some(LiteralSuffixStyle::Unseparated),
346+
"separated" => Some(LiteralSuffixStyle::Separated),
347+
_ => None,
348+
},
349+
_ => None,
350+
};
351+
352+
Self { literal_suffix_style }
353+
}
354+
355+
fn check_lit(&self, cx: &EarlyContext<'_>, lit: &Lit) {
319356
// We test if first character in snippet is a number, because the snippet could be an expansion
320357
// from a built-in macro like `line!()` or a proc-macro like `#[wasm_bindgen]`.
321358
// Note that this check also covers special case that `line!()` is eagerly expanded by compiler.
@@ -332,7 +369,7 @@ impl MiscEarlyLints {
332369
LitIntType::Unsigned(ty) => ty.name_str(),
333370
LitIntType::Unsuffixed => "",
334371
};
335-
unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
372+
unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer", self.literal_suffix_style);
336373
if lit_snip.starts_with("0x") {
337374
mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
338375
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
@@ -342,7 +379,13 @@ impl MiscEarlyLints {
342379
}
343380
} else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
344381
let suffix = float_ty.name_str();
345-
unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
382+
unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float", self.literal_suffix_style);
346383
}
347384
}
348385
}
386+
387+
#[derive(Copy, Clone)]
388+
enum LiteralSuffixStyle {
389+
Unseparated,
390+
Separated,
391+
}

clippy_lints/src/misc_early/unseparated_literal_suffix.rs

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,54 @@ use rustc_ast::ast::Lit;
33
use rustc_errors::Applicability;
44
use rustc_lint::EarlyContext;
55

6-
use super::UNSEPARATED_LITERAL_SUFFIX;
6+
use super::{LiteralSuffixStyle, UNSEPARATED_LITERAL_SUFFIX};
77

8-
pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
8+
pub(super) fn check(
9+
cx: &EarlyContext<'_>,
10+
lit: &Lit,
11+
lit_snip: &str,
12+
suffix: &str,
13+
sugg_type: &str,
14+
style_opt: Option<LiteralSuffixStyle>,
15+
) {
16+
let style = if let Some(suffix_style) = style_opt {
17+
suffix_style
18+
} else {
19+
return;
20+
};
921
let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
1022
val
1123
} else {
1224
return; // It's useless so shouldn't lint.
1325
};
14-
// Do not lint when literal is unsuffixed.
15-
if !suffix.is_empty() && lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
16-
span_lint_and_sugg(
17-
cx,
18-
UNSEPARATED_LITERAL_SUFFIX,
19-
lit.span,
20-
&format!("{} type suffix should be separated by an underscore", sugg_type),
21-
"add an underscore",
22-
format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
23-
Applicability::MachineApplicable,
24-
);
26+
27+
if suffix.is_empty() {
28+
return;
29+
}
30+
31+
match style {
32+
LiteralSuffixStyle::Separated if lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' => {
33+
span_lint_and_sugg(
34+
cx,
35+
UNSEPARATED_LITERAL_SUFFIX,
36+
lit.span,
37+
&format!("{} type suffix should be separated by an underscore", sugg_type),
38+
"add an underscore",
39+
format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
40+
Applicability::MachineApplicable,
41+
);
42+
},
43+
LiteralSuffixStyle::Unseparated if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' => {
44+
span_lint_and_sugg(
45+
cx,
46+
UNSEPARATED_LITERAL_SUFFIX,
47+
lit.span,
48+
&format!("{} type suffix should not be separated by an underscore", sugg_type),
49+
"remove the underscore",
50+
lit_snip[..=maybe_last_sep_idx].to_string(),
51+
Applicability::MachineApplicable,
52+
);
53+
},
54+
_ => (),
2555
}
2656
}

clippy_lints/src/utils/conf.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,14 @@ define_Conf! {
284284
///
285285
/// The list of unicode scripts allowed to be used in the scope.
286286
(allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
287+
/// Lint: UNSEPARATED_LITERAL_SUFFIX
288+
///
289+
/// Configure a specific style for writing literal suffix.
290+
/// Possible Options:
291+
/// - "unseparated" : enforce writing prefix without underscore `_`
292+
/// - "separated" : enforce writing prefix with underscore `_`
293+
/// - None : no style preference
294+
(literal_suffix_style: Option<String> = None),
287295
}
288296

289297
/// Search for the configuration file.

0 commit comments

Comments
 (0)