Add subdiagnostic and suggestion for overflowing bin hex with sign bits

This commit is contained in:
Nicky Lim 2023-05-05 00:29:11 +07:00
parent 34d64ab7a2
commit 6033895ec2
3 changed files with 63 additions and 4 deletions

View file

@ -425,6 +425,7 @@ lint_overflowing_bin_hex = literal out of range for `{$ty}`
.negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}` .negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}`
.positive_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}` .positive_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}`
.suggestion = consider using the type `{$suggestion_ty}` instead .suggestion = consider using the type `{$suggestion_ty}` instead
.sign_bit_suggestion = to use as a negative number (decimal `{$negative_val}`), consider using the type `{$uint_ty}` for the literal and cast it to `{$int_ty}`
.help = consider using the type `{$suggestion_ty}` instead .help = consider using the type `{$suggestion_ty}` instead
lint_overflowing_int = literal out of range for `{$ty}` lint_overflowing_int = literal out of range for `{$ty}`

View file

@ -1342,6 +1342,8 @@ pub struct OverflowingBinHex<'a> {
pub sign: OverflowingBinHexSign, pub sign: OverflowingBinHexSign,
#[subdiagnostic] #[subdiagnostic]
pub sub: Option<OverflowingBinHexSub<'a>>, pub sub: Option<OverflowingBinHexSub<'a>>,
#[subdiagnostic]
pub sign_bit_sub: Option<OverflowingBinHexSignBitSub<'a>>,
} }
pub enum OverflowingBinHexSign { pub enum OverflowingBinHexSign {
@ -1386,6 +1388,21 @@ pub enum OverflowingBinHexSub<'a> {
Help { suggestion_ty: &'a str }, Help { suggestion_ty: &'a str },
} }
#[derive(Subdiagnostic)]
#[suggestion(
lint_sign_bit_suggestion,
code = "{lit_no_suffix}{uint_ty} as {int_ty}",
applicability = "maybe-incorrect"
)]
pub struct OverflowingBinHexSignBitSub<'a> {
#[primary_span]
pub span: Span,
pub lit_no_suffix: &'a str,
pub negative_val: String,
pub uint_ty: &'a str,
pub int_ty: &'a str,
}
#[derive(LintDiagnostic)] #[derive(LintDiagnostic)]
#[diag(lint_overflowing_int)] #[diag(lint_overflowing_int)]
#[note] #[note]

View file

@ -3,9 +3,10 @@ use crate::{
lints::{ lints::{
AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes, AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes,
InvalidAtomicOrderingDiag, InvalidNanComparisons, InvalidNanComparisonsSuggestion, InvalidAtomicOrderingDiag, InvalidNanComparisons, InvalidNanComparisonsSuggestion,
OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSub, OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub,
OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral,
RangeEndpointOutOfRange, UnusedComparisons, UseInclusiveRange, VariantSizeDifferencesDiag, OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, UseInclusiveRange,
VariantSizeDifferencesDiag,
}, },
}; };
use crate::{LateContext, LateLintPass, LintContext}; use crate::{LateContext, LateLintPass, LintContext};
@ -297,10 +298,50 @@ fn report_bin_hex_error(
} }
}, },
); );
let sign_bit_sub = (!negative)
.then(|| {
let ty::Int(int_ty) = cx.typeck_results().node_type(expr.hir_id).kind() else {
return None;
};
let Some(bit_width) = int_ty.bit_width() else {
return None; // isize case
};
// Skip if sign bit is not set
if (val & (1 << (bit_width - 1))) == 0 {
return None;
}
let lit_no_suffix =
if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
repr_str.split_at(pos).0
} else {
&repr_str
};
Some(OverflowingBinHexSignBitSub {
span: expr.span,
lit_no_suffix,
negative_val: actually.clone(),
int_ty: int_ty.name_str(),
uint_ty: int_ty.to_unsigned().name_str(),
})
})
.flatten();
cx.emit_spanned_lint( cx.emit_spanned_lint(
OVERFLOWING_LITERALS, OVERFLOWING_LITERALS,
expr.span, expr.span,
OverflowingBinHex { ty: t, lit: repr_str.clone(), dec: val, actually, sign, sub }, OverflowingBinHex {
ty: t,
lit: repr_str.clone(),
dec: val,
actually,
sign,
sub,
sign_bit_sub,
},
) )
} }