|
| 1 | +use hir::AssocItem; |
1 | 2 | use ide_db::{ |
2 | 3 | assists::{AssistId, AssistKind}, |
3 | 4 | base_db::FileId, |
4 | 5 | defs::Definition, |
5 | 6 | search::FileReference, |
6 | 7 | syntax_helpers::node_ext::full_path_of_name_ref, |
| 8 | + traits::resolve_target_trait, |
7 | 9 | }; |
8 | 10 | use syntax::{ |
9 | | - ast::{self, NameLike, NameRef}, |
| 11 | + ast::{self, HasName, NameLike, NameRef}, |
10 | 12 | AstNode, SyntaxKind, TextRange, |
11 | 13 | }; |
12 | 14 |
|
@@ -44,7 +46,16 @@ pub(crate) fn unnecessary_async(acc: &mut Assists, ctx: &AssistContext<'_>) -> O |
44 | 46 | if function.body()?.syntax().descendants().find_map(ast::AwaitExpr::cast).is_some() { |
45 | 47 | return None; |
46 | 48 | } |
47 | | - |
| 49 | + // Do nothing if the method is an async member of trait. |
| 50 | + if let Some(fname) = function.name() { |
| 51 | + if let Some(trait_item) = find_corresponding_trait_member(ctx, fname.to_string()) { |
| 52 | + if let AssocItem::Function(method) = trait_item { |
| 53 | + if method.is_async(ctx.db()) { |
| 54 | + return None; |
| 55 | + } |
| 56 | + } |
| 57 | + } |
| 58 | + } |
48 | 59 | // Remove the `async` keyword plus whitespace after it, if any. |
49 | 60 | let async_range = { |
50 | 61 | let async_token = function.async_token()?; |
@@ -88,6 +99,23 @@ pub(crate) fn unnecessary_async(acc: &mut Assists, ctx: &AssistContext<'_>) -> O |
88 | 99 | ) |
89 | 100 | } |
90 | 101 |
|
| 102 | +fn find_corresponding_trait_member( |
| 103 | + ctx: &AssistContext<'_>, |
| 104 | + function_name: String, |
| 105 | +) -> Option<AssocItem> { |
| 106 | + let impl_ = ctx.find_node_at_offset::<ast::Impl>()?; |
| 107 | + let trait_ = resolve_target_trait(&ctx.sema, &impl_)?; |
| 108 | + |
| 109 | + trait_ |
| 110 | + .items(ctx.db()) |
| 111 | + .iter() |
| 112 | + .find(|item| match item.name(ctx.db()) { |
| 113 | + Some(method_name) => method_name.to_string() == function_name, |
| 114 | + _ => false, |
| 115 | + }) |
| 116 | + .cloned() |
| 117 | +} |
| 118 | + |
91 | 119 | fn find_all_references( |
92 | 120 | ctx: &AssistContext<'_>, |
93 | 121 | def: &Definition, |
@@ -254,4 +282,39 @@ pub async fn f(s: &S) { s.f2() }"#, |
254 | 282 | fn does_not_apply_when_not_on_prototype() { |
255 | 283 | check_assist_not_applicable(unnecessary_async, "pub async fn f() { $0f2() }") |
256 | 284 | } |
| 285 | + |
| 286 | + #[test] |
| 287 | + fn applies_on_unnecessary_async_on_trait_method() { |
| 288 | + check_assist( |
| 289 | + unnecessary_async, |
| 290 | + r#" |
| 291 | +trait Trait { |
| 292 | + fn foo(); |
| 293 | +} |
| 294 | +impl Trait for () { |
| 295 | + $0async fn foo() {} |
| 296 | +}"#, |
| 297 | + r#" |
| 298 | +trait Trait { |
| 299 | + fn foo(); |
| 300 | +} |
| 301 | +impl Trait for () { |
| 302 | + fn foo() {} |
| 303 | +}"#, |
| 304 | + ); |
| 305 | + } |
| 306 | + |
| 307 | + #[test] |
| 308 | + fn does_not_apply_on_async_trait_method() { |
| 309 | + check_assist_not_applicable( |
| 310 | + unnecessary_async, |
| 311 | + r#" |
| 312 | +trait Trait { |
| 313 | + async fn foo(); |
| 314 | +} |
| 315 | +impl Trait for () { |
| 316 | + $0async fn foo() {} |
| 317 | +}"#, |
| 318 | + ); |
| 319 | + } |
257 | 320 | } |
0 commit comments