diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-02-17 09:34:08 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-02-17 09:34:08 +0000 |
commit | 8d8d542dfa1d3b83088a1f48a91665e95fd008cc (patch) | |
tree | 495e3d223f595404e46d5e58b426cda4b0c633bc /crates/ra_assists/src/utils.rs | |
parent | 953dbe3e02fa87bab2f12452746e6c50a47ac153 (diff) | |
parent | 057d0bee5516dc7cba71479b27227c5ad22140ee (diff) |
Merge #3108
3108: Magic Completion for `impl Trait for` Associated Items r=matklad a=kdelorey
# Summary
This PR adds a set of magic completions to auto complete associated trait items (functions/consts/types).
![Associated Trait Impl](https://user-images.githubusercontent.com/2295721/74493144-d8f1af00-4e96-11ea-93a4-82725bf89646.gif)
## Notes
Since the assist and completion share the same logic when figuring out the associated items that are missing, a shared utility was created in the `ra_assists::utils` module.
Resolves #1046
As this is my first PR to the rust-analyzer project, I'm new to the codebase, feedback welcomed!
Co-authored-by: Kevin DeLorey <[email protected]>
Diffstat (limited to 'crates/ra_assists/src/utils.rs')
-rw-r--r-- | crates/ra_assists/src/utils.rs | 75 |
1 files changed, 73 insertions, 2 deletions
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index 0d5722295..6ff44c95c 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs | |||
@@ -1,10 +1,81 @@ | |||
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 | use rustc_hash::FxHashSet; | ||
10 | |||
11 | pub fn get_missing_impl_items( | ||
12 | db: &impl HirDatabase, | ||
13 | analyzer: &hir::SourceAnalyzer, | ||
14 | impl_block: &ast::ImplBlock, | ||
15 | ) -> Vec<hir::AssocItem> { | ||
16 | // Names must be unique between constants and functions. However, type aliases | ||
17 | // may share the same name as a function or constant. | ||
18 | let mut impl_fns_consts = FxHashSet::default(); | ||
19 | let mut impl_type = FxHashSet::default(); | ||
20 | |||
21 | if let Some(item_list) = impl_block.item_list() { | ||
22 | for item in item_list.impl_items() { | ||
23 | match item { | ||
24 | ast::ImplItem::FnDef(f) => { | ||
25 | if let Some(n) = f.name() { | ||
26 | impl_fns_consts.insert(n.syntax().to_string()); | ||
27 | } | ||
28 | } | ||
29 | |||
30 | ast::ImplItem::TypeAliasDef(t) => { | ||
31 | if let Some(n) = t.name() { | ||
32 | impl_type.insert(n.syntax().to_string()); | ||
33 | } | ||
34 | } | ||
35 | |||
36 | ast::ImplItem::ConstDef(c) => { | ||
37 | if let Some(n) = c.name() { | ||
38 | impl_fns_consts.insert(n.syntax().to_string()); | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | } | ||
43 | } | ||
44 | |||
45 | resolve_target_trait(db, analyzer, impl_block).map_or(vec![], |target_trait| { | ||
46 | target_trait | ||
47 | .items(db) | ||
48 | .iter() | ||
49 | .filter(|i| match i { | ||
50 | hir::AssocItem::Function(f) => !impl_fns_consts.contains(&f.name(db).to_string()), | ||
51 | hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(db).to_string()), | ||
52 | hir::AssocItem::Const(c) => c | ||
53 | .name(db) | ||
54 | .map(|n| !impl_fns_consts.contains(&n.to_string())) | ||
55 | .unwrap_or_default(), | ||
56 | }) | ||
57 | .cloned() | ||
58 | .collect() | ||
59 | }) | ||
60 | } | ||
61 | |||
62 | pub(crate) fn resolve_target_trait( | ||
63 | db: &impl HirDatabase, | ||
64 | analyzer: &hir::SourceAnalyzer, | ||
65 | impl_block: &ast::ImplBlock, | ||
66 | ) -> Option<hir::Trait> { | ||
67 | let ast_path = impl_block | ||
68 | .target_trait() | ||
69 | .map(|it| it.syntax().clone()) | ||
70 | .and_then(ast::PathType::cast)? | ||
71 | .path()?; | ||
72 | |||
73 | match analyzer.resolve_path(db, &ast_path) { | ||
74 | Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def), | ||
75 | _ => None, | ||
76 | } | ||
77 | } | ||
78 | |||
8 | pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { | 79 | pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { |
9 | if let Some(expr) = invert_special_case(&expr) { | 80 | if let Some(expr) = invert_special_case(&expr) { |
10 | return expr; | 81 | return expr; |