mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 07:04:22 +00:00
feat(ide-completion): extra sugar auto-completion async fn ...
in impl trait
for async fn in trait
that's defined in desugar form
This commit is contained in:
parent
8d1d5cdfc1
commit
18feb726be
2 changed files with 84 additions and 1 deletions
|
@ -2207,6 +2207,53 @@ impl Function {
|
|||
db.function_data(self.id).is_async()
|
||||
}
|
||||
|
||||
/// Whether this function is a `fn` that returns `impl Future`.
|
||||
pub fn is_desugar_async(self, db: &dyn HirDatabase) -> bool {
|
||||
if self.is_async(db) || self.is_const(db) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let Some(impl_traits) = self.ret_type(db).as_impl_traits(db) else { return false };
|
||||
|
||||
let Some(future_trait_id) =
|
||||
db.lang_item(self.ty(db).env.krate, LangItem::Future).and_then(|t| t.as_trait())
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(size_trait_id) =
|
||||
db.lang_item(self.ty(db).env.krate, LangItem::Sized).and_then(|t| t.as_trait())
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(sync_trait_id) =
|
||||
db.lang_item(self.ty(db).env.krate, LangItem::Sync).and_then(|t| t.as_trait())
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// TODO: There's no `LangItem::Send`. How do we get the id of `Send` trait?
|
||||
// let Some(send_trait_id) = db.lang_item(self.ty(db).env.krate, LangItem::Send).and_then(|t| t.as_trait()) else {
|
||||
// eprint!("no future_trait_id\n");
|
||||
// return false
|
||||
// };
|
||||
|
||||
let allowed_to_leaked_types = vec![size_trait_id, sync_trait_id];
|
||||
|
||||
let mut has_impl_future = false;
|
||||
let mut has_types_not_allow_to_leaked = false;
|
||||
for impl_trait in impl_traits {
|
||||
if impl_trait.id == future_trait_id {
|
||||
has_impl_future = true;
|
||||
} else if !allowed_to_leaked_types.contains(&impl_trait.id) {
|
||||
has_types_not_allow_to_leaked = true;
|
||||
}
|
||||
}
|
||||
|
||||
has_impl_future && !has_types_not_allow_to_leaked
|
||||
}
|
||||
|
||||
/// Does this function have `#[test]` attribute?
|
||||
pub fn is_test(self, db: &dyn HirDatabase) -> bool {
|
||||
db.function_data(self.id).attrs.is_test()
|
||||
|
|
|
@ -210,7 +210,7 @@ fn add_function_impl(
|
|||
ast::AssocItem::Fn(func) => func,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// TODO: need `function_decl` that unwraps future in the return type
|
||||
let function_decl = function_declaration(&transformed_fn, source.file_id.is_macro());
|
||||
match ctx.config.snippet_cap {
|
||||
Some(cap) => {
|
||||
|
@ -225,6 +225,42 @@ fn add_function_impl(
|
|||
item.add_to(acc, ctx.db);
|
||||
}
|
||||
}
|
||||
|
||||
eprint!("is_desugar_async: {}", func.is_desugar_async(ctx.db));
|
||||
if func.is_desugar_async(ctx.db) {
|
||||
let label = format_smolstr!(
|
||||
"async fn {}({})",
|
||||
fn_name.display(ctx.db),
|
||||
if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." }
|
||||
);
|
||||
let mut item = CompletionItem::new(completion_kind, replacement_range, label);
|
||||
item.lookup_by(format!("async fn {}", fn_name.display(ctx.db)))
|
||||
.set_documentation(func.docs(ctx.db))
|
||||
.set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() });
|
||||
if let Some(source) = ctx.sema.source(func) {
|
||||
let assoc_item = ast::AssocItem::Fn(source.value);
|
||||
if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
|
||||
let transformed_fn = match transformed_item {
|
||||
ast::AssocItem::Fn(func) => func,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let function_decl =
|
||||
function_declaration(&transformed_fn, source.file_id.is_macro());
|
||||
match ctx.config.snippet_cap {
|
||||
Some(cap) => {
|
||||
let snippet = format!("{function_decl} {{\n $0\n}}");
|
||||
item.snippet_edit(cap, TextEdit::replace(replacement_range, snippet));
|
||||
}
|
||||
None => {
|
||||
let header = format!("{function_decl} {{");
|
||||
item.text_edit(TextEdit::replace(replacement_range, header));
|
||||
}
|
||||
};
|
||||
item.add_to(acc, ctx.db);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.
|
||||
|
|
Loading…
Reference in a new issue