Skip to content

Number width formatting is less than possible output #15039

Open
@nyurik

Description

@nyurik

What it does

format!("{:#02X}", 7_u8) seems like a simple enough way to format a hex value as two digits, but is likely an error.

The # adds 0x in front of the value, making the minimum width of the output to be 3. Specifying width 2 is therefore ignored - making both the 0 and 2 params useless. The likely intent in this case was to do #04X - print value as a two digit HEX.

A lint should catch when format width is less than the minimum size of the output:

  • width is <= 2
  • the output formatter trait is non-blank - one of these: x, X, o, b, e, E, p
  • In case of x, X, o, b, only apply this rule for the alternative # format (the exponent and pointer formats should be checked in both the standard and alternative cases)
  • Exponents apply to both integer and floating types. p is only for the pointer types, and the rest are integer types only.

TBD

  • should the "noop" value of 3 be also reported? Setting 3 or 03 does not change the output, and should probably be removed to avoid accidental mis-understanding?

Variants

Here is a list of all variants I tested:

println!("--- integers ---");
println!("X={0:2X}, #2X={0:#2X}, #02X={0:#02X}, #4X={0:#4X}, #04X={0:#04X}", 1u8);
println!("x={0:2x}, #2x={0:#2x}, #02x={0:#02x}, #4x={0:#4x}, #04x={0:#04x}", 1u8);
println!("o={0:2o}, #2o={0:#2o}, #02o={0:#02o}, #4o={0:#4o}, #04o={0:#04o}", 1u8);
println!("b={0:2b}, #2b={0:#2b}, #02b={0:#02b}, #4b={0:#4b}, #04b={0:#04b}", 1u8);
println!("e={0:2e}, #2e={0:#2e}, #02e={0:#02e}, #4e={0:#4e}, #04e={0:#04e}", 1u8);
println!("E={0:2E}, #2E={0:#2E}, #02E={0:#02E}, #4E={0:#4E}, #04E={0:#04E}", 1u8);
println!("--- floats ---");
println!("e={0:2e}, #2e={0:#2e}, #02e={0:#02e}, #4e={0:#4e}, #04e={0:#04e}", 1.0);
println!("E={0:2E}, #2E={0:#2E}, #02E={0:#02E}, #4E={0:#4E}, #04E={0:#04E}", 1.0);
println!("--- pointers ---");
println!("p={0:2p}, #2p={0:#2p}, #02p={0:#02p}, #4p={0:#4p}, #04p={0:#04p}", 0 as *const usize);
println!("p={0:2p}, #2p={0:#2p}, #02p={0:#02p}, #4p={0:#4p}, #04p={0:#04p}", 1 as *const usize);
--- integers ---
X= 1, #2X=0x1, #02X=0x1, #4X= 0x1, #04X=0x01
x= 1, #2x=0x1, #02x=0x1, #4x= 0x1, #04x=0x01
o= 1, #2o=0o1, #02o=0o1, #4o= 0o1, #04o=0o01
b= 1, #2b=0b1, #02b=0b1, #4b= 0b1, #04b=0b01
e=1e0, #2e=1e0, #02e=1e0, #4e= 1e0, #04e=01e0
E=1E0, #2E=1E0, #02E=1E0, #4E= 1E0, #04E=01E0
--- floats ---
e=1e0, #2e=1e0, #02e=1e0, #4e= 1e0, #04e=01e0
E=1E0, #2E=1E0, #02E=1E0, #4E= 1E0, #04E=01E0
--- pointers ---
p=0x0, #2p=0x0, #02p=0x0, #4p=0x00, #04p=0x00
p=0x1, #2p=0x1, #02p=0x1, #4p=0x01, #04p=0x01

Advantage

  • catches a simple but non-obvious error

Drawbacks

No response

Example

format!("{:#02X}", 1_u8);

Could be written as:

format!("{:#04X}", 1_u8);

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lintArea: New lints

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions