Add separated_literal_suffix as an alternative 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.
This commit is contained in:
Dharma Saputra Wijaya 2021-09-22 22:13:54 +08:00
parent e6e6e7d211
commit 1085df58ac
8 changed files with 149 additions and 58 deletions

View file

@ -323,6 +323,7 @@ store.register_lints(&[
misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
misc_early::MIXED_CASE_HEX_LITERALS,
misc_early::REDUNDANT_PATTERN,
misc_early::SEPARATED_LITERAL_SUFFIX,
misc_early::UNNEEDED_FIELD_PATTERN,
misc_early::UNNEEDED_WILDCARD_PATTERN,
misc_early::UNSEPARATED_LITERAL_SUFFIX,

View file

@ -34,6 +34,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
LintId::of(methods::GET_UNWRAP),
LintId::of(methods::UNWRAP_USED),
LintId::of(misc::FLOAT_CMP_CONST),
LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),

View file

@ -1,4 +1,3 @@
use super::MiscEarlyLints;
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast::{Expr, ExprKind, UnOp};
use rustc_lint::EarlyContext;
@ -6,18 +5,14 @@ use rustc_lint::EarlyContext;
use super::DOUBLE_NEG;
pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) {
match expr.kind {
ExprKind::Unary(UnOp::Neg, ref inner) => {
if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
span_lint(
cx,
DOUBLE_NEG,
expr.span,
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
);
}
},
ExprKind::Lit(ref lit) => MiscEarlyLints::check_lit(cx, lit),
_ => (),
if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind {
if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
span_lint(
cx,
DOUBLE_NEG,
expr.span,
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
);
}
}
}

View file

@ -0,0 +1,38 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_ast::ast::Lit;
use rustc_errors::Applicability;
use rustc_lint::EarlyContext;
use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX};
pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
val
} else {
return; // It's useless so shouldn't lint.
};
// Do not lint when literal is unsuffixed.
if !suffix.is_empty() {
if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' {
span_lint_and_sugg(
cx,
SEPARATED_LITERAL_SUFFIX,
lit.span,
&format!("{} type suffix should not be separated by an underscore", sugg_type),
"remove the underscore",
format!("{}{}", &lit_snip[..maybe_last_sep_idx], suffix),
Applicability::MachineApplicable,
);
} else {
span_lint_and_sugg(
cx,
UNSEPARATED_LITERAL_SUFFIX,
lit.span,
&format!("{} type suffix should be separated by an underscore", sugg_type),
"add an underscore",
format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
Applicability::MachineApplicable,
);
}
}
}

View file

@ -1,15 +1,15 @@
mod builtin_type_shadow;
mod double_neg;
mod literal_suffix;
mod mixed_case_hex_literals;
mod redundant_pattern;
mod unneeded_field_pattern;
mod unneeded_wildcard_pattern;
mod unseparated_literal_suffix;
mod zero_prefixed_literal;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet_opt;
use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
use rustc_ast::visit::FnKind;
use rustc_data_structures::fx::FxHashMap;
use rustc_lint::{EarlyContext, EarlyLintPass};
@ -115,9 +115,11 @@ declare_clippy_lint! {
/// ### What it does
/// Warns if literal suffixes are not separated by an
/// underscore.
/// To enforce unseparated literal suffix style,
/// see the `separated_literal_suffix` lint.
///
/// ### Why is this bad?
/// It is much less readable.
/// Suffix style should be consistent.
///
/// ### Example
/// ```rust
@ -132,6 +134,28 @@ declare_clippy_lint! {
"literals whose suffix is not separated by an underscore"
}
declare_clippy_lint! {
/// ### What it does
/// Warns if literal suffixes are separated by an underscore.
/// To enforce separated literal suffix style,
/// see the `unseparated_literal_suffix` lint.
///
/// ### Why is this bad?
/// Suffix style should be consistent.
///
/// ### Example
/// ```rust
/// // Bad
/// let y = 123832_i32;
///
/// // Good
/// let y = 123832i32;
/// ```
pub SEPARATED_LITERAL_SUFFIX,
restriction,
"literals whose suffix is separated by an underscore"
}
declare_clippy_lint! {
/// ### What it does
/// Warns if an integral constant literal starts with `0`.
@ -260,6 +284,7 @@ declare_lint_pass!(MiscEarlyLints => [
DOUBLE_NEG,
MIXED_CASE_HEX_LITERALS,
UNSEPARATED_LITERAL_SUFFIX,
SEPARATED_LITERAL_SUFFIX,
ZERO_PREFIXED_LITERAL,
BUILTIN_TYPE_SHADOW,
REDUNDANT_PATTERN,
@ -310,6 +335,10 @@ impl EarlyLintPass for MiscEarlyLints {
if in_external_macro(cx.sess, expr.span) {
return;
}
if let ExprKind::Lit(ref lit) = expr.kind {
MiscEarlyLints::check_lit(cx, lit);
}
double_neg::check(cx, expr);
}
}
@ -332,7 +361,7 @@ impl MiscEarlyLints {
LitIntType::Unsigned(ty) => ty.name_str(),
LitIntType::Unsuffixed => "",
};
unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
if lit_snip.starts_with("0x") {
mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
@ -342,7 +371,7 @@ impl MiscEarlyLints {
}
} else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
let suffix = float_ty.name_str();
unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
}
}
}

View file

@ -1,26 +0,0 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_ast::ast::Lit;
use rustc_errors::Applicability;
use rustc_lint::EarlyContext;
use super::UNSEPARATED_LITERAL_SUFFIX;
pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
val
} else {
return; // It's useless so shouldn't lint.
};
// Do not lint when literal is unsuffixed.
if !suffix.is_empty() && lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
span_lint_and_sugg(
cx,
UNSEPARATED_LITERAL_SUFFIX,
lit.span,
&format!("{} type suffix should be separated by an underscore", sugg_type),
"add an underscore",
format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
Applicability::MachineApplicable,
);
}
}