diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-05-16 18:03:43 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-05-16 18:03:43 +0100 |
commit | 201dbbe6da180c47f2c866128f26a48378768bbc (patch) | |
tree | 6a8235bfb9867ed912236e7ebb67af118321061e | |
parent | 9df0a2336829c54fbbc57ee8c8585aff345d9e47 (diff) | |
parent | 1859df37fd6e308ea4304f69baae038ec09fe424 (diff) |
Merge #8854
8854: internal: use mutable syntax trees when filling fields r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r-- | crates/ide/src/diagnostics.rs | 6 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/fixes.rs | 7 | ||||
-rw-r--r-- | crates/syntax/src/ast/edit.rs | 100 | ||||
-rw-r--r-- | crates/syntax/src/ast/edit_in_place.rs | 40 |
4 files changed, 49 insertions, 104 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 273d8cfbb..d5fba6740 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -579,7 +579,7 @@ fn test_fn() { | |||
579 | struct TestStruct { one: i32, two: i64 } | 579 | struct TestStruct { one: i32, two: i64 } |
580 | 580 | ||
581 | fn test_fn() { | 581 | fn test_fn() { |
582 | let s = TestStruct { one: (), two: ()}; | 582 | let s = TestStruct { one: (), two: () }; |
583 | } | 583 | } |
584 | "#, | 584 | "#, |
585 | ); | 585 | ); |
@@ -599,7 +599,7 @@ impl TestStruct { | |||
599 | struct TestStruct { one: i32 } | 599 | struct TestStruct { one: i32 } |
600 | 600 | ||
601 | impl TestStruct { | 601 | impl TestStruct { |
602 | fn test_fn() { let s = Self { one: ()}; } | 602 | fn test_fn() { let s = Self { one: () }; } |
603 | } | 603 | } |
604 | "#, | 604 | "#, |
605 | ); | 605 | ); |
@@ -792,7 +792,7 @@ fn main() { | |||
792 | pub struct Foo { pub a: i32, pub b: i32 } | 792 | pub struct Foo { pub a: i32, pub b: i32 } |
793 | "#, | 793 | "#, |
794 | r#" | 794 | r#" |
795 | fn some(, b: ()) {} | 795 | fn some(, b: () ) {} |
796 | fn items() {} | 796 | fn items() {} |
797 | fn here() {} | 797 | fn here() {} |
798 | 798 | ||
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index 15821500f..695b59e27 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -100,11 +100,12 @@ impl DiagnosticWithFix for MissingFields { | |||
100 | let root = sema.db.parse_or_expand(self.file)?; | 100 | let root = sema.db.parse_or_expand(self.file)?; |
101 | let field_list_parent = self.field_list_parent.to_node(&root); | 101 | let field_list_parent = self.field_list_parent.to_node(&root); |
102 | let old_field_list = field_list_parent.record_expr_field_list()?; | 102 | let old_field_list = field_list_parent.record_expr_field_list()?; |
103 | let mut new_field_list = old_field_list.clone(); | 103 | let new_field_list = old_field_list.clone_for_update(); |
104 | for f in self.missed_fields.iter() { | 104 | for f in self.missed_fields.iter() { |
105 | let field = | 105 | let field = |
106 | make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit())); | 106 | make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit())) |
107 | new_field_list = new_field_list.append_field(&field); | 107 | .clone_for_update(); |
108 | new_field_list.add_field(field); | ||
108 | } | 109 | } |
109 | 110 | ||
110 | let edit = { | 111 | let edit = { |
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 5e6c1d44e..61952377f 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs | |||
@@ -10,12 +10,8 @@ use arrayvec::ArrayVec; | |||
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | algo, | 12 | algo, |
13 | ast::{ | 13 | ast::{self, make, AstNode}, |
14 | self, | 14 | ted, AstToken, InsertPosition, NodeOrToken, SyntaxElement, SyntaxKind, |
15 | make::{self, tokens}, | ||
16 | AstNode, | ||
17 | }, | ||
18 | ted, AstToken, Direction, InsertPosition, NodeOrToken, SmolStr, SyntaxElement, SyntaxKind, | ||
19 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, | 15 | SyntaxKind::{ATTR, COMMENT, WHITESPACE}, |
20 | SyntaxNode, SyntaxToken, T, | 16 | SyntaxNode, SyntaxToken, T, |
21 | }; | 17 | }; |
@@ -29,82 +25,6 @@ impl ast::BinExpr { | |||
29 | } | 25 | } |
30 | } | 26 | } |
31 | 27 | ||
32 | impl ast::RecordExprFieldList { | ||
33 | #[must_use] | ||
34 | pub fn append_field(&self, field: &ast::RecordExprField) -> ast::RecordExprFieldList { | ||
35 | self.insert_field(InsertPosition::Last, field) | ||
36 | } | ||
37 | |||
38 | #[must_use] | ||
39 | pub fn insert_field( | ||
40 | &self, | ||
41 | position: InsertPosition<&'_ ast::RecordExprField>, | ||
42 | field: &ast::RecordExprField, | ||
43 | ) -> ast::RecordExprFieldList { | ||
44 | let is_multiline = self.syntax().text().contains_char('\n'); | ||
45 | let ws; | ||
46 | let space = if is_multiline { | ||
47 | ws = tokens::WsBuilder::new(&format!( | ||
48 | "\n{} ", | ||
49 | leading_indent(self.syntax()).unwrap_or_default() | ||
50 | )); | ||
51 | ws.ws() | ||
52 | } else { | ||
53 | tokens::single_space() | ||
54 | }; | ||
55 | |||
56 | let mut to_insert: ArrayVec<SyntaxElement, 4> = ArrayVec::new(); | ||
57 | to_insert.push(space.into()); | ||
58 | to_insert.push(field.syntax().clone().into()); | ||
59 | to_insert.push(make::token(T![,]).into()); | ||
60 | |||
61 | macro_rules! after_l_curly { | ||
62 | () => {{ | ||
63 | let anchor = match self.l_curly_token() { | ||
64 | Some(it) => it.into(), | ||
65 | None => return self.clone(), | ||
66 | }; | ||
67 | InsertPosition::After(anchor) | ||
68 | }}; | ||
69 | } | ||
70 | |||
71 | macro_rules! after_field { | ||
72 | ($anchor:expr) => { | ||
73 | if let Some(comma) = $anchor | ||
74 | .syntax() | ||
75 | .siblings_with_tokens(Direction::Next) | ||
76 | .find(|it| it.kind() == T![,]) | ||
77 | { | ||
78 | InsertPosition::After(comma) | ||
79 | } else { | ||
80 | to_insert.insert(0, make::token(T![,]).into()); | ||
81 | InsertPosition::After($anchor.syntax().clone().into()) | ||
82 | } | ||
83 | }; | ||
84 | } | ||
85 | |||
86 | let position = match position { | ||
87 | InsertPosition::First => after_l_curly!(), | ||
88 | InsertPosition::Last => { | ||
89 | if !is_multiline { | ||
90 | // don't insert comma before curly | ||
91 | to_insert.pop(); | ||
92 | } | ||
93 | match self.fields().last() { | ||
94 | Some(it) => after_field!(it), | ||
95 | None => after_l_curly!(), | ||
96 | } | ||
97 | } | ||
98 | InsertPosition::Before(anchor) => { | ||
99 | InsertPosition::Before(anchor.syntax().clone().into()) | ||
100 | } | ||
101 | InsertPosition::After(anchor) => after_field!(anchor), | ||
102 | }; | ||
103 | |||
104 | self.insert_children(position, to_insert) | ||
105 | } | ||
106 | } | ||
107 | |||
108 | impl ast::Path { | 28 | impl ast::Path { |
109 | #[must_use] | 29 | #[must_use] |
110 | pub fn with_segment(&self, segment: ast::PathSegment) -> ast::Path { | 30 | pub fn with_segment(&self, segment: ast::PathSegment) -> ast::Path { |
@@ -308,22 +228,6 @@ impl IndentLevel { | |||
308 | } | 228 | } |
309 | } | 229 | } |
310 | 230 | ||
311 | // FIXME: replace usages with IndentLevel above | ||
312 | fn leading_indent(node: &SyntaxNode) -> Option<SmolStr> { | ||
313 | for token in prev_tokens(node.first_token()?) { | ||
314 | if let Some(ws) = ast::Whitespace::cast(token.clone()) { | ||
315 | let ws_text = ws.text(); | ||
316 | if let Some(pos) = ws_text.rfind('\n') { | ||
317 | return Some(ws_text[pos + 1..].into()); | ||
318 | } | ||
319 | } | ||
320 | if token.text().contains('\n') { | ||
321 | break; | ||
322 | } | ||
323 | } | ||
324 | None | ||
325 | } | ||
326 | |||
327 | fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> { | 231 | fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> { |
328 | iter::successors(Some(token), |token| token.prev_token()) | 232 | iter::successors(Some(token), |token| token.prev_token()) |
329 | } | 233 | } |
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index abab0269a..14624c682 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs | |||
@@ -368,6 +368,46 @@ impl ast::MatchArmList { | |||
368 | } | 368 | } |
369 | } | 369 | } |
370 | 370 | ||
371 | impl ast::RecordExprFieldList { | ||
372 | pub fn add_field(&self, field: ast::RecordExprField) { | ||
373 | let is_multiline = self.syntax().text().contains_char('\n'); | ||
374 | let whitespace = if is_multiline { | ||
375 | let indent = IndentLevel::from_node(self.syntax()) + 1; | ||
376 | make::tokens::whitespace(&format!("\n{}", indent)) | ||
377 | } else { | ||
378 | make::tokens::single_space() | ||
379 | }; | ||
380 | |||
381 | let position = match self.fields().last() { | ||
382 | Some(last_field) => { | ||
383 | let comma = match last_field | ||
384 | .syntax() | ||
385 | .siblings_with_tokens(Direction::Next) | ||
386 | .filter_map(|it| it.into_token()) | ||
387 | .find(|it| it.kind() == T![,]) | ||
388 | { | ||
389 | Some(it) => it, | ||
390 | None => { | ||
391 | let comma = ast::make::token(T![,]); | ||
392 | ted::insert(Position::after(last_field.syntax()), &comma); | ||
393 | comma | ||
394 | } | ||
395 | }; | ||
396 | Position::after(comma) | ||
397 | } | ||
398 | None => match self.l_curly_token() { | ||
399 | Some(it) => Position::after(it), | ||
400 | None => Position::last_child_of(self.syntax()), | ||
401 | }, | ||
402 | }; | ||
403 | |||
404 | ted::insert_all(position, vec![whitespace.into(), field.syntax().clone().into()]); | ||
405 | if is_multiline { | ||
406 | ted::insert(Position::after(field.syntax()), ast::make::token(T![,])); | ||
407 | } | ||
408 | } | ||
409 | } | ||
410 | |||
371 | fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> { | 411 | fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> { |
372 | let l = node | 412 | let l = node |
373 | .children_with_tokens() | 413 | .children_with_tokens() |