diff options
Diffstat (limited to 'crates/ra_assists')
-rw-r--r-- | crates/ra_assists/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/utils.rs | 77 |
2 files changed, 76 insertions, 3 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; | |||
9 | mod marks; | 9 | mod marks; |
10 | #[cfg(test)] | 10 | #[cfg(test)] |
11 | mod doc_tests; | 11 | mod doc_tests; |
12 | mod utils; | 12 | pub mod utils; |
13 | pub mod ast_transform; | 13 | pub mod ast_transform; |
14 | 14 | ||
15 | use ra_db::FileRange; | 15 | use 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 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | ast::{self, make}, | 4 | ast::{self, make, NameOwner}, |
5 | T, | 5 | AstNode, T, |
6 | }; | 6 | }; |
7 | 7 | ||
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 | |||
8 | pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { | 81 | pub(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; |