diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 3f21f7f0644d..bca23db12951 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -1,5 +1,7 @@ use crate::msrvs::Msrv; -use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename}; +use crate::types::{ + DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename, SuggestedPath, +}; use crate::ClippyConfiguration; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -39,6 +41,31 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ ]; const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"]; +const DEFAULT_BLOCKING_OP_PATHS: &[&str] = &[ + "std::thread::sleep", + // Filesystem functions + "std::fs::try_exists", + "std::fs::canonicalize", + "std::fs::copy", + "std::fs::create_dir", + "std::fs::create_dir_all", + "std::fs::hard_link", + "std::fs::metadata", + "std::fs::read", + "std::fs::read_dir", + "std::fs::read_link", + "std::fs::read_to_string", + "std::fs::remove_dir", + "std::fs::remove_dir_all", + "std::fs::remove_file", + "std::fs::rename", + "std::fs::set_permissions", + "std::fs::symlink_metadata", + "std::fs::write", + // IO functions + "std::io::copy", + "std::io::read_to_string", +]; /// Conf with parse errors #[derive(Default)] @@ -591,24 +618,22 @@ define_Conf! { (allowed_wildcard_imports: FxHashSet = FxHashSet::default()), /// Lint: UNNECESSARY_BLOCKING_OPS. /// - /// List of additional blocking function paths to check. + /// List of additional blocking function paths to check, with optional suggestions for each path. /// /// #### Example /// /// ```toml - /// blocking-ops = ["my_crate::some_blocking_fn"] + /// blocking-ops = [ "my_crate::blocking_foo" ] /// ``` - (blocking_ops: Vec = <_>::default()), - /// Lint: UNNECESSARY_BLOCKING_OPS. /// - /// List of additional blocking function paths to check, with replacement suggestion function paths. - /// - /// #### Example + /// Or, if you are sure that some functions can be replaced by a suggested one: /// /// ```toml - /// blocking-ops-with-suggestions = [["my_crate::some_blocking_fn" , "my_crate::use_this_instead"]] + /// blocking-ops = [ + /// { path = "my_crate::blocking_foo", suggestion = "my_crate::async::async_foo" } + /// ] /// ``` - (blocking_ops_with_suggestions: Vec<[String; 2]> = <_>::default()), + (blocking_ops: Vec = DEFAULT_BLOCKING_OP_PATHS.iter().map(SuggestedPath::from_path_str).collect()), } /// Search for the configuration file. diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs index 435aa9244c52..356523d80298 100644 --- a/clippy_config/src/types.rs +++ b/clippy_config/src/types.rs @@ -32,6 +32,33 @@ impl DisallowedPath { } } +#[derive(Clone, Debug, Deserialize, PartialEq, Eq)] +#[serde(untagged)] +pub enum SuggestedPath { + Simple(String), + WithSuggestion { path: String, suggestion: Option }, +} + +impl SuggestedPath { + pub fn path(&self) -> &str { + let (Self::Simple(path) | Self::WithSuggestion { path, .. }) = self; + + path + } + + pub fn from_path_str(path: &S) -> Self { + Self::Simple(path.to_string()) + } + + pub fn suggestion(&self) -> Option<&str> { + if let Self::WithSuggestion { suggestion, .. } = self { + suggestion.as_deref() + } else { + None + } + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] pub enum MatchLintBehaviour { AllTypes, @@ -125,6 +152,7 @@ unimplemented_serialize! { DisallowedPath, Rename, MacroMatcher, + SuggestedPath, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5b0049474c37..2996878ffa47 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -547,7 +547,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { avoid_breaking_exported_api, ref await_holding_invalid_types, ref blocking_ops, - ref blocking_ops_with_suggestions, cargo_ignore_publish, cognitive_complexity_threshold, ref disallowed_macros, @@ -1137,7 +1136,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| { Box::new(unnecessary_blocking_ops::UnnecessaryBlockingOps::new( blocking_ops.clone(), - blocking_ops_with_suggestions.clone(), )) }); // add lints here, do not remove this comment, it's used in `new_lint` diff --git a/clippy_lints/src/unnecessary_blocking_ops.rs b/clippy_lints/src/unnecessary_blocking_ops.rs index b155e7f3ccba..40e9ecedee1f 100644 --- a/clippy_lints/src/unnecessary_blocking_ops.rs +++ b/clippy_lints/src/unnecessary_blocking_ops.rs @@ -1,16 +1,17 @@ -use std::ops::ControlFlow; - +use clippy_config::types::SuggestedPath; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::visitors::for_each_expr_with_closures; use clippy_utils::{def_path_def_ids, fn_def_id, is_lint_allowed}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, Diag}; use rustc_hir::def_id::DefId; -use rustc_hir::hir_id::CRATE_HIR_ID; -use rustc_hir::{Body, Expr, ExprKind, GeneratorKind, HirIdSet}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_hir::{ + Body, BodyId, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, Expr, ExprKind, ImplItem, ImplItemKind, + Item, ItemKind, Node, TraitItem, TraitItemKind, +}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::impl_lint_pass; use rustc_span::Span; declare_clippy_lint! { @@ -43,81 +44,35 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.74.0"] pub UNNECESSARY_BLOCKING_OPS, - nursery, + pedantic, "blocking operations in an async context" } pub(crate) struct UnnecessaryBlockingOps { - blocking_ops: Vec, - blocking_ops_with_suggs: Vec<[String; 2]>, - /// Map of resolved funtion def_id with suggestion string after checking crate + blocking_ops: Vec, + /// Map of resolved funtion `def_id` with suggestion string after checking crate id_with_suggs: FxHashMap>, - /// Keep track of visited block ids to skip checking the same bodies in `check_body` calls - visited_block: HirIdSet, + /// Tracking whether a body is async after entering it. + body_asyncness: Vec, } impl UnnecessaryBlockingOps { - pub(crate) fn new(blocking_ops: Vec, blocking_ops_with_suggs: Vec<[String; 2]>) -> Self { + pub(crate) fn new(blocking_ops: Vec) -> Self { Self { blocking_ops, - blocking_ops_with_suggs, id_with_suggs: FxHashMap::default(), - visited_block: HirIdSet::default(), + body_asyncness: vec![], } } } impl_lint_pass!(UnnecessaryBlockingOps => [UNNECESSARY_BLOCKING_OPS]); -static HARD_CODED_BLOCKING_OPS: [&[&str]; 21] = [ - &["std", "thread", "sleep"], - // Filesystem functions - &["std", "fs", "try_exists"], - &["std", "fs", "canonicalize"], - &["std", "fs", "copy"], - &["std", "fs", "create_dir"], - &["std", "fs", "create_dir_all"], - &["std", "fs", "hard_link"], - &["std", "fs", "metadata"], - &["std", "fs", "read"], - &["std", "fs", "read_dir"], - &["std", "fs", "read_link"], - &["std", "fs", "read_to_string"], - &["std", "fs", "remove_dir"], - &["std", "fs", "remove_dir_all"], - &["std", "fs", "remove_file"], - &["std", "fs", "rename"], - &["std", "fs", "set_permissions"], - &["std", "fs", "symlink_metadata"], - &["std", "fs", "write"], - // IO functions - &["std", "io", "copy"], - &["std", "io", "read_to_string"], -]; - impl<'tcx> LateLintPass<'tcx> for UnnecessaryBlockingOps { fn check_crate(&mut self, cx: &LateContext<'tcx>) { - // Avoids processing and storing a long list of paths if this lint was allowed entirely - if is_lint_allowed(cx, UNNECESSARY_BLOCKING_OPS, CRATE_HIR_ID) { - return; - } - - let full_fn_list = HARD_CODED_BLOCKING_OPS - .into_iter() - .map(|p| (p.to_vec(), None)) - // Chain configured functions without suggestions - .chain( - self.blocking_ops - .iter() - .map(|p| (p.split("::").collect::>(), None)), - ) - // Chain configured functions with suggestions - .chain( - self.blocking_ops_with_suggs - .iter() - .map(|[p, s]| (p.split("::").collect::>(), Some(s.as_str()))), - ); - for (path, maybe_sugg_str) in full_fn_list { + let full_fn_list = self.blocking_ops.iter().map(|p| (p.path(), p.suggestion())); + for (path_str, maybe_sugg_str) in full_fn_list { + let path: Vec<&str> = path_str.split("::").collect(); for did in def_path_def_ids(cx, &path) { self.id_with_suggs.insert(did, maybe_sugg_str.map(ToOwned::to_owned)); } @@ -125,49 +80,82 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryBlockingOps { } fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) { - if is_lint_allowed(cx, UNNECESSARY_BLOCKING_OPS, body.value.hir_id) - || self.visited_block.contains(&body.value.hir_id) - { + if is_lint_allowed(cx, UNNECESSARY_BLOCKING_OPS, body.value.hir_id) { return; } - if let Some(GeneratorKind::Async(_)) = body.generator_kind() { - for_each_expr_with_closures(cx, body, |ex| { - match ex.kind { - ExprKind::Block(block, _) => { - self.visited_block.insert(block.hir_id); - } - ExprKind::Call(call, _) - if let Some(call_did) = fn_def_id(cx, ex) && - let Some(maybe_sugg) = self.id_with_suggs.get(&call_did) => { - span_lint_and_then( - cx, - UNNECESSARY_BLOCKING_OPS, - call.span, - "blocking function call detected in an async body", - |diag| { - if let Some(sugg_fn_path) = maybe_sugg { - make_suggestion(diag, cx, ex, call.span, sugg_fn_path); - } - } - ); + self.body_asyncness.push(in_async_body(cx, body.id())); + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if !in_external_macro(cx.sess(), expr.span) + && matches!(self.body_asyncness.last(), Some(true)) + && let ExprKind::Call(call, _) = &expr.kind + && let Some(call_did) = fn_def_id(cx, expr) + && let Some(maybe_sugg) = self.id_with_suggs.get(&call_did) + { + span_lint_and_then( + cx, + UNNECESSARY_BLOCKING_OPS, + call.span, + "blocking function call detected in an async body", + |diag| { + if let Some(sugg_fn_path) = maybe_sugg { + make_suggestion(diag, cx, expr, call.span, sugg_fn_path); } - _ => {} - } - ControlFlow::<()>::Continue(()) - }); + }, + ); } } + + fn check_body_post(&mut self, _: &LateContext<'tcx>, _: &'tcx Body<'tcx>) { + self.body_asyncness.pop(); + } } -fn make_suggestion(diag: &mut Diagnostic, cx: &LateContext<'_>, expr: &Expr<'_>, fn_span: Span, sugg_fn_path: &str) { - let mut applicability = Applicability::Unspecified; +fn make_suggestion(diag: &mut Diag<'_, ()>, cx: &LateContext<'_>, expr: &Expr<'_>, fn_span: Span, sugg_fn_path: &str) { + // Suggestion should only be offered when user specified it in the configuration file, + // so we only assume it can be fixed here if only the path could be found. + let mut applicability = if def_path_def_ids(cx, &sugg_fn_path.split("::").collect::>()) + .next() + .is_some() + { + Applicability::MaybeIncorrect + } else { + Applicability::Unspecified + }; + let args_span = expr.span.with_lo(fn_span.hi()); let args_snippet = snippet_with_applicability(cx, args_span, "..", &mut applicability); let suggestion = format!("{sugg_fn_path}{args_snippet}.await"); - diag.span_suggestion( - expr.span, - "try using its async counterpart", - suggestion, - Applicability::Unspecified, - ); + diag.span_suggestion(expr.span, "try using its async counterpart", suggestion, applicability); +} + +/// Check whether a body is from an async function/closure. +fn in_async_body(cx: &LateContext<'_>, body_id: BodyId) -> bool { + let parent_node = cx.tcx.parent_hir_node(body_id.hir_id); + match parent_node { + Node::Expr(expr) => matches!( + expr.kind, + ExprKind::Closure(Closure { + kind: ClosureKind::Coroutine(CoroutineKind::Desugared( + CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, + _ + )), + .. + }) + ), + Node::Item(Item { + kind: ItemKind::Fn(fn_sig, ..), + .. + }) + | Node::ImplItem(ImplItem { + kind: ImplItemKind::Fn(fn_sig, _), + .. + }) + | Node::TraitItem(TraitItem { + kind: TraitItemKind::Fn(fn_sig, _), + .. + }) => fn_sig.header.is_async(), + _ => false, + } } diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 737c062ea562..75d3e97241ff 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -23,6 +23,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect avoid-breaking-exported-api await-holding-invalid-types blacklisted-names + blocking-ops cargo-ignore-publish check-private-items cognitive-complexity-threshold @@ -102,6 +103,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect avoid-breaking-exported-api await-holding-invalid-types blacklisted-names + blocking-ops cargo-ignore-publish check-private-items cognitive-complexity-threshold @@ -181,6 +183,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni avoid-breaking-exported-api await-holding-invalid-types blacklisted-names + blocking-ops cargo-ignore-publish check-private-items cognitive-complexity-threshold diff --git a/tests/ui-toml/unnecessary_blocking_ops/clippy.toml b/tests/ui-toml/unnecessary_blocking_ops/clippy.toml index 0ce53ba99ee9..b191daaac49f 100644 --- a/tests/ui-toml/unnecessary_blocking_ops/clippy.toml +++ b/tests/ui-toml/unnecessary_blocking_ops/clippy.toml @@ -1,8 +1,6 @@ -blocking-ops = ["unnecessary_blocking_ops::blocking_mod::sleep"] -blocking-ops-with-suggestions = [ - ["std::fs::remove_dir", "tokio::fs::remove_dir"], - ["std::fs::copy", "tokio::fs::copy"], - ["std::io::copy", "tokio::io::copy"], - ["std::io::read_to_string", "unnecessary_blocking_ops::async_mod::read_to_string"], - ["std::thread::sleep", "unnecessary_blocking_ops::async_mod::sleep"], +blocking-ops = [ + { path = "unnecessary_blocking_ops::blocking_mod::sleep", suggestion = "crate::async_mod::sleep" }, + { path = "std::io::copy", suggestion = "tokio::io::copy" }, + { path = "std::io::read_to_string", suggestion = "crate::async_mod::read_to_string" }, + { path = "std::thread::sleep", suggestion = "crate::async_mod::sleep" }, ] diff --git a/tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.fixed b/tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.fixed new file mode 100644 index 000000000000..cd2fcbf40725 --- /dev/null +++ b/tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.fixed @@ -0,0 +1,31 @@ +#![warn(clippy::unnecessary_blocking_ops)] +use std::thread::sleep; +use std::time::Duration; +use std::{fs, io}; + +mod async_mod { + pub async fn sleep(_dur: std::time::Duration) {} + pub async fn read_to_string(mut reader: std::io::Stdin) -> Result { + Ok(String::new()) + } +} + +mod blocking_mod { + pub async fn sleep(_dur: std::time::Duration) {} +} + +pub async fn async_fn() { + crate::async_mod::sleep(Duration::from_secs(1)).await; + //~^ ERROR: blocking function call detected in an async body + crate::async_mod::sleep(Duration::from_secs(1)).await; + //~^ ERROR: blocking function call detected in an async body + let mut r: &[u8] = b"hello"; + let mut w: Vec = vec![]; + tokio::io::copy(&mut r, &mut w).await.unwrap(); + //~^ ERROR: blocking function call detected in an async body + let _cont = crate::async_mod::read_to_string(io::stdin()).await.unwrap(); + //~^ ERROR: blocking function call detected in an async body + fs::create_dir("").unwrap(); // Don't lint, config overrided +} + +fn main() {} diff --git a/tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.rs b/tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.rs index 4fce92aa70ef..bd57f5dbbe2a 100644 --- a/tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.rs +++ b/tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.rs @@ -1,4 +1,3 @@ -//@no-rustfix #![warn(clippy::unnecessary_blocking_ops)] use std::thread::sleep; use std::time::Duration; @@ -18,9 +17,7 @@ mod blocking_mod { pub async fn async_fn() { sleep(Duration::from_secs(1)); //~^ ERROR: blocking function call detected in an async body - fs::remove_dir("").unwrap(); - //~^ ERROR: blocking function call detected in an async body - fs::copy("", "_").unwrap(); + blocking_mod::sleep(Duration::from_secs(1)); //~^ ERROR: blocking function call detected in an async body let mut r: &[u8] = b"hello"; let mut w: Vec = vec![]; @@ -28,8 +25,7 @@ pub async fn async_fn() { //~^ ERROR: blocking function call detected in an async body let _cont = io::read_to_string(io::stdin()).unwrap(); //~^ ERROR: blocking function call detected in an async body - fs::create_dir("").unwrap(); - //~^ ERROR: blocking function call detected in an async body + fs::create_dir("").unwrap(); // Don't lint, config overrided } fn main() {} diff --git a/tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.stderr b/tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.stderr index de2414295939..faa1701d9dcc 100644 --- a/tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.stderr +++ b/tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.stderr @@ -1,32 +1,24 @@ error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:19:5 + --> tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.rs:18:5 | LL | sleep(Duration::from_secs(1)); | ^^^^^------------------------ | | - | help: try using its async counterpart: `unnecessary_blocking_ops::async_mod::sleep(Duration::from_secs(1)).await` + | help: try using its async counterpart: `crate::async_mod::sleep(Duration::from_secs(1)).await` | = note: `-D clippy::unnecessary-blocking-ops` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::unnecessary_blocking_ops)]` error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:21:5 + --> tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.rs:20:5 | -LL | fs::remove_dir("").unwrap(); - | ^^^^^^^^^^^^^^---- +LL | blocking_mod::sleep(Duration::from_secs(1)); + | ^^^^^^^^^^^^^^^^^^^------------------------ | | - | help: try using its async counterpart: `tokio::fs::remove_dir("").await` + | help: try using its async counterpart: `crate::async_mod::sleep(Duration::from_secs(1)).await` error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:23:5 - | -LL | fs::copy("", "_").unwrap(); - | ^^^^^^^^--------- - | | - | help: try using its async counterpart: `tokio::fs::copy("", "_").await` - -error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:27:5 + --> tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.rs:24:5 | LL | io::copy(&mut r, &mut w).unwrap(); | ^^^^^^^^---------------- @@ -34,18 +26,12 @@ LL | io::copy(&mut r, &mut w).unwrap(); | help: try using its async counterpart: `tokio::io::copy(&mut r, &mut w).await` error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:29:17 + --> tests/ui-toml/unnecessary_blocking_ops/unnecessary_blocking_ops.rs:26:17 | LL | let _cont = io::read_to_string(io::stdin()).unwrap(); | ^^^^^^^^^^^^^^^^^^------------- | | - | help: try using its async counterpart: `unnecessary_blocking_ops::async_mod::read_to_string(io::stdin()).await` - -error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:31:5 - | -LL | fs::create_dir("").unwrap(); - | ^^^^^^^^^^^^^^ + | help: try using its async counterpart: `crate::async_mod::read_to_string(io::stdin()).await` -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/unnecessary_blocking_ops.rs b/tests/ui/unnecessary_blocking_ops.rs index 0b941d06e1fc..f80d977e7c5e 100644 --- a/tests/ui/unnecessary_blocking_ops.rs +++ b/tests/ui/unnecessary_blocking_ops.rs @@ -1,4 +1,3 @@ -#![feature(async_fn_in_trait)] #![feature(async_closure)] #![allow(incomplete_features)] #![warn(clippy::unnecessary_blocking_ops)] @@ -70,4 +69,11 @@ fn closures() { }; } +fn thread_spawn() { + std::thread::spawn(|| sleep(Duration::from_secs(1))); + std::thread::spawn(async || {}); + std::thread::spawn(async || sleep(Duration::from_secs(1))); + //~^ ERROR: blocking function call detected in an async body +} + fn main() {} diff --git a/tests/ui/unnecessary_blocking_ops.stderr b/tests/ui/unnecessary_blocking_ops.stderr index 2f2118a622ac..e0a5cea992ae 100644 --- a/tests/ui/unnecessary_blocking_ops.stderr +++ b/tests/ui/unnecessary_blocking_ops.stderr @@ -1,5 +1,5 @@ error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:15:5 + --> tests/ui/unnecessary_blocking_ops.rs:14:5 | LL | sleep(Duration::from_secs(1)); | ^^^^^ @@ -8,52 +8,58 @@ LL | sleep(Duration::from_secs(1)); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_blocking_ops)]` error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:17:5 + --> tests/ui/unnecessary_blocking_ops.rs:16:5 | LL | fs::remove_dir("").unwrap(); | ^^^^^^^^^^^^^^ error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:19:5 + --> tests/ui/unnecessary_blocking_ops.rs:18:5 | LL | fs::copy("", "_").unwrap(); | ^^^^^^^^ error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:21:13 + --> tests/ui/unnecessary_blocking_ops.rs:20:13 | LL | let _ = fs::canonicalize(""); | ^^^^^^^^^^^^^^^^ error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:25:9 + --> tests/ui/unnecessary_blocking_ops.rs:24:9 | LL | fs::write("", "").unwrap(); | ^^^^^^^^^ error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:32:5 + --> tests/ui/unnecessary_blocking_ops.rs:31:5 | LL | io::copy(&mut r, &mut w).unwrap(); | ^^^^^^^^ error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:51:9 + --> tests/ui/unnecessary_blocking_ops.rs:50:9 | LL | sleep(Duration::from_secs(self.0 as _)); | ^^^^^ error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:59:22 + --> tests/ui/unnecessary_blocking_ops.rs:58:22 | LL | let _ = async || sleep(Duration::from_secs(1)); | ^^^^^ error: blocking function call detected in an async body - --> $DIR/unnecessary_blocking_ops.rs:64:9 + --> tests/ui/unnecessary_blocking_ops.rs:63:9 | LL | sleep(Duration::from_secs(1)); | ^^^^^ -error: aborting due to 9 previous errors +error: blocking function call detected in an async body + --> tests/ui/unnecessary_blocking_ops.rs:75:33 + | +LL | std::thread::spawn(async || sleep(Duration::from_secs(1))); + | ^^^^^ + +error: aborting due to 10 previous errors