aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/assists/src/handlers/auto_import.rs8
-rw-r--r--crates/assists/src/handlers/expand_glob_import.rs8
-rw-r--r--crates/assists/src/handlers/extract_struct_from_enum_variant.rs7
-rw-r--r--crates/assists/src/handlers/replace_qualified_name_with_use.rs26
-rw-r--r--crates/hir_def/src/path.rs26
-rw-r--r--crates/syntax/src/ast/make.rs33
6 files changed, 61 insertions, 47 deletions
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs
index ee7277c04..fa524ffd9 100644
--- a/crates/assists/src/handlers/auto_import.rs
+++ b/crates/assists/src/handlers/auto_import.rs
@@ -1,6 +1,5 @@
1use std::collections::BTreeSet; 1use std::collections::BTreeSet;
2 2
3use ast::make;
4use either::Either; 3use either::Either;
5use hir::{ 4use hir::{
6 AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait, 5 AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait,
@@ -54,11 +53,8 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
54 format!("Import `{}`", &import), 53 format!("Import `{}`", &import),
55 range, 54 range,
56 |builder| { 55 |builder| {
57 let new_syntax = insert_use( 56 let new_syntax =
58 &scope, 57 insert_use(&scope, import.to_ast_path(), ctx.config.insert_use.merge);
59 make::path_from_text(&import.to_string()),
60 ctx.config.insert_use.merge,
61 );
62 builder.replace(syntax.text_range(), new_syntax.to_string()) 58 builder.replace(syntax.text_range(), new_syntax.to_string())
63 }, 59 },
64 ); 60 );
diff --git a/crates/assists/src/handlers/expand_glob_import.rs b/crates/assists/src/handlers/expand_glob_import.rs
index e14ac7f65..d1adff972 100644
--- a/crates/assists/src/handlers/expand_glob_import.rs
+++ b/crates/assists/src/handlers/expand_glob_import.rs
@@ -264,12 +264,8 @@ fn replace_ast(
264 match use_trees.as_slice() { 264 match use_trees.as_slice() {
265 [name] => { 265 [name] => {
266 if let Some(end_path) = name.path() { 266 if let Some(end_path) = name.path() {
267 let replacement = make::use_tree( 267 let replacement =
268 make::path_from_text(&format!("{}::{}", path, end_path)), 268 make::use_tree(make::path_concat(path, end_path), None, None, false);
269 None,
270 None,
271 false,
272 );
273 269
274 algo::diff( 270 algo::diff(
275 &parent.either(|n| n.syntax().clone(), |n| n.syntax().clone()), 271 &parent.either(|n| n.syntax().clone(), |n| n.syntax().clone()),
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
index 3ea50f375..d1eadaa99 100644
--- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -12,7 +12,6 @@ use syntax::{
12use crate::{ 12use crate::{
13 assist_context::AssistBuilder, utils::insert_use, AssistContext, AssistId, AssistKind, Assists, 13 assist_context::AssistBuilder, utils::insert_use, AssistContext, AssistId, AssistKind, Assists,
14}; 14};
15use ast::make;
16use insert_use::ImportScope; 15use insert_use::ImportScope;
17 16
18// Assist: extract_struct_from_enum_variant 17// Assist: extract_struct_from_enum_variant
@@ -112,11 +111,7 @@ fn insert_import(
112 let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?; 111 let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?;
113 let syntax = scope.as_syntax_node(); 112 let syntax = scope.as_syntax_node();
114 113
115 let new_syntax = insert_use( 114 let new_syntax = insert_use(&scope, mod_path.to_ast_path(), ctx.config.insert_use.merge);
116 &scope,
117 make::path_from_text(&mod_path.to_string()),
118 ctx.config.insert_use.merge,
119 );
120 // FIXME: this will currently panic as multiple imports will have overlapping text ranges 115 // FIXME: this will currently panic as multiple imports will have overlapping text ranges
121 builder.replace(syntax.text_range(), new_syntax.to_string()) 116 builder.replace(syntax.text_range(), new_syntax.to_string())
122 } 117 }
diff --git a/crates/assists/src/handlers/replace_qualified_name_with_use.rs b/crates/assists/src/handlers/replace_qualified_name_with_use.rs
index 8ac907707..74afc123b 100644
--- a/crates/assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/assists/src/handlers/replace_qualified_name_with_use.rs
@@ -1,11 +1,10 @@
1use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode, TextRange}; 1use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode};
2use test_utils::mark; 2use test_utils::mark;
3 3
4use crate::{ 4use crate::{
5 utils::{insert_use, ImportScope}, 5 utils::{insert_use, ImportScope},
6 AssistContext, AssistId, AssistKind, Assists, 6 AssistContext, AssistId, AssistKind, Assists,
7}; 7};
8use ast::make;
9 8
10// Assist: replace_qualified_name_with_use 9// Assist: replace_qualified_name_with_use
11// 10//
@@ -33,15 +32,6 @@ pub(crate) fn replace_qualified_name_with_use(
33 mark::hit!(dont_import_trivial_paths); 32 mark::hit!(dont_import_trivial_paths);
34 return None; 33 return None;
35 } 34 }
36 let path_to_import = path.to_string();
37 let path_to_import = match path.segment()?.generic_arg_list() {
38 Some(generic_args) => {
39 let generic_args_start =
40 generic_args.syntax().text_range().start() - path.syntax().text_range().start();
41 &path_to_import[TextRange::up_to(generic_args_start)]
42 }
43 None => path_to_import.as_str(),
44 };
45 35
46 let target = path.syntax().text_range(); 36 let target = path.syntax().text_range();
47 let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?; 37 let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?;
@@ -54,14 +44,10 @@ pub(crate) fn replace_qualified_name_with_use(
54 // Now that we've brought the name into scope, re-qualify all paths that could be 44 // Now that we've brought the name into scope, re-qualify all paths that could be
55 // affected (that is, all paths inside the node we added the `use` to). 45 // affected (that is, all paths inside the node we added the `use` to).
56 let mut rewriter = SyntaxRewriter::default(); 46 let mut rewriter = SyntaxRewriter::default();
57 shorten_paths(&mut rewriter, syntax.clone(), path); 47 shorten_paths(&mut rewriter, syntax.clone(), &path);
58 let rewritten_syntax = rewriter.rewrite(&syntax); 48 let rewritten_syntax = rewriter.rewrite(&syntax);
59 if let Some(ref import_scope) = ImportScope::from(rewritten_syntax) { 49 if let Some(ref import_scope) = ImportScope::from(rewritten_syntax) {
60 let new_syntax = insert_use( 50 let new_syntax = insert_use(import_scope, path, ctx.config.insert_use.merge);
61 import_scope,
62 make::path_from_text(path_to_import),
63 ctx.config.insert_use.merge,
64 );
65 builder.replace(syntax.text_range(), new_syntax.to_string()) 51 builder.replace(syntax.text_range(), new_syntax.to_string())
66 } 52 }
67 }, 53 },
@@ -69,7 +55,7 @@ pub(crate) fn replace_qualified_name_with_use(
69} 55}
70 56
71/// Adds replacements to `re` that shorten `path` in all descendants of `node`. 57/// Adds replacements to `re` that shorten `path` in all descendants of `node`.
72fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: ast::Path) { 58fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: &ast::Path) {
73 for child in node.children() { 59 for child in node.children() {
74 match_ast! { 60 match_ast! {
75 match child { 61 match child {
@@ -82,10 +68,10 @@ fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path:
82 ast::Path(p) => { 68 ast::Path(p) => {
83 match maybe_replace_path(rewriter, p.clone(), path.clone()) { 69 match maybe_replace_path(rewriter, p.clone(), path.clone()) {
84 Some(()) => {}, 70 Some(()) => {},
85 None => shorten_paths(rewriter, p.syntax().clone(), path.clone()), 71 None => shorten_paths(rewriter, p.syntax().clone(), path),
86 } 72 }
87 }, 73 },
88 _ => shorten_paths(rewriter, child, path.clone()), 74 _ => shorten_paths(rewriter, child, path),
89 } 75 }
90 } 76 }
91 } 77 }
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 734310458..209b18e78 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -13,7 +13,7 @@ use hir_expand::{
13 hygiene::Hygiene, 13 hygiene::Hygiene,
14 name::{AsName, Name}, 14 name::{AsName, Name},
15}; 15};
16use syntax::ast; 16use syntax::ast::{self, make};
17 17
18use crate::{ 18use crate::{
19 type_ref::{TypeBound, TypeRef}, 19 type_ref::{TypeBound, TypeRef},
@@ -100,6 +100,26 @@ impl ModPath {
100 } 100 }
101 self.segments.first() 101 self.segments.first()
102 } 102 }
103
104 pub fn to_ast_path(&self) -> ast::Path {
105 let mut segments = Vec::new();
106 let mut is_abs = false;
107 match self.kind {
108 PathKind::Plain => {}
109 PathKind::Super(0) => segments.push(make::path_segment_self()),
110 PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())),
111 PathKind::Crate => segments.push(make::path_segment_crate()),
112 PathKind::Abs => is_abs = true,
113 PathKind::DollarCrate(_) => (),
114 }
115
116 segments.extend(
117 self.segments
118 .iter()
119 .map(|segment| make::path_segment(make::name_ref(&segment.to_string()))),
120 );
121 make::path_from_segments(segments, is_abs)
122 }
103} 123}
104 124
105#[derive(Debug, Clone, PartialEq, Eq, Hash)] 125#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -286,10 +306,8 @@ impl Display for ModPath {
286 }; 306 };
287 match self.kind { 307 match self.kind {
288 PathKind::Plain => {} 308 PathKind::Plain => {}
309 PathKind::Super(0) => add_segment("self")?,
289 PathKind::Super(n) => { 310 PathKind::Super(n) => {
290 if n == 0 {
291 add_segment("self")?;
292 }
293 for _ in 0..n { 311 for _ in 0..n {
294 add_segment("super")?; 312 add_segment("super")?;
295 } 313 }
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 4a0ffcbb0..3a184094c 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -28,18 +28,41 @@ pub fn assoc_item_list() -> ast::AssocItemList {
28pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment { 28pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
29 ast_from_text(&format!("use {};", name_ref)) 29 ast_from_text(&format!("use {};", name_ref))
30} 30}
31
31pub fn path_segment_self() -> ast::PathSegment { 32pub fn path_segment_self() -> ast::PathSegment {
32 ast_from_text("use self;") 33 ast_from_text("use self;")
33} 34}
35
36pub fn path_segment_super() -> ast::PathSegment {
37 ast_from_text("use super;")
38}
39
40pub fn path_segment_crate() -> ast::PathSegment {
41 ast_from_text("use crate;")
42}
43
34pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path { 44pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path {
35 path_from_text(&format!("use {}", segment)) 45 ast_from_text(&format!("use {}", segment))
36} 46}
47
37pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { 48pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path {
38 path_from_text(&format!("{}::{}", qual, segment)) 49 ast_from_text(&format!("{}::{}", qual, segment))
39} 50}
40// FIXME: make this private 51
41pub fn path_from_text(text: &str) -> ast::Path { 52pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path {
42 ast_from_text(text) 53 ast_from_text(&format!("{}::{}", first, second))
54}
55
56pub fn path_from_segments(
57 segments: impl IntoIterator<Item = ast::PathSegment>,
58 is_abs: bool,
59) -> ast::Path {
60 let segments = segments.into_iter().map(|it| it.syntax().clone()).join("::");
61 ast_from_text(&if is_abs {
62 format!("use ::{};", segments)
63 } else {
64 format!("use {};", segments)
65 })
43} 66}
44 67
45pub fn glob_use_tree() -> ast::UseTree { 68pub fn glob_use_tree() -> ast::UseTree {