diff options
Diffstat (limited to 'crates/ra_ide/src/completion')
-rw-r--r-- | crates/ra_ide/src/completion/complete_trait_impl.rs | 144 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 4 |
2 files changed, 131 insertions, 17 deletions
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 3bec57426..52ad7dd9d 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs | |||
@@ -1,22 +1,104 @@ | |||
1 | |||
2 | use crate::completion::{CompletionContext, Completions}; | 1 | use crate::completion::{CompletionContext, Completions}; |
3 | 2 | ||
4 | use hir::{ self, db::HirDatabase, HasSource }; | 3 | use ast::{ NameOwner }; |
4 | use hir::{ self, db::HirDatabase }; | ||
5 | 5 | ||
6 | use ra_syntax::{ ast, ast::AstNode }; | 6 | use ra_syntax::{ ast, ast::AstNode }; |
7 | 7 | ||
8 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | 8 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { |
9 | let impl_trait = ast::ItemList::cast(ctx.token.parent()) | 9 | let item_list = ast::ItemList::cast(ctx.token.parent()); |
10 | .and_then(|item_list| item_list.syntax().parent()) | 10 | let impl_block = item_list |
11 | .and_then(|item_list_parent| ast::ImplBlock::cast(item_list_parent)) | 11 | .clone() |
12 | .and_then(|impl_block| resolve_target_trait(ctx.db, &ctx.analyzer, &impl_block)); | 12 | .and_then(|i| i.syntax().parent()) |
13 | 13 | .and_then(|p| ast::ImplBlock::cast(p)); | |
14 | if let Some(x) = &impl_trait { | 14 | |
15 | for trait_item in x.0.items(ctx.db) { | 15 | if item_list.is_none() || impl_block.is_none() { |
16 | match trait_item { | 16 | return; |
17 | hir::AssocItem::Function(f) => acc.add_function_impl(ctx, f), | 17 | } |
18 | _ => {} | 18 | |
19 | let item_list = item_list.unwrap(); | ||
20 | let impl_block = impl_block.unwrap(); | ||
21 | |||
22 | let target_trait = resolve_target_trait(ctx.db, &ctx.analyzer, &impl_block); | ||
23 | if target_trait.is_none() { | ||
24 | return; | ||
25 | } | ||
26 | |||
27 | let trait_ = target_trait.unwrap(); | ||
28 | |||
29 | let trait_items = trait_.items(ctx.db); | ||
30 | let missing_items = trait_items | ||
31 | .iter() | ||
32 | .filter(|i| { | ||
33 | match i { | ||
34 | hir::AssocItem::Function(f) => { | ||
35 | let f_name = f.name(ctx.db).to_string(); | ||
36 | |||
37 | item_list | ||
38 | .impl_items() | ||
39 | .find(|impl_item| { | ||
40 | match impl_item { | ||
41 | ast::ImplItem::FnDef(impl_f) => { | ||
42 | if let Some(n) = impl_f.name() { | ||
43 | f_name == n.syntax().to_string() | ||
44 | } else { | ||
45 | false | ||
46 | } | ||
47 | }, | ||
48 | _ => false | ||
49 | } | ||
50 | }).is_none() | ||
51 | }, | ||
52 | hir::AssocItem::Const(c) => { | ||
53 | let c_name = c.name(ctx.db) | ||
54 | .map(|f| f.to_string()); | ||
55 | |||
56 | if c_name.is_none() { | ||
57 | return false; | ||
58 | } | ||
59 | |||
60 | let c_name = c_name.unwrap(); | ||
61 | |||
62 | item_list | ||
63 | .impl_items() | ||
64 | .find(|impl_item| { | ||
65 | match impl_item { | ||
66 | ast::ImplItem::ConstDef(c) => { | ||
67 | if let Some(n) = c.name() { | ||
68 | c_name == n.syntax().to_string() | ||
69 | } else { | ||
70 | false | ||
71 | } | ||
72 | }, | ||
73 | _ => false | ||
74 | } | ||
75 | }).is_none() | ||
76 | }, | ||
77 | hir::AssocItem::TypeAlias(t) => { | ||
78 | let t_name = t.name(ctx.db).to_string(); | ||
79 | |||
80 | item_list | ||
81 | .impl_items() | ||
82 | .find(|impl_item| { | ||
83 | match impl_item { | ||
84 | ast::ImplItem::TypeAliasDef(t) => { | ||
85 | if let Some(n) = t.name() { | ||
86 | t_name == n.syntax().to_string() | ||
87 | } else { | ||
88 | false | ||
89 | } | ||
90 | }, | ||
91 | _ => false | ||
92 | } | ||
93 | }).is_none() | ||
94 | } | ||
19 | } | 95 | } |
96 | }); | ||
97 | |||
98 | for item in missing_items { | ||
99 | match item { | ||
100 | hir::AssocItem::Function(f) => acc.add_function_impl(ctx, f), | ||
101 | _ => {} | ||
20 | } | 102 | } |
21 | } | 103 | } |
22 | } | 104 | } |
@@ -25,7 +107,7 @@ fn resolve_target_trait( | |||
25 | db: &impl HirDatabase, | 107 | db: &impl HirDatabase, |
26 | analyzer: &hir::SourceAnalyzer, | 108 | analyzer: &hir::SourceAnalyzer, |
27 | impl_block: &ast::ImplBlock | 109 | impl_block: &ast::ImplBlock |
28 | ) -> Option<(hir::Trait, ast::TraitDef)> { | 110 | ) -> Option<hir::Trait> { |
29 | let ast_path = impl_block | 111 | let ast_path = impl_block |
30 | .target_trait() | 112 | .target_trait() |
31 | .map(|it| it.syntax().clone()) | 113 | .map(|it| it.syntax().clone()) |
@@ -34,7 +116,7 @@ fn resolve_target_trait( | |||
34 | 116 | ||
35 | match analyzer.resolve_path(db, &ast_path) { | 117 | match analyzer.resolve_path(db, &ast_path) { |
36 | Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => { | 118 | Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => { |
37 | Some((def, def.source(db).value)) | 119 | Some(def) |
38 | } | 120 | } |
39 | _ => None, | 121 | _ => None, |
40 | } | 122 | } |
@@ -70,11 +152,43 @@ mod tests { | |||
70 | label: "fn foo()", | 152 | label: "fn foo()", |
71 | source_range: [138; 138), | 153 | source_range: [138; 138), |
72 | delete: [138; 138), | 154 | delete: [138; 138), |
73 | insert: "fn foo() { $0 }", | 155 | insert: "fn foo() { $0}", |
74 | kind: Function, | 156 | kind: Function, |
75 | lookup: "foo", | 157 | lookup: "foo", |
76 | }, | 158 | }, |
77 | ] | 159 | ] |
78 | "###); | 160 | "###); |
79 | } | 161 | } |
162 | |||
163 | #[test] | ||
164 | fn hide_implemented_fn() { | ||
165 | let completions = complete( | ||
166 | r" | ||
167 | trait Test { | ||
168 | fn foo(); | ||
169 | fn bar(); | ||
170 | } | ||
171 | |||
172 | struct T1; | ||
173 | |||
174 | impl Test for T1 { | ||
175 | fn foo() {} | ||
176 | |||
177 | <|> | ||
178 | } | ||
179 | ", | ||
180 | ); | ||
181 | assert_debug_snapshot!(completions, @r###" | ||
182 | [ | ||
183 | CompletionItem { | ||
184 | label: "fn bar()", | ||
185 | source_range: [193; 193), | ||
186 | delete: [193; 193), | ||
187 | insert: "fn bar() { $0}", | ||
188 | kind: Function, | ||
189 | lookup: "bar", | ||
190 | }, | ||
191 | ] | ||
192 | "###); | ||
193 | } | ||
80 | } \ No newline at end of file | 194 | } \ 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 d0a43261f..0689013ba 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -129,7 +129,7 @@ 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) { | 132 | pub(crate) fn add_function_impl(&mut self, ctx: &CompletionContext, func: &hir::Function) { |
133 | use crate::display::FunctionSignature; | 133 | use crate::display::FunctionSignature; |
134 | 134 | ||
135 | let display = FunctionSignature::from_hir(ctx.db, func.clone()); | 135 | let display = FunctionSignature::from_hir(ctx.db, func.clone()); |
@@ -150,7 +150,7 @@ impl Completions { | |||
150 | 150 | ||
151 | let snippet = { | 151 | let snippet = { |
152 | let mut s = format!("{}", display); | 152 | let mut s = format!("{}", display); |
153 | s.push_str(" { $0 }"); | 153 | s.push_str(" { $0}"); |
154 | s | 154 | s |
155 | }; | 155 | }; |
156 | 156 | ||