diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-01-11 22:42:39 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-01-11 22:42:39 +0000 |
commit | bcfd297f4910bbf2305ec859d7cf42b7dca25f57 (patch) | |
tree | c6b53cd774e7baacf213e91b295734852a83f40b /crates/ra_syntax | |
parent | e90aa86fbfa716c4028f38d0d22654065011a964 (diff) | |
parent | ccb75f7c979b56bc62b61fadd81903e11a7f5d74 (diff) |
Merge #2727
2727: Qualify paths in 'add impl members' r=flodiebold a=flodiebold
This makes the 'add impl members' assist qualify paths, so that they should resolve to the same thing as in the definition. To do that, it adds an algorithm that finds a path to refer to any item from any module (if possible), which is actually probably the more important part of this PR :smile: It handles visibility, reexports, renamed crates, prelude etc.; I think the only thing that's missing is support for local items. I'm not sure about the performance, since it takes into account every location where the target item has been `pub use`d, and then recursively goes up the module tree; there's probably potential for optimization by memoizing more, but I think the general shape of the algorithm is necessary to handle every case in Rust's module system.
~The 'find path' part is actually pretty complete, I think; I'm still working on the assist (hence the failing tests).~
Fixes #1943.
Co-authored-by: Florian Diebold <[email protected]>
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r-- | crates/ra_syntax/src/algo.rs | 6 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/edit.rs | 8 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/make.rs | 16 |
3 files changed, 22 insertions, 8 deletions
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs index 2b2b295f9..30a479f01 100644 --- a/crates/ra_syntax/src/algo.rs +++ b/crates/ra_syntax/src/algo.rs | |||
@@ -184,17 +184,17 @@ pub fn replace_children( | |||
184 | /// to create a type-safe abstraction on top of it instead. | 184 | /// to create a type-safe abstraction on top of it instead. |
185 | pub fn replace_descendants( | 185 | pub fn replace_descendants( |
186 | parent: &SyntaxNode, | 186 | parent: &SyntaxNode, |
187 | map: &FxHashMap<SyntaxElement, SyntaxElement>, | 187 | map: &impl Fn(&SyntaxElement) -> Option<SyntaxElement>, |
188 | ) -> SyntaxNode { | 188 | ) -> SyntaxNode { |
189 | // FIXME: this could be made much faster. | 189 | // FIXME: this could be made much faster. |
190 | let new_children = parent.children_with_tokens().map(|it| go(map, it)).collect::<Vec<_>>(); | 190 | let new_children = parent.children_with_tokens().map(|it| go(map, it)).collect::<Vec<_>>(); |
191 | return with_children(parent, new_children); | 191 | return with_children(parent, new_children); |
192 | 192 | ||
193 | fn go( | 193 | fn go( |
194 | map: &FxHashMap<SyntaxElement, SyntaxElement>, | 194 | map: &impl Fn(&SyntaxElement) -> Option<SyntaxElement>, |
195 | element: SyntaxElement, | 195 | element: SyntaxElement, |
196 | ) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { | 196 | ) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { |
197 | if let Some(replacement) = map.get(&element) { | 197 | if let Some(replacement) = map(&element) { |
198 | return match replacement { | 198 | return match replacement { |
199 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green().clone()), | 199 | NodeOrToken::Node(it) => NodeOrToken::Node(it.green().clone()), |
200 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().clone()), | 200 | NodeOrToken::Token(it) => NodeOrToken::Token(it.green().clone()), |
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs index ae5d63927..b736098ac 100644 --- a/crates/ra_syntax/src/ast/edit.rs +++ b/crates/ra_syntax/src/ast/edit.rs | |||
@@ -236,8 +236,8 @@ pub fn replace_descendants<N: AstNode, D: AstNode>( | |||
236 | ) -> N { | 236 | ) -> N { |
237 | let map = replacement_map | 237 | let map = replacement_map |
238 | .map(|(from, to)| (from.syntax().clone().into(), to.syntax().clone().into())) | 238 | .map(|(from, to)| (from.syntax().clone().into(), to.syntax().clone().into())) |
239 | .collect::<FxHashMap<_, _>>(); | 239 | .collect::<FxHashMap<SyntaxElement, _>>(); |
240 | let new_syntax = algo::replace_descendants(parent.syntax(), &map); | 240 | let new_syntax = algo::replace_descendants(parent.syntax(), &|n| map.get(n).cloned()); |
241 | N::cast(new_syntax).unwrap() | 241 | N::cast(new_syntax).unwrap() |
242 | } | 242 | } |
243 | 243 | ||
@@ -292,7 +292,7 @@ impl IndentLevel { | |||
292 | ) | 292 | ) |
293 | }) | 293 | }) |
294 | .collect(); | 294 | .collect(); |
295 | algo::replace_descendants(&node, &replacements) | 295 | algo::replace_descendants(&node, &|n| replacements.get(n).cloned()) |
296 | } | 296 | } |
297 | 297 | ||
298 | pub fn decrease_indent<N: AstNode>(self, node: N) -> N { | 298 | pub fn decrease_indent<N: AstNode>(self, node: N) -> N { |
@@ -320,7 +320,7 @@ impl IndentLevel { | |||
320 | ) | 320 | ) |
321 | }) | 321 | }) |
322 | .collect(); | 322 | .collect(); |
323 | algo::replace_descendants(&node, &replacements) | 323 | algo::replace_descendants(&node, &|n| replacements.get(n).cloned()) |
324 | } | 324 | } |
325 | } | 325 | } |
326 | 326 | ||
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 04a5408fe..9781b748f 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | //! of smaller pieces. | 2 | //! of smaller pieces. |
3 | use itertools::Itertools; | 3 | use itertools::Itertools; |
4 | 4 | ||
5 | use crate::{ast, AstNode, SourceFile}; | 5 | use crate::{algo, ast, AstNode, SourceFile}; |
6 | 6 | ||
7 | pub fn name(text: &str) -> ast::Name { | 7 | pub fn name(text: &str) -> ast::Name { |
8 | ast_from_text(&format!("mod {};", text)) | 8 | ast_from_text(&format!("mod {};", text)) |
@@ -21,6 +21,20 @@ pub fn path_qualified(qual: ast::Path, name_ref: ast::NameRef) -> ast::Path { | |||
21 | fn path_from_text(text: &str) -> ast::Path { | 21 | fn path_from_text(text: &str) -> ast::Path { |
22 | ast_from_text(text) | 22 | ast_from_text(text) |
23 | } | 23 | } |
24 | pub fn path_with_type_arg_list(path: ast::Path, args: Option<ast::TypeArgList>) -> ast::Path { | ||
25 | if let Some(args) = args { | ||
26 | let syntax = path.syntax(); | ||
27 | // FIXME: remove existing type args | ||
28 | let new_syntax = algo::insert_children( | ||
29 | syntax, | ||
30 | crate::algo::InsertPosition::Last, | ||
31 | &mut Some(args).into_iter().map(|n| n.syntax().clone().into()), | ||
32 | ); | ||
33 | ast::Path::cast(new_syntax).unwrap() | ||
34 | } else { | ||
35 | path | ||
36 | } | ||
37 | } | ||
24 | 38 | ||
25 | pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordField { | 39 | pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordField { |
26 | return match expr { | 40 | return match expr { |