aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs66
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 @@
1use hir::{self, ModPath}; 1use hir;
2use ra_syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SmolStr, SyntaxNode}; 2use ra_syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SmolStr, SyntaxNode};
3 3
4use crate::{ 4use 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`.
86fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: &ModPath) { 82fn 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
108fn maybe_replace_path( 104fn 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
124fn 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)]
139mod tests { 145mod tests {
140 use crate::tests::{check_assist, check_assist_not_applicable}; 146 use crate::tests::{check_assist, check_assist_not_applicable};