Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit d14fdc0

Browse files
committed
Move NumericLiteral to its own module.
1 parent 73deb72 commit d14fdc0

File tree

7 files changed

+243
-241
lines changed

7 files changed

+243
-241
lines changed

clippy_lints/src/float_literal.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use crate::utils::span_lint_and_sugg;
2-
use crate::utils::sugg::format_numeric_literal;
1+
use crate::utils::{numeric_literal, span_lint_and_sugg};
32
use if_chain::if_chain;
43
use rustc::ty;
54
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
@@ -109,7 +108,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatLiteral {
109108
expr.span,
110109
"literal cannot be represented as the underlying type without loss of precision",
111110
"consider changing the type or replacing it with",
112-
format_numeric_literal(&float_str, type_suffix, true),
111+
numeric_literal::format(&float_str, type_suffix, true),
113112
Applicability::MachineApplicable,
114113
);
115114
}
@@ -120,7 +119,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatLiteral {
120119
expr.span,
121120
"float has excessive precision",
122121
"consider changing the type or truncating it to",
123-
format_numeric_literal(&float_str, type_suffix, true),
122+
numeric_literal::format(&float_str, type_suffix, true),
124123
Applicability::MachineApplicable,
125124
);
126125
}

clippy_lints/src/floating_point_arithmetic.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::consts::{
22
constant, constant_simple, Constant,
33
Constant::{F32, F64},
44
};
5-
use crate::utils::{higher, span_lint_and_sugg, sugg, SpanlessEq};
5+
use crate::utils::{higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq};
66
use if_chain::if_chain;
77
use rustc::ty;
88
use rustc_errors::Applicability;
@@ -14,7 +14,7 @@ use rustc_span::source_map::Spanned;
1414
use rustc_ast::ast;
1515
use std::f32::consts as f32_consts;
1616
use std::f64::consts as f64_consts;
17-
use sugg::{format_numeric_literal, Sugg};
17+
use sugg::Sugg;
1818

1919
declare_clippy_lint! {
2020
/// **What it does:** Looks for floating-point expressions that
@@ -276,7 +276,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
276276
format!(
277277
"{}.powi({})",
278278
Sugg::hir(cx, &args[0], ".."),
279-
format_numeric_literal(&exponent.to_string(), None, false)
279+
numeric_literal::format(&exponent.to_string(), None, false)
280280
),
281281
)
282282
} else {

clippy_lints/src/literal_representation.rs

Lines changed: 6 additions & 228 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
//! Lints concerned with the grouping of digits with underscores in integral or
22
//! floating-point literal expressions.
33
4-
use crate::utils::{in_macro, snippet_opt, span_lint_and_sugg};
4+
use crate::utils::{
5+
in_macro,
6+
numeric_literal::{NumericLiteral, Radix},
7+
snippet_opt, span_lint_and_sugg,
8+
};
59
use if_chain::if_chain;
610
use rustc::lint::in_external_macro;
7-
use rustc_ast::ast::{Expr, ExprKind, Lit, LitFloatType, LitIntType, LitKind};
11+
use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind};
812
use rustc_errors::Applicability;
913
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
1014
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
@@ -103,232 +107,6 @@ declare_clippy_lint! {
103107
"using decimal representation when hexadecimal would be better"
104108
}
105109

