Skip to content

Commit def1383

Browse files
committed
Uplift clippy::zero_prefixed_literal
1 parent 826b673 commit def1383

11 files changed

+156
-81
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

+67-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,69 @@ impl EarlyLintPass for SpecialModuleName {
30613061
}
30623062
}
30633063
}
3064+
3065+
// TODO: rewrite to match rustc's style instead of clippy's
3066+
declare_lint! {
3067+
/// ### What it does
3068+
/// Warns if an integral constant literal starts with `0`.
3069+
///
3070+
/// ### Why is this bad?
3071+
/// In some languages (including the infamous C language and most of its family),
3072+
/// this marks an octal constant. In Rust however, this is a decimal constant.
3073+
/// This could be confusing for both the writer and a reader of the constant.
3074+
///
3075+
/// ### Example
3076+
///
3077+
/// In Rust:
3078+
/// ```no_run
3079+
/// fn main() {
3080+
/// let a = 0123;
3081+
/// println!("{}", a);
3082+
/// }
3083+
/// ```
3084+
///
3085+
/// prints `123`, while in C:
3086+
///
3087+
/// ```c
3088+
/// #include <stdio.h>
3089+
///
3090+
/// int main() {
3091+
/// int a = 0123;
3092+
/// printf("%d\n", a);
3093+
/// }
3094+
/// ```
3095+
///
3096+
/// prints `83` (as `83 == 0o123` while `123 == 0o173`).
3097+
pub LEADING_ZEROS_IN_DECIMAL_LITERALS,
3098+
Warn,
3099+
"leading `0` in decimal integer literals",
3100+
}
3101+
3102+
declare_lint_pass!(LeadingZerosInDecimals => [LEADING_ZEROS_IN_DECIMAL_LITERALS]);
3103+
3104+
impl EarlyLintPass for LeadingZerosInDecimals {
3105+
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
3106+
if let ExprKind::Lit(literal) = expr.kind
3107+
&& let token::Lit { kind: token::LitKind::Integer, symbol, suffix: _ } = literal
3108+
&& let s = symbol.as_str()
3109+
&& let Some(tail) = s.strip_prefix('0')
3110+
&& !tail.starts_with(['b', 'o', 'x'])
3111+
&& let nonzero_digits = tail.trim_start_matches(['0', '_'])
3112+
&& !nonzero_digits.is_empty()
3113+
{
3114+
let lit_span = expr.span;
3115+
let zeros_offset = s.len() - nonzero_digits.len();
3116+
let leading_zeros_span = lit_span.with_hi(lit_span.lo() + BytePos(zeros_offset as u32));
3117+
let can_be_octal = !nonzero_digits.contains(['8', '9']);
3118+
let (remove_zeros_applicability, prefix_octal) = if can_be_octal {
3119+
(Applicability::MaybeIncorrect, Some(lit_span.with_hi(lit_span.lo() + BytePos(1))))
3120+
} else {
3121+
(Applicability::MachineApplicable, None)
3122+
};
3123+
cx.emit_span_lint(LEADING_ZEROS_IN_DECIMAL_LITERALS, lit_span, LeadingZeros {
3124+
remove_zeros: (leading_zeros_span, remove_zeros_applicability),
3125+
prefix_octal,
3126+
});
3127+
}
3128+
}
3129+
}

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

+10
Original file line numberDiff line numberDiff line change
@@ -3059,3 +3059,13 @@ pub(crate) struct ReservedString {
30593059
#[suggestion(code = " ", applicability = "machine-applicable")]
30603060
pub suggestion: Span,
30613061
}
3062+
3063+
#[derive(LintDiagnostic)]
3064+
#[diag(lint_leading_zeros_in_decimal_literals)]
3065+
3066+
pub(crate) struct LeadingZeros {
3067+
#[suggestion(lint_suggestion_remove_zeros, code = "")]
3068+
pub remove_zeros: (Span, Applicability),
3069+
#[suggestion(lint_suggestion_prefix_octal, code = "0o", applicability = "maybe-incorrect")]
3070+
pub prefix_octal: Option<Span>,
3071+
}

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

-1
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
510510
crate::misc_early::UNNEEDED_FIELD_PATTERN_INFO,
511511
crate::misc_early::UNNEEDED_WILDCARD_PATTERN_INFO,
512512
crate::misc_early::UNSEPARATED_LITERAL_SUFFIX_INFO,
513-
crate::misc_early::ZERO_PREFIXED_LITERAL_INFO,
514513
crate::mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER_INFO,
515514
crate::missing_assert_message::MISSING_ASSERT_MESSAGE_INFO,
516515
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.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@ check-pass
2+
//@ run-rustfix
3+
//@ rustfix-only-machine-applicable
4+
5+
fn main() {
6+
let _ = 0111; //~ WARNING [leading_zeros_in_decimal_literals]
7+
let _ = 0007; //~ WARNING [leading_zeros_in_decimal_literals]
8+
let _ = 8; //~ WARNING [leading_zeros_in_decimal_literals]
9+
let _ = 0_0_;
10+
let _ = 00;
11+
let _ = 0;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@ check-pass
2+
//@ run-rustfix
3+
//@ rustfix-only-machine-applicable
4+
5+
fn main() {
6+
let _ = 0111; //~ WARNING [leading_zeros_in_decimal_literals]
7+
let _ = 0007; //~ WARNING [leading_zeros_in_decimal_literals]
8+
let _ = 0008; //~ WARNING [leading_zeros_in_decimal_literals]
9+
let _ = 0_0_;
10+
let _ = 00;
11+
let _ = 0;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
warning: this is a decimal constant
2+
--> $DIR/leading-zeros-in-decimal-literals.rs:6:13
3+
|
4+
LL | let _ = 0111;
5+
| ^^^^
6+
|
7+
= note: `#[warn(leading_zeros_in_decimal_literals)]` on by default
8+
help: if you meant to use a decimal constant, remove leading zeros to avoid confusion
9+
|
10+
LL - let _ = 0111;
11+
LL + let _ = 111;
12+
|
13+
help: if you meant to use an octal constant, prefix it with `0o` instead
14+
|
15+
LL | let _ = 0o111;
16+
| ~~
17+
18+
warning: this is a decimal constant
19+
--> $DIR/leading-zeros-in-decimal-literals.rs:7:13
20+
|
21+
LL | let _ = 0007;
22+
| ^^^^
23+
|
24+
help: if you meant to use a decimal constant, remove leading zeros to avoid confusion
25+
|
26+
LL - let _ = 0007;
27+
LL + let _ = 7;
28+
|
29+
help: if you meant to use an octal constant, prefix it with `0o` instead
30+
|
31+
LL | let _ = 0o007;
32+
| ~~
33+
34+
warning: this is a decimal constant
35+
--> $DIR/leading-zeros-in-decimal-literals.rs:8:13
36+
|
37+
LL | let _ = 0008;
38+
| ^^^^
39+
|
40+
help: if you meant to use a decimal constant, remove leading zeros to avoid confusion
41+
|
42+
LL - let _ = 0008;
43+
LL + let _ = 8;
44+
|
45+
46+
warning: 3 warnings emitted
47+

0 commit comments

Comments
 (0)