aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_assists/src/utils.rs77
-rw-r--r--crates/ra_ide/src/completion.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs132
4 files changed, 95 insertions, 118 deletions
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 828a8e9e8..cb124eaf0 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -9,7 +9,7 @@ mod assist_ctx;
9mod marks; 9mod marks;
10#[cfg(test)] 10#[cfg(test)]
11mod doc_tests; 11mod doc_tests;
12mod utils; 12pub mod utils;
13pub mod ast_transform; 13pub mod ast_transform;
14 14
15use ra_db::FileRange; 15use ra_db::FileRange;
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs
index 0d5722295..7bc21c6e4 100644
--- a/crates/ra_assists/src/utils.rs
+++ b/crates/ra_assists/src/utils.rs
@@ -1,10 +1,83 @@
1//! Assorted functions shared by several assists. 1//! Assorted functions shared by several assists.
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, make}, 4 ast::{self, make, NameOwner},
5 T, 5 AstNode, T,
6}; 6};
7 7
8use hir::db::HirDatabase;
9
10use rustc_hash::FxHashSet;
11
12pub fn get_missing_impl_items(
13 db: &impl HirDatabase,
14 analyzer: &hir::SourceAnalyzer,
15 impl_block: &ast::ImplBlock,
16) -> Vec<hir::AssocItem> {
17 // since the names are unique only to each associated type (fn/type/const),
18 // create buckets of each already implemented type that we'll use in the
19 // lookup later.
20 let mut impl_fns = FxHashSet::default();
21 let mut impl_type = FxHashSet::default();
22 let mut impl_const = FxHashSet::default();
23
24 if let Some(item_list) = impl_block.item_list() {
25 for item in item_list.impl_items() {
26 match item {
27 ast::ImplItem::FnDef(f) => {
28 if let Some(n) = f.name() {
29 impl_fns.insert(n.syntax().to_string());
30 }
31 }
32
33 ast::ImplItem::TypeAliasDef(t) => {
34 if let Some(n) = t.name() {
35 impl_type.insert(n.syntax().to_string());
36 }
37 }
38
39 ast::ImplItem::ConstDef(c) => {
40 if let Some(n) = c.name() {
41 impl_const.insert(n.syntax().to_string());
42 }
43 }
44 }
45 }
46 }
47
48 resolve_target_trait(db, analyzer, impl_block).map_or(vec![], |target_trait| {
49 target_trait
50 .items(db)
51 .iter()
52 .filter(|i| match i {
53 hir::AssocItem::Function(f) => !impl_fns.contains(&f.name(db).to_string()),
54 hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(db).to_string()),
55 hir::AssocItem::Const(c) => {
56 c.name(db).map(|n| !impl_const.contains(&n.to_string())).unwrap_or_default()
57 }
58 })
59 .map(|i| i.clone())
60 .collect()
61 })
62}
63
64fn resolve_target_trait(
65 db: &impl HirDatabase,
66 analyzer: &hir::SourceAnalyzer,
67 impl_block: &ast::ImplBlock,
68) -> Option<hir::Trait> {
69 let ast_path = impl_block
70 .target_trait()
71 .map(|it| it.syntax().clone())
72 .and_then(ast::PathType::cast)?
73 .path()?;
74
75 match analyzer.resolve_path(db, &ast_path) {
76 Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def),
77 _ => None,
78 }
79}
80
8pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { 81pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
9 if let Some(expr) = invert_special_case(&expr) { 82 if let Some(expr) = invert_special_case(&expr) {
10 return expr; 83 return expr;
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs
index 4f24cd1f9..4bdc6ba23 100644
--- a/crates/ra_ide/src/completion.rs
+++ b/crates/ra_ide/src/completion.rs
@@ -76,6 +76,6 @@ pub(crate) fn completions(db: &RootDatabase, position: FilePosition) -> Option<C
76 complete_postfix::complete_postfix(&mut acc, &ctx); 76 complete_postfix::complete_postfix(&mut acc, &ctx);
77 complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); 77 complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
78 complete_trait_impl::complete_trait_impl(&mut acc, &ctx); 78 complete_trait_impl::complete_trait_impl(&mut acc, &ctx);
79 79
80 Some(acc) 80 Some(acc)
81} 81}
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs
index 0175f5e55..e2854ee97 100644
--- a/crates/ra_ide/src/completion/complete_trait_impl.rs
+++ b/crates/ra_ide/src/completion/complete_trait_impl.rs
@@ -1,124 +1,27 @@
1use crate::completion::{CompletionContext, Completions, CompletionItem, CompletionKind, CompletionItemKind}; 1use crate::completion::{
2 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
3};
2 4
3use ra_syntax::ast::{self, NameOwner, AstNode}; 5use hir::{self, Docs};
4
5use hir::{self, db::HirDatabase, Docs};
6 6
7use ra_assists::utils::get_missing_impl_items;
7 8
8pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { 9pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
9 let impl_block = ctx.impl_block.as_ref(); 10 let impl_block = ctx.impl_block.as_ref();
10 let item_list = impl_block.and_then(|i| i.item_list()); 11 let item_list = impl_block.and_then(|i| i.item_list());
11 12
12 if item_list.is_none() 13 if item_list.is_none() || impl_block.is_none() || ctx.function_syntax.is_some() {
13 || impl_block.is_none()
14 || ctx.function_syntax.is_some() {
15 return; 14 return;
16 } 15 }
17 16
18 let item_list = item_list.unwrap();
19 let impl_block = impl_block.unwrap(); 17 let impl_block = impl_block.unwrap();
20 18
21 let target_trait = resolve_target_trait(ctx.db, &ctx.analyzer, &impl_block); 19 for item in get_missing_impl_items(ctx.db, &ctx.analyzer, impl_block) {
22 if target_trait.is_none() {
23 return;
24 }
25
26 let target_trait = target_trait.unwrap();
27
28 let trait_items = target_trait.items(ctx.db);
29 let missing_items = trait_items
30 .iter()
31 .filter(|i| {
32 match i {
33 hir::AssocItem::Function(f) => {
34 let f_name = f.name(ctx.db).to_string();
35
36 item_list
37 .impl_items()
38 .find(|impl_item| {
39 match impl_item {
40 ast::ImplItem::FnDef(impl_f) => {
41 if let Some(n) = impl_f.name() {
42 f_name == n.syntax().to_string()
43 } else {
44 false
45 }
46 },
47 _ => false
48 }
49 }).is_none()
50 },
51 hir::AssocItem::Const(c) => {
52 let c_name = c.name(ctx.db)
53 .map(|f| f.to_string());
54
55 if c_name.is_none() {
56 return false;
57 }
58
59 let c_name = c_name.unwrap();
60
61 item_list
62 .impl_items()
63 .find(|impl_item| {
64 match impl_item {
65 ast::ImplItem::ConstDef(c) => {
66 if let Some(n) = c.name() {
67 c_name == n.syntax().to_string()
68 } else {
69 false
70 }
71 },
72 _ => false
73 }
74 }).is_none()
75 },
76 hir::AssocItem::TypeAlias(t) => {
77 let t_name = t.name(ctx.db).to_string();
78
79 item_list
80 .impl_items()
81 .find(|impl_item| {
82 match impl_item {
83 ast::ImplItem::TypeAliasDef(t) => {
84 if let Some(n) = t.name() {
85 t_name == n.syntax().to_string()
86 } else {
87 false
88 }
89 },
90 _ => false
91 }
92 }).is_none()
93 }
94 }
95 });
96
97 for item in missing_items {
98 match item { 20 match item {
99 hir::AssocItem::Function(f) => add_function_impl(acc, ctx, f), 21 hir::AssocItem::Function(f) => add_function_impl(acc, ctx, &f),
100 hir::AssocItem::TypeAlias(t) => add_type_alias_impl(acc, ctx, t), 22 hir::AssocItem::TypeAlias(t) => add_type_alias_impl(acc, ctx, &t),
101 _ => {}, 23 _ => {}
102 }
103 }
104}
105
106fn resolve_target_trait(
107 db: &impl HirDatabase,
108 analyzer: &hir::SourceAnalyzer,
109 impl_block: &ast::ImplBlock
110) -> Option<hir::Trait> {
111 let ast_path = impl_block
112 .target_trait()
113 .map(|it| it.syntax().clone())
114 .and_then(ast::PathType::cast)?
115 .path()?;
116
117 match analyzer.resolve_path(db, &ast_path) {
118 Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => {
119 Some(def)
120 } 24 }
121 _ => None,
122 } 25 }
123} 26}
124 27
@@ -144,20 +47,21 @@ fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir:
144 } else { 47 } else {
145 CompletionItemKind::Function 48 CompletionItemKind::Function
146 }; 49 };
147 50
148 let snippet = { 51 let snippet = {
149 let mut s = format!("{}", display); 52 let mut s = format!("{}", display);
150 s.push_str(" {}"); 53 s.push_str(" {}");
151 s 54 s
152 }; 55 };
153 56
154 builder 57 builder.insert_text(snippet).kind(completion_kind).add_to(acc);
155 .insert_text(snippet)
156 .kind(completion_kind)
157 .add_to(acc);
158} 58}
159 59
160fn add_type_alias_impl(acc: &mut Completions, ctx: &CompletionContext, type_alias: &hir::TypeAlias) { 60fn add_type_alias_impl(
61 acc: &mut Completions,
62 ctx: &CompletionContext,
63 type_alias: &hir::TypeAlias,
64) {
161 let snippet = format!("type {} = ", type_alias.name(ctx.db).to_string()); 65 let snippet = format!("type {} = ", type_alias.name(ctx.db).to_string());
162 66
163 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) 67 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
@@ -290,4 +194,4 @@ mod tests {
290 ] 194 ]
291 "###); 195 "###);
292 } 196 }
293} \ No newline at end of file 197}