Skip to content

Commit d85abd7

Browse files
committed
Added a utility function that can be used to determine the missing impl items.
1 parent a957c47 commit d85abd7

File tree

4 files changed

+95
-118
lines changed

4 files changed

+95
-118
lines changed

crates/ra_assists/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mod assist_ctx;
99
mod marks;
1010
#[cfg(test)]
1111
mod doc_tests;
12-
mod utils;
12+
pub mod utils;
1313
pub mod ast_transform;
1414

1515
use ra_db::FileRange;

crates/ra_assists/src/utils.rs

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,83 @@
11
//! Assorted functions shared by several assists.
22
33
use ra_syntax::{
4-
ast::{self, make},
5-
T,
4+
ast::{self, make, NameOwner},
5+
AstNode, T,
66
};
77

8+
use hir::db::HirDatabase;
9+
10+
use rustc_hash::FxHashSet;
11+
12+
pub 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+
64+
fn 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+
881
pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
982
if let Some(expr) = invert_special_case(&expr) {
1083
return expr;

crates/ra_ide/src/completion.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,6 @@ pub(crate) fn completions(db: &RootDatabase, position: FilePosition) -> Option<C
7676
complete_postfix::complete_postfix(&mut acc, &ctx);
7777
complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
7878
complete_trait_impl::complete_trait_impl(&mut acc, &ctx);
79-
79+
8080
Some(acc)
8181
}

crates/ra_ide/src/completion/complete_trait_impl.rs

Lines changed: 18 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,27 @@
1-
use crate::completion::{CompletionContext, Completions, CompletionItem, CompletionKind, CompletionItemKind};
1+
use crate::completion::{
2+
CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
3+
};
24

3-
use ra_syntax::ast::{self, NameOwner, AstNode};
4-
5-
use hir::{self, db::HirDatabase, Docs};
5+
use hir::{self, Docs};
66

7+
use ra_assists::utils::get_missing_impl_items;
78

89
pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
910
let impl_block = ctx.impl_block.as_ref();
1011
let item_list = impl_block.and_then(|i| i.item_list());
1112

12-
if item_list.is_none()
13-
|| impl_block.is_none()
14-
|| ctx.function_syntax.is_some() {
13+
if item_list.is_none() || impl_block.is_none() || ctx.function_syntax.is_some() {
1514
return;
1615
}
1716

18-
let item_list = item_list.unwrap();
1917
let impl_block = impl_block.unwrap();
2018

21-
let target_trait = resolve_target_trait(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 {
19+
for item in get_missing_impl_items(ctx.db, &ctx.analyzer, impl_block) {
9820
match item {
99-
hir::AssocItem::Function(f) => add_function_impl(acc, ctx, f),
100-
hir::AssocItem::TypeAlias(t) => add_type_alias_impl(acc, ctx, t),
101-
_ => {},
102-
}
103-
}
104-
}
105-
106-
fn 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)
21+
hir::AssocItem::Function(f) => add_function_impl(acc, ctx, &f),
22+
hir::AssocItem::TypeAlias(t) => add_type_alias_impl(acc, ctx, &t),
23+
_ => {}
12024
}
121-
_ => None,
12225
}
12326
}
12427

@@ -144,20 +47,21 @@ fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir:
14447
} else {
14548
CompletionItemKind::Function
14649
};
147-
50+
14851
let snippet = {
14952
let mut s = format!("{}", display);
15053
s.push_str(" {}");
15154
s
15255
};
15356

154-
builder
155-
.insert_text(snippet)
156-
.kind(completion_kind)
157-
.add_to(acc);
57+
builder.insert_text(snippet).kind(completion_kind).add_to(acc);
15858
}
15959

160-
fn add_type_alias_impl(acc: &mut Completions, ctx: &CompletionContext, type_alias: &hir::TypeAlias) {
60+
fn add_type_alias_impl(
61+
acc: &mut Completions,
62+
ctx: &CompletionContext,
63+
type_alias: &hir::TypeAlias,
64+
) {
16165
let snippet = format!("type {} = ", type_alias.name(ctx.db).to_string());
16266

16367
CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
@@ -290,4 +194,4 @@ mod tests {
290194
]
291195
"###);
292196
}
293-
}
197+
}

0 commit comments

Comments
 (0)