aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax
diff options
context:
space:
mode:
Diffstat (limited to 'crates/syntax')
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/algo.rs4
-rw-r--r--crates/syntax/src/ast/edit.rs52
-rw-r--r--crates/syntax/src/ast/edit_in_place.rs44
-rw-r--r--crates/syntax/src/ast/expr_ext.rs44
-rw-r--r--crates/syntax/src/ast/make.rs4
-rw-r--r--crates/syntax/src/ast/node_ext.rs28
-rw-r--r--crates/syntax/src/ast/token_ext.rs10
-rw-r--r--crates/syntax/src/fuzz.rs2
-rw-r--r--crates/syntax/src/ted.rs28
-rw-r--r--crates/syntax/src/validation.rs4
11 files changed, 123 insertions, 99 deletions
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/algo.rs b/crates/syntax/src/algo.rs
index 82ebf9037..a153a9e1c 100644
--- a/crates/syntax/src/algo.rs
+++ b/crates/syntax/src/algo.rs
@@ -567,7 +567,7 @@ impl<'a> SyntaxRewriter<'a> {
567 567
568fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { 568fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> {
569 match element { 569 match element {
570 NodeOrToken::Node(it) => NodeOrToken::Node(it.green().to_owned()), 570 NodeOrToken::Node(it) => NodeOrToken::Node(it.green()),
571 NodeOrToken::Token(it) => NodeOrToken::Token(it.green().to_owned()), 571 NodeOrToken::Token(it) => NodeOrToken::Token(it.green().to_owned()),
572 } 572 }
573} 573}
@@ -625,7 +625,7 @@ fn position_of_child(parent: &SyntaxNode, child: SyntaxElement) -> usize {
625 625
626fn to_green_element(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { 626fn to_green_element(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> {
627 match element { 627 match element {
628 NodeOrToken::Node(it) => it.green().to_owned().into(), 628 NodeOrToken::Node(it) => it.green().into(),
629 NodeOrToken::Token(it) => it.green().to_owned().into(), 629 NodeOrToken::Token(it) => it.green().to_owned().into(),
630 } 630 }
631} 631}
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index 64fac13a7..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,28 +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 ws_text.starts_with('\n') {
337 let rest = &ws_text[1..];
338 if rest.is_empty() {
339 res.delete(next_ws.syntax())
340 } else {
341 res.replace(next_ws.syntax(), &make::tokens::whitespace(rest));
342 }
343 }
344 }
345 res
346 }
347} 325}
348 326
349impl ast::UseTree { 327impl ast::UseTree {
@@ -397,22 +375,6 @@ impl ast::UseTree {
397 Some(res) 375 Some(res)
398 } 376 }
399 } 377 }
400
401 pub fn remove(&self) -> SyntaxRewriter<'static> {
402 let mut res = SyntaxRewriter::default();
403 res.delete(self.syntax());
404 for &dir in [Direction::Next, Direction::Prev].iter() {
405 if let Some(nb) = neighbor(self, dir) {
406 self.syntax()
407 .siblings_with_tokens(dir)
408 .skip(1)
409 .take_while(|it| it.as_node() != Some(nb.syntax()))
410 .for_each(|el| res.delete(&el));
411 return res;
412 }
413 }
414 res
415 }
416} 378}
417 379
418impl ast::MatchArmList { 380impl ast::MatchArmList {
@@ -462,8 +424,7 @@ impl ast::MatchArmList {
462 let end = if let Some(comma) = start 424 let end = if let Some(comma) = start
463 .siblings_with_tokens(Direction::Next) 425 .siblings_with_tokens(Direction::Next)
464 .skip(1) 426 .skip(1)
465 .skip_while(|it| it.kind().is_trivia()) 427 .find(|it| !it.kind().is_trivia())
466 .next()
467 .filter(|it| it.kind() == T![,]) 428 .filter(|it| it.kind() == T![,])
468 { 429 {
469 comma 430 comma
@@ -594,10 +555,17 @@ impl ops::Add<u8> for IndentLevel {
594} 555}
595 556
596impl 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
597 pub fn from_node(node: &SyntaxNode) -> IndentLevel { 565 pub fn from_node(node: &SyntaxNode) -> IndentLevel {
598 match node.first_token() { 566 match node.first_token() {
599 Some(it) => Self::from_token(&it), 567 Some(it) => Self::from_token(&it),
600 None => return IndentLevel(0), 568 None => IndentLevel(0),
601 } 569 }
602 } 570 }
603 571
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/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs
index 636ce166d..6317d84ba 100644
--- a/crates/syntax/src/ast/expr_ext.rs
+++ b/crates/syntax/src/ast/expr_ext.rs
@@ -11,16 +11,16 @@ impl ast::AttrsOwner for ast::Expr {}
11 11
12impl ast::Expr { 12impl ast::Expr {
13 pub fn is_block_like(&self) -> bool { 13 pub fn is_block_like(&self) -> bool {
14 match self { 14 matches!(
15 self,
15 ast::Expr::IfExpr(_) 16 ast::Expr::IfExpr(_)
16 | ast::Expr::LoopExpr(_) 17 | ast::Expr::LoopExpr(_)
17 | ast::Expr::ForExpr(_) 18 | ast::Expr::ForExpr(_)
18 | ast::Expr::WhileExpr(_) 19 | ast::Expr::WhileExpr(_)
19 | ast::Expr::BlockExpr(_) 20 | ast::Expr::BlockExpr(_)
20 | ast::Expr::MatchExpr(_) 21 | ast::Expr::MatchExpr(_)
21 | ast::Expr::EffectExpr(_) => true, 22 | ast::Expr::EffectExpr(_)
22 _ => false, 23 )
23 }
24 } 24 }
25 25
26 pub fn name_ref(&self) -> Option<ast::NameRef> { 26 pub fn name_ref(&self) -> Option<ast::NameRef> {
@@ -151,20 +151,20 @@ pub enum BinOp {
151 151
152impl BinOp { 152impl BinOp {
153 pub fn is_assignment(self) -> bool { 153 pub fn is_assignment(self) -> bool {
154 match self { 154 matches!(
155 self,
155 BinOp::Assignment 156 BinOp::Assignment
156 | BinOp::AddAssign 157 | BinOp::AddAssign
157 | BinOp::DivAssign 158 | BinOp::DivAssign
158 | BinOp::MulAssign 159 | BinOp::MulAssign
159 | BinOp::RemAssign 160 | BinOp::RemAssign
160 | BinOp::ShrAssign 161 | BinOp::ShrAssign
161 | BinOp::ShlAssign 162 | BinOp::ShlAssign
162 | BinOp::SubAssign 163 | BinOp::SubAssign
163 | BinOp::BitOrAssign 164 | BinOp::BitOrAssign
164 | BinOp::BitAndAssign 165 | BinOp::BitAndAssign
165 | BinOp::BitXorAssign => true, 166 | BinOp::BitXorAssign
166 _ => false, 167 )
167 }
168 } 168 }
169} 169}
170 170
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 810c8d4c8..c08f2c14f 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -532,7 +532,7 @@ fn ast_from_text<N: AstNode>(text: &str) -> N {
532} 532}
533 533
534fn unroot(n: SyntaxNode) -> SyntaxNode { 534fn unroot(n: SyntaxNode) -> SyntaxNode {
535 SyntaxNode::new_root(n.green().to_owned()) 535 SyntaxNode::new_root(n.green())
536} 536}
537 537
538pub mod tokens { 538pub mod tokens {
@@ -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/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 01f580a40..bdf907a21 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -58,10 +58,7 @@ impl From<ast::MacroDef> for Macro {
58 58
59impl AstNode for Macro { 59impl AstNode for Macro {
60 fn can_cast(kind: SyntaxKind) -> bool { 60 fn can_cast(kind: SyntaxKind) -> bool {
61 match kind { 61 matches!(kind, SyntaxKind::MACRO_RULES | SyntaxKind::MACRO_DEF)
62 SyntaxKind::MACRO_RULES | SyntaxKind::MACRO_DEF => true,
63 _ => false,
64 }
65 } 62 }
66 fn cast(syntax: SyntaxNode) -> Option<Self> { 63 fn cast(syntax: SyntaxNode) -> Option<Self> {
67 let res = match syntax.kind() { 64 let res = match syntax.kind() {
@@ -380,6 +377,15 @@ impl fmt::Display for NameOrNameRef {
380 } 377 }
381} 378}
382 379
380impl NameOrNameRef {
381 pub fn text(&self) -> &str {
382 match self {
383 NameOrNameRef::Name(name) => name.text(),
384 NameOrNameRef::NameRef(name_ref) => name_ref.text(),
385 }
386 }
387}
388
383impl ast::RecordPatField { 389impl ast::RecordPatField {
384 pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> { 390 pub fn for_field_name_ref(field_name: &ast::NameRef) -> Option<ast::RecordPatField> {
385 let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?; 391 let candidate = field_name.syntax().parent().and_then(ast::RecordPatField::cast)?;
@@ -453,10 +459,8 @@ impl ast::FieldExpr {
453 pub fn field_access(&self) -> Option<FieldKind> { 459 pub fn field_access(&self) -> Option<FieldKind> {
454 if let Some(nr) = self.name_ref() { 460 if let Some(nr) = self.name_ref() {
455 Some(FieldKind::Name(nr)) 461 Some(FieldKind::Name(nr))
456 } else if let Some(tok) = self.index_token() {
457 Some(FieldKind::Index(tok))
458 } else { 462 } else {
459 None 463 self.index_token().map(FieldKind::Index)
460 } 464 }
461 } 465 }
462} 466}
@@ -473,16 +477,10 @@ impl ast::SlicePat {
473 let prefix = args 477 let prefix = args
474 .peeking_take_while(|p| match p { 478 .peeking_take_while(|p| match p {
475 ast::Pat::RestPat(_) => false, 479 ast::Pat::RestPat(_) => false,
476 ast::Pat::IdentPat(bp) => match bp.pat() { 480 ast::Pat::IdentPat(bp) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
477 Some(ast::Pat::RestPat(_)) => false,
478 _ => true,
479 },
480 ast::Pat::RefPat(rp) => match rp.pat() { 481 ast::Pat::RefPat(rp) => match rp.pat() {
481 Some(ast::Pat::RestPat(_)) => false, 482 Some(ast::Pat::RestPat(_)) => false,
482 Some(ast::Pat::IdentPat(bp)) => match bp.pat() { 483 Some(ast::Pat::IdentPat(bp)) => !matches!(bp.pat(), Some(ast::Pat::RestPat(_))),
483 Some(ast::Pat::RestPat(_)) => false,
484 _ => true,
485 },
486 _ => true, 484 _ => true,
487 }, 485 },
488 _ => true, 486 _ => true,
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index 6c242d126..29d25a58a 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -102,8 +102,9 @@ impl CommentKind {
102 kind 102 kind
103 } 103 }
104 104
105 fn prefix(&self) -> &'static str { 105 pub fn prefix(&self) -> &'static str {
106 let &(prefix, _) = CommentKind::BY_PREFIX.iter().find(|(_, kind)| kind == self).unwrap(); 106 let &(prefix, _) =
107 CommentKind::BY_PREFIX.iter().rev().find(|(_, kind)| kind == self).unwrap();
107 prefix 108 prefix
108 } 109 }
109} 110}
@@ -494,9 +495,8 @@ pub trait HasFormatSpecifier: AstToken {
494 } 495 }
495 _ => { 496 _ => {
496 while let Some((_, Ok(next_char))) = chars.peek() { 497 while let Some((_, Ok(next_char))) = chars.peek() {
497 match next_char { 498 if next_char == &'{' {
498 '{' => break, 499 break;
499 _ => {}
500 } 500 }
501 chars.next(); 501 chars.next();
502 } 502 }
diff --git a/crates/syntax/src/fuzz.rs b/crates/syntax/src/fuzz.rs
index fbb97aa27..aa84239d2 100644
--- a/crates/syntax/src/fuzz.rs
+++ b/crates/syntax/src/fuzz.rs
@@ -43,7 +43,7 @@ impl CheckReparse {
43 TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap()); 43 TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap());
44 let edited_text = 44 let edited_text =
45 format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]); 45 format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]);
46 let edit = Indel { delete, insert }; 46 let edit = Indel { insert, delete };
47 Some(CheckReparse { text, edit, edited_text }) 47 Some(CheckReparse { text, edit, edited_text })
48 } 48 }
49 49
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}
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs
index 3e216fb70..bbe802174 100644
--- a/crates/syntax/src/validation.rs
+++ b/crates/syntax/src/validation.rs
@@ -297,7 +297,7 @@ fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxErro
297 } 297 }
298 }; 298 };
299 } 299 }
300 return None; 300 None
301 } 301 }
302 302
303 fn all_supers(path: &ast::Path) -> bool { 303 fn all_supers(path: &ast::Path) -> bool {
@@ -314,7 +314,7 @@ fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxErro
314 return all_supers(subpath); 314 return all_supers(subpath);
315 } 315 }
316 316
317 return true; 317 true
318 } 318 }
319} 319}
320 320