Skip to content

Commit ea90417

Browse files
committed
Uplift clippy::zero_prefixed_literal as leading_zeros_in_decimal_literals
1 parent c44b3d5 commit ea90417

15 files changed

+214
-117
lines changed

compiler/rustc_lint/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,10 @@ lint_invalid_reference_casting_note_book = for more information, visit <https://
464464
465465
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`
466466
467+
lint_leading_zeros_in_decimal_literals = this is a decimal constant
468+
.suggestion_remove_zeros = if you meant to use a decimal constant, remove leading zeros to avoid confusion
469+
.suggestion_prefix_octal = if you meant to use an octal constant, prefix it with `0o` instead
470+
467471
lint_legacy_derive_helpers = derive helper attribute is used before it is introduced
468472
.label = the attribute is introduced here
469473

compiler/rustc_lint/src/builtin.rs

+74-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ use crate::lints::{
5959
BuiltinTrivialBounds, BuiltinTypeAliasBounds, BuiltinUngatedAsyncFnTrackCaller,
6060
BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub,
6161
BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
62-
BuiltinWhileTrue, InvalidAsmLabel,
62+
BuiltinWhileTrue, InvalidAsmLabel, LeadingZeros,
6363
};
6464
use crate::nonstandard_style::{MethodLateContext, method_context};
6565
use crate::{
@@ -3061,3 +3061,76 @@ impl EarlyLintPass for SpecialModuleName {
30613061
}
30623062
}
30633063
}
3064+
3065+
declare_lint! {
3066+
/// The `leading_zeros_in_decimal_literals` lint
3067+
/// detects decimal integral literals with leading zeros.
3068+
///
3069+
/// ### Example
3070+
///
3071+
/// ```rust,no_run
3072+
/// fn is_executable(unix_mode: u32) -> bool {
3073+
/// unix_mode & 0111 != 0
3074+
/// }
3075+
/// ```
3076+
///
3077+
/// {{produces}}
3078+
///
3079+
/// ### Explanation
3080+
/// In some languages (including the infamous C language and most of its family),
3081+
/// a leading zero marks an octal constant. In Rust however, a `0o` prefix is used instead.
3082+
/// Thus, a leading zero can be confusing for both the writer and a reader.
3083+
///
3084+
/// In Rust:
3085+
/// ```rust,no_run
3086+
/// fn main() {
3087+
/// let a = 0123;
3088+
/// println!("{}", a);
3089+
/// }
3090+
/// ```
3091+
///
3092+
/// prints `123`, while in C:
3093+
///
3094+
/// ```c
3095+
/// #include <stdio.h>
3096+
///
3097+
/// int main() {
3098+
/// int a = 0123;
3099+
/// printf("%d\n", a);
3100+
/// }
3101+
/// ```
3102+
///
3103+
/// prints `83` (as `83 == 0o123` while `123 == 0o173`).
3104+
pub LEADING_ZEROS_IN_DECIMAL_LITERALS,
3105+
Warn,
3106+
"leading `0` in decimal integer literals",
3107+
}
3108+
3109+
declare_lint_pass!(LeadingZerosInDecimals => [LEADING_ZEROS_IN_DECIMAL_LITERALS]);
3110+
3111+
impl EarlyLintPass for LeadingZerosInDecimals {
3112+
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
3113+
if let ExprKind::Lit(literal) = expr.kind
3114+
&& let token::Lit { kind: token::LitKind::Integer, symbol, suffix: _ } = literal
3115+
&& let s = symbol.as_str()
3116+
&& let Some(tail) = s.strip_prefix('0')
3117+
&& !tail.starts_with(['b', 'o', 'x'])
3118+
&& let nonzero_digits = tail.trim_start_matches(['0', '_'])
3119+
&& !nonzero_digits.is_empty()
3120+
{
3121+
let lit_span = expr.span;
3122+
let zeros_offset = s.len() - nonzero_digits.len();
3123+
let leading_zeros_span = lit_span.with_hi(lit_span.lo() + BytePos(zeros_offset as u32));
3124+
let can_be_octal = !nonzero_digits.contains(['8', '9']);
3125+
let (remove_zeros_applicability, prefix_octal) = if can_be_octal {
3126+
(Applicability::MaybeIncorrect, Some(lit_span.with_hi(lit_span.lo() + BytePos(1))))
3127+
} else {
3128+
(Applicability::MachineApplicable, None)
3129+
};
3130+
cx.emit_span_lint(LEADING_ZEROS_IN_DECIMAL_LITERALS, lit_span, LeadingZeros {
3131+
remove_zeros: (leading_zeros_span, remove_zeros_applicability),
3132+
prefix_octal,
3133+
});
3134+
}
3135+
}
3136+
}

compiler/rustc_lint/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ early_lint_methods!(
179179
UnusedDocComment: UnusedDocComment,
180180
Expr2024: Expr2024,
181181
Precedence: Precedence,
182+
LeadingZerosInDecimals: LeadingZerosInDecimals,
182183
]
183184
]
184185
);

compiler/rustc_lint/src/lints.rs

+9
Original file line numberDiff line numberDiff line change
@@ -3071,3 +3071,12 @@ pub(crate) struct ReservedMultihash {
30713071
#[suggestion(code = " ", applicability = "machine-applicable")]
30723072
pub suggestion: Span,
30733073
}
3074+
3075+
#[derive(LintDiagnostic)]
3076+
#[diag(lint_leading_zeros_in_decimal_literals)]
3077+
pub(crate) struct LeadingZeros {
3078+
#[suggestion(lint_suggestion_remove_zeros, code = "")]
3079+
pub remove_zeros: (Span, Applicability),
3080+
#[suggestion(lint_suggestion_prefix_octal, code = "0o", applicability = "maybe-incorrect")]
3081+
pub prefix_octal: Option<Span>,
3082+
}

