aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/syntax/src')
-rw-r--r--crates/syntax/src/algo.rs6
-rw-r--r--crates/syntax/src/ast/edit.rs4
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs2
-rw-r--r--crates/syntax/src/ast/make.rs2
-rw-r--r--crates/syntax/src/ast/node_ext.rs2
-rw-r--r--crates/syntax/src/lib.rs9
-rw-r--r--crates/syntax/src/parsing/lexer.rs8
-rw-r--r--crates/syntax/src/parsing/reparsing.rs56
-rw-r--r--crates/syntax/src/tests.rs9
-rw-r--r--crates/syntax/src/validation.rs6
10 files changed, 60 insertions, 44 deletions
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs
index 5696c014f..384d031e7 100644
--- a/crates/syntax/src/algo.rs
+++ b/crates/syntax/src/algo.rs
@@ -19,7 +19,7 @@ use crate::{
19 19
20/// Returns ancestors of the node at the offset, sorted by length. This should 20/// Returns ancestors of the node at the offset, sorted by length. This should
21/// do the right thing at an edge, e.g. when searching for expressions at `{ 21/// do the right thing at an edge, e.g. when searching for expressions at `{
22/// <|>foo }` we will get the name reference instead of the whole block, which 22/// $0foo }` we will get the name reference instead of the whole block, which
23/// we would get if we just did `find_token_at_offset(...).flat_map(|t| 23/// we would get if we just did `find_token_at_offset(...).flat_map(|t|
24/// t.parent().ancestors())`. 24/// t.parent().ancestors())`.
25pub fn ancestors_at_offset( 25pub fn ancestors_at_offset(
@@ -88,8 +88,8 @@ pub fn least_common_ancestor(u: &SyntaxNode, v: &SyntaxNode) -> Option<SyntaxNod
88 let keep = u_depth.min(v_depth); 88 let keep = u_depth.min(v_depth);
89 89
90 let u_candidates = u.ancestors().skip(u_depth - keep); 90 let u_candidates = u.ancestors().skip(u_depth - keep);
91 let v_canidates = v.ancestors().skip(v_depth - keep); 91 let v_candidates = v.ancestors().skip(v_depth - keep);
92 let (res, _) = u_candidates.zip(v_canidates).find(|(x, y)| x == y)?; 92 let (res, _) = u_candidates.zip(v_candidates).find(|(x, y)| x == y)?;
93 Some(res) 93 Some(res)
94} 94}
95 95
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index 77233ab31..824ebf41c 100644
--- a/crates/syntax/src/ast/edit.rs
+++ b/crates/syntax/src/ast/edit.rs
@@ -220,7 +220,7 @@ impl ast::RecordExprFieldList {
220 InsertPosition::After($anchor.syntax().clone().into()) 220 InsertPosition::After($anchor.syntax().clone().into())
221 } 221 }
222 }; 222 };
223 }; 223 }
224 224
225 let position = match position { 225 let position = match position {
226 InsertPosition::First => after_l_curly!(), 226 InsertPosition::First => after_l_curly!(),
@@ -533,7 +533,7 @@ impl ast::GenericParamList {
533 InsertPosition::After($anchor.syntax().clone().into()) 533 InsertPosition::After($anchor.syntax().clone().into())
534 } 534 }
535 }; 535 };
536 }; 536 }
537 537
538 let position = match self.generic_params().last() { 538 let position = match self.generic_params().last() {
539 Some(it) => after_field!(it), 539 Some(it) => after_field!(it),
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index c5b80bffe..92ed2ee9d 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -484,7 +484,7 @@ impl ast::AttrsOwner for BlockExpr {}
484impl BlockExpr { 484impl BlockExpr {
485 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } 485 pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) }
486 pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) } 486 pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) }
487 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } 487 pub fn tail_expr(&self) -> Option<Expr> { support::child(&self.syntax) }
488 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } 488 pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) }
489} 489}
490#[derive(Debug, Clone, PartialEq, Eq, Hash)] 490#[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index cafa4c198..1ed8a96e5 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -241,7 +241,7 @@ pub fn wildcard_pat() -> ast::WildcardPat {
241 } 241 }
242} 242}
243 243
244/// Creates a tuple of patterns from an interator of patterns. 244/// Creates a tuple of patterns from an iterator of patterns.
245/// 245///
246/// Invariant: `pats` must be length > 1 246/// Invariant: `pats` must be length > 1
247/// 247///
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 2aa472fb4..27381ba80 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -133,7 +133,7 @@ impl ast::Attr {
133 first_token.and_then(|token| token.next_token()).as_ref().map(SyntaxToken::kind); 133 first_token.and_then(|token| token.next_token()).as_ref().map(SyntaxToken::kind);
134 134
135 match (first_token_kind, second_token_kind) { 135 match (first_token_kind, second_token_kind) {
136 (Some(SyntaxKind::POUND), Some(T![!])) => AttrKind::Inner, 136 (Some(T![#]), Some(T![!])) => AttrKind::Inner,
137 _ => AttrKind::Outer, 137 _ => AttrKind::Outer,
138 } 138 }
139 } 139 }
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index 4d272f367..ea7482bb1 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -212,6 +212,13 @@ impl ast::Attr {
212 } 212 }
213} 213}
214 214
215impl ast::Stmt {
216 /// Returns `text`, parsed as statement, but only if it has no errors.
217 pub fn parse(text: &str) -> Result<Self, ()> {
218 parsing::parse_text_fragment(text, parser::FragmentKind::StatementOptionalSemi)
219 }
220}
221
215/// Matches a `SyntaxNode` against an `ast` type. 222/// Matches a `SyntaxNode` against an `ast` type.
216/// 223///
217/// # Example: 224/// # Example:
@@ -283,7 +290,7 @@ fn api_walkthrough() {
283 290
284 // Let's get the `1 + 1` expression! 291 // Let's get the `1 + 1` expression!
285 let body: ast::BlockExpr = func.body().unwrap(); 292 let body: ast::BlockExpr = func.body().unwrap();
286 let expr: ast::Expr = body.expr().unwrap(); 293 let expr: ast::Expr = body.tail_expr().unwrap();
287 294
288 // Enums are used to group related ast nodes together, and can be used for 295 // Enums are used to group related ast nodes together, and can be used for
289 // matching. However, because there are no public fields, it's possible to 296 // matching. However, because there are no public fields, it's possible to
diff --git a/crates/syntax/src/parsing/lexer.rs b/crates/syntax/src/parsing/lexer.rs
index 0cbba73c5..7c8d0a4c4 100644
--- a/crates/syntax/src/parsing/lexer.rs
+++ b/crates/syntax/src/parsing/lexer.rs
@@ -24,7 +24,7 @@ pub struct Token {
24/// Beware that it checks for shebang first and its length contributes to resulting 24/// Beware that it checks for shebang first and its length contributes to resulting
25/// tokens offsets. 25/// tokens offsets.
26pub fn tokenize(text: &str) -> (Vec<Token>, Vec<SyntaxError>) { 26pub fn tokenize(text: &str) -> (Vec<Token>, Vec<SyntaxError>) {
27 // non-empty string is a precondtion of `rustc_lexer::strip_shebang()`. 27 // non-empty string is a precondition of `rustc_lexer::strip_shebang()`.
28 if text.is_empty() { 28 if text.is_empty() {
29 return Default::default(); 29 return Default::default();
30 } 30 }
@@ -76,7 +76,7 @@ pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxEr
76} 76}
77 77
78/// The same as `lex_single_syntax_kind()` but returns only `SyntaxKind` and 78/// The same as `lex_single_syntax_kind()` but returns only `SyntaxKind` and
79/// returns `None` if any tokenization error occured. 79/// returns `None` if any tokenization error occurred.
80/// 80///
81/// Beware that unescape errors are not checked at tokenization time. 81/// Beware that unescape errors are not checked at tokenization time.
82pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> { 82pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> {
@@ -96,7 +96,7 @@ pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> {
96/// 96///
97/// Beware that unescape errors are not checked at tokenization time. 97/// Beware that unescape errors are not checked at tokenization time.
98fn lex_first_token(text: &str) -> Option<(Token, Option<SyntaxError>)> { 98fn lex_first_token(text: &str) -> Option<(Token, Option<SyntaxError>)> {
99 // non-empty string is a precondtion of `rustc_lexer::first_token()`. 99 // non-empty string is a precondition of `rustc_lexer::first_token()`.
100 if text.is_empty() { 100 if text.is_empty() {
101 return None; 101 return None;
102 } 102 }
@@ -117,7 +117,7 @@ fn rustc_token_kind_to_syntax_kind(
117 token_text: &str, 117 token_text: &str,
118) -> (SyntaxKind, Option<&'static str>) { 118) -> (SyntaxKind, Option<&'static str>) {
119 // A note on an intended tradeoff: 119 // A note on an intended tradeoff:
120 // We drop some useful infromation here (see patterns with double dots `..`) 120 // We drop some useful information here (see patterns with double dots `..`)
121 // Storing that info in `SyntaxKind` is not possible due to its layout requirements of 121 // Storing that info in `SyntaxKind` is not possible due to its layout requirements of
122 // being `u16` that come from `rowan::SyntaxKind`. 122 // being `u16` that come from `rowan::SyntaxKind`.
123 123
diff --git a/crates/syntax/src/parsing/reparsing.rs b/crates/syntax/src/parsing/reparsing.rs
index 190f5f67a..78eaf3410 100644
--- a/crates/syntax/src/parsing/reparsing.rs
+++ b/crates/syntax/src/parsing/reparsing.rs
@@ -223,7 +223,7 @@ mod tests {
223 do_check( 223 do_check(
224 r" 224 r"
225fn foo() { 225fn foo() {
226 let x = foo + <|>bar<|> 226 let x = foo + $0bar$0
227} 227}
228", 228",
229 "baz", 229 "baz",
@@ -232,7 +232,7 @@ fn foo() {
232 do_check( 232 do_check(
233 r" 233 r"
234fn foo() { 234fn foo() {
235 let x = foo<|> + bar<|> 235 let x = foo$0 + bar$0
236} 236}
237", 237",
238 "baz", 238 "baz",
@@ -241,7 +241,7 @@ fn foo() {
241 do_check( 241 do_check(
242 r" 242 r"
243struct Foo { 243struct Foo {
244 f: foo<|><|> 244 f: foo$0$0
245} 245}
246", 246",
247 ",\n g: (),", 247 ",\n g: (),",
@@ -252,7 +252,7 @@ struct Foo {
252fn foo { 252fn foo {
253 let; 253 let;
254 1 + 1; 254 1 + 1;
255 <|>92<|>; 255 $092$0;
256} 256}
257", 257",
258 "62", 258 "62",
@@ -261,7 +261,7 @@ fn foo {
261 do_check( 261 do_check(
262 r" 262 r"
263mod foo { 263mod foo {
264 fn <|><|> 264 fn $0$0
265} 265}
266", 266",
267 "bar", 267 "bar",
@@ -271,7 +271,7 @@ mod foo {
271 do_check( 271 do_check(
272 r" 272 r"
273trait Foo { 273trait Foo {
274 type <|>Foo<|>; 274 type $0Foo$0;
275} 275}
276", 276",
277 "Output", 277 "Output",
@@ -280,17 +280,17 @@ trait Foo {
280 do_check( 280 do_check(
281 r" 281 r"
282impl IntoIterator<Item=i32> for Foo { 282impl IntoIterator<Item=i32> for Foo {
283 f<|><|> 283 f$0$0
284} 284}
285", 285",
286 "n next(", 286 "n next(",
287 9, 287 9,
288 ); 288 );
289 do_check(r"use a::b::{foo,<|>,bar<|>};", "baz", 10); 289 do_check(r"use a::b::{foo,$0,bar$0};", "baz", 10);
290 do_check( 290 do_check(
291 r" 291 r"
292pub enum A { 292pub enum A {
293 Foo<|><|> 293 Foo$0$0
294} 294}
295", 295",
296 "\nBar;\n", 296 "\nBar;\n",
@@ -298,7 +298,7 @@ pub enum A {
298 ); 298 );
299 do_check( 299 do_check(
300 r" 300 r"
301foo!{a, b<|><|> d} 301foo!{a, b$0$0 d}
302", 302",
303 ", c[3]", 303 ", c[3]",
304 8, 304 8,
@@ -306,7 +306,7 @@ foo!{a, b<|><|> d}
306 do_check( 306 do_check(
307 r" 307 r"
308fn foo() { 308fn foo() {
309 vec![<|><|>] 309 vec![$0$0]
310} 310}
311", 311",
312 "123", 312 "123",
@@ -315,7 +315,7 @@ fn foo() {
315 do_check( 315 do_check(
316 r" 316 r"
317extern { 317extern {
318 fn<|>;<|> 318 fn$0;$0
319} 319}
320", 320",
321 " exit(code: c_int)", 321 " exit(code: c_int)",
@@ -326,7 +326,7 @@ extern {
326 #[test] 326 #[test]
327 fn reparse_token_tests() { 327 fn reparse_token_tests() {
328 do_check( 328 do_check(
329 r"<|><|> 329 r"$0$0
330fn foo() -> i32 { 1 } 330fn foo() -> i32 { 1 }
331", 331",
332 "\n\n\n \n", 332 "\n\n\n \n",
@@ -334,49 +334,49 @@ fn foo() -> i32 { 1 }
334 ); 334 );
335 do_check( 335 do_check(
336 r" 336 r"
337fn foo() -> <|><|> {} 337fn foo() -> $0$0 {}
338", 338",
339 " \n", 339 " \n",
340 2, 340 2,
341 ); 341 );
342 do_check( 342 do_check(
343 r" 343 r"
344fn <|>foo<|>() -> i32 { 1 } 344fn $0foo$0() -> i32 { 1 }
345", 345",
346 "bar", 346 "bar",
347 3, 347 3,
348 ); 348 );
349 do_check( 349 do_check(
350 r" 350 r"
351fn foo<|><|>foo() { } 351fn foo$0$0foo() { }
352", 352",
353 "bar", 353 "bar",
354 6, 354 6,
355 ); 355 );
356 do_check( 356 do_check(
357 r" 357 r"
358fn foo /* <|><|> */ () {} 358fn foo /* $0$0 */ () {}
359", 359",
360 "some comment", 360 "some comment",
361 6, 361 6,
362 ); 362 );
363 do_check( 363 do_check(
364 r" 364 r"
365fn baz <|><|> () {} 365fn baz $0$0 () {}
366", 366",
367 " \t\t\n\n", 367 " \t\t\n\n",
368 2, 368 2,
369 ); 369 );
370 do_check( 370 do_check(
371 r" 371 r"
372fn baz <|><|> () {} 372fn baz $0$0 () {}
373", 373",
374 " \t\t\n\n", 374 " \t\t\n\n",
375 2, 375 2,
376 ); 376 );
377 do_check( 377 do_check(
378 r" 378 r"
379/// foo <|><|>omment 379/// foo $0$0omment
380mod { } 380mod { }
381", 381",
382 "c", 382 "c",
@@ -384,28 +384,28 @@ mod { }
384 ); 384 );
385 do_check( 385 do_check(
386 r#" 386 r#"
387fn -> &str { "Hello<|><|>" } 387fn -> &str { "Hello$0$0" }
388"#, 388"#,
389 ", world", 389 ", world",
390 7, 390 7,
391 ); 391 );
392 do_check( 392 do_check(
393 r#" 393 r#"
394fn -> &str { // "Hello<|><|>" 394fn -> &str { // "Hello$0$0"
395"#, 395"#,
396 ", world", 396 ", world",
397 10, 397 10,
398 ); 398 );
399 do_check( 399 do_check(
400 r##" 400 r##"
401fn -> &str { r#"Hello<|><|>"# 401fn -> &str { r#"Hello$0$0"#
402"##, 402"##,
403 ", world", 403 ", world",
404 10, 404 10,
405 ); 405 );
406 do_check( 406 do_check(
407 r" 407 r"
408#[derive(<|>Copy<|>)] 408#[derive($0Copy$0)]
409enum Foo { 409enum Foo {
410 410
411} 411}
@@ -417,12 +417,12 @@ enum Foo {
417 417
418 #[test] 418 #[test]
419 fn reparse_str_token_with_error_unchanged() { 419 fn reparse_str_token_with_error_unchanged() {
420 do_check(r#""<|>Unclosed<|> string literal"#, "Still unclosed", 24); 420 do_check(r#""$0Unclosed$0 string literal"#, "Still unclosed", 24);
421 } 421 }
422 422
423 #[test] 423 #[test]
424 fn reparse_str_token_with_error_fixed() { 424 fn reparse_str_token_with_error_fixed() {
425 do_check(r#""unterinated<|><|>"#, "\"", 12); 425 do_check(r#""unterinated$0$0"#, "\"", 12);
426 } 426 }
427 427
428 #[test] 428 #[test]
@@ -430,7 +430,7 @@ enum Foo {
430 do_check( 430 do_check(
431 r#"fn main() { 431 r#"fn main() {
432 if {} 432 if {}
433 32 + 4<|><|> 433 32 + 4$0$0
434 return 434 return
435 if {} 435 if {}
436 }"#, 436 }"#,
@@ -444,7 +444,7 @@ enum Foo {
444 do_check( 444 do_check(
445 r#"fn main() { 445 r#"fn main() {
446 if {} 446 if {}
447 32 + 4<|><|> 447 32 + 4$0$0
448 return 448 return
449 if {} 449 if {}
450 }"#, 450 }"#,
diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs
index 8c217dfe0..9d3433c9d 100644
--- a/crates/syntax/src/tests.rs
+++ b/crates/syntax/src/tests.rs
@@ -103,6 +103,15 @@ fn type_parser_tests() {
103} 103}
104 104
105#[test] 105#[test]
106fn stmt_parser_tests() {
107 fragment_parser_dir_test(
108 &["parser/fragments/stmt/ok"],
109 &["parser/fragments/stmt/err"],
110 crate::ast::Stmt::parse,
111 );
112}
113
114#[test]
106fn parser_fuzz_tests() { 115fn parser_fuzz_tests() {
107 for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) { 116 for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) {
108 fuzz::check_parser(&text) 117 fuzz::check_parser(&text)
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs
index 2ddaeb176..bfa2dc4ba 100644
--- a/crates/syntax/src/validation.rs
+++ b/crates/syntax/src/validation.rs
@@ -173,7 +173,7 @@ pub(crate) fn validate_block_structure(root: &SyntaxNode) {
173 assert_eq!( 173 assert_eq!(
174 node.parent(), 174 node.parent(),
175 pair.parent(), 175 pair.parent(),
176 "\nunpaired curleys:\n{}\n{:#?}\n", 176 "\nunpaired curlys:\n{}\n{:#?}\n",
177 root.text(), 177 root.text(),
178 root, 178 root,
179 ); 179 );
@@ -344,9 +344,9 @@ fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> {
344 344
345 if tbl.bounds().count() > 1 { 345 if tbl.bounds().count() > 1 {
346 let dyn_token = ty.dyn_token()?; 346 let dyn_token = ty.dyn_token()?;
347 let potential_parentheses = 347 let potential_parenthesis =
348 algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?; 348 algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?;
349 let kind = potential_parentheses.kind(); 349 let kind = potential_parenthesis.kind();
350 if !matches!(kind, T!['('] | T![<] | T![=]) { 350 if !matches!(kind, T!['('] | T![<] | T![=]) {
351 return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range())); 351 return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()));
352 } 352 }