Skip to content

Commit 2a688ad

Browse files
feat: add a config option to enable lint on external crate
1 parent 2164830 commit 2a688ad

12 files changed

+354
-172
lines changed

clippy_config/src/conf.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,10 @@ define_Conf! {
609609
/// - Use `".."` as part of the list to indicate that the configured values should be appended to the
610610
/// default configuration of Clippy. By default, any configuration will replace the default value
611611
(allowed_prefixes: Vec<String> = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()),
612+
/// Lint: UNNECESSARY_MIN_OR_MAX.
613+
///
614+
/// Whether to also run the lints on external defined consts.
615+
(allowed_external_crates: bool = false),
612616
}
613617

614618
/// Search for the configuration file.

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
595595
ref allowed_duplicate_crates,
596596
allow_comparison_to_zero,
597597
ref allowed_prefixes,
598+
allowed_external_crates,
598599

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

clippy_lints/src/methods/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4119,6 +4119,7 @@ pub struct Methods {
41194119
allow_expect_in_tests: bool,
41204120
allow_unwrap_in_tests: bool,
41214121
allowed_dotfiles: FxHashSet<String>,
4122+
allowed_external_crates: bool,
41224123
}
41234124

41244125
impl Methods {
@@ -4129,6 +4130,7 @@ impl Methods {
41294130
allow_expect_in_tests: bool,
41304131
allow_unwrap_in_tests: bool,
41314132
mut allowed_dotfiles: FxHashSet<String>,
4133+
allowed_external_crates: bool,
41324134
) -> Self {
41334135
allowed_dotfiles.extend(DEFAULT_ALLOWED_DOTFILES.iter().map(ToString::to_string));
41344136

@@ -4138,6 +4140,7 @@ impl Methods {
41384140
allow_expect_in_tests,
41394141
allow_unwrap_in_tests,
41404142
allowed_dotfiles,
4143+
allowed_external_crates,
41414144
}
41424145
}
41434146
}
@@ -4566,7 +4569,9 @@ impl Methods {
45664569
Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
45674570
_ => {},
45684571
},
4569-
("min" | "max", [arg]) => unnecessary_min_or_max::check(cx, expr, name, recv, arg),
4572+
("min" | "max", [arg]) => {
4573+
unnecessary_min_or_max::check(cx, expr, name, recv, arg, self.allowed_external_crates)
4574+
},
45704575
("drain", ..) => {
45714576
if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id)
45724577
&& matches!(kind, StmtKind::Semi(_))

clippy_lints/src/methods/unnecessary_min_or_max.rs

Lines changed: 18 additions & 2 deletions
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

Lines changed: 3 additions & 0 deletions
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-prefixes
1819
allowed-scripts
@@ -93,6 +94,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
9394
allow-unwrap-in-tests
9495
allowed-dotfiles
9596
allowed-duplicate-crates
97+
allowed-external-crates
9698
allowed-idents-below-min-chars
9799
allowed-prefixes
98100
allowed-scripts
@@ -173,6 +175,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
173175
allow-unwrap-in-tests
174176
allowed-dotfiles
175177
allowed-duplicate-crates
178+
allowed-external-crates
176179
allowed-idents-below-min-chars
177180
allowed-prefixes
178181
allowed-scripts
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
allowed-external-crates = true
Lines changed: 62 additions & 0 deletions
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+
}
Lines changed: 62 additions & 0 deletions
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)