Skip to content

Commit f2d83ed

Browse files
committed
Use token::Lit in ast::ExprKind::Lit.
Instead of `ast::Lit`. Literal lowering now happens at two different times. Expression literals are lowered when HIR is crated. Attribute literals are lowered during parsing. This commit changes the language very slightly. Some programs that used to not compile now will compile. This is because some invalid literals that are removed by `cfg` or attribute macros will no longer trigger errors. See this comment for more details: rust-lang#102944 (comment)
1 parent 8a2d0f2 commit f2d83ed

12 files changed

+90
-77
lines changed

clippy_lints/src/almost_complete_letter_range.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,21 @@ impl EarlyLintPass for AlmostCompleteLetterRange {
7373
}
7474

7575
fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) {
76-
if let ExprKind::Lit(start_lit) = &start.peel_parens().kind
77-
&& let ExprKind::Lit(end_lit) = &end.peel_parens().kind
76+
if let ExprKind::Lit(start_token_lit) = start.peel_parens().kind
77+
&& let ExprKind::Lit(end_token_lit) = end.peel_parens().kind
7878
&& matches!(
79-
(&start_lit.kind, &end_lit.kind),
80-
(LitKind::Byte(b'a') | LitKind::Char('a'), LitKind::Byte(b'z') | LitKind::Char('z'))
81-
| (LitKind::Byte(b'A') | LitKind::Char('A'), LitKind::Byte(b'Z') | LitKind::Char('Z'))
79+
(
80+
LitKind::from_token_lit(start_token_lit),
81+
LitKind::from_token_lit(end_token_lit),
82+
),
83+
(
84+
Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
85+
Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
86+
)
87+
| (
88+
Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
89+
Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
90+
)
8291
)
8392
&& !in_external_macro(cx.sess(), span)
8493
{

clippy_lints/src/int_plus_one.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
33
use clippy_utils::diagnostics::span_lint_and_sugg;
44
use clippy_utils::source::snippet_opt;
5-
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, Lit, LitKind};
5+
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind};
6+
use rustc_ast::token;
67
use rustc_errors::Applicability;
78
use rustc_lint::{EarlyContext, EarlyLintPass};
89
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -52,8 +53,8 @@ enum Side {
5253

5354
impl IntPlusOne {
5455
#[expect(clippy::cast_sign_loss)]
55-
fn check_lit(lit: &Lit, target_value: i128) -> bool {
56-
if let LitKind::Int(value, ..) = lit.kind {
56+
fn check_lit(token_lit: token::Lit, target_value: i128) -> bool {
57+
if let Ok(LitKind::Int(value, ..)) = LitKind::from_token_lit(token_lit) {
5758
return value == (target_value as u128);
5859
}
5960
false
@@ -65,11 +66,11 @@ impl IntPlusOne {
6566
(BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => {
6667
match (lhskind.node, &lhslhs.kind, &lhsrhs.kind) {
6768
// `-1 + x`
68-
(BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
69+
(BinOpKind::Add, &ExprKind::Lit(lit), _) if Self::check_lit(lit, -1) => {
6970
Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
7071
},
7172
// `x - 1`
72-
(BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
73+
(BinOpKind::Sub, _, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
7374
Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
7475
},
7576
_ => None,
@@ -81,10 +82,10 @@ impl IntPlusOne {
8182
{
8283
match (&rhslhs.kind, &rhsrhs.kind) {
8384
// `y + 1` and `1 + y`
84-
(&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
85+
(&ExprKind::Lit(lit), _) if Self::check_lit(lit, 1) => {
8586
Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
8687
},
87-
(_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
88+
(_, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
8889
Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
8990
},
9091
_ => None,
@@ -96,10 +97,10 @@ impl IntPlusOne {
9697
{
9798
match (&lhslhs.kind, &lhsrhs.kind) {
9899
// `1 + x` and `x + 1`
99-
(&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
100+
(&ExprKind::Lit(lit), _) if Self::check_lit(lit, 1) => {
100101
Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
101102
},
102-
(_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
103+
(_, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
103104
Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
104105
},
105106
_ => None,
@@ -109,11 +110,11 @@ impl IntPlusOne {
109110
(BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
110111
match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {
111112
// `-1 + y`
112-
(BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
113+
(BinOpKind::Add, &ExprKind::Lit(lit), _) if Self::check_lit(lit, -1) => {
113114
Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
114115
},
115116
// `y - 1`
116-
(BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
117+
(BinOpKind::Sub, _, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
117118
Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
118119
},
119120
_ => None,

clippy_lints/src/literal_representation.rs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
55
use clippy_utils::numeric_literal::{NumericLiteral, Radix};
66
use clippy_utils::source::snippet_opt;
77
use if_chain::if_chain;
8-
use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind};
8+
use rustc_ast::ast::{Expr, ExprKind, LitKind};
9+
use rustc_ast::token;
910
use rustc_errors::Applicability;
1011
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
1112
use rustc_middle::lint::in_external_macro;
1213
use rustc_session::{declare_tool_lint, impl_lint_pass};
14+
use rustc_span::Span;
1315
use std::iter;
1416

1517
declare_clippy_lint! {
@@ -236,8 +238,8 @@ impl EarlyLintPass for LiteralDigitGrouping {
236238
return;
237239
}
238240

239-
if let ExprKind::Lit(ref lit) = expr.kind {
240-
self.check_lit(cx, lit);
241+
if let ExprKind::Lit(lit) = expr.kind {
242+
self.check_lit(cx, lit, expr.span);
241243
}
242244
}
243245
}
@@ -252,12 +254,13 @@ impl LiteralDigitGrouping {
252254
}
253255
}
254256

255-
fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
257+
fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
256258
if_chain! {
257-
if let Some(src) = snippet_opt(cx, lit.span);
258-
if let Some(mut num_lit) = NumericLiteral::from_lit(&src, lit);
259+
if let Some(src) = snippet_opt(cx, span);
260+
if let Ok(lit_kind) = LitKind::from_token_lit(lit);
261+
if let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind);
259262
then {
260-
if !Self::check_for_mistyped_suffix(cx, lit.span, &mut num_lit) {
263+
if !Self::check_for_mistyped_suffix(cx, span, &mut num_lit) {
261264
return;
262265
}
263266

@@ -293,14 +296,14 @@ impl LiteralDigitGrouping {
293296
| WarningType::InconsistentDigitGrouping
294297
| WarningType::UnusualByteGroupings
295298
| WarningType::LargeDigitGroups => {
296-
!lit.span.from_expansion()
299+
!span.from_expansion()
297300
}
298301
WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => {
299302
true
300303
}
301304
};
302305
if should_warn {
303-
warning_type.display(num_lit.format(), cx, lit.span);
306+
warning_type.display(num_lit.format(), cx, span);
304307
}
305308
}
306309
}
@@ -458,8 +461,8 @@ impl EarlyLintPass for DecimalLiteralRepresentation {
458461
return;
459462
}
460463

461-
if let ExprKind::Lit(ref lit) = expr.kind {
462-
self.check_lit(cx, lit);
464+
if let ExprKind::Lit(lit) = expr.kind {
465+
self.check_lit(cx, lit, expr.span);
463466
}
464467
}
465468
}
@@ -469,19 +472,20 @@ impl DecimalLiteralRepresentation {
469472
pub fn new(threshold: u64) -> Self {
470473
Self { threshold }
471474
}
472-
fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
475+
fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
473476
// Lint integral literals.
474477
if_chain! {
475-
if let LitKind::Int(val, _) = lit.kind;
476-
if let Some(src) = snippet_opt(cx, lit.span);
477-
if let Some(num_lit) = NumericLiteral::from_lit(&src, lit);
478+
if let Ok(lit_kind) = LitKind::from_token_lit(lit);
479+
if let LitKind::Int(val, _) = lit_kind;
480+
if let Some(src) = snippet_opt(cx, span);
481+
if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind);
478482
if num_lit.radix == Radix::Decimal;
479483
if val >= u128::from(self.threshold);
480484
then {
481485
let hex = format!("{val:#X}");
482486
let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
483487
let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| {
484-
warning_type.display(num_lit.format(), cx, lit.span);
488+
warning_type.display(num_lit.format(), cx, span);
485489
});
486490
}
487491
}

clippy_lints/src/misc_early/literal_suffix.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use rustc_ast::ast::Lit;
32
use rustc_errors::Applicability;
43
use rustc_lint::EarlyContext;
4+
use rustc_span::Span;
55

66
use super::{SEPARATED_LITERAL_SUFFIX, 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(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffix: &str, sugg_type: &str) {
99
let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else {
1010
return; // It's useless so shouldn't lint.
1111
};
@@ -15,7 +15,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &s
1515
span_lint_and_sugg(
1616
cx,
1717
SEPARATED_LITERAL_SUFFIX,
18-
lit.span,
18+
lit_span,
1919
&format!("{sugg_type} type suffix should not be separated by an underscore"),
2020
"remove the underscore",
2121
format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]),
@@ -25,7 +25,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &s
2525
span_lint_and_sugg(
2626
cx,
2727
UNSEPARATED_LITERAL_SUFFIX,
28-
lit.span,
28+
lit_span,
2929
&format!("{sugg_type} type suffix should be separated by an underscore"),
3030
"add an underscore",
3131
format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]),

clippy_lints/src/misc_early/mixed_case_hex_literals.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use clippy_utils::diagnostics::span_lint;
2-
use rustc_ast::ast::Lit;
32
use rustc_lint::EarlyContext;
3+
use rustc_span::Span;
44

55
use super::MIXED_CASE_HEX_LITERALS;
66

7-
pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, suffix: &str, lit_snip: &str) {
7+
pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, suffix: &str, lit_snip: &str) {
88
let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else {
99
return; // It's useless so shouldn't lint.
1010
};
@@ -23,7 +23,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, suffix: &str, lit_snip: &s
2323
span_lint(
2424
cx,
2525
MIXED_CASE_HEX_LITERALS,
26-
lit.span,
26+
lit_span,
2727
"inconsistent casing in hexadecimal literal",
2828
);
2929
break;

clippy_lints/src/misc_early/mod.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ 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, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
12+
use rustc_ast::ast::{Expr, ExprKind, Generics, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
13+
use rustc_ast::token;
1314
use rustc_ast::visit::FnKind;
1415
use rustc_data_structures::fx::FxHashMap;
1516
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
@@ -374,42 +375,43 @@ impl EarlyLintPass for MiscEarlyLints {
374375
return;
375376
}
376377

377-
if let ExprKind::Lit(ref lit) = expr.kind {
378-
MiscEarlyLints::check_lit(cx, lit);
378+
if let ExprKind::Lit(lit) = expr.kind {
379+
MiscEarlyLints::check_lit(cx, lit, expr.span);
379380
}
380381
double_neg::check(cx, expr);
381382
}
382383
}
383384

384385
impl MiscEarlyLints {
385-
fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
386+
fn check_lit(cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
386387
// We test if first character in snippet is a number, because the snippet could be an expansion
387388
// from a built-in macro like `line!()` or a proc-macro like `#[wasm_bindgen]`.
388389
// Note that this check also covers special case that `line!()` is eagerly expanded by compiler.
389390
// See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression.
390391
// FIXME: Find a better way to detect those cases.
391-
let lit_snip = match snippet_opt(cx, lit.span) {
392+
let lit_snip = match snippet_opt(cx, span) {
392393
Some(snip) if snip.chars().next().map_or(false, |c| c.is_ascii_digit()) => snip,
393394
_ => return,
394395
};
395396

396-
if let LitKind::Int(value, lit_int_type) = lit.kind {
397+
let lit_kind = LitKind::from_token_lit(lit);
398+
if let Ok(LitKind::Int(value, lit_int_type)) = lit_kind {
397399
let suffix = match lit_int_type {
398400
LitIntType::Signed(ty) => ty.name_str(),
399401
LitIntType::Unsigned(ty) => ty.name_str(),
400402
LitIntType::Unsuffixed => "",
401403
};
402-
literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
404+
literal_suffix::check(cx, span, &lit_snip, suffix, "integer");
403405
if lit_snip.starts_with("0x") {
404-
mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
406+
mixed_case_hex_literals::check(cx, span, suffix, &lit_snip);
405407
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
406408
// nothing to do
407409
} else if value != 0 && lit_snip.starts_with('0') {
408-
zero_prefixed_literal::check(cx, lit, &lit_snip);
410+
zero_prefixed_literal::check(cx, span, &lit_snip);
409411
}
410-
} else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
412+
} else if let Ok(LitKind::Float(_, LitFloatType::Suffixed(float_ty))) = lit_kind {
411413
let suffix = float_ty.name_str();
412-
literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
414+
literal_suffix::check(cx, span, &lit_snip, suffix, "float");
413415
}
414416
}
415417
}

clippy_lints/src/misc_early/zero_prefixed_literal.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
2-
use rustc_ast::ast::Lit;
32
use rustc_errors::Applicability;
43
use rustc_lint::EarlyContext;
4+
use rustc_span::Span;
55

66
use super::ZERO_PREFIXED_LITERAL;
77

8-
pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str) {
8+
pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str) {
99
let trimmed_lit_snip = lit_snip.trim_start_matches(|c| c == '_' || c == '0');
1010
span_lint_and_then(
1111
cx,
1212
ZERO_PREFIXED_LITERAL,
13-
lit.span,
13+
lit_span,
1414
"this is a decimal constant",
1515
|diag| {
1616
diag.span_suggestion(
17-
lit.span,
17+
lit_span,
1818
"if you mean to use a decimal constant, remove the `0` to avoid confusion",
1919
trimmed_lit_snip.to_string(),
2020
Applicability::MaybeIncorrect,
2121
);
2222
// do not advise to use octal form if the literal cannot be expressed in base 8.
2323
if !lit_snip.contains(|c| c == '8' || c == '9') {
2424
diag.span_suggestion(
25-
lit.span,
25+
lit_span,
2626
"if you mean to use an octal constant, use `0o`",
2727
format!("0o{trimmed_lit_snip}"),
2828
Applicability::MaybeIncorrect,

clippy_lints/src/octal_escapes.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ impl EarlyLintPass for OctalEscapes {
5656
return;
5757
}
5858

59-
if let ExprKind::Lit(lit) = &expr.kind {
60-
if matches!(lit.token_lit.kind, LitKind::Str) {
61-
check_lit(cx, &lit.token_lit, lit.span, true);
62-
} else if matches!(lit.token_lit.kind, LitKind::ByteStr) {
63-
check_lit(cx, &lit.token_lit, lit.span, false);
59+
if let ExprKind::Lit(token_lit) = &expr.kind {
60+
if matches!(token_lit.kind, LitKind::Str) {
61+
check_lit(cx, &token_lit, expr.span, true);
62+
} else if matches!(token_lit.kind, LitKind::ByteStr) {
63+
check_lit(cx, &token_lit, expr.span, false);
6464
}
6565
}
6666
}

clippy_lints/src/precedence.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::source::snippet_with_applicability;
33
use if_chain::if_chain;
4-
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp};
4+
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp};
5+
use rustc_ast::token;
56
use rustc_errors::Applicability;
67
use rustc_lint::{EarlyContext, EarlyLintPass};
78
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -120,7 +121,7 @@ impl EarlyLintPass for Precedence {
120121
if_chain! {
121122
if !all_odd;
122123
if let ExprKind::Lit(lit) = &arg.kind;
123-
if let LitKind::Int(..) | LitKind::Float(..) = &lit.kind;
124+
if let token::LitKind::Integer | token::LitKind::Float = &lit.kind;
124125
then {
125126
let mut applicability = Applicability::MachineApplicable;
126127
span_lint_and_sugg(

0 commit comments

Comments
 (0)