From e3cda83f90a5e64ccf288438466e6c447df253a8 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Wed, 22 Jan 2020 22:25:41 -0600 Subject: Added basic support for completing `fn` for trait impl. --- crates/ra_ide/src/completion.rs | 3 + crates/ra_ide/src/completion/complete_impl_fn.rs | 80 ++++++++++++++++++++++++ crates/ra_ide/src/completion/presentation.rs | 33 ++++++++++ 3 files changed, 116 insertions(+) create mode 100644 crates/ra_ide/src/completion/complete_impl_fn.rs (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index abe1f36ce..f31f2593c 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs @@ -15,6 +15,7 @@ mod complete_path; mod complete_scope; mod complete_postfix; mod complete_macro_in_item_position; +mod complete_impl_fn; use ra_db::SourceDatabase; @@ -73,5 +74,7 @@ pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Opti complete_pattern::complete_pattern(&mut acc, &ctx); complete_postfix::complete_postfix(&mut acc, &ctx); complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); + complete_impl_fn::complete_impl_fn(&mut acc, &ctx); + Some(acc) } diff --git a/crates/ra_ide/src/completion/complete_impl_fn.rs b/crates/ra_ide/src/completion/complete_impl_fn.rs new file mode 100644 index 000000000..6d464cc1f --- /dev/null +++ b/crates/ra_ide/src/completion/complete_impl_fn.rs @@ -0,0 +1,80 @@ + +use crate::completion::{CompletionContext, Completions}; + +use hir::{ self, db::HirDatabase, HasSource }; + +use ra_syntax::{ ast, ast::AstNode }; + +pub(crate) fn complete_impl_fn(acc: &mut Completions, ctx: &CompletionContext) { + let impl_trait = ast::ItemList::cast(ctx.token.parent()) + .and_then(|item_list| item_list.syntax().parent()) + .and_then(|item_list_parent| ast::ImplBlock::cast(item_list_parent)) + .and_then(|impl_block| resolve_target_trait(ctx.db, &ctx.analyzer, &impl_block)); + + if let Some(x) = &impl_trait { + for trait_item in x.0.items(ctx.db) { + match trait_item { + hir::AssocItem::Function(f) => acc.add_function_impl(ctx, f), + _ => {} + } + } + } +} + +fn resolve_target_trait( + db: &impl HirDatabase, + analyzer: &hir::SourceAnalyzer, + impl_block: &ast::ImplBlock +) -> Option<(hir::Trait, ast::TraitDef)> { + let ast_path = impl_block + .target_trait() + .map(|it| it.syntax().clone()) + .and_then(ast::PathType::cast)? + .path()?; + + match analyzer.resolve_path(db, &ast_path) { + Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => { + Some((def, def.source(db).value)) + } + _ => None, + } +} + +#[cfg(test)] +mod tests { + use crate::completion::{do_completion, CompletionItem, CompletionKind}; + use insta::assert_debug_snapshot; + + fn complete(code: &str) -> Vec { + do_completion(code, CompletionKind::Reference) + } + + #[test] + fn single_function() { + let completions = complete( + r" + trait Test { + fn foo(); + } + + struct T1; + + impl Test for T1 { + <|> + } + ", + ); + assert_debug_snapshot!(completions, @r###" + [ + CompletionItem { + label: "fn foo()", + source_range: [138; 138), + delete: [138; 138), + insert: "fn foo() { $0 }", + kind: Function, + lookup: "foo", + }, + ] + "###); + } +} \ No newline at end of file diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 97475fc0b..d0a43261f 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -129,6 +129,39 @@ impl Completions { self.add_function_with_name(ctx, None, func) } + pub(crate) fn add_function_impl(&mut self, ctx: &CompletionContext, func: hir::Function) { + use crate::display::FunctionSignature; + + let display = FunctionSignature::from_hir(ctx.db, func.clone()); + + let func_name = func.name(ctx.db); + + let mut builder = CompletionItem::new( + CompletionKind::Reference, + ctx.source_range(), + format!("fn {}()", func_name.to_string())) + .set_documentation(func.docs(ctx.db)); + + let completion_kind = if func.has_self_param(ctx.db) { + CompletionItemKind::Method + } else { + CompletionItemKind::Function + }; + + let snippet = { + let mut s = format!("{}", display); + s.push_str(" { $0 }"); + s + }; + + builder = builder + .insert_text(snippet) + .kind(completion_kind) + .lookup_by(func_name.to_string()); + + self.add(builder.build()); + } + fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str { let mut votes = [0, 0, 0]; for (idx, s) in docs.match_indices(¯o_name) { -- cgit v1.2.3