Skip to content

Commit a9c5a59

Browse files
author
Michael Wright
committed
literal representation restructure 9
Only store valid suffixes (and not mistyped suffixes) in DigitInfo. Check for mistyped suffixes later and not when DigitInfo is created. This opens the door to more sophisticated mistyped suffix checks later.
1 parent a58b980 commit a9c5a59

File tree

2 files changed

+86
-77
lines changed

2 files changed

+86
-77
lines changed

clippy_lints/src/excessive_precision.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ impl ExcessivePrecision {
8686
if sym_str == s {
8787
None
8888
} else {
89-
let di = super::literal_representation::DigitInfo::new(&s, true);
89+
let di = super::literal_representation::DigitInfo::new(&s, None, true);
9090
Some(di.grouping_hint())
9191
}
9292
} else {

clippy_lints/src/literal_representation.rs

Lines changed: 85 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,21 @@ pub(super) struct DigitInfo<'a> {
138138

139139
/// The type suffix, including preceding underscore if present.
140140
crate suffix: Option<&'a str>,
141-
/// True for floating-point literals.
142-
crate float: bool,
143141
}
144142

145143
impl<'a> DigitInfo<'a> {
144+
fn from_lit(src: &'a str, lit: &Lit) -> Option<DigitInfo<'a>> {
145+
if lit.kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) {
146+
let (unsuffixed, suffix) = split_suffix(&src, &lit.kind);
147+
let float = if let LitKind::Float(..) = lit.kind { true } else { false };
148+
Some(DigitInfo::new(unsuffixed, suffix, float))
149+
} else {
150+
None
151+
}
152+
}
153+
146154
#[must_use]
147-
crate fn new(lit: &'a str, float: bool) -> Self {
155+
crate fn new(lit: &'a str, suffix: Option<&'a str>, float: bool) -> Self {
148156
// Determine delimiter for radix prefix, if present, and radix.
149157
let radix = if lit.starts_with("0x") {
150158
Radix::Hexadecimal
@@ -157,35 +165,19 @@ impl<'a> DigitInfo<'a> {
157165
};
158166

159167
// Grab part of the literal after prefix, if present.
160-
let (prefix, sans_prefix) = if let Radix::Decimal = radix {
168+
let (prefix, mut sans_prefix) = if let Radix::Decimal = radix {
161169
(None, lit)
162170
} else {
163171
let (p, s) = lit.split_at(2);
164172
(Some(p), s)
165173
};
166174

167-
let mut digits = sans_prefix;
168-
let mut suffix = None;
169-
170-
let len = sans_prefix.len();
171-
let mut last_d = '\0';
172-
for (d_idx, d) in sans_prefix.char_indices() {
173-
let suffix_start = if last_d == '_' { d_idx - 1 } else { d_idx };
174-
if float
175-
&& (d == 'f'
176-
|| is_possible_float_suffix_index(&sans_prefix, suffix_start, len)
177-
|| ((d == 'E' || d == 'e') && !has_possible_float_suffix(&sans_prefix)))
178-
|| !float && (d == 'i' || d == 'u' || is_possible_suffix_index(&sans_prefix, suffix_start, len))
179-
{
180-
let (d, s) = sans_prefix.split_at(suffix_start);
181-
digits = d;
182-
suffix = Some(s);
183-
break;
184-
}
185-
last_d = d
175+
if suffix.is_some() && sans_prefix.ends_with('_') {
176+
// The '_' before the suffix isn't part of the digits
177+
sans_prefix = &sans_prefix[..sans_prefix.len() - 1];
186178
}
187179

188-
let (integer, fraction, exponent) = Self::split_digit_parts(digits, float);
180+
let (integer, fraction, exponent) = Self::split_digit_parts(sans_prefix, float);
189181

190182
Self {
191183
radix,
@@ -194,7 +186,6 @@ impl<'a> DigitInfo<'a> {
194186
fraction,
195187
exponent,
196188
suffix,
197-
float,
198189
}
199190
}
200191

@@ -256,15 +247,8 @@ impl<'a> DigitInfo<'a> {
256247
}
257248

258249
if let Some(suffix) = self.suffix {
259-
if self.float && is_mistyped_float_suffix(suffix) {
260-
output.push_str("_f");
261-
output.push_str(&suffix[1..]);
262-
} else if is_mistyped_suffix(suffix) {
263-
output.push_str("_i");
264-
output.push_str(&suffix[1..]);
265-
} else {
266-
output.push_str(suffix);
267-
}
250+
output.push('_');
251+
output.push_str(suffix);
268252
}
269253

270254
output
@@ -303,6 +287,34 @@ impl<'a> DigitInfo<'a> {
303287
}
304288
}
305289

290+
fn split_suffix<'a>(src: &'a str, lit_kind: &LitKind) -> (&'a str, Option<&'a str>) {
291+
debug_assert!(lit_kind.is_numeric());
292+
if let Some(suffix_length) = lit_suffix_length(lit_kind) {
293+
let (unsuffixed, suffix) = src.split_at(src.len() - suffix_length);
294+
(unsuffixed, Some(suffix))
295+
} else {
296+
(src, None)
297+
}
298+
}
299+
300+
fn lit_suffix_length(lit_kind: &LitKind) -> Option<usize> {
301+
debug_assert!(lit_kind.is_numeric());
302+
let suffix = match lit_kind {
303+
LitKind::Int(_, int_lit_kind) => match int_lit_kind {
304+
LitIntType::Signed(int_ty) => Some(int_ty.name_str()),
305+
LitIntType::Unsigned(uint_ty) => Some(uint_ty.name_str()),
306+
LitIntType::Unsuffixed => None,
307+
},
308+
LitKind::Float(_, float_lit_kind) => match float_lit_kind {
309+
LitFloatType::Suffixed(float_ty) => Some(float_ty.name_str()),
310+
LitFloatType::Unsuffixed => None,
311+
},
312+
_ => None,
313+
};
314+
315+
suffix.map(str::len)
316+
}
317+
306318
enum WarningType {
307319
UnreadableLiteral,
308320
InconsistentDigitGrouping,
@@ -388,22 +400,13 @@ impl LiteralDigitGrouping {
388400

389401
if_chain! {
390402
if let Some(src) = snippet_opt(cx, lit.span);
391-
if let Some(firstch) = src.chars().next();
392-
if char::is_digit(firstch, 10);
403+
if let Some(mut digit_info) = DigitInfo::from_lit(&src, &lit);
393404
then {
394-
395-
let digit_info = match lit.kind {
396-
LitKind::Int(..) => DigitInfo::new(&src, false),
397-
LitKind::Float(..) => DigitInfo::new(&src, true),
398-
_ => return,
399-
};
405+
if !Self::check_for_mistyped_suffix(cx, lit.span, &mut digit_info) {
406+
return;
407+
}
400408

401409
let result = (|| {
402-
if let Some(suffix) = digit_info.suffix {
403-
if is_mistyped_suffix(suffix) {
404-
return Err(WarningType::MistypedLiteralSuffix);
405-
}
406-
}
407410

408411
let integral_group_size = Self::get_group_size(digit_info.integer.split('_'), in_macro)?;
409412
if let Some(fraction) = digit_info.fraction {
@@ -428,6 +431,39 @@ impl LiteralDigitGrouping {
428431
}
429432
}
430433

434+
// Returns `false` if the check fails
435+
fn check_for_mistyped_suffix(
436+
cx: &EarlyContext<'_>,
437+
span: syntax_pos::Span,
438+
digit_info: &mut DigitInfo<'_>,
439+
) -> bool {
440+
if digit_info.suffix.is_some() {
441+
return true;
442+
}
443+
444+
let (part, mistyped_suffixes, missing_char) = if let Some((_, exponent)) = &mut digit_info.exponent {
445+
(exponent, &["32", "64"][..], 'f')
446+
} else if let Some(fraction) = &mut digit_info.fraction {
447+
(fraction, &["32", "64"][..], 'f')
448+
} else {
449+
(&mut digit_info.integer, &["8", "16", "32", "64"][..], 'i')
450+
};
451+
452+
let mut split = part.rsplit('_');
453+
let last_group = split.next().expect("At least one group");
454+
if split.next().is_some() && mistyped_suffixes.contains(&last_group) {
455+
*part = &part[..part.len() - last_group.len()];
456+
let mut hint = digit_info.grouping_hint();
457+
hint.push('_');
458+
hint.push(missing_char);
459+
hint.push_str(last_group);
460+
WarningType::MistypedLiteralSuffix.display(&hint, cx, span);
461+
false
462+
} else {
463+
true
464+
}
465+
}
466+
431467
/// Given the sizes of the digit groups of both integral and fractional
432468
/// parts, and the length
433469
/// of both parts, determine if the digits have been grouped consistently.
@@ -503,14 +539,12 @@ impl DecimalLiteralRepresentation {
503539
if_chain! {
504540
if let LitKind::Int(val, _) = lit.kind;
505541
if let Some(src) = snippet_opt(cx, lit.span);
506-
if let Some(firstch) = src.chars().next();
507-
if char::is_digit(firstch, 10);
508-
let digit_info = DigitInfo::new(&src, false);
542+
if let Some(digit_info) = DigitInfo::from_lit(&src, &lit);
509543
if digit_info.radix == Radix::Decimal;
510544
if val >= u128::from(self.threshold);
511545
then {
512546
let hex = format!("{:#X}", val);
513-
let digit_info = DigitInfo::new(&hex, false);
547+
let digit_info = DigitInfo::new(&hex, None, false);
514548
let _ = Self::do_lint(digit_info.integer).map_err(|warning_type| {
515549
warning_type.display(&digit_info.grouping_hint(), cx, lit.span)
516550
});
@@ -563,28 +597,3 @@ impl DecimalLiteralRepresentation {
563597
Ok(())
564598
}
565599
}
566-
567-
#[must_use]
568-
fn is_mistyped_suffix(suffix: &str) -> bool {
569-
["_8", "_16", "_32", "_64"].contains(&suffix)
570-
}
571-
572-
#[must_use]
573-
fn is_possible_suffix_index(lit: &str, idx: usize, len: usize) -> bool {
574-
((len > 3 && idx == len - 3) || (len > 2 && idx == len - 2)) && is_mistyped_suffix(lit.split_at(idx).1)
575-
}
576-
577-
#[must_use]
578-
fn is_mistyped_float_suffix(suffix: &str) -> bool {
579-
["_32", "_64"].contains(&suffix)
580-
}
581-
582-
#[must_use]
583-
fn is_possible_float_suffix_index(lit: &str, idx: usize, len: usize) -> bool {
584-
(len > 3 && idx == len - 3) && is_mistyped_float_suffix(lit.split_at(idx).1)
585-
}
586-
587-
#[must_use]
588-
fn has_possible_float_suffix(lit: &str) -> bool {
589-
lit.ends_with("_32") || lit.ends_with("_64")
590-
}

0 commit comments

Comments
 (0)