Skip to content

Commit

Permalink
Uplift clippy::zero_prefixed_literal as `leading_zeros_in_decimal_l…
Browse files Browse the repository at this point in the history
…iterals`
  • Loading branch information
GrigorenkoPV committed Dec 4, 2024
1 parent c44b3d5 commit e7881ba
Show file tree
Hide file tree
Showing 14 changed files with 212 additions and 115 deletions.
4 changes: 4 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,10 @@ lint_invalid_reference_casting_note_book = for more information, visit <https://
lint_invalid_reference_casting_note_ty_has_interior_mutability = even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get`
lint_leading_zeros_in_decimal_literals = this is a decimal constant
.suggestion_remove_zeros = if you meant to use a decimal constant, remove leading zeros to avoid confusion
.suggestion_prefix_octal = if you meant to use an octal constant, prefix it with `0o` instead
lint_legacy_derive_helpers = derive helper attribute is used before it is introduced
.label = the attribute is introduced here
Expand Down
75 changes: 74 additions & 1 deletion compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ use crate::lints::{
BuiltinTrivialBounds, BuiltinTypeAliasBounds, BuiltinUngatedAsyncFnTrackCaller,
BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub,
BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
BuiltinWhileTrue, InvalidAsmLabel,
BuiltinWhileTrue, InvalidAsmLabel, LeadingZeros,
};
use crate::nonstandard_style::{MethodLateContext, method_context};
use crate::{
Expand Down Expand Up @@ -3061,3 +3061,76 @@ impl EarlyLintPass for SpecialModuleName {
}
}
}

declare_lint! {
/// The `leading_zeros_in_decimal_literals` lint
/// detects decimal integral literals with leading zeros.
///
/// ### Example
///
/// ```rust,no_run
/// fn is_executable(unix_mode: u32) -> bool {
/// unix_mode & 0111 != 0
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
/// In some languages (including the infamous C language and most of its family),
/// a leading zero marks an octal constant. In Rust however, a `0o` prefix is used instead.
/// Thus, a leading zero can be confusing for both the writer and a reader.
///
/// In Rust:
/// ```rust,no_run
/// fn main() {
/// let a = 0123;
/// println!("{}", a);
/// }
/// ```
///
/// prints `123`, while in C:
///
/// ```c
/// #include <stdio.h>
///
/// int main() {
/// int a = 0123;
/// printf("%d\n", a);
/// }
/// ```
///
/// prints `83` (as `83 == 0o123` while `123 == 0o173`).
pub LEADING_ZEROS_IN_DECIMAL_LITERALS,
Warn,
"leading `0` in decimal integer literals",
}

declare_lint_pass!(LeadingZerosInDecimals => [LEADING_ZEROS_IN_DECIMAL_LITERALS]);

impl EarlyLintPass for LeadingZerosInDecimals {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
if let ExprKind::Lit(literal) = expr.kind
&& let token::Lit { kind: token::LitKind::Integer, symbol, suffix: _ } = literal
&& let s = symbol.as_str()
&& let Some(tail) = s.strip_prefix('0')
&& !tail.starts_with(['b', 'o', 'x'])
&& let nonzero_digits = tail.trim_start_matches(['0', '_'])
&& !nonzero_digits.is_empty()
{
let lit_span = expr.span;
let zeros_offset = s.len() - nonzero_digits.len();
let leading_zeros_span = lit_span.with_hi(lit_span.lo() + BytePos(zeros_offset as u32));
let can_be_octal = !nonzero_digits.contains(['8', '9']);
let (remove_zeros_applicability, prefix_octal) = if can_be_octal {
(Applicability::MaybeIncorrect, Some(lit_span.with_hi(lit_span.lo() + BytePos(1))))
} else {
(Applicability::MachineApplicable, None)
};
cx.emit_span_lint(LEADING_ZEROS_IN_DECIMAL_LITERALS, lit_span, LeadingZeros {
remove_zeros: (leading_zeros_span, remove_zeros_applicability),
prefix_octal,
});
}
}
}
1 change: 1 addition & 0 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ early_lint_methods!(
UnusedDocComment: UnusedDocComment,
Expr2024: Expr2024,
Precedence: Precedence,
LeadingZerosInDecimals: LeadingZerosInDecimals,
]
]
);
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3071,3 +3071,12 @@ pub(crate) struct ReservedMultihash {
#[suggestion(code = " ", applicability = "machine-applicable")]
pub suggestion: Span,
}

