diff --git a/Configurations.md b/Configurations.md index a4f3bb0b943..6d8d1353c85 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1056,6 +1056,13 @@ fn lorem() -> usize { See also: [`tab_spaces`](#tab_spaces). +## `hex_literal_case` + +Control the case of the letters in hexadecimal literal values + +- **Default value**: `Preserve` +- **Possible values**: `Upper`, `Lower` +- **Stable**: No ## `hide_parse_errors` diff --git a/src/config/mod.rs b/src/config/mod.rs index 3d6e32fdb60..c6cee8ed227 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -69,6 +69,8 @@ create_config! { format_macro_matchers: bool, false, false, "Format the metavariable matching patterns in macros"; format_macro_bodies: bool, true, false, "Format the bodies of macros"; + hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false, + "Format hexadecimal integer literals"; // Single line expressions and items empty_item_single_line: bool, true, false, @@ -570,6 +572,7 @@ license_template_path = "" format_strings = false format_macro_matchers = false format_macro_bodies = true +hex_literal_case = "Preserve" empty_item_single_line = true struct_lit_single_line = true fn_single_line = false diff --git a/src/config/options.rs b/src/config/options.rs index 3b91021813c..516f6e461da 100644 --- a/src/config/options.rs +++ b/src/config/options.rs @@ -127,6 +127,17 @@ pub enum ImportGranularity { Item, } +/// Controls how rustfmt should handle case in hexadecimal literals. +#[config_type] +pub enum HexLiteralCase { + /// Leave the literal as-is + Preserve, + /// Ensure all literals use uppercase lettering + Upper, + /// Ensure all literals use lowercase lettering + Lower, +} + #[config_type] pub enum ReportTactic { Always, diff --git a/src/expr.rs b/src/expr.rs index 84eccc42b7d..16d81f0389e 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -13,7 +13,7 @@ use crate::comment::{ rewrite_missing_comment, CharClasses, FindUncommented, }; use crate::config::lists::*; -use crate::config::{Config, ControlBraceStyle, IndentStyle, Version}; +use crate::config::{Config, ControlBraceStyle, HexLiteralCase, IndentStyle, Version}; use crate::lists::{ definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape, struct_lit_tactic, write_list, ListFormatting, Separator, @@ -1166,6 +1166,7 @@ pub(crate) fn rewrite_literal( ) -> Option { match l.kind { ast::LitKind::Str(_, ast::StrStyle::Cooked) => rewrite_string_lit(context, l.span, shape), + ast::LitKind::Int(..) => rewrite_int_lit(context, l, shape), _ => wrap_str( context.snippet(l.span).to_owned(), context.config.max_width(), @@ -1200,6 +1201,36 @@ fn rewrite_string_lit(context: &RewriteContext<'_>, span: Span, shape: Shape) -> ) } +fn rewrite_int_lit(context: &RewriteContext<'_>, lit: &ast::Lit, shape: Shape) -> Option { + let span = lit.span; + let symbol = lit.token.symbol.as_str(); + + if symbol.starts_with("0x") { + let hex_lit = match context.config.hex_literal_case() { + HexLiteralCase::Preserve => None, + HexLiteralCase::Upper => Some(symbol[2..].to_ascii_uppercase()), + HexLiteralCase::Lower => Some(symbol[2..].to_ascii_lowercase()), + }; + if let Some(hex_lit) = hex_lit { + return wrap_str( + format!( + "0x{}{}", + hex_lit, + lit.token.suffix.map_or(String::new(), |s| s.to_string()) + ), + context.config.max_width(), + shape, + ); + } + } + + wrap_str( + context.snippet(span).to_owned(), + context.config.max_width(), + shape, + ) +} + fn choose_separator_tactic(context: &RewriteContext<'_>, span: Span) -> Option { if context.inside_macro() { if span_ends_with_comma(context, span) { diff --git a/tests/source/hex_literal_lower.rs b/tests/source/hex_literal_lower.rs new file mode 100644 index 00000000000..ce307b3aa52 --- /dev/null +++ b/tests/source/hex_literal_lower.rs @@ -0,0 +1,5 @@ +// rustfmt-hex_literal_case: Lower +fn main() { + let h1 = 0xCAFE_5EA7; + let h2 = 0xCAFE_F00Du32; +} diff --git a/tests/source/hex_literal_upper.rs b/tests/source/hex_literal_upper.rs new file mode 100644 index 00000000000..b1092ad71ba --- /dev/null +++ b/tests/source/hex_literal_upper.rs @@ -0,0 +1,5 @@ +// rustfmt-hex_literal_case: Upper +fn main() { + let h1 = 0xCaFE_5ea7; + let h2 = 0xCAFE_F00Du32; +} diff --git a/tests/target/hex_literal_lower.rs b/tests/target/hex_literal_lower.rs new file mode 100644 index 00000000000..5c27fded167 --- /dev/null +++ b/tests/target/hex_literal_lower.rs @@ -0,0 +1,5 @@ +// rustfmt-hex_literal_case: Lower +fn main() { + let h1 = 0xcafe_5ea7; + let h2 = 0xcafe_f00du32; +} diff --git a/tests/target/hex_literal_preserve.rs b/tests/target/hex_literal_preserve.rs new file mode 100644 index 00000000000..e8774d0bb24 --- /dev/null +++ b/tests/target/hex_literal_preserve.rs @@ -0,0 +1,5 @@ +// rustfmt-hex_literal_case: Preserve +fn main() { + let h1 = 0xcAfE_5Ea7; + let h2 = 0xCaFe_F00du32; +} diff --git a/tests/target/hex_literal_upper.rs b/tests/target/hex_literal_upper.rs new file mode 100644 index 00000000000..48bb93d2c1c --- /dev/null +++ b/tests/target/hex_literal_upper.rs @@ -0,0 +1,5 @@ +// rustfmt-hex_literal_case: Upper +fn main() { + let h1 = 0xCAFE_5EA7; + let h2 = 0xCAFE_F00Du32; +}