mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-27 15:11:30 +00:00
add large future lint
This commit is contained in:
parent
ba7fd68e87
commit
4fdae81c70
13 changed files with 292 additions and 1 deletions
|
@ -278,7 +278,7 @@ Released 2022-12-15
|
||||||
[#9490](https://github.com/rust-lang/rust-clippy/pull/9490)
|
[#9490](https://github.com/rust-lang/rust-clippy/pull/9490)
|
||||||
* [`almost_complete_letter_range`]: No longer lints in external macros
|
* [`almost_complete_letter_range`]: No longer lints in external macros
|
||||||
[#9467](https://github.com/rust-lang/rust-clippy/pull/9467)
|
[#9467](https://github.com/rust-lang/rust-clippy/pull/9467)
|
||||||
* [`drop_copy`]: No longer lints on idiomatic cases in match arms
|
* [`drop_copy`]: No longer lints on idiomatic cases in match arms
|
||||||
[#9491](https://github.com/rust-lang/rust-clippy/pull/9491)
|
[#9491](https://github.com/rust-lang/rust-clippy/pull/9491)
|
||||||
* [`question_mark`]: No longer lints in const context
|
* [`question_mark`]: No longer lints in const context
|
||||||
[#9487](https://github.com/rust-lang/rust-clippy/pull/9487)
|
[#9487](https://github.com/rust-lang/rust-clippy/pull/9487)
|
||||||
|
@ -4485,6 +4485,7 @@ Released 2018-09-13
|
||||||
[`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays
|
[`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays
|
||||||
[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
|
[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
|
||||||
[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
|
[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
|
||||||
|
[`large_futures`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_futures
|
||||||
[`large_include_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file
|
[`large_include_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file
|
||||||
[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
|
[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
|
||||||
[`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value
|
[`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value
|
||||||
|
|
|
@ -216,6 +216,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
||||||
crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO,
|
crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO,
|
||||||
crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO,
|
crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO,
|
||||||
crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO,
|
crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO,
|
||||||
|
crate::large_futures::LARGE_FUTURES_INFO,
|
||||||
crate::large_include_file::LARGE_INCLUDE_FILE_INFO,
|
crate::large_include_file::LARGE_INCLUDE_FILE_INFO,
|
||||||
crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO,
|
crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO,
|
||||||
crate::len_zero::COMPARISON_TO_EMPTY_INFO,
|
crate::len_zero::COMPARISON_TO_EMPTY_INFO,
|
||||||
|
|
90
clippy_lints/src/large_futures.rs
Normal file
90
clippy_lints/src/large_futures.rs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
use clippy_utils::source::snippet;
|
||||||
|
use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait};
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
|
||||||
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
|
use rustc_target::abi::Size;
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// It checks for the size of a `Future` created by `async fn` or `async {}`.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// Due to the current [unideal implemention](https://github.com/rust-lang/rust/issues/69826) of `Generator`,
|
||||||
|
/// large size of a `Future` may cause stack overflows.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```rust
|
||||||
|
/// async fn wait(f: impl std::future::Future<Output = ()>) {}
|
||||||
|
///
|
||||||
|
/// async fn big_fut(arg: [u8; 1024]) {}
|
||||||
|
///
|
||||||
|
/// pub async fn test() {
|
||||||
|
/// let fut = big_fut([0u8; 1024]);
|
||||||
|
/// wait(fut).await;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// `Box::pin` the big future instead.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// async fn wait(f: impl std::future::Future<Output = ()>) {}
|
||||||
|
///
|
||||||
|
/// async fn big_fut(arg: [u8; 1024]) {}
|
||||||
|
///
|
||||||
|
/// pub async fn test() {
|
||||||
|
/// let fut = Box::pin(big_fut([0u8; 1024]));
|
||||||
|
/// wait(fut).await;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.68.0"]
|
||||||
|
pub LARGE_FUTURES,
|
||||||
|
pedantic,
|
||||||
|
"large future may lead to unexpected stack overflows"
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct LargeFuture {
|
||||||
|
future_size_threshold: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LargeFuture {
|
||||||
|
pub fn new(future_size_threshold: u64) -> Self {
|
||||||
|
Self { future_size_threshold }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_lint_pass!(LargeFuture => [LARGE_FUTURES]);
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for LargeFuture {
|
||||||
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||||
|
if let ExprKind::Match(expr, _, MatchSource::AwaitDesugar) = expr.kind {
|
||||||
|
if let ExprKind::Call(func, [expr, ..]) = expr.kind {
|
||||||
|
if matches!(
|
||||||
|
func.kind,
|
||||||
|
ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..))
|
||||||
|
) {
|
||||||
|
let ty = cx.typeck_results().expr_ty(expr);
|
||||||
|
if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
|
||||||
|
&& implements_trait(cx, ty, future_trait_def_id, &[]) {
|
||||||
|
if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) {
|
||||||
|
let size = layout.layout.size();
|
||||||
|
if size >= Size::from_bytes(self.future_size_threshold) {
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
LARGE_FUTURES,
|
||||||
|
expr.span,
|
||||||
|
&format!("large future with a size of {} bytes", size.bytes()),
|
||||||
|
"consider `Box::pin` on it",
|
||||||
|
format!("Box::pin({})", snippet(cx, expr.span, "..")),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -161,6 +161,7 @@ mod items_after_statements;
|
||||||
mod iter_not_returning_iterator;
|
mod iter_not_returning_iterator;
|
||||||
mod large_const_arrays;
|
mod large_const_arrays;
|
||||||
mod large_enum_variant;
|
mod large_enum_variant;
|
||||||
|
mod large_futures;
|
||||||
mod large_include_file;
|
mod large_include_file;
|
||||||
mod large_stack_arrays;
|
mod large_stack_arrays;
|
||||||
mod len_zero;
|
mod len_zero;
|
||||||
|
@ -800,6 +801,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv())));
|
store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv())));
|
||||||
store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse));
|
store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse));
|
||||||
store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend));
|
store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend));
|
||||||
|
let future_size_threshold = conf.future_size_threshold;
|
||||||
|
store.register_late_pass(move |_| Box::new(large_futures::LargeFuture::new(future_size_threshold)));
|
||||||
store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex));
|
store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex));
|
||||||
store.register_late_pass(|_| Box::new(if_not_else::IfNotElse));
|
store.register_late_pass(|_| Box::new(if_not_else::IfNotElse));
|
||||||
store.register_late_pass(|_| Box::new(equatable_if_let::PatternEquality));
|
store.register_late_pass(|_| Box::new(equatable_if_let::PatternEquality));
|
||||||
|
|
|
@ -459,6 +459,10 @@ define_Conf! {
|
||||||
/// Whether to **only** check for missing documentation in items visible within the current
|
/// Whether to **only** check for missing documentation in items visible within the current
|
||||||
/// crate. For example, `pub(crate)` items.
|
/// crate. For example, `pub(crate)` items.
|
||||||
(missing_docs_in_crate_items: bool = false),
|
(missing_docs_in_crate_items: bool = false),
|
||||||
|
/// Lint: LARGE_FUTURES.
|
||||||
|
///
|
||||||
|
/// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint
|
||||||
|
(future_size_threshold: u64 = 16 * 1024),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Search for the configuration file.
|
/// Search for the configuration file.
|
||||||
|
|
1
tests/ui-toml/large_futures/clippy.toml
Normal file
1
tests/ui-toml/large_futures/clippy.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
future-size-threshold = 1024
|
29
tests/ui-toml/large_futures/large_futures.fixed
Normal file
29
tests/ui-toml/large_futures/large_futures.fixed
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![warn(clippy::large_futures)]
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
pub async fn should_warn() {
|
||||||
|
let x = [0u8; 1024];
|
||||||
|
async {}.await;
|
||||||
|
dbg!(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn should_not_warn() {
|
||||||
|
let x = [0u8; 1020];
|
||||||
|
async {}.await;
|
||||||
|
dbg!(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn bar() {
|
||||||
|
Box::pin(should_warn()).await;
|
||||||
|
|
||||||
|
async {
|
||||||
|
let x = [0u8; 1024];
|
||||||
|
dbg!(x);
|
||||||
|
}
|
||||||
|
.await;
|
||||||
|
|
||||||
|
should_not_warn().await;
|
||||||
|
}
|
29
tests/ui-toml/large_futures/large_futures.rs
Normal file
29
tests/ui-toml/large_futures/large_futures.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![warn(clippy::large_futures)]
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
pub async fn should_warn() {
|
||||||
|
let x = [0u8; 1024];
|
||||||
|
async {}.await;
|
||||||
|
dbg!(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn should_not_warn() {
|
||||||
|
let x = [0u8; 1020];
|
||||||
|
async {}.await;
|
||||||
|
dbg!(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn bar() {
|
||||||
|
should_warn().await;
|
||||||
|
|
||||||
|
async {
|
||||||
|
let x = [0u8; 1024];
|
||||||
|
dbg!(x);
|
||||||
|
}
|
||||||
|
.await;
|
||||||
|
|
||||||
|
should_not_warn().await;
|
||||||
|
}
|
10
tests/ui-toml/large_futures/large_futures.stderr
Normal file
10
tests/ui-toml/large_futures/large_futures.stderr
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
error: large future with a size of 1026 bytes
|
||||||
|
--> $DIR/large_futures.rs:20:5
|
||||||
|
|
|
||||||
|
LL | should_warn().await;
|
||||||
|
| ^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(should_warn())`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::large-futures` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -24,6 +24,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
|
||||||
enforced-import-renames
|
enforced-import-renames
|
||||||
enum-variant-name-threshold
|
enum-variant-name-threshold
|
||||||
enum-variant-size-threshold
|
enum-variant-size-threshold
|
||||||
|
future-size-threshold
|
||||||
ignore-interior-mutability
|
ignore-interior-mutability
|
||||||
large-error-threshold
|
large-error-threshold
|
||||||
literal-representation-threshold
|
literal-representation-threshold
|
||||||
|
|
41
tests/ui/large_futures.fixed
Normal file
41
tests/ui/large_futures.fixed
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![feature(generators)]
|
||||||
|
#![warn(clippy::large_futures)]
|
||||||
|
#![allow(clippy::future_not_send)]
|
||||||
|
#![allow(clippy::manual_async_fn)]
|
||||||
|
|
||||||
|
async fn big_fut(_arg: [u8; 1024 * 16]) {}
|
||||||
|
|
||||||
|
async fn wait() {
|
||||||
|
let f = async {
|
||||||
|
Box::pin(big_fut([0u8; 1024 * 16])).await;
|
||||||
|
};
|
||||||
|
Box::pin(f).await
|
||||||
|
}
|
||||||
|
async fn calls_fut(fut: impl std::future::Future<Output = ()>) {
|
||||||
|
loop {
|
||||||
|
Box::pin(wait()).await;
|
||||||
|
if true {
|
||||||
|
return fut.await;
|
||||||
|
} else {
|
||||||
|
Box::pin(wait()).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn test() {
|
||||||
|
let fut = big_fut([0u8; 1024 * 16]);
|
||||||
|
Box::pin(foo()).await;
|
||||||
|
Box::pin(calls_fut(fut)).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn foo() -> impl std::future::Future<Output = ()> {
|
||||||
|
async {
|
||||||
|
let x = [0i32; 1024 * 16];
|
||||||
|
async {}.await;
|
||||||
|
dbg!(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
41
tests/ui/large_futures.rs
Normal file
41
tests/ui/large_futures.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![feature(generators)]
|
||||||
|
#![warn(clippy::large_futures)]
|
||||||
|
#![allow(clippy::future_not_send)]
|
||||||
|
#![allow(clippy::manual_async_fn)]
|
||||||
|
|
||||||
|
async fn big_fut(_arg: [u8; 1024 * 16]) {}
|
||||||
|
|
||||||
|
async fn wait() {
|
||||||
|
let f = async {
|
||||||
|
big_fut([0u8; 1024 * 16]).await;
|
||||||
|
};
|
||||||
|
f.await
|
||||||
|
}
|
||||||
|
async fn calls_fut(fut: impl std::future::Future<Output = ()>) {
|
||||||
|
loop {
|
||||||
|
wait().await;
|
||||||
|
if true {
|
||||||
|
return fut.await;
|
||||||
|
} else {
|
||||||
|
wait().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn test() {
|
||||||
|
let fut = big_fut([0u8; 1024 * 16]);
|
||||||
|
foo().await;
|
||||||
|
calls_fut(fut).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn foo() -> impl std::future::Future<Output = ()> {
|
||||||
|
async {
|
||||||
|
let x = [0i32; 1024 * 16];
|
||||||
|
async {}.await;
|
||||||
|
dbg!(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
40
tests/ui/large_futures.stderr
Normal file
40
tests/ui/large_futures.stderr
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
error: large future with a size of 16385 bytes
|
||||||
|
--> $DIR/large_futures.rs:12:9
|
||||||
|
|
|
||||||
|
LL | big_fut([0u8; 1024 * 16]).await;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::large-futures` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: large future with a size of 16386 bytes
|
||||||
|
--> $DIR/large_futures.rs:14:5
|
||||||
|
|
|
||||||
|
LL | f.await
|
||||||
|
| ^ help: consider `Box::pin` on it: `Box::pin(f)`
|
||||||
|
|
||||||
|
error: large future with a size of 16387 bytes
|
||||||
|
--> $DIR/large_futures.rs:18:9
|
||||||
|
|
|
||||||
|
LL | wait().await;
|
||||||
|
| ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())`
|
||||||
|
|
||||||
|
error: large future with a size of 16387 bytes
|
||||||
|
--> $DIR/large_futures.rs:22:13
|
||||||
|
|
|
||||||
|
LL | wait().await;
|
||||||
|
| ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())`
|
||||||
|
|
||||||
|
error: large future with a size of 65540 bytes
|
||||||
|
--> $DIR/large_futures.rs:29:5
|
||||||
|
|
|
||||||
|
LL | foo().await;
|
||||||
|
| ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())`
|
||||||
|
|
||||||
|
error: large future with a size of 49159 bytes
|
||||||
|
--> $DIR/large_futures.rs:30:5
|
||||||
|
|
|
||||||
|
LL | calls_fut(fut).await;
|
||||||
|
| ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))`
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
Loading…
Reference in a new issue