pub mod len_zero;
pub mod let_if_seq;
pub mod lifetimes;
-pub mod literal_digit_grouping;
+pub mod literal_representation;
pub mod loops;
pub mod map_clone;
pub mod matches;
reg.register_late_lint_pass(box large_enum_variant::LargeEnumVariant::new(conf.enum_variant_size_threshold));
reg.register_late_lint_pass(box explicit_write::Pass);
reg.register_late_lint_pass(box needless_pass_by_value::NeedlessPassByValue);
- reg.register_early_lint_pass(box literal_digit_grouping::LiteralDigitGrouping);
+ reg.register_early_lint_pass(box literal_representation::LiteralDigitGrouping);
+ reg.register_early_lint_pass(box literal_representation::LiteralRepresentation);
reg.register_late_lint_pass(box use_self::UseSelf);
reg.register_late_lint_pass(box bytecount::ByteCount);
reg.register_late_lint_pass(box infinite_iter::Pass);
let_if_seq::USELESS_LET_IF_SEQ,
lifetimes::NEEDLESS_LIFETIMES,
lifetimes::UNUSED_LIFETIMES,
- literal_digit_grouping::INCONSISTENT_DIGIT_GROUPING,
- literal_digit_grouping::LARGE_DIGIT_GROUPS,
- literal_digit_grouping::UNREADABLE_LITERAL,
+ literal_representation::INCONSISTENT_DIGIT_GROUPING,
+ literal_representation::LARGE_DIGIT_GROUPS,
+ literal_representation::UNREADABLE_LITERAL,
+ literal_representation::BAD_LITERAL_REPRESENTATION,
loops::EMPTY_LOOP,
loops::EXPLICIT_COUNTER_LOOP,
loops::EXPLICIT_INTO_ITER_LOOP,
+++ /dev/null
-//! Lints concerned with the grouping of digits with underscores in integral or
-//! floating-point literal expressions.
-
-use rustc::lint::*;
-use syntax::ast::*;
-use syntax_pos;
-use utils::{in_external_macro, snippet_opt, span_help_and_lint};
-
-/// **What it does:** Warns if a long integral or floating-point constant does
-/// not contain underscores.
-///
-/// **Why is this bad?** Reading long numbers is difficult without separators.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// 61864918973511
-/// ```
-declare_lint! {
- pub UNREADABLE_LITERAL,
- Warn,
- "long integer literal without underscores"
-}
-
-/// **What it does:** Warns if an integral or floating-point constant is
-/// grouped inconsistently with underscores.
-///
-/// **Why is this bad?** Readers may incorrectly interpret inconsistently
-/// grouped digits.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// 618_64_9189_73_511
-/// ```
-declare_lint! {
- pub INCONSISTENT_DIGIT_GROUPING,
- Warn,
- "integer literals with digits grouped inconsistently"
-}
-
-/// **What it does:** Warns if the digits of an integral or floating-point
-/// constant are grouped into groups that
-/// are too large.
-///
-/// **Why is this bad?** Negatively impacts readability.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-///
-/// ```rust
-/// 6186491_8973511
-/// ```
-declare_lint! {
- pub LARGE_DIGIT_GROUPS,
- Warn,
- "grouping digits into groups that are too large"
-}
-
-#[derive(Debug)]
-enum Radix {
- Binary,
- Octal,
- Decimal,
- Hexadecimal,
-}
-
-impl Radix {
- /// Return a reasonable digit group size for this radix.
- pub fn suggest_grouping(&self) -> usize {
- match *self {
- Radix::Binary | Radix::Hexadecimal => 4,
- Radix::Octal | Radix::Decimal => 3,
- }
- }
-}
-
-#[derive(Debug)]
-struct DigitInfo<'a> {
- /// Characters of a literal between the radix prefix and type suffix.
- pub digits: &'a str,
- /// Which radix the literal was represented in.
- pub radix: Radix,
- /// The radix prefix, if present.
- pub prefix: Option<&'a str>,
- /// The type suffix, including preceding underscore if present.
- pub suffix: Option<&'a str>,
- /// True for floating-point literals.
- pub float: bool,
-}
-
-impl<'a> DigitInfo<'a> {
- pub fn new(lit: &'a str, float: bool) -> Self {
- // Determine delimiter for radix prefix, if present, and radix.
- let radix = if lit.starts_with("0x") {
- Radix::Hexadecimal
- } else if lit.starts_with("0b") {
- Radix::Binary
- } else if lit.starts_with("0o") {
- Radix::Octal
- } else {
- Radix::Decimal
- };
-
- // Grab part of the literal after prefix, if present.
- let (prefix, sans_prefix) = if let Radix::Decimal = radix {
- (None, lit)
- } else {
- let (p, s) = lit.split_at(2);
- (Some(p), s)
- };
-
- let mut last_d = '\0';
- for (d_idx, d) in sans_prefix.char_indices() {
- if !float && (d == 'i' || d == 'u') || float && d == 'f' {
- let suffix_start = if last_d == '_' { d_idx - 1 } else { d_idx };
- let (digits, suffix) = sans_prefix.split_at(suffix_start);
- return Self {
- digits: digits,
- radix: radix,
- prefix: prefix,
- suffix: Some(suffix),
- float: float,
- };
- }
- last_d = d
- }
-
- // No suffix found
- Self {
- digits: sans_prefix,
- radix: radix,
- prefix: prefix,
- suffix: None,
- float: float,
- }
- }
-
- /// Returns digits grouped in a sensible way.
- fn grouping_hint(&self) -> String {
- let group_size = self.radix.suggest_grouping();
- if self.digits.contains('.') {
- let mut parts = self.digits.split('.');
- let int_part_hint = parts
- .next()
- .expect("split always returns at least one element")
- .chars()
- .rev()
- .filter(|&c| c != '_')
- .collect::<Vec<_>>()
- .chunks(group_size)
- .map(|chunk| chunk.into_iter().rev().collect())
- .rev()
- .collect::<Vec<String>>()
- .join("_");
- let frac_part_hint = parts
- .next()
- .expect("already checked that there is a `.`")
- .chars()
- .filter(|&c| c != '_')
- .collect::<Vec<_>>()
- .chunks(group_size)
- .map(|chunk| chunk.into_iter().collect())
- .collect::<Vec<String>>()
- .join("_");
- format!("{}.{}{}", int_part_hint, frac_part_hint, self.suffix.unwrap_or(""))
- } else {
- let hint = self.digits
- .chars()
- .rev()
- .filter(|&c| c != '_')
- .collect::<Vec<_>>()
- .chunks(group_size)
- .map(|chunk| chunk.into_iter().rev().collect())
- .rev()
- .collect::<Vec<String>>()
- .join("_");
- format!("{}{}{}", self.prefix.unwrap_or(""), hint, self.suffix.unwrap_or(""))
- }
- }
-}
-
-enum WarningType {
- UnreadableLiteral,
- InconsistentDigitGrouping,
- LargeDigitGroups,
-}
-
-
-impl WarningType {
- pub fn display(&self, grouping_hint: &str, cx: &EarlyContext, span: &syntax_pos::Span) {
- match *self {
- WarningType::UnreadableLiteral => span_help_and_lint(
- cx,
- UNREADABLE_LITERAL,
- *span,
- "long literal lacking separators",
- &format!("consider: {}", grouping_hint),
- ),
- WarningType::LargeDigitGroups => span_help_and_lint(
- cx,
- LARGE_DIGIT_GROUPS,
- *span,
- "digit groups should be smaller",
- &format!("consider: {}", grouping_hint),
- ),
- WarningType::InconsistentDigitGrouping => span_help_and_lint(
- cx,
- INCONSISTENT_DIGIT_GROUPING,
- *span,
- "digits grouped inconsistently by underscores",
- &format!("consider: {}", grouping_hint),
- ),
- };
- }
-}
-
-#[derive(Copy, Clone)]
-pub struct LiteralDigitGrouping;
-
-impl LintPass for LiteralDigitGrouping {
- fn get_lints(&self) -> LintArray {
- lint_array!(UNREADABLE_LITERAL, INCONSISTENT_DIGIT_GROUPING, LARGE_DIGIT_GROUPS)
- }
-}
-
-impl EarlyLintPass for LiteralDigitGrouping {
- fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
- if in_external_macro(cx, expr.span) {
- return;
- }
-
- if let ExprKind::Lit(ref lit) = expr.node {
- self.check_lit(cx, lit)
- }
- }
-}
-
-impl LiteralDigitGrouping {
- fn check_lit(&self, cx: &EarlyContext, lit: &Lit) {
- // Lint integral literals.
- if_chain! {
- if let LitKind::Int(..) = lit.node;
- if let Some(src) = snippet_opt(cx, lit.span);
- if let Some(firstch) = src.chars().next();
- if char::to_digit(firstch, 10).is_some();
- then {
- let digit_info = DigitInfo::new(&src, false);
- let _ = Self::do_lint(digit_info.digits).map_err(|warning_type| {
- warning_type.display(&digit_info.grouping_hint(), cx, &lit.span)
- });
- }
- }
-
- // Lint floating-point literals.
- if_chain! {
- if let LitKind::Float(..) = lit.node;
- if let Some(src) = snippet_opt(cx, lit.span);
- if let Some(firstch) = src.chars().next();
- if char::to_digit(firstch, 10).is_some();
- then {
- let digit_info = DigitInfo::new(&src, true);
- // Separate digits into integral and fractional parts.
- let parts: Vec<&str> = digit_info
- .digits
- .split_terminator('.')
- .collect();
-
- // Lint integral and fractional parts separately, and then check consistency of digit
- // groups if both pass.
- let _ = Self::do_lint(parts[0])
- .map(|integral_group_size| {
- if parts.len() > 1 {
- // Lint the fractional part of literal just like integral part, but reversed.
- let fractional_part = &parts[1].chars().rev().collect::<String>();
- let _ = Self::do_lint(fractional_part)
- .map(|fractional_group_size| {
- let consistent = Self::parts_consistent(integral_group_size,
- fractional_group_size,
- parts[0].len(),
- parts[1].len());
- if !consistent {
- WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(),
- cx,
- &lit.span);
- }
- })
- .map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(),
- cx,
- &lit.span));
- }
- })
- .map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), cx, &lit.span));
- }
- }
- }
-
- /// Given the sizes of the digit groups of both integral and fractional
- /// parts, and the length
- /// of both parts, determine if the digits have been grouped consistently.
- fn parts_consistent(int_group_size: usize, frac_group_size: usize, int_size: usize, frac_size: usize) -> bool {
- match (int_group_size, frac_group_size) {
- // No groups on either side of decimal point - trivially consistent.
- (0, 0) => true,
- // Integral part has grouped digits, fractional part does not.
- (_, 0) => frac_size <= int_group_size,
- // Fractional part has grouped digits, integral part does not.
- (0, _) => int_size <= frac_group_size,
- // Both parts have grouped digits. Groups should be the same size.
- (_, _) => int_group_size == frac_group_size,
- }
- }
-
- /// Performs lint on `digits` (no decimal point) and returns the group
- /// size on success or `WarningType` when emitting a warning.
- fn do_lint(digits: &str) -> Result<usize, WarningType> {
- // Grab underscore indices with respect to the units digit.
- let underscore_positions: Vec<usize> = digits
- .chars()
- .rev()
- .enumerate()
- .filter_map(|(idx, digit)| if digit == '_' { Some(idx) } else { None })
- .collect();
-
- if underscore_positions.is_empty() {
- // Check if literal needs underscores.
- if digits.len() > 4 {
- Err(WarningType::UnreadableLiteral)
- } else {
- Ok(0)
- }
- } else {
- // Check consistency and the sizes of the groups.
- let group_size = underscore_positions[0];
- let consistent = underscore_positions
- .windows(2)
- .all(|ps| ps[1] - ps[0] == group_size + 1)
- // number of digits to the left of the last group cannot be bigger than group size.
- && (digits.len() - underscore_positions.last()
- .expect("there's at least one element") <= group_size + 1);
-
- if !consistent {
- return Err(WarningType::InconsistentDigitGrouping);
- } else if group_size > 4 {
- return Err(WarningType::LargeDigitGroups);
- }
- Ok(group_size)
- }
- }
-}
--- /dev/null
+//! Lints concerned with the grouping of digits with underscores in integral or
+//! floating-point literal expressions.
+
+use rustc::lint::*;
+use syntax::ast::*;
+use syntax_pos;
+use utils::{in_external_macro, snippet_opt, span_help_and_lint};
+
+/// **What it does:** Warns if a long integral or floating-point constant does
+/// not contain underscores.
+///
+/// **Why is this bad?** Reading long numbers is difficult without separators.
+///
+/// **Known problems:** None.
+///
+/// **Example:**
+///
+/// ```rust
+/// 61864918973511
+/// ```
+declare_lint! {
+ pub UNREADABLE_LITERAL,
+ Warn,
+ "long integer literal without underscores"
+}
+
+/// **What it does:** Warns if an integral or floating-point constant is
+/// grouped inconsistently with underscores.
+///
+/// **Why is this bad?** Readers may incorrectly interpret inconsistently
+/// grouped digits.
+///
+/// **Known problems:** None.
+///
+/// **Example:**
+///
+/// ```rust
+/// 618_64_9189_73_511
+/// ```
+declare_lint! {
+ pub INCONSISTENT_DIGIT_GROUPING,
+ Warn,
+ "integer literals with digits grouped inconsistently"
+}
+
+/// **What it does:** Warns if the digits of an integral or floating-point
+/// constant are grouped into groups that
+/// are too large.
+///
+/// **Why is this bad?** Negatively impacts readability.
+///
+/// **Known problems:** None.
+///
+/// **Example:**
+///
+/// ```rust
+/// 6186491_8973511
+/// ```
+declare_lint! {
+ pub LARGE_DIGIT_GROUPS,
+ Warn,
+ "grouping digits into groups that are too large"
+}
+
+/// **What it does:** Warns if there is a better representation for a numeric literal.
+///
+/// **Why is this bad?** Especially for big powers of 2 a hexadecimal representation is more
+/// readable than a decimal representation.
+///
+/// **Known problems:** None.
+///
+/// **Example:**
+///
+/// `255` => `0xFF`
+/// `65_535` => `0xFFFF`
+/// `4_042_322_160` => `0xF0F0_F0F0`
+declare_lint! {
+ pub BAD_LITERAL_REPRESENTATION,
+ Warn,
+ "using decimal representation when hexadecimal would be better"
+}
+
+#[derive(Debug, PartialEq)]
+enum Radix {
+ Binary,
+ Octal,
+ Decimal,
+ Hexadecimal,
+}
+
+impl Radix {
+ /// Return a reasonable digit group size for this radix.
+ pub fn suggest_grouping(&self) -> usize {
+ match *self {
+ Radix::Binary | Radix::Hexadecimal => 4,
+ Radix::Octal | Radix::Decimal => 3,
+ }
+ }
+}
+
+#[derive(Debug)]
+struct DigitInfo<'a> {
+ /// Characters of a literal between the radix prefix and type suffix.
+ pub digits: &'a str,
+ /// Which radix the literal was represented in.
+ pub radix: Radix,
+ /// The radix prefix, if present.
+ pub prefix: Option<&'a str>,
+ /// The type suffix, including preceding underscore if present.
+ pub suffix: Option<&'a str>,
+ /// True for floating-point literals.
+ pub float: bool,
+}
+
+impl<'a> DigitInfo<'a> {
+ pub fn new(lit: &'a str, float: bool) -> Self {
+ // Determine delimiter for radix prefix, if present, and radix.
+ let radix = if lit.starts_with("0x") {
+ Radix::Hexadecimal
+ } else if lit.starts_with("0b") {
+ Radix::Binary
+ } else if lit.starts_with("0o") {
+ Radix::Octal
+ } else {
+ Radix::Decimal
+ };
+
+ // Grab part of the literal after prefix, if present.
+ let (prefix, sans_prefix) = if let Radix::Decimal = radix {
+ (None, lit)
+ } else {
+ let (p, s) = lit.split_at(2);
+ (Some(p), s)
+ };
+
+ let mut last_d = '\0';
+ for (d_idx, d) in sans_prefix.char_indices() {
+ if !float && (d == 'i' || d == 'u') || float && d == 'f' {
+ let suffix_start = if last_d == '_' { d_idx - 1 } else { d_idx };
+ let (digits, suffix) = sans_prefix.split_at(suffix_start);
+ return Self {
+ digits: digits,
+ radix: radix,
+ prefix: prefix,
+ suffix: Some(suffix),
+ float: float,
+ };
+ }
+ last_d = d
+ }
+
+ // No suffix found
+ Self {
+ digits: sans_prefix,
+ radix: radix,
+ prefix: prefix,
+ suffix: None,
+ float: float,
+ }
+ }
+
+ /// Returns digits grouped in a sensible way.
+ fn grouping_hint(&self) -> String {
+ let group_size = self.radix.suggest_grouping();
+ if self.digits.contains('.') {
+ let mut parts = self.digits.split('.');
+ let int_part_hint = parts
+ .next()
+ .expect("split always returns at least one element")
+ .chars()
+ .rev()
+ .filter(|&c| c != '_')
+ .collect::<Vec<_>>()
+ .chunks(group_size)
+ .map(|chunk| chunk.into_iter().rev().collect())
+ .rev()
+ .collect::<Vec<String>>()
+ .join("_");
+ let frac_part_hint = parts
+ .next()
+ .expect("already checked that there is a `.`")
+ .chars()
+ .filter(|&c| c != '_')
+ .collect::<Vec<_>>()
+ .chunks(group_size)
+ .map(|chunk| chunk.into_iter().collect())
+ .collect::<Vec<String>>()
+ .join("_");
+ format!(
+ "{}.{}{}",
+ int_part_hint,
+ frac_part_hint,
+ self.suffix.unwrap_or("")
+ )
+ } else {
+ let hint = self.digits
+ .chars()
+ .rev()
+ .filter(|&c| c != '_')
+ .collect::<Vec<_>>()
+ .chunks(group_size)
+ .map(|chunk| chunk.into_iter().rev().collect())
+ .rev()
+ .collect::<Vec<String>>()
+ .join("_");
+ format!(
+ "{}{}{}",
+ self.prefix.unwrap_or(""),
+ hint,
+ self.suffix.unwrap_or("")
+ )
+ }
+ }
+}
+
+enum WarningType {
+ UnreadableLiteral,
+ InconsistentDigitGrouping,
+ LargeDigitGroups,
+ BadRepresentation,
+}
+
+impl WarningType {
+ pub fn display(&self, grouping_hint: &str, cx: &EarlyContext, span: &syntax_pos::Span) {
+ match *self {
+ WarningType::UnreadableLiteral => span_help_and_lint(
+ cx,
+ UNREADABLE_LITERAL,
+ *span,
+ "long literal lacking separators",
+ &format!("consider: {}", grouping_hint),
+ ),
+ WarningType::LargeDigitGroups => span_help_and_lint(
+ cx,
+ LARGE_DIGIT_GROUPS,
+ *span,
+ "digit groups should be smaller",
+ &format!("consider: {}", grouping_hint),
+ ),
+ WarningType::InconsistentDigitGrouping => span_help_and_lint(
+ cx,
+ INCONSISTENT_DIGIT_GROUPING,
+ *span,
+ "digits grouped inconsistently by underscores",
+ &format!("consider: {}", grouping_hint),
+ ),
+ WarningType::BadRepresentation => span_help_and_lint(
+ cx,
+ BAD_LITERAL_REPRESENTATION,
+ *span,
+ "bad representation of integer literal",
+ &format!("consider: {}", grouping_hint),
+ ),
+ };
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct LiteralDigitGrouping;
+
+impl LintPass for LiteralDigitGrouping {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(
+ UNREADABLE_LITERAL,
+ INCONSISTENT_DIGIT_GROUPING,
+ LARGE_DIGIT_GROUPS
+ )
+ }
+}
+
+impl EarlyLintPass for LiteralDigitGrouping {
+ fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
+ if in_external_macro(cx, expr.span) {
+ return;
+ }
+
+ if let ExprKind::Lit(ref lit) = expr.node {
+ self.check_lit(cx, lit)
+ }
+ }
+}
+
+impl LiteralDigitGrouping {
+ fn check_lit(&self, cx: &EarlyContext, lit: &Lit) {
+ // Lint integral literals.
+ if_chain! {
+ if let LitKind::Int(..) = lit.node;
+ if let Some(src) = snippet_opt(cx, lit.span);
+ if let Some(firstch) = src.chars().next();
+ if char::to_digit(firstch, 10).is_some();
+ then {
+ let digit_info = DigitInfo::new(&src, false);
+ let _ = Self::do_lint(digit_info.digits).map_err(|warning_type| {
+ warning_type.display(&digit_info.grouping_hint(), cx, &lit.span)
+ });
+ }
+ }
+
+ // Lint floating-point literals.
+ if_chain! {
+ if let LitKind::Float(..) = lit.node;
+ if let Some(src) = snippet_opt(cx, lit.span);
+ if let Some(firstch) = src.chars().next();
+ if char::to_digit(firstch, 10).is_some();
+ then {
+ let digit_info = DigitInfo::new(&src, true);
+ // Separate digits into integral and fractional parts.
+ let parts: Vec<&str> = digit_info
+ .digits
+ .split_terminator('.')
+ .collect();
+
+ // Lint integral and fractional parts separately, and then check consistency of digit
+ // groups if both pass.
+ let _ = Self::do_lint(parts[0])
+ .map(|integral_group_size| {
+ if parts.len() > 1 {
+ // Lint the fractional part of literal just like integral part, but reversed.
+ let fractional_part = &parts[1].chars().rev().collect::<String>();
+ let _ = Self::do_lint(fractional_part)
+ .map(|fractional_group_size| {
+ let consistent = Self::parts_consistent(integral_group_size,
+ fractional_group_size,
+ parts[0].len(),
+ parts[1].len());
+ if !consistent {
+ WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(),
+ cx,
+ &lit.span);
+ }
+ })
+ .map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(),
+ cx,
+ &lit.span));
+ }
+ })
+ .map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), cx, &lit.span));
+ }
+ }
+ }
+
+ /// Given the sizes of the digit groups of both integral and fractional
+ /// parts, and the length
+ /// of both parts, determine if the digits have been grouped consistently.
+ fn parts_consistent(int_group_size: usize, frac_group_size: usize, int_size: usize, frac_size: usize) -> bool {
+ match (int_group_size, frac_group_size) {
+ // No groups on either side of decimal point - trivially consistent.
+ (0, 0) => true,
+ // Integral part has grouped digits, fractional part does not.
+ (_, 0) => frac_size <= int_group_size,
+ // Fractional part has grouped digits, integral part does not.
+ (0, _) => int_size <= frac_group_size,
+ // Both parts have grouped digits. Groups should be the same size.
+ (_, _) => int_group_size == frac_group_size,
+ }
+ }
+
+ /// Performs lint on `digits` (no decimal point) and returns the group
+ /// size on success or `WarningType` when emitting a warning.
+ fn do_lint(digits: &str) -> Result<usize, WarningType> {
+ // Grab underscore indices with respect to the units digit.
+ let underscore_positions: Vec<usize> = digits
+ .chars()
+ .rev()
+ .enumerate()
+ .filter_map(|(idx, digit)| if digit == '_' { Some(idx) } else { None })
+ .collect();
+
+ if underscore_positions.is_empty() {
+ // Check if literal needs underscores.
+ if digits.len() > 4 {
+ Err(WarningType::UnreadableLiteral)
+ } else {
+ Ok(0)
+ }
+ } else {
+ // Check consistency and the sizes of the groups.
+ let group_size = underscore_positions[0];
+ let consistent = underscore_positions
+ .windows(2)
+ .all(|ps| ps[1] - ps[0] == group_size + 1)
+ // number of digits to the left of the last group cannot be bigger than group size.
+ && (digits.len() - underscore_positions.last()
+ .expect("there's at least one element") <= group_size + 1);
+
+ if !consistent {
+ return Err(WarningType::InconsistentDigitGrouping);
+ } else if group_size > 4 {
+ return Err(WarningType::LargeDigitGroups);
+ }
+ Ok(group_size)
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct LiteralRepresentation;
+
+impl LintPass for LiteralRepresentation {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(BAD_LITERAL_REPRESENTATION)
+ }
+}
+
+impl EarlyLintPass for LiteralRepresentation {
+ fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
+ if in_external_macro(cx, expr.span) {
+ return;
+ }
+
+ if let ExprKind::Lit(ref lit) = expr.node {
+ self.check_lit(cx, lit)
+ }
+ }
+}
+
+impl LiteralRepresentation {
+ fn check_lit(&self, cx: &EarlyContext, lit: &Lit) {
+ // Lint integral literals.
+ if_chain! {
+ if let LitKind::Int(..) = lit.node;
+ if let Some(src) = snippet_opt(cx, lit.span);
+ if let Some(firstch) = src.chars().next();
+ if char::to_digit(firstch, 10).is_some();
+ then {
+ let digit_info = DigitInfo::new(&src, false);
+ if digit_info.radix == Radix::Decimal {
+ let hex = format!("{:#X}", digit_info.digits
+ .chars()
+ .filter(|&c| c != '_')
+ .collect::<String>()
+ .parse::<u128>().unwrap());
+ let digit_info = DigitInfo::new(&hex[..], false);
+ let _ = Self::do_lint(digit_info.digits).map_err(|warning_type| {
+ warning_type.display(&digit_info.grouping_hint(), cx, &lit.span)
+ });
+ }
+ }
+ }
+ }
+
+ fn do_lint(digits: &str) -> Result<(), WarningType> {
+ if digits.len() == 2 && digits == "FF" {
+ return Err(WarningType::BadRepresentation);
+ } else if digits.len() == 3 {
+ // Lint for Literals with a hex-representation of 3 digits
+ let f = &digits[0..1]; // first digit
+ let s = &digits[1..]; // suffix
+ // Powers of 2 minus 1
+ if (f.eq("1") || f.eq("3") || f.eq("7") || f.eq("F")) && s.eq("FF") {
+ return Err(WarningType::BadRepresentation);
+ }
+ } else if digits.len() > 3 {
+ // Lint for Literals with a hex-representation of 4 digits or more
+ let f = &digits[0..1]; // first digit
+ let m = &digits[1..digits.len() - 1]; // middle digits, except last
+ let s = &digits[1..]; // suffix
+ // Powers of 2 with a margin of +15/-16
+ if ((f.eq("1") || f.eq("2") || f.eq("4") || f.eq("8")) && m.chars().all(|c| c == '0'))
+ || ((f.eq("1") || f.eq("3") || f.eq("7") || f.eq("F")) && m.chars().all(|c| c == 'F'))
+ // Lint for representations with only 0s and Fs, while allowing 7 as the first
+ // digit
+ || ((f.eq("7") || f.eq("F")) && s.chars().all(|c| c == '0' || c == 'F'))
+ {
+ return Err(WarningType::BadRepresentation);
+ }
+ }
+
+ Ok(())
+ }
+}
--- /dev/null
+
+
+
+#[warn(bad_literal_representation)]
+#[allow(unused_variables)]
+fn main() {
+ // Hex: 7F, 80, 100, 800, FFA, F0F3, 7F0F_F00D
+ let good = (127, 128, 256, 2048, 4090, 61_683, 2_131_750_925);
+ let bad = ( // Hex:
+ 255, // 0xFF
+ 511, // 0x1FF
+ 1023, // 0x3FF
+ 2047, // 0x7FF
+ 4095, // 0xFFF
+ 4096, // 0x1000
+ 16_371, // 0x3FF3
+ 32_773, // 0x8005
+ 65_280, // 0xFF00
+ 2_131_750_927, // 0x7F0F_F00F
+ 2_147_483_647, // 0x7FFF_FFFF
+ 4_042_322_160, // 0xF0F0_F0F0
+ );
+}
--- /dev/null
+error: bad representation of integer literal
+ --> $DIR/bad_literal_representation.rs:10:9
+ |
+10 | 255, // 0xFF
+ | ^^^
+ |
+ = note: `-D bad-literal-representation` implied by `-D warnings`
+ = help: consider: 0xFF
+
+error: bad representation of integer literal
+ --> $DIR/bad_literal_representation.rs:11:9
+ |
+11 | 511, // 0x1FF
+ | ^^^
+ |
+ = help: consider: 0x1FF
+
+error: bad representation of integer literal
+ --> $DIR/bad_literal_representation.rs:12:9
+ |
+12 | 1023, // 0x3FF
+ | ^^^^
+ |
+ = help: consider: 0x3FF
+
+error: bad representation of integer literal
+ --> $DIR/bad_literal_representation.rs:13:9
+ |
+13 | 2047, // 0x7FF
+ | ^^^^
+ |
+ = help: consider: 0x7FF
+
+error: bad representation of integer literal
+ --> $DIR/bad_literal_representation.rs:14:9
+ |
+14 | 4095, // 0xFFF
+ | ^^^^
+ |
+ = help: consider: 0xFFF
+
+error: bad representation of integer literal
+ --> $DIR/bad_literal_representation.rs:15:9
+ |
+15 | 4096, // 0x1000
+ | ^^^^
+ |
+ = help: consider: 0x1000
+
+error: bad representation of integer literal
+ --> $DIR/bad_literal_representation.rs:16:9
+ |
+16 | 16_371, // 0x3FF3
+ | ^^^^^^
+ |
+ = help: consider: 0x3FF3
+
+error: bad representation of integer literal
+ --> $DIR/bad_literal_representation.rs:17:9
+ |
+17 | 32_773, // 0x8005
+ | ^^^^^^
+ |
+ = help: consider: 0x8005
+
+error: bad representation of integer literal
+ --> $DIR/bad_literal_representation.rs:18:9
+ |
+18 | 65_280, // 0xFF00
+ | ^^^^^^
+ |
+ = help: consider: 0xFF00
+
+error: bad representation of integer literal
+ --> $DIR/bad_literal_representation.rs:19:9
+ |
+19 | 2_131_750_927, // 0x7F0F_F00F
+ | ^^^^^^^^^^^^^
+ |
+ = help: consider: 0x7F0F_F00F
+
+error: bad representation of integer literal
+ --> $DIR/bad_literal_representation.rs:20:9
+ |
+20 | 2_147_483_647, // 0x7FFF_FFFF
+ | ^^^^^^^^^^^^^
+ |
+ = help: consider: 0x7FFF_FFFF
+
+error: bad representation of integer literal
+ --> $DIR/bad_literal_representation.rs:21:9
+ |
+21 | 4_042_322_160, // 0xF0F0_F0F0
+ | ^^^^^^^^^^^^^
+ |
+ = help: consider: 0xF0F0_F0F0
+
forget(s4);
forget(s5);
- let a1 = AnotherStruct {x: 255, y: 0, z: vec![1, 2, 3]};
+ let a1 = AnotherStruct {x: 0xFF, y: 0, z: vec![1, 2, 3]};
let a2 = &a1;
let mut a3 = a1.clone();
let ref a4 = a1;
-1 & x;
let u : u8 = 0;
- u & 255;
+ u & 0xFF;
}
error: the operation is ineffective. Consider reducing it to `u`
--> $DIR/identity_op.rs:32:5
|
-32 | u & 255;
- | ^^^^^^^
+32 | u & 0xFF;
+ | ^^^^^^^^