src/tools/clippy/clippy_lints/src/declared_lints.rs

-1
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
511511
crate::misc_early::UNNEEDED_FIELD_PATTERN_INFO,
512512
crate::misc_early::UNNEEDED_WILDCARD_PATTERN_INFO,
513513
crate::misc_early::UNSEPARATED_LITERAL_SUFFIX_INFO,
514-
crate::misc_early::ZERO_PREFIXED_LITERAL_INFO,
515514
crate::mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER_INFO,
516515
crate::missing_assert_message::MISSING_ASSERT_MESSAGE_INFO,
517516
crate::missing_asserts_for_indexing::MISSING_ASSERTS_FOR_INDEXING_INFO,

src/tools/clippy/clippy_lints/src/deprecated_lints.rs

+2
Original file line numberDiff line numberDiff line change
@@ -177,5 +177,7 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
177177
("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"),
178178
#[clippy::version = ""]
179179
("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"),
180+
#[clippy::version = "CURRENT_RUSTC_VERSION"]
181+
("clippy::zero_prefixed_literal", "leading_zeros_in_decimal_literals"),
180182
// end renamed lints. used by `cargo dev rename_lint`
181183
]}

src/tools/clippy/clippy_lints/src/misc_early/mod.rs

+1-46
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ mod redundant_at_rest_pattern;
66
mod redundant_pattern;
77
mod unneeded_field_pattern;
88
mod unneeded_wildcard_pattern;
9-
mod zero_prefixed_literal;
109

1110
use clippy_utils::diagnostics::span_lint;
1211
use clippy_utils::source::snippet_opt;
@@ -188,45 +187,6 @@ declare_clippy_lint! {
188187
"literals whose suffix is separated by an underscore"
189188
}
190189

191-
declare_clippy_lint! {
192-
/// ### What it does
193-
/// Warns if an integral constant literal starts with `0`.
194-
///
195-
/// ### Why is this bad?
196-
/// In some languages (including the infamous C language
197-
/// and most of its
198-
/// family), this marks an octal constant. In Rust however, this is a decimal
199-
/// constant. This could
200-
/// be confusing for both the writer and a reader of the constant.
201-
///
202-
/// ### Example
203-
///
204-
/// In Rust:
205-
/// ```no_run
206-
/// fn main() {
207-
/// let a = 0123;
208-
/// println!("{}", a);
209-
/// }
210-
/// ```
211-
///
212-
/// prints `123`, while in C:
213-
///
214-
/// ```c
215-
/// #include <stdio.h>
216-
///
217-
/// int main() {
218-
/// int a = 0123;
219-
/// printf("%d\n", a);
220-
/// }
221-
/// ```
222-
///
223-
/// prints `83` (as `83 == 0o123` while `123 == 0o173`).
224-
#[clippy::version = "pre 1.29.0"]
225-
pub ZERO_PREFIXED_LITERAL,
226-
complexity,
227-
"integer literals starting with `0`"
228-
}
229-
230190
declare_clippy_lint! {
231191
/// ### What it does
232192
/// Warns if a generic shadows a built-in type.
@@ -356,7 +316,6 @@ declare_lint_pass!(MiscEarlyLints => [
356316
MIXED_CASE_HEX_LITERALS,
357317
UNSEPARATED_LITERAL_SUFFIX,
358318
SEPARATED_LITERAL_SUFFIX,
359-
ZERO_PREFIXED_LITERAL,
360319
BUILTIN_TYPE_SHADOW,
361320
REDUNDANT_PATTERN,
362321
UNNEEDED_WILDCARD_PATTERN,
@@ -432,7 +391,7 @@ impl MiscEarlyLints {
432391
};
433392

434393
let lit_kind = LitKind::from_token_lit(lit);
435-
if let Ok(LitKind::Int(value, lit_int_type)) = lit_kind {
394+
if let Ok(LitKind::Int(_value, lit_int_type)) = lit_kind {
436395
let suffix = match lit_int_type {
437396
LitIntType::Signed(ty) => ty.name_str(),
438397
LitIntType::Unsigned(ty) => ty.name_str(),
@@ -441,10 +400,6 @@ impl MiscEarlyLints {
441400
literal_suffix::check(cx, span, &lit_snip, suffix, "integer");
442401
if lit_snip.starts_with("0x") {
443402
mixed_case_hex_literals::check(cx, span, suffix, &lit_snip);
444-
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
445-
// nothing to do
446-
} else if value != 0 && lit_snip.starts_with('0') {
447-
zero_prefixed_literal::check(cx, span, &lit_snip);
448403
}
449404
} else if let Ok(LitKind::Float(_, LitFloatType::Suffixed(float_ty))) = lit_kind {
450405
let suffix = float_ty.name_str();

src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs

-33
This file was deleted.

src/tools/clippy/tests/ui/literals.rs

-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ fn main() {
3030
//~^ ERROR: integer type suffix should be separated by an underscore
3131
//~| NOTE: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
3232
//~| ERROR: this is a decimal constant
33-
//~| NOTE: `-D clippy::zero-prefixed-literal` implied by `-D warnings`
3433

3534
let ok9 = 0;
3635
let ok10 = 0_i64;

0 commit comments

Comments
 (0)