-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
311 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
use clippy_utils::{ | ||
diagnostics::span_lint_and_sugg, | ||
get_parent_expr, is_from_proc_macro, last_path_segment, | ||
msrvs::{self, Msrv}, | ||
}; | ||
use rustc_errors::Applicability; | ||
use rustc_hir::{def::Res, def_id::DefId}; | ||
use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TyKind}; | ||
use rustc_lint::{LateContext, LateLintPass, LintContext}; | ||
use rustc_middle::lint::in_external_macro; | ||
use rustc_session::{declare_tool_lint, impl_lint_pass}; | ||
use rustc_span::{sym, Symbol}; | ||
|
||
declare_clippy_lint! { | ||
/// ### What it does | ||
/// Checks for usage of `<integer>::max_value()`, `std::<integer>::MAX`, | ||
/// `std::<float>::EPSILON`, etc. | ||
/// | ||
/// ### Why is this bad? | ||
/// All of these have been superceded by the associated constants on their respective types, | ||
/// such as `i128::MAX`. These legacy constants may be deprecated in a future version of rust. | ||
/// | ||
/// ### Example | ||
/// ```rust | ||
/// let eps = std::f32::EPSILON; | ||
/// ``` | ||
/// Use instead: | ||
/// ```rust | ||
/// let eps = f32::EPSILON; | ||
/// ``` | ||
#[clippy::version = "1.72.0"] | ||
pub LEGACY_INTEGRAL_CONSTANTS, | ||
style, | ||
"checks for usage of legacy std integral constants" | ||
} | ||
pub struct LegacyIntegralConstants { | ||
msrv: Msrv, | ||
} | ||
|
||
impl LegacyIntegralConstants { | ||
#[must_use] | ||
pub fn new(msrv: Msrv) -> Self { | ||
Self { msrv } | ||
} | ||
} | ||
|
||
impl_lint_pass!(LegacyIntegralConstants => [LEGACY_INTEGRAL_CONSTANTS]); | ||
|
||
impl<'tcx> LateLintPass<'tcx> for LegacyIntegralConstants { | ||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { | ||
if !self.msrv.meets(msrvs::STD_INTEGRAL_CONSTANTS) || in_external_macro(cx.sess(), expr.span) { | ||
return; | ||
} | ||
let ExprKind::Path(qpath) = expr.kind else { | ||
return; | ||
}; | ||
|
||
// `std::<integer>::<CONST>` check | ||
let (span, sugg, is_method) = if let QPath::Resolved(_, path) = qpath | ||
&& let Some(def_id) = path.res.opt_def_id() | ||
&& let Some(name) = path.segments.iter().last().map(|segment| segment.ident.name) | ||
&& let Some(module_name) = is_path_in_integral_module(cx, def_id) | ||
{ | ||
( | ||
expr.span, | ||
format!("{module_name}::{name}"), | ||
false, | ||
) | ||
// `<integer>::xxx_value` check | ||
} else if let QPath::TypeRelative(ty, _) = qpath | ||
&& let TyKind::Path(ty_qpath) = ty.kind | ||
&& let Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_)) = cx.qpath_res(&ty_qpath, ty.hir_id) | ||
&& let last_segment = last_path_segment(&qpath) | ||
&& let name = last_segment.ident.name.as_str() | ||
&& (name == "max_value" || name == "min_value") | ||
// Also remove the `()` | ||
&& let Some(par_expr) = get_parent_expr(cx, expr) | ||
&& let ExprKind::Call(_, _) = par_expr.kind | ||
{ | ||
( | ||
qpath.last_segment_span().with_hi(par_expr.span.hi()), | ||
name[..=2].to_ascii_uppercase(), | ||
true, | ||
) | ||
} else { | ||
return; | ||
}; | ||
|
||
if !is_from_proc_macro(cx, expr) { | ||
let msg = if is_method { | ||
"usage of a legacy integral constant method" | ||
} else { | ||
"usage of a legacy integral constant" | ||
}; | ||
|
||
span_lint_and_sugg( | ||
cx, | ||
LEGACY_INTEGRAL_CONSTANTS, | ||
span, | ||
msg, | ||
"try using the associated constant instead", | ||
sugg, | ||
Applicability::MachineApplicable, | ||
); | ||
} | ||
} | ||
|
||
extract_msrv_attr!(LateContext); | ||
} | ||
|
||
fn is_path_in_integral_module(cx: &LateContext<'_>, def_id: DefId) -> Option<Symbol> { | ||
if let [ | ||
sym::core, | ||
module @ (sym::u8 | ||
| sym::i8 | ||
| sym::u16 | ||
| sym::i16 | ||
| sym::u32 | ||
| sym::i32 | ||
| sym::u64 | ||
| sym::i64 | ||
| sym::u128 | ||
| sym::i128 | ||
| sym::usize | ||
| sym::isize | ||
| sym::f32 | ||
| sym::f64), | ||
_, | ||
] = &*cx.get_def_path(def_id) | ||
{ | ||
return Some(*module); | ||
} | ||
|
||
None | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
//@run-rustfix | ||
//@aux-build:proc_macros.rs | ||
#![allow(clippy::no_effect, deprecated, unused)] | ||
#![warn(clippy::legacy_integral_constants)] | ||
|
||
#[macro_use] | ||
extern crate proc_macros; | ||
|
||
fn main() { | ||
f32::EPSILON; | ||
u8::MIN; | ||
usize::MIN; | ||
u32::MAX; | ||
use std::u32::MAX; | ||
u32::MAX; | ||
u32::MAX; | ||
u8::MAX; | ||
u8::MIN; | ||
::std::primitive::u8::MIN; | ||
::std::u8::MIN; | ||
::std::primitive::u8::MIN; | ||
std::primitive::u32::MAX; | ||
// Don't lint | ||
f32::EPSILON; | ||
u8::MIN; | ||
external! { | ||
::std::primitive::u8::MIN; | ||
::std::u8::MIN; | ||
::std::primitive::u8::min_value(); | ||
} | ||
} |
Oops, something went wrong.