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/handlers | |
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/handlers')
-rw-r--r-- | crates/ra_assists/src/handlers/add_missing_impl_members.rs | 47 |
1 files changed, 14 insertions, 33 deletions
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs index 448697d31..ab21388c8 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use hir::{db::HirDatabase, HasSource, InFile}; | 1 | use hir::{HasSource, InFile}; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast::{self, edit, make, AstNode, NameOwner}, | 3 | ast::{self, edit, make, AstNode, NameOwner}, |
4 | SmolStr, | 4 | SmolStr, |
@@ -6,6 +6,7 @@ use ra_syntax::{ | |||
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, | 8 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, |
9 | utils::{get_missing_impl_items, resolve_target_trait}, | ||
9 | Assist, AssistCtx, AssistId, | 10 | Assist, AssistCtx, AssistId, |
10 | }; | 11 | }; |
11 | 12 | ||
@@ -103,11 +104,9 @@ fn add_missing_impl_members_inner( | |||
103 | let impl_node = ctx.find_node_at_offset::<ast::ImplBlock>()?; | 104 | let impl_node = ctx.find_node_at_offset::<ast::ImplBlock>()?; |
104 | let impl_item_list = impl_node.item_list()?; | 105 | let impl_item_list = impl_node.item_list()?; |
105 | 106 | ||
106 | let (trait_, trait_def) = { | 107 | let analyzer = ctx.source_analyzer(impl_node.syntax(), None); |
107 | let analyzer = ctx.source_analyzer(impl_node.syntax(), None); | ||
108 | 108 | ||
109 | resolve_target_trait_def(ctx.db, &analyzer, &impl_node)? | 109 | let trait_ = resolve_target_trait(ctx.db, &analyzer, &impl_node)?; |
110 | }; | ||
111 | 110 | ||
112 | let def_name = |item: &ast::ImplItem| -> Option<SmolStr> { | 111 | let def_name = |item: &ast::ImplItem| -> Option<SmolStr> { |
113 | match item { | 112 | match item { |
@@ -118,11 +117,14 @@ fn add_missing_impl_members_inner( | |||
118 | .map(|it| it.text().clone()) | 117 | .map(|it| it.text().clone()) |
119 | }; | 118 | }; |
120 | 119 | ||
121 | let trait_items = trait_def.item_list()?.impl_items(); | 120 | let missing_items = get_missing_impl_items(ctx.db, &analyzer, &impl_node) |
122 | let impl_items = impl_item_list.impl_items().collect::<Vec<_>>(); | 121 | .iter() |
123 | 122 | .map(|i| match i { | |
124 | let missing_items: Vec<_> = trait_items | 123 | hir::AssocItem::Function(i) => ast::ImplItem::FnDef(i.source(ctx.db).value), |
125 | .filter(|t| def_name(t).is_some()) | 124 | hir::AssocItem::TypeAlias(i) => ast::ImplItem::TypeAliasDef(i.source(ctx.db).value), |
125 | hir::AssocItem::Const(i) => ast::ImplItem::ConstDef(i.source(ctx.db).value), | ||
126 | }) | ||
127 | .filter(|t| def_name(&t).is_some()) | ||
126 | .filter(|t| match t { | 128 | .filter(|t| match t { |
127 | ast::ImplItem::FnDef(def) => match mode { | 129 | ast::ImplItem::FnDef(def) => match mode { |
128 | AddMissingImplMembersMode::DefaultMethodsOnly => def.body().is_some(), | 130 | AddMissingImplMembersMode::DefaultMethodsOnly => def.body().is_some(), |
@@ -130,8 +132,8 @@ fn add_missing_impl_members_inner( | |||
130 | }, | 132 | }, |
131 | _ => mode == AddMissingImplMembersMode::NoDefaultMethods, | 133 | _ => mode == AddMissingImplMembersMode::NoDefaultMethods, |
132 | }) | 134 | }) |
133 | .filter(|t| impl_items.iter().all(|i| def_name(i) != def_name(t))) | 135 | .collect::<Vec<_>>(); |
134 | .collect(); | 136 | |
135 | if missing_items.is_empty() { | 137 | if missing_items.is_empty() { |
136 | return None; | 138 | return None; |
137 | } | 139 | } |
@@ -177,27 +179,6 @@ fn add_body(fn_def: ast::FnDef) -> ast::FnDef { | |||
177 | } | 179 | } |
178 | } | 180 | } |
179 | 181 | ||
180 | /// Given an `ast::ImplBlock`, resolves the target trait (the one being | ||
181 | /// implemented) to a `ast::TraitDef`. | ||
182 | fn resolve_target_trait_def( | ||
183 | db: &impl HirDatabase, | ||
184 | analyzer: &hir::SourceAnalyzer, | ||
185 | impl_block: &ast::ImplBlock, | ||
186 | ) -> Option<(hir::Trait, ast::TraitDef)> { | ||
187 | let ast_path = impl_block | ||
188 | .target_trait() | ||
189 | .map(|it| it.syntax().clone()) | ||
190 | .and_then(ast::PathType::cast)? | ||
191 | .path()?; | ||
192 | |||
193 | match analyzer.resolve_path(db, &ast_path) { | ||
194 | Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => { | ||
195 | Some((def, def.source(db).value)) | ||
196 | } | ||
197 | _ => None, | ||
198 | } | ||
199 | } | ||
200 | |||
201 | #[cfg(test)] | 182 | #[cfg(test)] |
202 | mod tests { | 183 | mod tests { |
203 | use super::*; | 184 | use super::*; |