From ac6cf0128842f1ce50b9120227004dee866eb511 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Thu, 18 Apr 2024 23:49:00 -0400 Subject: [PATCH] Ignore stub functions in unused-async --- .../resources/test/fixtures/ruff/RUF029.py | 8 ++- .../src/rules/ruff/rules/unused_async.rs | 6 +++ ..._rules__ruff__tests__RUF029_RUF029.py.snap | 52 ++++++++----------- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF029.py b/crates/ruff_linter/resources/test/fixtures/ruff/RUF029.py index e2a6cf0af7b8f..f2c42b3d9cdb4 100644 --- a/crates/ruff_linter/resources/test/fixtures/ruff/RUF029.py +++ b/crates/ruff_linter/resources/test/fixtures/ruff/RUF029.py @@ -22,7 +22,7 @@ async def pass_3(): # OK: uses an async loop class Foo: - async def pass_4(): # OK: method of a class + async def pass_4(self): # OK: method of a class pass @@ -31,6 +31,10 @@ async def pass_5(): # OK: uses an await await bla +async def pass_6(): # OK: just a stub + ... + + async def fail_1a(): # RUF029 time.sleep(1) @@ -58,7 +62,7 @@ async def foo(): async def fail_4b(): # RUF029: the /outer/ function does not await class Foo: - async def foo(): + async def foo(self): await bla diff --git a/crates/ruff_linter/src/rules/ruff/rules/unused_async.rs b/crates/ruff_linter/src/rules/ruff/rules/unused_async.rs index 470b16cfa861a..e6180c945a906 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/unused_async.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/unused_async.rs @@ -3,6 +3,7 @@ use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::identifier::Identifier; use ruff_python_ast::visitor::preorder; use ruff_python_ast::{self as ast, AnyNodeRef, Expr, Stmt}; +use ruff_python_semantic::analyze::function_type::is_stub; use crate::checkers::ast::Checker; @@ -160,6 +161,11 @@ pub(crate) fn unused_async( return; } + // Ignore stubs (e.g., `...`). + if is_stub(function_def, checker.semantic()) { + return; + } + let found_await_or_async = { let mut visitor = AsyncExprVisitor::default(); preorder::walk_body(&mut visitor, body); diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF029_RUF029.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF029_RUF029.py.snap index fba1b92b00221..34cbd80ea666f 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF029_RUF029.py.snap +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF029_RUF029.py.snap @@ -1,56 +1,48 @@ --- source: crates/ruff_linter/src/rules/ruff/mod.rs --- -RUF029.py:34:11: RUF029 Function `fail_1a` is declared `async`, but doesn't `await` or use `async` features. +RUF029.py:38:11: RUF029 Function `fail_1a` is declared `async`, but doesn't `await` or use `async` features. | -34 | async def fail_1a(): # RUF029 +38 | async def fail_1a(): # RUF029 | ^^^^^^^ RUF029 -35 | time.sleep(1) +39 | time.sleep(1) | -RUF029.py:38:11: RUF029 Function `fail_1b` is declared `async`, but doesn't `await` or use `async` features. +RUF029.py:42:11: RUF029 Function `fail_1b` is declared `async`, but doesn't `await` or use `async` features. | -38 | async def fail_1b(): # RUF029: yield does not require async +42 | async def fail_1b(): # RUF029: yield does not require async | ^^^^^^^ RUF029 -39 | yield "hello" +43 | yield "hello" | -RUF029.py:42:11: RUF029 Function `fail_2` is declared `async`, but doesn't `await` or use `async` features. +RUF029.py:46:11: RUF029 Function `fail_2` is declared `async`, but doesn't `await` or use `async` features. | -42 | async def fail_2(): # RUF029 +46 | async def fail_2(): # RUF029 | ^^^^^^ RUF029 -43 | with None as i: -44 | pass +47 | with None as i: +48 | pass | -RUF029.py:47:11: RUF029 Function `fail_3` is declared `async`, but doesn't `await` or use `async` features. +RUF029.py:51:11: RUF029 Function `fail_3` is declared `async`, but doesn't `await` or use `async` features. | -47 | async def fail_3(): # RUF029 +51 | async def fail_3(): # RUF029 | ^^^^^^ RUF029 -48 | for i in []: -49 | pass +52 | for i in []: +53 | pass | -RUF029.py:54:11: RUF029 Function `fail_4a` is declared `async`, but doesn't `await` or use `async` features. +RUF029.py:58:11: RUF029 Function `fail_4a` is declared `async`, but doesn't `await` or use `async` features. | -54 | async def fail_4a(): # RUF029: the /outer/ function does not await +58 | async def fail_4a(): # RUF029: the /outer/ function does not await | ^^^^^^^ RUF029 -55 | async def foo(): -56 | await bla +59 | async def foo(): +60 | await bla | -RUF029.py:59:11: RUF029 Function `fail_4b` is declared `async`, but doesn't `await` or use `async` features. +RUF029.py:63:11: RUF029 Function `fail_4b` is declared `async`, but doesn't `await` or use `async` features. | -59 | async def fail_4b(): # RUF029: the /outer/ function does not await +63 | async def fail_4b(): # RUF029: the /outer/ function does not await | ^^^^^^^ RUF029 -60 | class Foo: -61 | async def foo(): - | - -RUF029.py:66:15: RUF029 Function `fail_4c` is declared `async`, but doesn't `await` or use `async` features. - | -65 | def foo(): -66 | async def fail_4c(): # RUF029: the /inner/ function does not await - | ^^^^^^^ RUF029 -67 | pass +64 | class Foo: +65 | async def foo(self): |