106-
#[derive(Debug, PartialEq)]
107-
pub(super) enum Radix {
108-
Binary,
109-
Octal,
110-
Decimal,
111-
Hexadecimal,
112-
}
113-
114-
impl Radix {
115-
/// Returns a reasonable digit group size for this radix.
116-
#[must_use]
117-
fn suggest_grouping(&self) -> usize {
118-
match *self {
119-
Self::Binary | Self::Hexadecimal => 4,
120-
Self::Octal | Self::Decimal => 3,
121-
}
122-
}
123-
}
124-
125-
/// A helper method to format numeric literals with digit grouping.
126-
/// `lit` must be a valid numeric literal without suffix.
127-
pub fn format_numeric_literal(lit: &str, type_suffix: Option<&str>, float: bool) -> String {
128-
NumericLiteral::new(lit, type_suffix, float).format()
129-
}
130-
131-
#[derive(Debug)]
132-
pub(super) struct NumericLiteral<'a> {
133-
/// Which radix the literal was represented in.
134-
radix: Radix,
135-
/// The radix prefix, if present.
136-
prefix: Option<&'a str>,
137-
138-
/// The integer part of the number.
139-
integer: &'a str,
140-
/// The fraction part of the number.
141-
fraction: Option<&'a str>,
142-
/// The character used as exponent seperator (b'e' or b'E') and the exponent part.
143-
exponent: Option<(char, &'a str)>,
144-
145-
/// The type suffix, including preceding underscore if present.
146-
suffix: Option<&'a str>,
147-
}
148-
149-
impl<'a> NumericLiteral<'a> {
150-
fn from_lit(src: &'a str, lit: &Lit) -> Option<NumericLiteral<'a>> {
151-
NumericLiteral::from_lit_kind(src, &lit.kind)
152-
}
153-
154-
pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> {
155-
if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) {
156-
let (unsuffixed, suffix) = split_suffix(&src, lit_kind);
157-
let float = if let LitKind::Float(..) = lit_kind { true } else { false };
158-
Some(NumericLiteral::new(unsuffixed, suffix, float))
159-
} else {
160-
None
161-
}
162-
}
163-
164-
#[must_use]
165-
fn new(lit: &'a str, suffix: Option<&'a str>, float: bool) -> Self {
166-
// Determine delimiter for radix prefix, if present, and radix.
167-
let radix = if lit.starts_with("0x") {
168-
Radix::Hexadecimal
169-
} else if lit.starts_with("0b") {
170-
Radix::Binary
171-
} else if lit.starts_with("0o") {
172-
Radix::Octal
173-
} else {
174-
Radix::Decimal
175-
};
176-
177-
// Grab part of the literal after prefix, if present.
178-
let (prefix, mut sans_prefix) = if let Radix::Decimal = radix {
179-
(None, lit)
180-
} else {
181-
let (p, s) = lit.split_at(2);
182-
(Some(p), s)
183-
};
184-
185-
if suffix.is_some() && sans_prefix.ends_with('_') {
186-
// The '_' before the suffix isn't part of the digits
187-
sans_prefix = &sans_prefix[..sans_prefix.len() - 1];
188-
}
189-
190-
let (integer, fraction, exponent) = Self::split_digit_parts(sans_prefix, float);
191-
192-
Self {
193-
radix,
194-
prefix,
195-
integer,
196-
fraction,
197-
exponent,
198-
suffix,
199-
}
200-
}
201-
202-
pub fn is_decimal(&self) -> bool {
203-
self.radix == Radix::Decimal
204-
}
205-
206-
fn split_digit_parts(digits: &str, float: bool) -> (&str, Option<&str>, Option<(char, &str)>) {
207-
let mut integer = digits;
208-
let mut fraction = None;
209-
let mut exponent = None;
210-
211-
if float {
212-
for (i, c) in digits.char_indices() {
213-
match c {
214-
'.' => {
215-
integer = &digits[..i];
216-
fraction = Some(&digits[i + 1..]);
217-
},
218-
'e' | 'E' => {
219-
if integer.len() > i {
220-
integer = &digits[..i];
221-
} else {
222-
fraction = Some(&digits[integer.len() + 1..i]);
223-
};
224-
exponent = Some((c, &digits[i + 1..]));
225-
break;
226-
},
227-
_ => {},
228-
}
229-
}
230-
}
231-
232-
(integer, fraction, exponent)
233-
}
234-
235-
/// Returns literal formatted in a sensible way.
236-
fn format(&self) -> String {
237-
let mut output = String::new();
238-
239-
if let Some(prefix) = self.prefix {
240-
output.push_str(prefix);
241-
}
242-
243-
let group_size = self.radix.suggest_grouping();
244-
245-
Self::group_digits(
246-
&mut output,
247-
self.integer,
248-
group_size,
249-
true,
250-
self.radix == Radix::Hexadecimal,
251-
);
252-
253-
if let Some(fraction) = self.fraction {
254-
output.push('.');
255-
Self::group_digits(&mut output, fraction, group_size, false, false);
256-
}
257-
258-
if let Some((separator, exponent)) = self.exponent {
259-
output.push(separator);
260-
Self::group_digits(&mut output, exponent, group_size, true, false);
261-
}
262-
263-
if let Some(suffix) = self.suffix {
264-
output.push('_');
265-
output.push_str(suffix);
266-
}
267-
268-
output
269-
}
270-
271-
fn group_digits(output: &mut String, input: &str, group_size: usize, partial_group_first: bool, pad: bool) {
272-
debug_assert!(group_size > 0);
273-
274-
let mut digits = input.chars().filter(|&c| c != '_');
275-
276-
let first_group_size;
277-
278-
if partial_group_first {
279-
first_group_size = (digits.clone().count() - 1) % group_size + 1;
280-
if pad {
281-
for _ in 0..group_size - first_group_size {
282-
output.push('0');
283-
}
284-
}
285-
} else {
286-
first_group_size = group_size;
287-
}
288-
289-
for _ in 0..first_group_size {
290-
if let Some(digit) = digits.next() {
291-
output.push(digit);
292-
}
293-
}
294-
295-
for (c, i) in digits.zip((0..group_size).cycle()) {
296-
if i == 0 {
297-
output.push('_');
298-
}
299-
output.push(c);
300-
}
301-
}
302-
}
303-
304-
fn split_suffix<'a>(src: &'a str, lit_kind: &LitKind) -> (&'a str, Option<&'a str>) {
305-
debug_assert!(lit_kind.is_numeric());
306-
if let Some(suffix_length) = lit_suffix_length(lit_kind) {
307-
let (unsuffixed, suffix) = src.split_at(src.len() - suffix_length);
308-
(unsuffixed, Some(suffix))
309-
} else {
310-
(src, None)
311-
}
312-
}
313-
314-
fn lit_suffix_length(lit_kind: &LitKind) -> Option<usize> {
315-
debug_assert!(lit_kind.is_numeric());
316-
let suffix = match lit_kind {
317-
LitKind::Int(_, int_lit_kind) => match int_lit_kind {
318-
LitIntType::Signed(int_ty) => Some(int_ty.name_str()),
319-
LitIntType::Unsigned(uint_ty) => Some(uint_ty.name_str()),
320-
LitIntType::Unsuffixed => None,
321-
},
322-
LitKind::Float(_, float_lit_kind) => match float_lit_kind {
323-
LitFloatType::Suffixed(float_ty) => Some(float_ty.name_str()),
324-
LitFloatType::Unsuffixed => None,
325-
},
326-
_ => None,
327-
};
328-
329-
suffix.map(str::len)
330-
}
331-
332110
enum WarningType {
333111
UnreadableLiteral,
334112
InconsistentDigitGrouping,

clippy_lints/src/types.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,12 @@ use rustc_target::spec::abi::Abi;
2727
use rustc_typeck::hir_ty_to_ty;
2828

2929
use crate::consts::{constant, Constant};
30-
use crate::literal_representation::NumericLiteral;
3130
use crate::utils::paths;
3231
use crate::utils::{
3332
clip, comparisons, differing_macro_contexts, higher, in_constant, int_bits, last_path_segment, match_def_path,
34-
match_path, method_chain_args, multispan_sugg, qpath_res, same_tys, sext, snippet, snippet_opt,
35-
snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg,
36-
span_lint_and_then, unsext,
33+
match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral, qpath_res, same_tys, sext, snippet,
34+
snippet_opt, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help,
35+
span_lint_and_sugg, span_lint_and_then, unsext,
3736
};
3837

3938
declare_clippy_lint! {

clippy_lints/src/utils/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub mod higher;
1212
mod hir_utils;
1313
pub mod inspector;
1414
pub mod internal_lints;
15+
pub mod numeric_literal;
1516
pub mod paths;
1617
pub mod ptr;
1718
pub mod sugg;

0 commit comments

Comments
 (0)