Skip to content

Commit 388aa5d

Browse files
committed
now mentions use statements to remove
1 parent fe60a3e commit 388aa5d

15 files changed

+386
-263
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4913,7 +4913,7 @@ Released 2018-09-13
49134913
[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
49144914
[`large_stack_frames`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames
49154915
[`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value
4916-
[`legacy_integral_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#legacy_integral_constants
4916+
[`legacy_numeric_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants
49174917
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
49184918
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
49194919
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
231231
crate::large_include_file::LARGE_INCLUDE_FILE_INFO,
232232
crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO,
233233
crate::large_stack_frames::LARGE_STACK_FRAMES_INFO,
234-
crate::legacy_integral_constants::LEGACY_INTEGRAL_CONSTANTS_INFO,
234+
crate::legacy_numeric_constants::LEGACY_NUMERIC_CONSTANTS_INFO,
235235
crate::len_zero::COMPARISON_TO_EMPTY_INFO,
236236
crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO,
237237
crate::len_zero::LEN_ZERO_INFO,

clippy_lints/src/legacy_integral_constants.rs

Lines changed: 0 additions & 147 deletions
This file was deleted.
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
use clippy_utils::{
2+
diagnostics::span_lint_and_then,
3+
get_parent_expr, is_from_proc_macro, last_path_segment,
4+
msrvs::{self, Msrv},
5+
};
6+
use itertools::Itertools;
7+
use rustc_data_structures::fx::FxHashMap;
8+
use rustc_errors::Applicability;
9+
use rustc_hir::{
10+
def::Res,
11+
def_id::DefId,
12+
intravisit::{walk_expr, Visitor},
13+
Item, UseKind,
14+
};
15+
use rustc_hir::{Expr, ExprKind, ItemKind, PrimTy, QPath, TyKind};
16+
use rustc_lint::{LateContext, LateLintPass, LintContext};
17+
use rustc_middle::{hir::nested_filter::OnlyBodies, lint::in_external_macro};
18+
use rustc_session::{declare_tool_lint, impl_lint_pass};
19+
use rustc_span::{sym, Span, Symbol};
20+
21+
declare_clippy_lint! {
22+
/// ### What it does
23+
/// Checks for usage of `<integer>::max_value()`, `std::<integer>::MAX`,
24+
/// `std::<float>::EPSILON`, etc.
25+
///
26+
/// ### Why is this bad?
27+
/// All of these have been superceded by the associated constants on their respective types,
28+
/// such as `i128::MAX`. These legacy constants may be deprecated in a future version of rust.
29+
///
30+
/// ### Example
31+
/// ```rust
32+
/// let eps = std::f32::EPSILON;
33+
/// ```
34+
/// Use instead:
35+
/// ```rust
36+
/// let eps = f32::EPSILON;
37+
/// ```
38+
#[clippy::version = "1.72.0"]
39+
pub LEGACY_NUMERIC_CONSTANTS,
40+
style,
41+
"checks for usage of legacy std numeric constants and methods"
42+
}
43+
pub struct LegacyNumericConstants {
44+
msrv: Msrv,
45+
use_stmts: FxHashMap<Symbol, Vec<Span>>,
46+
glob_use_stmts: Vec<Span>,
47+
}
48+
49+
impl LegacyNumericConstants {
50+
#[must_use]
51+
pub fn new(msrv: Msrv) -> Self {
52+
Self {
53+
msrv,
54+
use_stmts: FxHashMap::default(),
55+
glob_use_stmts: vec![],
56+
}
57+
}
58+
}
59+
60+
impl_lint_pass!(LegacyNumericConstants => [LEGACY_NUMERIC_CONSTANTS]);
61+
62+
impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
63+
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
64+
let Self {
65+
msrv: _,
66+
use_stmts,
67+
glob_use_stmts,
68+
} = self;
69+
70+
if !item.span.is_dummy() && let ItemKind::Use(path, kind) = item.kind {
71+
match kind {
72+
UseKind::Single => {
73+
for res in &path.res {
74+
if let Some(def_id) = res.opt_def_id()
75+
&& let Some(module_name) = is_path_in_integral_module(cx, def_id)
76+
&& let _ = use_stmts.insert(module_name, vec![])
77+
&& let Some(use_stmts) = use_stmts.get_mut(&module_name)
78+
{
79+
use_stmts.push(item.span);
80+
}
81+
}
82+
},
83+
UseKind::Glob => glob_use_stmts.push(item.span),
84+
UseKind::ListStem => {},
85+
}
86+
}
87+
}
88+
89+
fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
90+
let Self {
91+
msrv,
92+
use_stmts,
93+
glob_use_stmts,
94+
} = self;
95+
96+
let mut v = V {
97+
cx,
98+
msrv,
99+
use_stmts,
100+
glob_use_stmts,
101+
};
102+
cx.tcx.hir().visit_all_item_likes_in_crate(&mut v);
103+
}
104+
105+
extract_msrv_attr!(LateContext);
106+
}
107+
108+
struct V<'a, 'tcx> {
109+
cx: &'a LateContext<'tcx>,
110+
msrv: &'a Msrv,
111+
use_stmts: &'a FxHashMap<Symbol, Vec<Span>>,
112+
glob_use_stmts: &'a Vec<Span>,
113+
}
114+
115+
impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
116+
type NestedFilter = OnlyBodies;
117+
118+
fn nested_visit_map(&mut self) -> Self::Map {
119+
self.cx.tcx.hir()
120+
}
121+
122+
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
123+
walk_expr(self, expr);
124+
let Self {
125+
cx,
126+
msrv,
127+
use_stmts,
128+
glob_use_stmts,
129+
} = *self;
130+
131+
if !msrv.meets(msrvs::STD_INTEGRAL_CONSTANTS) || in_external_macro(cx.sess(), expr.span) {
132+
return;
133+
}
134+
let ExprKind::Path(qpath) = expr.kind else {
135+
return;
136+
};
137+
138+
// `std::<integer>::<CONST>` check
139+
let (span, sugg, is_method, use_stmts) = if let QPath::Resolved(_, path) = qpath
140+
&& let Some(def_id) = path.res.opt_def_id()
141+
&& let Some(name) = path.segments.iter().last().map(|segment| segment.ident.name)
142+
&& let Some(module_name) = is_path_in_integral_module(cx, def_id)
143+
{
144+
(
145+
expr.span,
146+
format!("{module_name}::{name}"),
147+
false,
148+
if path.segments.get(0).is_some_and(|segment| segment.ident.name == module_name) {
149+
use_stmts.get(&module_name)
150+
} else {
151+
None
152+
}
153+
)
154+
// `<integer>::xxx_value` check
155+
} else if let QPath::TypeRelative(ty, _) = qpath
156+
&& let TyKind::Path(ty_qpath) = ty.kind
157+
&& let Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_)) = cx.qpath_res(&ty_qpath, ty.hir_id)
158+
&& let last_segment = last_path_segment(&qpath)
159+
&& let name = last_segment.ident.name.as_str()
160+
&& (name == "max_value" || name == "min_value")
161+
// Also remove the `()`
162+
&& let Some(par_expr) = get_parent_expr(cx, expr)
163+
&& let ExprKind::Call(_, _) = par_expr.kind
164+
{
165+
(
166+
qpath.last_segment_span().with_hi(par_expr.span.hi()),
167+
name[..=2].to_ascii_uppercase(),
168+
true,
169+
None,
170+
)
171+
} else {
172+
return;
173+
};
174+
175+
if !is_from_proc_macro(cx, expr) {
176+
let msg = if is_method {
177+
"usage of a legacy numeric method"
178+
} else {
179+
"usage of a legacy numeric constant"
180+
};
181+
182+
span_lint_and_then(cx, LEGACY_NUMERIC_CONSTANTS, span, msg, |diag| {
183+
let app = if use_stmts.is_none() {
184+
Applicability::MachineApplicable
185+
} else {
186+
Applicability::MaybeIncorrect
187+
};
188+
diag.span_suggestion(span, "use the associated constant instead", sugg, app);
189+
if let Some(use_stmts) = use_stmts {
190+
diag.span_note(
191+
use_stmts.iter().chain(glob_use_stmts).copied().collect_vec(),
192+
"you may need to remove one of the following `use` statements",
193+
);
194+
}
195+
});
196+
}
197+
}
198+
}
199+
200+
fn is_path_in_integral_module(cx: &LateContext<'_>, def_id: DefId) -> Option<Symbol> {
201+
let path = cx.get_def_path(def_id);
202+
if let [
203+
sym::core | sym::std,
204+
module @ (sym::u8
205+
| sym::i8
206+
| sym::u16
207+
| sym::i16
208+
| sym::u32
209+
| sym::i32
210+
| sym::u64
211+
| sym::i64
212+
| sym::u128
213+
| sym::i128
214+
| sym::usize
215+
| sym::isize
216+
| sym::f32
217+
| sym::f64),
218+
..,
219+
] = &*cx.get_def_path(def_id)
220+
// So `use` statements like `std::f32` also work
221+
&& path.len() <= 3
222+
{
223+
return Some(*module);
224+
}
225+
226+
None
227+
}

0 commit comments

Comments
 (0)