Skip to content

Commit b4b77cd

Browse files
feat: add a config option to enable lint on external crate
1 parent d7d6b41 commit b4b77cd

12 files changed

+354
-172
lines changed

clippy_config/src/conf.rs

+4
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,10 @@ define_Conf! {
589589
/// 2. Paths with any segment that containing the word 'prelude'
590590
/// are already allowed by default.
591591
(allowed_wildcard_imports: FxHashSet<String> = FxHashSet::default()),
592+
/// Lint: UNNECESSARY_MIN_OR_MAX.
593+
///
594+
/// Whether to also run the lints on external defined consts.
595+
(allowed_external_crates: bool = false),
592596
}
593597

594598
/// Search for the configuration file.

clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
594594
pub_underscore_fields_behavior,
595595
ref allowed_duplicate_crates,
596596
allow_comparison_to_zero,
597+
allowed_external_crates,
597598

598599
blacklisted_names: _,
599600
cyclomatic_complexity_threshold: _,
@@ -702,6 +703,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
702703
allow_expect_in_tests,
703704
allow_unwrap_in_tests,
704705
allowed_dotfiles.clone(),
706+
allowed_external_crates,
705707
))
706708
});
707709
store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv())));

clippy_lints/src/methods/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -4115,6 +4115,7 @@ pub struct Methods {
41154115
allow_expect_in_tests: bool,
41164116
allow_unwrap_in_tests: bool,
41174117
allowed_dotfiles: FxHashSet<String>,
4118+
allowed_external_crates: bool,
41184119
}
41194120

41204121
impl Methods {
@@ -4125,6 +4126,7 @@ impl Methods {
41254126
allow_expect_in_tests: bool,
41264127
allow_unwrap_in_tests: bool,
41274128
mut allowed_dotfiles: FxHashSet<String>,
4129+
allowed_external_crates: bool,
41284130
) -> Self {
41294131
allowed_dotfiles.extend(DEFAULT_ALLOWED_DOTFILES.iter().map(ToString::to_string));
41304132

@@ -4134,6 +4136,7 @@ impl Methods {
41344136
allow_expect_in_tests,
41354137
allow_unwrap_in_tests,
41364138
allowed_dotfiles,
4139+
allowed_external_crates,
41374140
}
41384141
}
41394142
}
@@ -4562,7 +4565,9 @@ impl Methods {
45624565
Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
45634566
_ => {},
45644567
},
4565-
("min" | "max", [arg]) => unnecessary_min_or_max::check(cx, expr, name, recv, arg),
4568+
("min" | "max", [arg]) => {
4569+
unnecessary_min_or_max::check(cx, expr, name, recv, arg, self.allowed_external_crates)
4570+
},
45664571
("drain", ..) => {
45674572
if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id)
45684573
&& matches!(kind, StmtKind::Semi(_))

clippy_lints/src/methods/unnecessary_min_or_max.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ use super::UNNECESSARY_MIN_OR_MAX;
44
use clippy_utils::diagnostics::span_lint_and_sugg;
55

66
use clippy_utils::consts::{constant, Constant, FullInt};
7+
use clippy_utils::macros::HirNode;
78
use clippy_utils::source::snippet;
8-
use hir::Expr;
9+
use hir::{Expr, ExprKind};
910

1011
use rustc_errors::Applicability;
1112
use rustc_hir as hir;
@@ -14,13 +15,17 @@ use rustc_lint::LateContext;
1415
use rustc_middle::ty;
1516
use rustc_span::Span;
1617

17-
pub fn check<'tcx>(
18+
pub(super) fn check<'tcx>(
1819
cx: &LateContext<'tcx>,
1920
expr: &'tcx Expr<'_>,
2021
name: &str,
2122
recv: &'tcx Expr<'_>,
2223
arg: &'tcx Expr<'_>,
24+
allowed_external_crates: bool,
2325
) {
26+
if !allowed_external_crates && (is_external_const(cx, recv) || is_external_const(cx, arg)) {
27+
return;
28+
}
2429
let typeck_results = cx.typeck_results();
2530
if let (Some(left), Some(right)) = (constant(cx, typeck_results, recv), constant(cx, typeck_results, arg)) {
2631
let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else {
@@ -86,3 +91,14 @@ fn detect_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
8691
_ => None,
8792
}
8893
}
94+
95+
fn is_external_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
96+
let ExprKind::Path(ref qpath) = expr.kind else {
97+
return false;
98+
};
99+
100+
let Some(def_id) = cx.qpath_res(qpath, expr.hir_id()).opt_def_id() else {
101+
return false;
102+
};
103+
!def_id.is_local()
104+
}

tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
1313
allow-unwrap-in-tests
1414
allowed-dotfiles
1515
allowed-duplicate-crates
16+
allowed-external-crates
1617
allowed-idents-below-min-chars
1718
allowed-scripts
1819
allowed-wildcard-imports
@@ -92,6 +93,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
9293
allow-unwrap-in-tests
9394
allowed-dotfiles
9495
allowed-duplicate-crates
96+
allowed-external-crates
9597
allowed-idents-below-min-chars
9698
allowed-scripts
9799
allowed-wildcard-imports
@@ -171,6 +173,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
171173
allow-unwrap-in-tests
172174
allowed-dotfiles
173175
allowed-duplicate-crates
176+
allowed-external-crates
174177
allowed-idents-below-min-chars
175178
allowed-scripts
176179
allowed-wildcard-imports
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
allowed-external-crates = true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#![allow(unused)]
2+
#![warn(clippy::unnecessary_min_or_max)]
3+
fn main() {
4+
// Both are Literals
5+
let _ = (-6_i32);
6+
let _ = 9;
7+
let _ = 6;
8+
let _ = 9_u32;
9+
let _ = 6;
10+
let _ = 7_u8;
11+
12+
let x: i32 = 42;
13+
// signed MIN
14+
let _ = i32::MIN;
15+
let _ = x;
16+
let _ = i32::MIN;
17+
let _ = x;
18+
19+
// signed MAX
20+
let _ = x;
21+
let _ = i32::MAX;
22+
let _ = x;
23+
let _ = i32::MAX;
24+
25+
let x: u32 = 42;
26+
// unsigned MAX
27+
let _ = x;
28+
let _ = u32::MAX;
29+
let _ = x;
30+
let _ = u32::MAX;
31+
32+
// unsigned MIN
33+
let _ = u32::MIN;
34+
let _ = x;
35+
let _ = u32::MIN;
36+
let _ = x;
37+
38+
// unsigned with zero
39+
let _ = 0;
40+
let _ = x;
41+
let _ = 0_u32;
42+
let _ = x;
43+
44+
let _ = std::f64::consts::E;
45+
46+
// The below cases shouldn't be lint
47+
let mut min = u32::MAX;
48+
for _ in 0..1000 {
49+
min = min.min(random_u32());
50+
}
51+
52+
const I32_MIN_ISIZE: isize = i32::MIN as isize;
53+
let x: isize = 42;
54+
let _ = I32_MIN_ISIZE.min(x);
55+
let _ = I32_MIN_ISIZE.max(x);
56+
let _ = x.min(I32_MIN_ISIZE);
57+
let _ = x.max(I32_MIN_ISIZE);
58+
}
59+
fn random_u32() -> u32 {
60+
// random number generator
61+
0
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#![allow(unused)]
2+
#![warn(clippy::unnecessary_min_or_max)]
3+
fn main() {
4+
// Both are Literals
5+
let _ = (-6_i32).min(9);
6+
let _ = (-6_i32).max(9);
7+
let _ = 9_u32.min(6);
8+
let _ = 9_u32.max(6);
9+
let _ = 6.min(7_u8);
10+
let _ = 6.max(7_u8);
11+
12+
let x: i32 = 42;
13+
// signed MIN
14+
let _ = i32::MIN.min(x);
15+
let _ = i32::MIN.max(x);
16+
let _ = x.min(i32::MIN);
17+
let _ = x.max(i32::MIN);
18+
19+
// signed MAX
20+
let _ = i32::MAX.min(x);
21+
let _ = i32::MAX.max(x);
22+
let _ = x.min(i32::MAX);
23+
let _ = x.max(i32::MAX);
24+
25+
let x: u32 = 42;
26+
// unsigned MAX
27+
let _ = u32::MAX.min(x);
28+
let _ = u32::MAX.max(x);
29+
let _ = x.min(u32::MAX);
30+
let _ = x.max(u32::MAX);
31+
32+
// unsigned MIN
33+
let _ = u32::MIN.min(x);
34+
let _ = u32::MIN.max(x);
35+
let _ = x.min(u32::MIN);
36+
let _ = x.max(u32::MIN);
37+
38+
// unsigned with zero
39+
let _ = 0.min(x);
40+
let _ = 0.max(x);
41+
let _ = x.min(0_u32);
42+
let _ = x.max(0_u32);
43+
44+
let _ = (6.0_f64).min(std::f64::consts::E);
45+
46+
// The below cases shouldn't be lint
47+
let mut min = u32::MAX;
48+
for _ in 0..1000 {
49+
min = min.min(random_u32());
50+
}
51+
52+
const I32_MIN_ISIZE: isize = i32::MIN as isize;
53+
let x: isize = 42;
54+
let _ = I32_MIN_ISIZE.min(x);
55+
let _ = I32_MIN_ISIZE.max(x);
56+
let _ = x.min(I32_MIN_ISIZE);
57+
let _ = x.max(I32_MIN_ISIZE);
58+
}
59+
fn random_u32() -> u32 {
60+
// random number generator
61+
0
62+
}

0 commit comments

Comments
 (0)