aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-01-11 22:42:39 +0000
committerGitHub <[email protected]>2020-01-11 22:42:39 +0000
commitbcfd297f4910bbf2305ec859d7cf42b7dca25f57 (patch)
treec6b53cd774e7baacf213e91b295734852a83f40b /crates/ra_syntax
parente90aa86fbfa716c4028f38d0d22654065011a964 (diff)
parentccb75f7c979b56bc62b61fadd81903e11a7f5d74 (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.rs6
-rw-r--r--crates/ra_syntax/src/ast/edit.rs8
-rw-r--r--crates/ra_syntax/src/ast/make.rs16
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.
185pub fn replace_descendants( 185pub 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.
3use itertools::Itertools; 3use itertools::Itertools;
4 4
5use crate::{ast, AstNode, SourceFile}; 5use crate::{algo, ast, AstNode, SourceFile};
6 6
7pub fn name(text: &str) -> ast::Name { 7pub 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 {
21fn path_from_text(text: &str) -> ast::Path { 21fn path_from_text(text: &str) -> ast::Path {
22 ast_from_text(text) 22 ast_from_text(text)
23} 23}
24pub 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
25pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordField { 39pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordField {
26 return match expr { 40 return match expr {