diff options
-rw-r--r-- | crates/ra_ide/src/completion.rs | 3 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_impl_fn.rs | 80 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 33 |
3 files changed, 116 insertions, 0 deletions
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; | |||
15 | mod complete_scope; | 15 | mod complete_scope; |
16 | mod complete_postfix; | 16 | mod complete_postfix; |
17 | mod complete_macro_in_item_position; | 17 | mod complete_macro_in_item_position; |
18 | mod complete_impl_fn; | ||
18 | 19 | ||
19 | use ra_db::SourceDatabase; | 20 | use ra_db::SourceDatabase; |
20 | 21 | ||
@@ -73,5 +74,7 @@ pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Opti | |||
73 | complete_pattern::complete_pattern(&mut acc, &ctx); | 74 | complete_pattern::complete_pattern(&mut acc, &ctx); |
74 | complete_postfix::complete_postfix(&mut acc, &ctx); | 75 | complete_postfix::complete_postfix(&mut acc, &ctx); |
75 | complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); | 76 | complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); |
77 | complete_impl_fn::complete_impl_fn(&mut acc, &ctx); | ||
78 | |||
76 | Some(acc) | 79 | Some(acc) |
77 | } | 80 | } |
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 @@ | |||
1 | |||
2 | use crate::completion::{CompletionContext, Completions}; | ||
3 | |||
4 | use hir::{ self, db::HirDatabase, HasSource }; | ||
5 | |||
6 | use ra_syntax::{ ast, ast::AstNode }; | ||
7 | |||
8 | pub(crate) fn complete_impl_fn(acc: &mut Completions, ctx: &CompletionContext) { | ||
9 | let impl_trait = ast::ItemList::cast(ctx.token.parent()) | ||
10 | .and_then(|item_list| item_list.syntax().parent()) | ||
11 | .and_then(|item_list_parent| ast::ImplBlock::cast(item_list_parent)) | ||
12 | .and_then(|impl_block| resolve_target_trait(ctx.db, &ctx.analyzer, &impl_block)); | ||
13 | |||
14 | if let Some(x) = &impl_trait { | ||
15 | for trait_item in x.0.items(ctx.db) { | ||
16 | match trait_item { | ||
17 | hir::AssocItem::Function(f) => acc.add_function_impl(ctx, f), | ||
18 | _ => {} | ||
19 | } | ||
20 | } | ||
21 | } | ||
22 | } | ||
23 | |||
24 | fn resolve_target_trait( | ||
25 | db: &impl HirDatabase, | ||
26 | analyzer: &hir::SourceAnalyzer, | ||
27 | impl_block: &ast::ImplBlock | ||
28 | ) -> Option<(hir::Trait, ast::TraitDef)> { | ||
29 | let ast_path = impl_block | ||
30 | .target_trait() | ||
31 | .map(|it| it.syntax().clone()) | ||
32 | .and_then(ast::PathType::cast)? | ||
33 | .path()?; | ||
34 | |||
35 | match analyzer.resolve_path(db, &ast_path) { | ||
36 | Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => { | ||
37 | Some((def, def.source(db).value)) | ||
38 | } | ||
39 | _ => None, | ||
40 | } | ||
41 | } | ||
42 | |||
43 | #[cfg(test)] | ||
44 | mod tests { | ||
45 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | ||
46 | use insta::assert_debug_snapshot; | ||
47 | |||
48 | fn complete(code: &str) -> Vec<CompletionItem> { | ||
49 | do_completion(code, CompletionKind::Reference) | ||
50 | } | ||
51 | |||
52 | #[test] | ||
53 | fn single_function() { | ||
54 | let completions = complete( | ||
55 | r" | ||
56 | trait Test { | ||
57 | fn foo(); | ||
58 | } | ||
59 | |||
60 | struct T1; | ||
61 | |||
62 | impl Test for T1 { | ||
63 | <|> | ||
64 | } | ||
65 | ", | ||
66 | ); | ||
67 | assert_debug_snapshot!(completions, @r###" | ||
68 | [ | ||
69 | CompletionItem { | ||
70 | label: "fn foo()", | ||
71 | source_range: [138; 138), | ||
72 | delete: [138; 138), | ||
73 | insert: "fn foo() { $0 }", | ||
74 | kind: Function, | ||
75 | lookup: "foo", | ||
76 | }, | ||
77 | ] | ||
78 | "###); | ||
79 | } | ||
80 | } \ 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 { | |||
129 | self.add_function_with_name(ctx, None, func) | 129 | self.add_function_with_name(ctx, None, func) |
130 | } | 130 | } |
131 | 131 | ||
132 | pub(crate) fn add_function_impl(&mut self, ctx: &CompletionContext, func: hir::Function) { | ||
133 | use crate::display::FunctionSignature; | ||
134 | |||
135 | let display = FunctionSignature::from_hir(ctx.db, func.clone()); | ||
136 | |||
137 | let func_name = func.name(ctx.db); | ||
138 | |||
139 | let mut builder = CompletionItem::new( | ||
140 | CompletionKind::Reference, | ||
141 | ctx.source_range(), | ||
142 | format!("fn {}()", func_name.to_string())) | ||
143 | .set_documentation(func.docs(ctx.db)); | ||
144 | |||
145 | let completion_kind = if func.has_self_param(ctx.db) { | ||
146 | CompletionItemKind::Method | ||
147 | } else { | ||
148 | CompletionItemKind::Function | ||
149 | }; | ||
150 | |||
151 | let snippet = { | ||
152 | let mut s = format!("{}", display); | ||
153 | s.push_str(" { $0 }"); | ||
154 | s | ||
155 | }; | ||
156 | |||
157 | builder = builder | ||
158 | .insert_text(snippet) | ||
159 | .kind(completion_kind) | ||
160 | .lookup_by(func_name.to_string()); | ||
161 | |||
162 | self.add(builder.build()); | ||
163 | } | ||
164 | |||
132 | fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str { | 165 | fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str { |
133 | let mut votes = [0, 0, 0]; | 166 | let mut votes = [0, 0, 0]; |
134 | for (idx, s) in docs.match_indices(¯o_name) { | 167 | for (idx, s) in docs.match_indices(¯o_name) { |