diff options
-rw-r--r-- | Cargo.lock | 4 | ||||
-rw-r--r-- | crates/hir_def/src/nameres.rs | 17 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/path_resolution.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/resolver.rs | 18 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/regression.rs | 13 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/merge_imports.rs | 49 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/unmerge_use.rs | 30 | ||||
-rw-r--r-- | crates/ide_db/src/helpers/insert_use.rs | 4 | ||||
-rw-r--r-- | crates/syntax/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/syntax/src/ast/edit.rs | 46 | ||||
-rw-r--r-- | crates/syntax/src/ast/edit_in_place.rs | 44 | ||||
-rw-r--r-- | crates/syntax/src/ast/make.rs | 2 | ||||
-rw-r--r-- | crates/syntax/src/ted.rs | 28 |
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]] |
1326 | name = "rowan" | 1326 | name = "rowan" |
1327 | version = "0.13.0-pre.2" | 1327 | version = "0.13.0-pre.3" |
1328 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1329 | checksum = "8f300be7fa17c3fa563d2bc6ab5b1a8d5163162f9111599eda4f86a563714724" | 1329 | checksum = "77d315d6f2e33f294412faa47f41b56bdb3fce72c999d384b5e78c8d21551b13" |
1330 | dependencies = [ | 1330 | dependencies = [ |
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 | ||
628 | impl HasResolver for ModuleId { | 628 | impl 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] | ||
966 | fn 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 @@ | |||
1 | use ide_db::helpers::insert_use::{try_merge_imports, try_merge_trees, MergeBehavior}; | 1 | use ide_db::helpers::insert_use::{try_merge_imports, try_merge_trees, MergeBehavior}; |
2 | use syntax::{ | 2 | use syntax::{algo::neighbor, ast, ted, AstNode}; |
3 | algo::{neighbor, SyntaxRewriter}, | ||
4 | ast, AstNode, | ||
5 | }; | ||
6 | 3 | ||
7 | use crate::{ | 4 | use crate::{ |
8 | assist_context::{AssistContext, Assists}, | 5 | assist_context::{AssistContext, Assists}, |
@@ -24,33 +21,29 @@ use crate::{ | |||
24 | // ``` | 21 | // ``` |
25 | pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 22 | pub(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 @@ | |||
1 | use syntax::{ | 1 | use 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 | // ``` |
24 | pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 24 | pub(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 | ||
219 | pub fn try_merge_trees( | 219 | pub 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] |
14 | cov-mark = { version = "1.1", features = ["thread-local"] } | 14 | cov-mark = { version = "1.1", features = ["thread-local"] } |
15 | itertools = "0.10.0" | 15 | itertools = "0.10.0" |
16 | rowan = "0.13.0-pre.2" | 16 | rowan = "0.13.0-pre.3" |
17 | rustc_lexer = { version = "710.0.0", package = "rustc-ap-rustc_lexer" } | 17 | rustc_lexer = { version = "710.0.0", package = "rustc-ap-rustc_lexer" } |
18 | rustc-hash = "1.1.0" | 18 | rustc-hash = "1.1.0" |
19 | arrayvec = "0.5.1" | 19 | arrayvec = "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::{ | |||
9 | use arrayvec::ArrayVec; | 9 | use arrayvec::ArrayVec; |
10 | 10 | ||
11 | use crate::{ | 11 | use 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 | ||
348 | impl ast::UseTree { | 327 | impl 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 | ||
417 | impl ast::MatchArmList { | 380 | impl ast::MatchArmList { |
@@ -592,6 +555,13 @@ impl ops::Add<u8> for IndentLevel { | |||
592 | } | 555 | } |
593 | 556 | ||
594 | impl IndentLevel { | 557 | impl 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 | ||
3 | use std::iter::empty; | 3 | use std::iter::empty; |
4 | 4 | ||
5 | use ast::{edit::AstNodeEdit, make, GenericParamsOwner, WhereClause}; | ||
6 | use parser::T; | 5 | use parser::T; |
7 | 6 | ||
8 | use crate::{ | 7 | use 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 | ||
14 | use super::NameOwner; | 14 | use super::NameOwner; |
@@ -126,3 +126,41 @@ impl ast::TypeBoundList { | |||
126 | } | 126 | } |
127 | } | 127 | } |
128 | } | 128 | } |
129 | |||
130 | impl 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 | |||
147 | impl 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. |
5 | use std::ops::RangeInclusive; | 5 | use std::{mem, ops::RangeInclusive}; |
6 | 6 | ||
7 | use parser::T; | 7 | use parser::T; |
8 | 8 | ||
9 | use crate::{ast::make, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken}; | 9 | use 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 | ||
103 | pub fn remove(elem: impl Element) { | 106 | pub fn remove(elem: impl Element) { |
104 | let elem = elem.syntax_element(); | 107 | elem.syntax_element().detach() |
105 | remove_all(elem.clone()..=elem) | ||
106 | } | 108 | } |
107 | pub fn remove_all(range: RangeInclusive<SyntaxElement>) { | 109 | pub fn remove_all(range: RangeInclusive<SyntaxElement>) { |
108 | replace_all(range, Vec::new()) | 110 | replace_all(range, Vec::new()) |
109 | } | 111 | } |
112 | pub 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 | ||
111 | pub fn replace(old: impl Element, new: impl Element) { | 127 | pub 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 | } |