aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock4
-rw-r--r--crates/hir_def/src/nameres.rs17
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs2
-rw-r--r--crates/hir_def/src/resolver.rs18
-rw-r--r--crates/hir_ty/src/tests/regression.rs13
-rw-r--r--crates/ide_assists/src/handlers/merge_imports.rs49
-rw-r--r--crates/ide_assists/src/handlers/unmerge_use.rs30
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs4
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/ast/edit.rs46
-rw-r--r--crates/syntax/src/ast/edit_in_place.rs44
-rw-r--r--crates/syntax/src/ast/make.rs2
-rw-r--r--crates/syntax/src/ted.rs28
13 files changed, 166 insertions, 93 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9f013c275..19ee689cb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1324,9 +1324,9 @@ checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
1324 1324
1325[[package]] 1325[[package]]
1326name = "rowan" 1326name = "rowan"
1327version = "0.13.0-pre.2" 1327version = "0.13.0-pre.3"
1328source = "registry+https://github.com/rust-lang/crates.io-index" 1328source = "registry+https://github.com/rust-lang/crates.io-index"
1329checksum = "8f300be7fa17c3fa563d2bc6ab5b1a8d5163162f9111599eda4f86a563714724" 1329checksum = "77d315d6f2e33f294412faa47f41b56bdb3fce72c999d384b5e78c8d21551b13"
1330dependencies = [ 1330dependencies = [
1331 "countme", 1331 "countme",
1332 "hashbrown", 1332 "hashbrown",
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 0d3a0b54f..9e8e4e9ec 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -322,6 +322,23 @@ impl DefMap {
322 (res.resolved_def, res.segment_index) 322 (res.resolved_def, res.segment_index)
323 } 323 }
324 324
325 pub(crate) fn resolve_path_locally(
326 &self,
327 db: &dyn DefDatabase,
328 original_module: LocalModuleId,
329 path: &ModPath,
330 shadow: BuiltinShadowMode,
331 ) -> (PerNs, Option<usize>) {
332 let res = self.resolve_path_fp_with_macro_single(
333 db,
334 ResolveMode::Other,
335 original_module,
336 path,
337 shadow,
338 );
339 (res.resolved_def, res.segment_index)
340 }
341
325 /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module. 342 /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module.
326 /// 343 ///
327 /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns 344 /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index db459b1ed..60471937c 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -156,7 +156,7 @@ impl DefMap {
156 } 156 }
157 } 157 }
158 158
159 fn resolve_path_fp_with_macro_single( 159 pub(super) fn resolve_path_fp_with_macro_single(
160 &self, 160 &self,
161 db: &dyn DefDatabase, 161 db: &dyn DefDatabase,
162 mode: ResolveMode, 162 mode: ResolveMode,
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 04ea9c5d7..a73585ee7 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -548,7 +548,7 @@ impl ModuleItemMap {
548 path: &ModPath, 548 path: &ModPath,
549 ) -> Option<ResolveValueResult> { 549 ) -> Option<ResolveValueResult> {
550 let (module_def, idx) = 550 let (module_def, idx) =
551 self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other); 551 self.def_map.resolve_path_locally(db, self.module_id, &path, BuiltinShadowMode::Other);
552 match idx { 552 match idx {
553 None => { 553 None => {
554 let value = to_value_ns(module_def)?; 554 let value = to_value_ns(module_def)?;
@@ -578,7 +578,7 @@ impl ModuleItemMap {
578 path: &ModPath, 578 path: &ModPath,
579 ) -> Option<(TypeNs, Option<usize>)> { 579 ) -> Option<(TypeNs, Option<usize>)> {
580 let (module_def, idx) = 580 let (module_def, idx) =
581 self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other); 581 self.def_map.resolve_path_locally(db, self.module_id, &path, BuiltinShadowMode::Other);
582 let res = to_type_ns(module_def)?; 582 let res = to_type_ns(module_def)?;
583 Some((res, idx)) 583 Some((res, idx))
584 } 584 }
@@ -627,8 +627,18 @@ pub trait HasResolver: Copy {
627 627
628impl HasResolver for ModuleId { 628impl HasResolver for ModuleId {
629 fn resolver(self, db: &dyn DefDatabase) -> Resolver { 629 fn resolver(self, db: &dyn DefDatabase) -> Resolver {
630 let def_map = self.def_map(db); 630 let mut def_map = self.def_map(db);
631 Resolver::default().push_module_scope(def_map, self.local_id) 631 let mut modules = Vec::new();
632 modules.push((def_map.clone(), self.local_id));
633 while let Some(parent) = def_map.parent() {
634 def_map = parent.def_map(db);
635 modules.push((def_map.clone(), parent.local_id));
636 }
637 let mut resolver = Resolver::default();
638 for (def_map, module) in modules.into_iter().rev() {
639 resolver = resolver.push_module_scope(def_map, module);
640 }
641 resolver
632 } 642 }
633} 643}
634 644
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 69314e245..b69f86050 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -961,3 +961,16 @@ fn issue_6852() {
961 "#]], 961 "#]],
962 ); 962 );
963} 963}
964
965#[test]
966fn param_overrides_fn() {
967 check_types(
968 r#"
969 fn example(example: i32) {
970 fn f() {}
971 example;
972 //^^^^^^^ i32
973 }
974 "#,
975 )
976}
diff --git a/crates/ide_assists/src/handlers/merge_imports.rs b/crates/ide_assists/src/handlers/merge_imports.rs
index 7bd7e1e36..cfc472a32 100644
--- a/crates/ide_assists/src/handlers/merge_imports.rs
+++ b/crates/ide_assists/src/handlers/merge_imports.rs
@@ -1,8 +1,5 @@
1use ide_db::helpers::insert_use::{try_merge_imports, try_merge_trees, MergeBehavior}; 1use ide_db::helpers::insert_use::{try_merge_imports, try_merge_trees, MergeBehavior};
2use syntax::{ 2use syntax::{algo::neighbor, ast, ted, AstNode};
3 algo::{neighbor, SyntaxRewriter},
4 ast, AstNode,
5};
6 3
7use crate::{ 4use crate::{
8 assist_context::{AssistContext, Assists}, 5 assist_context::{AssistContext, Assists},
@@ -24,33 +21,29 @@ use crate::{
24// ``` 21// ```
25pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 22pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 let tree: ast::UseTree = ctx.find_node_at_offset()?; 23 let tree: ast::UseTree = ctx.find_node_at_offset()?;
27 let mut rewriter = SyntaxRewriter::default(); 24 let original_parent = tree.syntax().ancestors().last()?;
25
26 let tree = tree.clone_for_update();
27 let new_parent = tree.syntax().ancestors().last()?;
28
28 let mut offset = ctx.offset(); 29 let mut offset = ctx.offset();
29 30
31 let mut imports = None;
32 let mut uses = None;
30 if let Some(use_item) = tree.syntax().parent().and_then(ast::Use::cast) { 33 if let Some(use_item) = tree.syntax().parent().and_then(ast::Use::cast) {
31 let (merged, to_delete) = 34 let (merged, to_remove) =
32 next_prev().filter_map(|dir| neighbor(&use_item, dir)).find_map(|use_item2| { 35 next_prev().filter_map(|dir| neighbor(&use_item, dir)).find_map(|use_item2| {
33 try_merge_imports(&use_item, &use_item2, MergeBehavior::Full).zip(Some(use_item2)) 36 try_merge_imports(&use_item, &use_item2, MergeBehavior::Full).zip(Some(use_item2))
34 })?; 37 })?;
35 38
36 rewriter.replace_ast(&use_item, &merged); 39 imports = Some((use_item, merged, to_remove));
37 rewriter += to_delete.remove();
38
39 if to_delete.syntax().text_range().end() < offset {
40 offset -= to_delete.syntax().text_range().len();
41 }
42 } else { 40 } else {
43 let (merged, to_delete) = 41 let (merged, to_remove) =
44 next_prev().filter_map(|dir| neighbor(&tree, dir)).find_map(|use_tree| { 42 next_prev().filter_map(|dir| neighbor(&tree, dir)).find_map(|use_tree| {
45 try_merge_trees(&tree, &use_tree, MergeBehavior::Full).zip(Some(use_tree)) 43 try_merge_trees(&tree, &use_tree, MergeBehavior::Full).zip(Some(use_tree))
46 })?; 44 })?;
47 45
48 rewriter.replace_ast(&tree, &merged); 46 uses = Some((tree.clone(), merged, to_remove))
49 rewriter += to_delete.remove();
50
51 if to_delete.syntax().text_range().end() < offset {
52 offset -= to_delete.syntax().text_range().len();
53 }
54 }; 47 };
55 48
56 let target = tree.syntax().text_range(); 49 let target = tree.syntax().text_range();
@@ -59,7 +52,23 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()
59 "Merge imports", 52 "Merge imports",
60 target, 53 target,
61 |builder| { 54 |builder| {
62 builder.rewrite(rewriter); 55 if let Some((to_replace, replacement, to_remove)) = imports {
56 if to_remove.syntax().text_range().end() < offset {
57 offset -= to_remove.syntax().text_range().len();
58 }
59 ted::replace(to_replace.syntax().clone(), replacement.syntax().clone());
60 to_remove.remove();
61 }
62
63 if let Some((to_replace, replacement, to_remove)) = uses {
64 if to_remove.syntax().text_range().end() < offset {
65 offset -= to_remove.syntax().text_range().len();
66 }
67 ted::replace(to_replace.syntax().clone(), replacement.syntax().clone());
68 to_remove.remove()
69 }
70
71 builder.replace(original_parent.text_range(), new_parent.to_string())
63 }, 72 },
64 ) 73 )
65} 74}
diff --git a/crates/ide_assists/src/handlers/unmerge_use.rs b/crates/ide_assists/src/handlers/unmerge_use.rs
index 616af7c2e..8d271e056 100644
--- a/crates/ide_assists/src/handlers/unmerge_use.rs
+++ b/crates/ide_assists/src/handlers/unmerge_use.rs
@@ -1,6 +1,6 @@
1use syntax::{ 1use syntax::{
2 algo::SyntaxRewriter, 2 ast::{self, VisibilityOwner},
3 ast::{self, edit::AstNodeEdit, VisibilityOwner}, 3 ted::{self, Position},
4 AstNode, SyntaxKind, 4 AstNode, SyntaxKind,
5}; 5};
6 6
@@ -22,7 +22,7 @@ use crate::{
22// use std::fmt::Display; 22// use std::fmt::Display;
23// ``` 23// ```
24pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 24pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
25 let tree: ast::UseTree = ctx.find_node_at_offset()?; 25 let tree: ast::UseTree = ctx.find_node_at_offset::<ast::UseTree>()?.clone_for_update();
26 26
27 let tree_list = tree.syntax().parent().and_then(ast::UseTreeList::cast)?; 27 let tree_list = tree.syntax().parent().and_then(ast::UseTreeList::cast)?;
28 if tree_list.use_trees().count() < 2 { 28 if tree_list.use_trees().count() < 2 {
@@ -33,6 +33,9 @@ pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
33 let use_: ast::Use = tree_list.syntax().ancestors().find_map(ast::Use::cast)?; 33 let use_: ast::Use = tree_list.syntax().ancestors().find_map(ast::Use::cast)?;
34 let path = resolve_full_path(&tree)?; 34 let path = resolve_full_path(&tree)?;
35 35
36 let old_parent_range = use_.syntax().parent()?.text_range();
37 let new_parent = use_.syntax().parent()?;
38
36 let target = tree.syntax().text_range(); 39 let target = tree.syntax().text_range();
37 acc.add( 40 acc.add(
38 AssistId("unmerge_use", AssistKind::RefactorRewrite), 41 AssistId("unmerge_use", AssistKind::RefactorRewrite),
@@ -47,20 +50,13 @@ pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
47 tree.rename(), 50 tree.rename(),
48 tree.star_token().is_some(), 51 tree.star_token().is_some(),
49 ), 52 ),
50 ); 53 )
51 54 .clone_for_update();
52 let mut rewriter = SyntaxRewriter::default(); 55
53 rewriter += tree.remove(); 56 tree.remove();
54 rewriter.insert_after(use_.syntax(), &ast::make::tokens::single_newline()); 57 ted::insert(Position::after(use_.syntax()), new_use.syntax());
55 if let ident_level @ 1..=usize::MAX = use_.indent_level().0 as usize { 58
56 rewriter.insert_after( 59 builder.replace(old_parent_range, new_parent.to_string());
57 use_.syntax(),
58 &ast::make::tokens::whitespace(&" ".repeat(4 * ident_level)),
59 );
60 }
61 rewriter.insert_after(use_.syntax(), new_use.syntax());
62
63 builder.rewrite(rewriter);
64 }, 60 },
65 ) 61 )
66} 62}
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index 37acf95f0..20c195f82 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -213,7 +213,7 @@ pub fn try_merge_imports(
213 let lhs_tree = lhs.use_tree()?; 213 let lhs_tree = lhs.use_tree()?;
214 let rhs_tree = rhs.use_tree()?; 214 let rhs_tree = rhs.use_tree()?;
215 let merged = try_merge_trees(&lhs_tree, &rhs_tree, merge_behavior)?; 215 let merged = try_merge_trees(&lhs_tree, &rhs_tree, merge_behavior)?;
216 Some(lhs.with_use_tree(merged)) 216 Some(lhs.with_use_tree(merged).clone_for_update())
217} 217}
218 218
219pub fn try_merge_trees( 219pub fn try_merge_trees(
@@ -234,7 +234,7 @@ pub fn try_merge_trees(
234 } else { 234 } else {
235 (lhs.split_prefix(&lhs_prefix), rhs.split_prefix(&rhs_prefix)) 235 (lhs.split_prefix(&lhs_prefix), rhs.split_prefix(&rhs_prefix))
236 }; 236 };
237 recursive_merge(&lhs, &rhs, merge) 237 recursive_merge(&lhs, &rhs, merge).map(|it| it.clone_for_update())
238} 238}
239 239
240/// Recursively "zips" together lhs and rhs. 240/// Recursively "zips" together lhs and rhs.
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 74cafaa8d..0c3fec3c7 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
13[dependencies] 13[dependencies]
14cov-mark = { version = "1.1", features = ["thread-local"] } 14cov-mark = { version = "1.1", features = ["thread-local"] }
15itertools = "0.10.0" 15itertools = "0.10.0"
16rowan = "0.13.0-pre.2" 16rowan = "0.13.0-pre.3"
17rustc_lexer = { version = "710.0.0", package = "rustc-ap-rustc_lexer" } 17rustc_lexer = { version = "710.0.0", package = "rustc-ap-rustc_lexer" }
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19arrayvec = "0.5.1" 19arrayvec = "0.5.1"
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index 347862b8a..18820786a 100644
--- a/crates/syntax/src/ast/edit.rs
+++ b/crates/syntax/src/ast/edit.rs
@@ -9,7 +9,7 @@ use std::{
9use arrayvec::ArrayVec; 9use arrayvec::ArrayVec;
10 10
11use crate::{ 11use crate::{
12 algo::{self, neighbor, SyntaxRewriter}, 12 algo::{self, SyntaxRewriter},
13 ast::{ 13 ast::{
14 self, 14 self,
15 make::{self, tokens}, 15 make::{self, tokens},
@@ -322,27 +322,6 @@ impl ast::Use {
322 } 322 }
323 self.clone() 323 self.clone()
324 } 324 }
325
326 pub fn remove(&self) -> SyntaxRewriter<'static> {
327 let mut res = SyntaxRewriter::default();
328 res.delete(self.syntax());
329 let next_ws = self
330 .syntax()
331 .next_sibling_or_token()
332 .and_then(|it| it.into_token())
333 .and_then(ast::Whitespace::cast);
334 if let Some(next_ws) = next_ws {
335 let ws_text = next_ws.syntax().text();
336 if let Some(rest) = ws_text.strip_prefix('\n') {
337 if rest.is_empty() {
338 res.delete(next_ws.syntax())
339 } else {
340 res.replace(next_ws.syntax(), &make::tokens::whitespace(rest));
341 }
342 }
343 }
344 res
345 }
346} 325}
347 326
348impl ast::UseTree { 327impl ast::UseTree {
@@ -396,22 +375,6 @@ impl ast::UseTree {
396 Some(res) 375 Some(res)
397 } 376 }
398 } 377 }
399
400 pub fn remove(&self) -> SyntaxRewriter<'static> {
401 let mut res = SyntaxRewriter::default();
402 res.delete(self.syntax());
403 for &dir in [Direction::Next, Direction::Prev].iter() {
404 if let Some(nb) = neighbor(self, dir) {
405 self.syntax()
406 .siblings_with_tokens(dir)
407 .skip(1)
408 .take_while(|it| it.as_node() != Some(nb.syntax()))
409 .for_each(|el| res.delete(&el));
410 return res;
411 }
412 }
413 res
414 }
415} 378}
416 379
417impl ast::MatchArmList { 380impl ast::MatchArmList {
@@ -592,6 +555,13 @@ impl ops::Add<u8> for IndentLevel {
592} 555}
593 556
594impl IndentLevel { 557impl IndentLevel {
558 pub fn from_element(element: &SyntaxElement) -> IndentLevel {
559 match element {
560 rowan::NodeOrToken::Node(it) => IndentLevel::from_node(it),
561 rowan::NodeOrToken::Token(it) => IndentLevel::from_token(it),
562 }
563 }
564
595 pub fn from_node(node: &SyntaxNode) -> IndentLevel { 565 pub fn from_node(node: &SyntaxNode) -> IndentLevel {
596 match node.first_token() { 566 match node.first_token() {
597 Some(it) => Self::from_token(&it), 567 Some(it) => Self::from_token(&it),
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index b1eed0a2c..529bd0eb1 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -2,13 +2,13 @@
2 2
3use std::iter::empty; 3use std::iter::empty;
4 4
5use ast::{edit::AstNodeEdit, make, GenericParamsOwner, WhereClause};
6use parser::T; 5use parser::T;
7 6
8use crate::{ 7use crate::{
9 ast, 8 algo::neighbor,
9 ast::{self, edit::AstNodeEdit, make, GenericParamsOwner, WhereClause},
10 ted::{self, Position}, 10 ted::{self, Position},
11 AstNode, Direction, 11 AstNode, AstToken, Direction,
12}; 12};
13 13
14use super::NameOwner; 14use super::NameOwner;
@@ -126,3 +126,41 @@ impl ast::TypeBoundList {
126 } 126 }
127 } 127 }
128} 128}
129
130impl ast::UseTree {
131 pub fn remove(&self) {
132 for &dir in [Direction::Next, Direction::Prev].iter() {
133 if let Some(next_use_tree) = neighbor(self, dir) {
134 let separators = self
135 .syntax()
136 .siblings_with_tokens(dir)
137 .skip(1)
138 .take_while(|it| it.as_node() != Some(next_use_tree.syntax()));
139 ted::remove_all_iter(separators);
140 break;
141 }
142 }
143 ted::remove(self.syntax())
144 }
145}
146
147impl ast::Use {
148 pub fn remove(&self) {
149 let next_ws = self
150 .syntax()
151 .next_sibling_or_token()
152 .and_then(|it| it.into_token())
153 .and_then(ast::Whitespace::cast);
154 if let Some(next_ws) = next_ws {
155 let ws_text = next_ws.syntax().text();
156 if let Some(rest) = ws_text.strip_prefix('\n') {
157 if rest.is_empty() {
158 ted::remove(next_ws.syntax())
159 } else {
160 ted::replace(next_ws.syntax(), make::tokens::whitespace(rest))
161 }
162 }
163 }
164 ted::remove(self.syntax())
165 }
166}
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 7049affd9..c08f2c14f 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -560,7 +560,7 @@ pub mod tokens {
560 pub fn whitespace(text: &str) -> SyntaxToken { 560 pub fn whitespace(text: &str) -> SyntaxToken {
561 assert!(text.trim().is_empty()); 561 assert!(text.trim().is_empty());
562 let sf = SourceFile::parse(text).ok().unwrap(); 562 let sf = SourceFile::parse(text).ok().unwrap();
563 sf.syntax().first_child_or_token().unwrap().into_token().unwrap() 563 sf.syntax().clone_for_update().first_child_or_token().unwrap().into_token().unwrap()
564 } 564 }
565 565
566 pub fn doc_comment(text: &str) -> SyntaxToken { 566 pub fn doc_comment(text: &str) -> SyntaxToken {
diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs
index be2b846b1..177d4ff67 100644
--- a/crates/syntax/src/ted.rs
+++ b/crates/syntax/src/ted.rs
@@ -2,11 +2,14 @@
2//! 2//!
3//! The `_raw`-suffixed functions insert elements as is, unsuffixed versions fix 3//! The `_raw`-suffixed functions insert elements as is, unsuffixed versions fix
4//! up elements around the edges. 4//! up elements around the edges.
5use std::ops::RangeInclusive; 5use std::{mem, ops::RangeInclusive};
6 6
7use parser::T; 7use parser::T;
8 8
9use crate::{ast::make, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken}; 9use crate::{
10 ast::{edit::IndentLevel, make},
11 SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken,
12};
10 13
11/// Utility trait to allow calling `ted` functions with references or owned 14/// Utility trait to allow calling `ted` functions with references or owned
12/// nodes. Do not use outside of this module. 15/// nodes. Do not use outside of this module.
@@ -101,12 +104,25 @@ pub fn insert_all_raw(position: Position, elements: Vec<SyntaxElement>) {
101} 104}
102 105
103pub fn remove(elem: impl Element) { 106pub fn remove(elem: impl Element) {
104 let elem = elem.syntax_element(); 107 elem.syntax_element().detach()
105 remove_all(elem.clone()..=elem)
106} 108}
107pub fn remove_all(range: RangeInclusive<SyntaxElement>) { 109pub fn remove_all(range: RangeInclusive<SyntaxElement>) {
108 replace_all(range, Vec::new()) 110 replace_all(range, Vec::new())
109} 111}
112pub fn remove_all_iter(range: impl IntoIterator<Item = SyntaxElement>) {
113 let mut it = range.into_iter();
114 if let Some(mut first) = it.next() {
115 match it.last() {
116 Some(mut last) => {
117 if first.index() > last.index() {
118 mem::swap(&mut first, &mut last)
119 }
120 remove_all(first..=last)
121 }
122 None => remove(first),
123 }
124 }
125}
110 126
111pub fn replace(old: impl Element, new: impl Element) { 127pub fn replace(old: impl Element, new: impl Element) {
112 let old = old.syntax_element(); 128 let old = old.syntax_element();
@@ -149,5 +165,9 @@ fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option<SyntaxToken
149 if right.kind() == T![;] || right.kind() == T![,] { 165 if right.kind() == T![;] || right.kind() == T![,] {
150 return None; 166 return None;
151 } 167 }
168 if right.kind() == SyntaxKind::USE {
169 let indent = IndentLevel::from_element(left);
170 return Some(make::tokens::whitespace(&format!("\n{}", indent)));
171 }
152 Some(make::tokens::single_space()) 172 Some(make::tokens::single_space())
153} 173}