Skip to content

Commit 0bf6239

Browse files
committed
reduce [unnecessary_blocking_ops]'s configuration to one
by re-using `DisallowedPath` from configuration mod
1 parent 184f30c commit 0bf6239

File tree

8 files changed

+87
-107
lines changed

8 files changed

+87
-107
lines changed

clippy_config/src/conf.rs

+1-11
Original file line numberDiff line numberDiff line change
@@ -552,17 +552,7 @@ define_Conf! {
552552
/// ```toml
553553
/// blocking-ops = ["my_crate::some_blocking_fn"]
554554
/// ```
555-
(blocking_ops: Vec<String> = <_>::default()),
556-
/// Lint: UNNECESSARY_BLOCKING_OPS.
557-
///
558-
/// List of additional blocking function paths to check, with replacement suggestion function paths.
559-
///
560-
/// #### Example
561-
///
562-
/// ```toml
563-
/// blocking-ops-with-suggestions = [["my_crate::some_blocking_fn" , "my_crate::use_this_instead"]]
564-
/// ```
565-
(blocking_ops_with_suggestions: Vec<[String; 2]> = <_>::default()),
555+
(blocking_ops: Vec<DisallowedPath> = <_>::default()),
566556
}
567557

568558
/// Search for the configuration file.

clippy_config/src/types.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ pub struct Rename {
1414
pub enum DisallowedPath {
1515
Simple(String),
1616
WithReason { path: String, reason: Option<String> },
17+
WithSuggestion(String, String),
1718
}
1819

1920
impl DisallowedPath {
2021
pub fn path(&self) -> &str {
21-
let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
22+
let (Self::Simple(path) | Self::WithReason { path, .. } | Self::WithSuggestion(path, _)) = self;
2223

2324
path
2425
}
@@ -31,6 +32,14 @@ impl DisallowedPath {
3132
_ => None,
3233
}
3334
}
35+
36+
pub fn suggestion(&self) -> Option<&str> {
37+
if let Self::WithSuggestion(_, sugg) = self {
38+
Some(sugg)
39+
} else {
40+
None
41+
}
42+
}
3443
}
3544

3645
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]

clippy_lints/src/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1066,11 +1066,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10661066
store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv())));
10671067
store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter));
10681068
let blocking_ops = conf.blocking_ops.clone();
1069-
let blocking_ops_with_suggs = conf.blocking_ops_with_suggestions.clone();
10701069
store.register_late_pass(move |_| {
10711070
Box::new(unnecessary_blocking_ops::UnnecessaryBlockingOps::new(
10721071
blocking_ops.clone(),
1073-
blocking_ops_with_suggs.clone(),
10741072
))
10751073
});
10761074
// add lints here, do not remove this comment, it's used in `new_lint`

clippy_lints/src/unnecessary_blocking_ops.rs

+63-81
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
use std::ops::ControlFlow;
2-
1+
use clippy_config::types::DisallowedPath;
32
use clippy_utils::diagnostics::span_lint_and_then;
43
use clippy_utils::source::snippet_with_applicability;
5-
use clippy_utils::visitors::for_each_expr_with_closures;
64
use clippy_utils::{def_path_def_ids, fn_def_id, is_lint_allowed};
75
use rustc_data_structures::fx::FxHashMap;
86
use rustc_errors::{Applicability, Diagnostic};
97
use rustc_hir::def_id::DefId;
10-
use rustc_hir::hir_id::CRATE_HIR_ID;
11-
use rustc_hir::{Body, Expr, ExprKind, GeneratorKind, HirIdSet};
8+
use rustc_hir::{Body, CoroutineKind, Expr, ExprKind};
129
use rustc_lint::{LateContext, LateLintPass};
1310
use rustc_session::{declare_tool_lint, impl_lint_pass};
1411
use rustc_span::Span;
@@ -48,113 +45,98 @@ declare_clippy_lint! {
4845
}
4946

