diff options
Diffstat (limited to 'crates/ra_assists')
-rw-r--r-- | crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs | 66 |
1 files changed, 36 insertions, 30 deletions
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs index f2286c9f6..b4784c333 100644 --- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use hir::{self, ModPath}; | 1 | use hir; |
2 | use ra_syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SmolStr, SyntaxNode}; | 2 | use ra_syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SmolStr, SyntaxNode}; |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
@@ -50,13 +50,9 @@ pub(crate) fn replace_qualified_name_with_use( | |||
50 | 50 | ||
51 | // Now that we've brought the name into scope, re-qualify all paths that could be | 51 | // Now that we've brought the name into scope, re-qualify all paths that could be |
52 | // affected (that is, all paths inside the node we added the `use` to). | 52 | // affected (that is, all paths inside the node we added the `use` to). |
53 | let hir_path = match hir::Path::from_ast(path.clone()) { | ||
54 | Some(p) => p, | ||
55 | None => return, | ||
56 | }; | ||
57 | let mut rewriter = SyntaxRewriter::default(); | 53 | let mut rewriter = SyntaxRewriter::default(); |
58 | let syntax = container.either(|l| l.syntax().clone(), |r| r.syntax().clone()); | 54 | let syntax = container.either(|l| l.syntax().clone(), |r| r.syntax().clone()); |
59 | shorten_paths(&mut rewriter, syntax, hir_path.mod_path()); | 55 | shorten_paths(&mut rewriter, syntax, path); |
60 | builder.rewrite(rewriter); | 56 | builder.rewrite(rewriter); |
61 | }, | 57 | }, |
62 | ) | 58 | ) |
@@ -83,7 +79,7 @@ fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { | |||
83 | } | 79 | } |
84 | 80 | ||
85 | /// Adds replacements to `re` that shorten `path` in all descendants of `node`. | 81 | /// Adds replacements to `re` that shorten `path` in all descendants of `node`. |
86 | fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: &ModPath) { | 82 | fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: ast::Path) { |
87 | for child in node.children() { | 83 | for child in node.children() { |
88 | match_ast! { | 84 | match_ast! { |
89 | match child { | 85 | match child { |
@@ -94,47 +90,57 @@ fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: | |||
94 | ast::Module(_it) => continue, | 90 | ast::Module(_it) => continue, |
95 | 91 | ||
96 | ast::Path(p) => { | 92 | ast::Path(p) => { |
97 | match maybe_replace_path(rewriter, &p, path) { | 93 | match maybe_replace_path(rewriter, p.clone(), path.clone()) { |
98 | Some(()) => {}, | 94 | Some(()) => {}, |
99 | None => shorten_paths(rewriter, p.syntax().clone(), path), | 95 | None => shorten_paths(rewriter, p.syntax().clone(), path.clone()), |
100 | } | 96 | } |
101 | }, | 97 | }, |
102 | _ => shorten_paths(rewriter, child, path), | 98 | _ => shorten_paths(rewriter, child, path.clone()), |
103 | } | 99 | } |
104 | } | 100 | } |
105 | } | 101 | } |
106 | } | 102 | } |
107 | 103 | ||
108 | fn maybe_replace_path( | 104 | fn maybe_replace_path( |
109 | re: &mut SyntaxRewriter<'static>, | 105 | rewriter: &mut SyntaxRewriter<'static>, |
110 | p: &ast::Path, | 106 | path: ast::Path, |
111 | path: &ModPath, | 107 | target: ast::Path, |
112 | ) -> Option<()> { | 108 | ) -> Option<()> { |
113 | let hir_path = hir::Path::from_ast(p.clone())?; | 109 | if !path_eq(path.clone(), target.clone()) { |
114 | |||
115 | if hir_path.mod_path() != path { | ||
116 | return None; | 110 | return None; |
117 | } | 111 | } |
118 | 112 | ||
119 | // Replace path with its last "plain" segment. | 113 | // Shorten `path`, leaving only its last segment. |
120 | let mut mod_path = hir_path.mod_path().clone(); | 114 | if let Some(parent) = path.qualifier() { |
121 | let last = mod_path.segments.len() - 1; | 115 | rewriter.delete(parent.syntax()); |
122 | mod_path.segments.swap(0, last); | 116 | } |
123 | mod_path.segments.truncate(1); | 117 | if let Some(double_colon) = path.coloncolon_token() { |
124 | mod_path.kind = hir::PathKind::Plain; | 118 | rewriter.delete(&double_colon); |
125 | |||
126 | let mut new_path = crate::ast_transform::path_to_ast(mod_path); | ||
127 | |||
128 | let type_args = p.segment().and_then(|s| s.type_arg_list()); | ||
129 | if let Some(type_args) = type_args { | ||
130 | let last_segment = new_path.segment().unwrap(); | ||
131 | new_path = new_path.with_segment(last_segment.with_type_args(type_args)); | ||
132 | } | 119 | } |
133 | 120 | ||
134 | re.replace(p.syntax(), new_path.syntax()); | ||
135 | Some(()) | 121 | Some(()) |
136 | } | 122 | } |
137 | 123 | ||
124 | fn path_eq(lhs: ast::Path, rhs: ast::Path) -> bool { | ||
125 | let mut lhs_curr = lhs; | ||
126 | let mut rhs_curr = rhs; | ||
127 | loop { | ||
128 | match (lhs_curr.segment(), rhs_curr.segment()) { | ||
129 | (Some(lhs), Some(rhs)) if lhs.syntax().text() == rhs.syntax().text() => (), | ||
130 | _ => return false, | ||
131 | } | ||
132 | |||
133 | match (lhs_curr.qualifier(), rhs_curr.qualifier()) { | ||
134 | (Some(lhs), Some(rhs)) => { | ||
135 | lhs_curr = lhs; | ||
136 | rhs_curr = rhs; | ||
137 | } | ||
138 | (None, None) => return true, | ||
139 | _ => return false, | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
138 | #[cfg(test)] | 144 | #[cfg(test)] |
139 | mod tests { | 145 | mod tests { |
140 | use crate::tests::{check_assist, check_assist_not_applicable}; | 146 | use crate::tests::{check_assist, check_assist_not_applicable}; |