#[derive(LintDiagnostic)]
#[diag(lint_leading_zeros_in_decimal_literals)]
pub(crate) struct LeadingZeros {
#[suggestion(lint_suggestion_remove_zeros, code = "")]
pub remove_zeros: (Span, Applicability),
#[suggestion(lint_suggestion_prefix_octal, code = "0o", applicability = "maybe-incorrect")]
pub prefix_octal: Option<Span>,
}
1 change: 0 additions & 1 deletion src/tools/clippy/clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
crate::misc_early::UNNEEDED_FIELD_PATTERN_INFO,
crate::misc_early::UNNEEDED_WILDCARD_PATTERN_INFO,
crate::misc_early::UNSEPARATED_LITERAL_SUFFIX_INFO,
crate::misc_early::ZERO_PREFIXED_LITERAL_INFO,
crate::mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER_INFO,
crate::missing_assert_message::MISSING_ASSERT_MESSAGE_INFO,
crate::missing_asserts_for_indexing::MISSING_ASSERTS_FOR_INDEXING_INFO,
Expand Down
2 changes: 2 additions & 0 deletions src/tools/clippy/clippy_lints/src/deprecated_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,5 +177,7 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"),
#[clippy::version = ""]
("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"),
#[clippy::version = "CURRENT_RUSTC_VERSION"]
("clippy::zero_prefixed_literal", "leading_zeros_in_decimal_literals"),
// end renamed lints. used by `cargo dev rename_lint`
]}
47 changes: 1 addition & 46 deletions src/tools/clippy/clippy_lints/src/misc_early/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ mod redundant_at_rest_pattern;
mod redundant_pattern;
mod unneeded_field_pattern;
mod unneeded_wildcard_pattern;
mod zero_prefixed_literal;

use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet_opt;
Expand Down Expand Up @@ -188,45 +187,6 @@ declare_clippy_lint! {
"literals whose suffix is separated by an underscore"
}

declare_clippy_lint! {
/// ### What it does
/// Warns if an integral constant literal starts with `0`.
///
/// ### Why is this bad?
/// In some languages (including the infamous C language
/// and most of its
/// family), this marks an octal constant. In Rust however, this is a decimal
/// constant. This could
/// be confusing for both the writer and a reader of the constant.
///
/// ### Example
///
/// In Rust:
/// ```no_run
/// fn main() {
/// let a = 0123;
/// println!("{}", a);
/// }
/// ```
///
/// prints `123`, while in C:
///
/// ```c
/// #include <stdio.h>
///
/// int main() {
/// int a = 0123;
/// printf("%d\n", a);
/// }
/// ```
///
/// prints `83` (as `83 == 0o123` while `123 == 0o173`).
#[clippy::version = "pre 1.29.0"]
pub ZERO_PREFIXED_LITERAL,
complexity,
"integer literals starting with `0`"
}

declare_clippy_lint! {
/// ### What it does
/// Warns if a generic shadows a built-in type.
Expand Down Expand Up @@ -356,7 +316,6 @@ declare_lint_pass!(MiscEarlyLints => [
MIXED_CASE_HEX_LITERALS,
UNSEPARATED_LITERAL_SUFFIX,
SEPARATED_LITERAL_SUFFIX,
ZERO_PREFIXED_LITERAL,
BUILTIN_TYPE_SHADOW,
REDUNDANT_PATTERN,
UNNEEDED_WILDCARD_PATTERN,
Expand Down Expand Up @@ -432,7 +391,7 @@ impl MiscEarlyLints {
};

let lit_kind = LitKind::from_token_lit(lit);
if let Ok(LitKind::Int(value, lit_int_type)) = lit_kind {
if let Ok(LitKind::Int(_value, lit_int_type)) = lit_kind {
let suffix = match lit_int_type {
LitIntType::Signed(ty) => ty.name_str(),
LitIntType::Unsigned(ty) => ty.name_str(),
Expand All @@ -441,10 +400,6 @@ impl MiscEarlyLints {
literal_suffix::check(cx, span, &lit_snip, suffix, "integer");
if lit_snip.starts_with("0x") {
mixed_case_hex_literals::check(cx, span, suffix, &lit_snip);
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
// nothing to do
} else if value != 0 && lit_snip.starts_with('0') {
zero_prefixed_literal::check(cx, span, &lit_snip);
}
} else if let Ok(LitKind::Float(_, LitFloatType::Suffixed(float_ty))) = lit_kind {
let suffix = float_ty.name_str();
Expand Down

This file was deleted.

1 change: 0 additions & 1 deletion src/tools/clippy/tests/ui/literals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ fn main() {
//~^ ERROR: integer type suffix should be separated by an underscore
//~| NOTE: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
//~| ERROR: this is a decimal constant
//~| NOTE: `-D clippy::zero-prefixed-literal` implied by `-D warnings`

let ok9 = 0;
let ok10 = 0_i64;
Expand Down
Loading

0 comments on commit e7881ba

Please sign in to comment.