5047
pub(crate) struct UnnecessaryBlockingOps {
51-
blocking_ops: Vec<String>,
52-
blocking_ops_with_suggs: Vec<[String; 2]>,
48+
blocking_ops: Vec<DisallowedPath>,
5349
/// Map of resolved funtion def_id with suggestion string after checking crate
5450
id_with_suggs: FxHashMap<DefId, Option<String>>,
55-
/// Keep track of visited block ids to skip checking the same bodies in `check_body` calls
56-
visited_block: HirIdSet,
51+
is_in_async: bool,
5752
}
5853

5954
impl UnnecessaryBlockingOps {
60-
pub(crate) fn new(blocking_ops: Vec<String>, blocking_ops_with_suggs: Vec<[String; 2]>) -> Self {
55+
pub(crate) fn new(blocking_ops: Vec<DisallowedPath>) -> Self {
6156
Self {
6257
blocking_ops,
63-
blocking_ops_with_suggs,
6458
id_with_suggs: FxHashMap::default(),
65-
visited_block: HirIdSet::default(),
59+
is_in_async: false,
6660
}
6761
}
6862
}
6963

7064
impl_lint_pass!(UnnecessaryBlockingOps => [UNNECESSARY_BLOCKING_OPS]);
7165

72-
static HARD_CODED_BLOCKING_OPS: [&[&str]; 21] = [
73-
&["std", "thread", "sleep"],
66+
static HARD_CODED_BLOCKING_OP_PATHS: &[&str] = &[
67+
"std::thread::sleep",
7468
// Filesystem functions
75-
&["std", "fs", "try_exists"],
76-
&["std", "fs", "canonicalize"],
77-
&["std", "fs", "copy"],
78-
&["std", "fs", "create_dir"],
79-
&["std", "fs", "create_dir_all"],
80-
&["std", "fs", "hard_link"],
81-
&["std", "fs", "metadata"],
82-
&["std", "fs", "read"],
83-
&["std", "fs", "read_dir"],
84-
&["std", "fs", "read_link"],
85-
&["std", "fs", "read_to_string"],
86-
&["std", "fs", "remove_dir"],
87-
&["std", "fs", "remove_dir_all"],
88-
&["std", "fs", "remove_file"],
89-
&["std", "fs", "rename"],
90-
&["std", "fs", "set_permissions"],
91-
&["std", "fs", "symlink_metadata"],
92-
&["std", "fs", "write"],
69+
"std::fs::try_exists",
70+
"std::fs::canonicalize",
71+
"std::fs::copy",
72+
"std::fs::create_dir",
73+
"std::fs::create_dir_all",
74+
"std::fs::hard_link",
75+
"std::fs::metadata",
76+
"std::fs::read",
77+
"std::fs::read_dir",
78+
"std::fs::read_link",
79+
"std::fs::read_to_string",
80+
"std::fs::remove_dir",
81+
"std::fs::remove_dir_all",
82+
"std::fs::remove_file",
83+
"std::fs::rename",
84+
"std::fs::set_permissions",
85+
"std::fs::symlink_metadata",
86+
"std::fs::write",
9387
// IO functions
94-
&["std", "io", "copy"],
95-
&["std", "io", "read_to_string"],
88+
"std::io::copy",
89+
"std::io::read_to_string",
9690
];
9791

9892
impl<'tcx> LateLintPass<'tcx> for UnnecessaryBlockingOps {
9993
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
100-
// Avoids processing and storing a long list of paths if this lint was allowed entirely
101-
if is_lint_allowed(cx, UNNECESSARY_BLOCKING_OPS, CRATE_HIR_ID) {
102-
return;
103-
}
104-
105-
let full_fn_list = HARD_CODED_BLOCKING_OPS
106-
.into_iter()
107-
.map(|p| (p.to_vec(), None))
108-
// Chain configured functions without suggestions
109-
.chain(
110-
self.blocking_ops
111-
.iter()
112-
.map(|p| (p.split("::").collect::<Vec<_>>(), None)),
113-
)
114-
// Chain configured functions with suggestions
115-
.chain(
116-
self.blocking_ops_with_suggs
117-
.iter()
118-
.map(|[p, s]| (p.split("::").collect::<Vec<_>>(), Some(s.as_str()))),
119-
);
120-
for (path, maybe_sugg_str) in full_fn_list {
94+
let full_fn_list = HARD_CODED_BLOCKING_OP_PATHS
95+
.iter()
96+
.map(|p| (*p, None))
97+
// Chain configured functions with possible suggestions
98+
.chain(self.blocking_ops.iter().map(|p| (p.path(), p.suggestion())));
99+
for (path_str, maybe_sugg_str) in full_fn_list {
100+
let path: Vec<&str> = path_str.split("::").collect();
121101
for did in def_path_def_ids(cx, &path) {
122102
self.id_with_suggs.insert(did, maybe_sugg_str.map(ToOwned::to_owned));
123103
}
124104
}
125105
}
126106

127107
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) {
128-
if is_lint_allowed(cx, UNNECESSARY_BLOCKING_OPS, body.value.hir_id)
129-
|| self.visited_block.contains(&body.value.hir_id)
130-
{
108+
if is_lint_allowed(cx, UNNECESSARY_BLOCKING_OPS, body.value.hir_id) {
131109
return;
132110
}
133-
if let Some(GeneratorKind::Async(_)) = body.generator_kind() {
134-
for_each_expr_with_closures(cx, body, |ex| {
135-
match ex.kind {
136-
ExprKind::Block(block, _) => {
137-
self.visited_block.insert(block.hir_id);
138-
}
139-
ExprKind::Call(call, _)
140-
if let Some(call_did) = fn_def_id(cx, ex) &&
141-
let Some(maybe_sugg) = self.id_with_suggs.get(&call_did) => {
142-
span_lint_and_then(
143-
cx,
144-
UNNECESSARY_BLOCKING_OPS,
145-
call.span,
146-
"blocking function call detected in an async body",
147-
|diag| {
148-
if let Some(sugg_fn_path) = maybe_sugg {
149-
make_suggestion(diag, cx, ex, call.span, sugg_fn_path);
150-
}
151-
}
152-
);
111+
112+
if let Some(CoroutineKind::Async(_)) = body.coroutine_kind() {
113+
self.is_in_async = true;
114+
}
115+
}
116+
117+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
118+
if self.is_in_async &&
119+
let ExprKind::Call(call, _) = &expr.kind &&
120+
let Some(call_did) = fn_def_id(cx, expr) &&
121+
let Some(maybe_sugg) = self.id_with_suggs.get(&call_did)
122+
{
123+
span_lint_and_then(
124+
cx,
125+
UNNECESSARY_BLOCKING_OPS,
126+
call.span,
127+
"blocking function call detected in an async body",
128+
|diag| {
129+
if let Some(sugg_fn_path) = maybe_sugg {
130+
make_suggestion(diag, cx, expr, call.span, sugg_fn_path);
153131
}
154-
_ => {}
155132
}
156-
ControlFlow::<()>::Continue(())
157-
});
133+
);
134+
}
135+
}
136+
137+
fn check_body_post(&mut self, _: &LateContext<'tcx>, body: &'tcx Body<'tcx>) {
138+
if !matches!(body.coroutine_kind(), Some(CoroutineKind::Async(_))) {
139+
self.is_in_async = false;
158140
}
159141
}
160142
}

tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
2020
avoid-breaking-exported-api
2121
await-holding-invalid-types
2222
blacklisted-names
23+
blocking-ops
2324
cargo-ignore-publish
2425
cognitive-complexity-threshold
2526
cyclomatic-complexity-threshold
@@ -94,6 +95,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
9495
avoid-breaking-exported-api
9596
await-holding-invalid-types
9697
blacklisted-names
98+
blocking-ops
9799
cargo-ignore-publish
98100
cognitive-complexity-threshold
99101
cyclomatic-complexity-threshold

tests/ui-toml/unnecessary_blocking_ops/clippy.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
blocking-ops = ["unnecessary_blocking_ops::blocking_mod::sleep"]
2-
blocking-ops-with-suggestions = [
1+
blocking-ops = [
2+
"unnecessary_blocking_ops::blocking_mod::sleep",
33
["std::fs::remove_dir", "tokio::fs::remove_dir"],
44
["std::fs::copy", "tokio::fs::copy"],
55
["std::io::copy", "tokio::io::copy"],

tests/ui/unnecessary_blocking_ops.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#![feature(async_fn_in_trait)]
21
#![feature(async_closure)]
32
#![allow(incomplete_features)]
43
#![warn(clippy::unnecessary_blocking_ops)]

tests/ui/unnecessary_blocking_ops.stderr

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: blocking function call detected in an async body
2-
--> $DIR/unnecessary_blocking_ops.rs:15:5
2+
--> $DIR/unnecessary_blocking_ops.rs:14:5
33
|
44
LL | sleep(Duration::from_secs(1));
55
| ^^^^^
@@ -8,49 +8,49 @@ LL | sleep(Duration::from_secs(1));
88
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_blocking_ops)]`
99

1010
error: blocking function call detected in an async body
11-
--> $DIR/unnecessary_blocking_ops.rs:17:5
11+
--> $DIR/unnecessary_blocking_ops.rs:16:5
1212
|
1313
LL | fs::remove_dir("").unwrap();
1414
| ^^^^^^^^^^^^^^
1515

1616
error: blocking function call detected in an async body
17-
--> $DIR/unnecessary_blocking_ops.rs:19:5
17+
--> $DIR/unnecessary_blocking_ops.rs:18:5
1818
|
1919
LL | fs::copy("", "_").unwrap();
2020
| ^^^^^^^^
2121

2222
error: blocking function call detected in an async body
23-
--> $DIR/unnecessary_blocking_ops.rs:21:13
23+
--> $DIR/unnecessary_blocking_ops.rs:20:13
2424
|
2525
LL | let _ = fs::canonicalize("");
2626
| ^^^^^^^^^^^^^^^^
2727

2828
error: blocking function call detected in an async body
29-
--> $DIR/unnecessary_blocking_ops.rs:25:9
29+
--> $DIR/unnecessary_blocking_ops.rs:24:9
3030
|
3131
LL | fs::write("", "").unwrap();
3232
| ^^^^^^^^^
3333

3434
error: blocking function call detected in an async body
35-
--> $DIR/unnecessary_blocking_ops.rs:32:5
35+
--> $DIR/unnecessary_blocking_ops.rs:31:5
3636
|
3737
LL | io::copy(&mut r, &mut w).unwrap();
3838
| ^^^^^^^^
3939

4040
error: blocking function call detected in an async body
41-
--> $DIR/unnecessary_blocking_ops.rs:51:9
41+
--> $DIR/unnecessary_blocking_ops.rs:50:9
4242
|
4343
LL | sleep(Duration::from_secs(self.0 as _));
4444
| ^^^^^
4545

4646
error: blocking function call detected in an async body
47-
--> $DIR/unnecessary_blocking_ops.rs:59:22
47+
--> $DIR/unnecessary_blocking_ops.rs:58:22
4848
|
4949
LL | let _ = async || sleep(Duration::from_secs(1));
5050
| ^^^^^
5151

5252
error: blocking function call detected in an async body
53-
--> $DIR/unnecessary_blocking_ops.rs:64:9
53+
--> $DIR/unnecessary_blocking_ops.rs:63:9
5454
|
5555
LL | sleep(Duration::from_secs(1));
5656
| ^^^^^

0 commit comments

Comments
 (0)