|
| 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