aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-16 10:51:40 +0100
committerAleksey Kladov <[email protected]>2018-08-16 10:51:40 +0100
commit7094291573dc819e3115950ec3b2316bd5e9ea33 (patch)
treebe18ef6c5baab68acac484d00277125484d15820 /crates
parent1193c5f829dc96683132c12d5395d7805787af2a (diff)
tt-attrs
Diffstat (limited to 'crates')
-rw-r--r--crates/libanalysis/src/lib.rs11
-rw-r--r--crates/libeditor/src/code_actions.rs2
-rw-r--r--crates/libeditor/src/lib.rs15
-rw-r--r--crates/libeditor/src/symbols.rs6
-rw-r--r--crates/libsyntax2/src/ast/generated.rs52
-rw-r--r--crates/libsyntax2/src/ast/mod.rs53
-rw-r--r--crates/libsyntax2/src/grammar.ron20
-rw-r--r--crates/libsyntax2/src/grammar/attributes.rs56
-rw-r--r--crates/libsyntax2/src/grammar/items/mod.rs7
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0005_attribute_recover.txt63
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0008_item_block_recovery.txt7
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0039_path_expr.txt5
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0078_mod_contents.txt15
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0006_inner_attributes.txt178
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0008_mod_item.txt6
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0011_outer_attribute.txt18
-rw-r--r--crates/libsyntax2/tests/data/parser/ok/0017_attr_trailing_comma.txt14
-rw-r--r--crates/libsyntax2/tests/test/main.rs8
18 files changed, 260 insertions, 276 deletions
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs
index 983029587..85c23e4d9 100644
--- a/crates/libanalysis/src/lib.rs
+++ b/crates/libanalysis/src/lib.rs
@@ -26,9 +26,8 @@ use std::{
26use libsyntax2::{ 26use libsyntax2::{
27 TextUnit, 27 TextUnit,
28 ast::{self, AstNode}, 28 ast::{self, AstNode},
29 algo::{find_leaf_at_offset, ancestors},
30}; 29};
31use libeditor::{LineIndex, FileSymbol}; 30use libeditor::{LineIndex, FileSymbol, find_node};
32 31
33use self::symbol_index::FileSymbols; 32use self::symbol_index::FileSymbols;
34pub use self::symbol_index::Query; 33pub use self::symbol_index::Query;
@@ -123,13 +122,7 @@ impl World {
123 let file = self.file_syntax(id)?; 122 let file = self.file_syntax(id)?;
124 let syntax = file.syntax(); 123 let syntax = file.syntax();
125 let syntax = syntax.as_ref(); 124 let syntax = syntax.as_ref();
126 let name_ref = 125 let name_ref = find_node::<ast::NameRef<_>>(syntax, offset);
127 find_leaf_at_offset(syntax, offset)
128 .left_biased()
129 .into_iter()
130 .flat_map(|node| ancestors(node))
131 .flat_map(ast::NameRef::cast)
132 .next();
133 let name = match name_ref { 126 let name = match name_ref {
134 None => return Ok(vec![]), 127 None => return Ok(vec![]),
135 Some(name_ref) => name_ref.text(), 128 Some(name_ref) => name_ref.text(),
diff --git a/crates/libeditor/src/code_actions.rs b/crates/libeditor/src/code_actions.rs
index 88c348436..4987964d2 100644
--- a/crates/libeditor/src/code_actions.rs
+++ b/crates/libeditor/src/code_actions.rs
@@ -66,7 +66,7 @@ fn find_non_trivia_leaf(syntax: SyntaxNodeRef, offset: TextUnit) -> Option<Synta
66 .find(|leaf| !leaf.kind().is_trivia()) 66 .find(|leaf| !leaf.kind().is_trivia())
67} 67}
68 68
69fn find_node<'a, N: AstNode<&'a SyntaxRoot>>(syntax: SyntaxNodeRef<'a>, offset: TextUnit) -> Option<N> { 69pub fn find_node<'a, N: AstNode<&'a SyntaxRoot>>(syntax: SyntaxNodeRef<'a>, offset: TextUnit) -> Option<N> {
70 let leaf = find_non_trivia_leaf(syntax, offset)?; 70 let leaf = find_non_trivia_leaf(syntax, offset)?;
71 ancestors(leaf) 71 ancestors(leaf)
72 .filter_map(N::cast) 72 .filter_map(N::cast)
diff --git a/crates/libeditor/src/lib.rs b/crates/libeditor/src/lib.rs
index 28da457d1..76cb4d028 100644
--- a/crates/libeditor/src/lib.rs
+++ b/crates/libeditor/src/lib.rs
@@ -21,7 +21,10 @@ pub use self::{
21 extend_selection::extend_selection, 21 extend_selection::extend_selection,
22 symbols::{StructureNode, file_structure, FileSymbol, file_symbols}, 22 symbols::{StructureNode, file_structure, FileSymbol, file_symbols},
23 edit::{EditBuilder, Edit, AtomEdit}, 23 edit::{EditBuilder, Edit, AtomEdit},
24 code_actions::{flip_comma, add_derive, ActionResult, CursorPosition}, 24 code_actions::{
25 ActionResult, CursorPosition, find_node,
26 flip_comma, add_derive,
27 },
25}; 28};
26 29
27#[derive(Debug)] 30#[derive(Debug)]
@@ -59,9 +62,7 @@ pub fn matching_brace(file: &ast::File, offset: TextUnit) -> Option<TextUnit> {
59 L_PAREN, R_PAREN, 62 L_PAREN, R_PAREN,
60 L_ANGLE, R_ANGLE, 63 L_ANGLE, R_ANGLE,
61 ]; 64 ];
62 let syntax = file.syntax(); 65 let (brace_node, brace_idx) = find_leaf_at_offset(file.syntax_ref(), offset)
63 let syntax = syntax.as_ref();
64 let (brace_node, brace_idx) = find_leaf_at_offset(syntax, offset)
65 .filter_map(|node| { 66 .filter_map(|node| {
66 let idx = BRACES.iter().position(|&brace| brace == node.kind())?; 67 let idx = BRACES.iter().position(|&brace| brace == node.kind())?;
67 Some((node, idx)) 68 Some((node, idx))
@@ -75,9 +76,8 @@ pub fn matching_brace(file: &ast::File, offset: TextUnit) -> Option<TextUnit> {
75} 76}
76 77
77pub fn highlight(file: &ast::File) -> Vec<HighlightedRange> { 78pub fn highlight(file: &ast::File) -> Vec<HighlightedRange> {
78 let syntax = file.syntax();
79 let mut res = Vec::new(); 79 let mut res = Vec::new();
80 for node in walk::preorder(syntax.as_ref()) { 80 for node in walk::preorder(file.syntax_ref()) {
81 let tag = match node.kind() { 81 let tag = match node.kind() {
82 ERROR => "error", 82 ERROR => "error",
83 COMMENT | DOC_COMMENT => "comment", 83 COMMENT | DOC_COMMENT => "comment",
@@ -99,10 +99,9 @@ pub fn highlight(file: &ast::File) -> Vec<HighlightedRange> {
99} 99}
100 100
101pub fn diagnostics(file: &ast::File) -> Vec<Diagnostic> { 101pub fn diagnostics(file: &ast::File) -> Vec<Diagnostic> {
102 let syntax = file.syntax();
103 let mut res = Vec::new(); 102 let mut res = Vec::new();
104 103
105 for node in walk::preorder(syntax.as_ref()) { 104 for node in walk::preorder(file.syntax_ref()) {
106 if node.kind() == ERROR { 105 if node.kind() == ERROR {
107 res.push(Diagnostic { 106 res.push(Diagnostic {
108 range: node.range(), 107 range: node.range(),
diff --git a/crates/libeditor/src/symbols.rs b/crates/libeditor/src/symbols.rs
index 6f8853770..2585d9579 100644
--- a/crates/libeditor/src/symbols.rs
+++ b/crates/libeditor/src/symbols.rs
@@ -26,8 +26,7 @@ pub struct FileSymbol {
26} 26}
27 27
28pub fn file_symbols(file: &ast::File) -> Vec<FileSymbol> { 28pub fn file_symbols(file: &ast::File) -> Vec<FileSymbol> {
29 let syntax = file.syntax(); 29 preorder(file.syntax_ref())
30 preorder(syntax.as_ref())
31 .filter_map(to_symbol) 30 .filter_map(to_symbol)
32 .collect() 31 .collect()
33} 32}
@@ -57,9 +56,8 @@ fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> {
57pub fn file_structure(file: &ast::File) -> Vec<StructureNode> { 56pub fn file_structure(file: &ast::File) -> Vec<StructureNode> {
58 let mut res = Vec::new(); 57 let mut res = Vec::new();
59 let mut stack = Vec::new(); 58 let mut stack = Vec::new();
60 let syntax = file.syntax();
61 59
62 for event in walk(syntax.as_ref()) { 60 for event in walk(file.syntax_ref()) {
63 match event { 61 match event {
64 WalkEvent::Enter(node) => { 62 WalkEvent::Enter(node) => {
65 match structure_node(node) { 63 match structure_node(node) {
diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs
index 1ec05c950..c575e15df 100644
--- a/crates/libsyntax2/src/ast/generated.rs
+++ b/crates/libsyntax2/src/ast/generated.rs
@@ -23,6 +23,31 @@ impl<R: TreeRoot> AstNode<R> for ArrayType<R> {
23 23
24impl<R: TreeRoot> ArrayType<R> {} 24impl<R: TreeRoot> ArrayType<R> {}
25 25
26// Attr
27#[derive(Debug, Clone, Copy)]
28pub struct Attr<R: TreeRoot = Arc<SyntaxRoot>> {
29 syntax: SyntaxNode<R>,
30}
31
32impl<R: TreeRoot> AstNode<R> for Attr<R> {
33 fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
34 match syntax.kind() {
35 ATTR => Some(Attr { syntax }),
36 _ => None,
37 }
38 }
39 fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
40}
41
42impl<R: TreeRoot> Attr<R> {
43 pub fn value(&self) -> Option<TokenTree<R>> {
44 self.syntax()
45 .children()
46 .filter_map(TokenTree::cast)
47 .next()
48 }
49}
50
26// ConstDef 51// ConstDef
27#[derive(Debug, Clone, Copy)] 52#[derive(Debug, Clone, Copy)]
28pub struct ConstDef<R: TreeRoot = Arc<SyntaxRoot>> { 53pub struct ConstDef<R: TreeRoot = Arc<SyntaxRoot>> {
@@ -40,6 +65,7 @@ impl<R: TreeRoot> AstNode<R> for ConstDef<R> {
40} 65}
41 66
42impl<R: TreeRoot> ast::NameOwner<R> for ConstDef<R> {} 67impl<R: TreeRoot> ast::NameOwner<R> for ConstDef<R> {}
68impl<R: TreeRoot> ast::AttrsOwner<R> for ConstDef<R> {}
43impl<R: TreeRoot> ConstDef<R> {} 69impl<R: TreeRoot> ConstDef<R> {}
44 70
45// DynTraitType 71// DynTraitType
@@ -77,6 +103,7 @@ impl<R: TreeRoot> AstNode<R> for EnumDef<R> {
77} 103}
78 104
79impl<R: TreeRoot> ast::NameOwner<R> for EnumDef<R> {} 105impl<R: TreeRoot> ast::NameOwner<R> for EnumDef<R> {}
106impl<R: TreeRoot> ast::AttrsOwner<R> for EnumDef<R> {}
80impl<R: TreeRoot> EnumDef<R> {} 107impl<R: TreeRoot> EnumDef<R> {}
81 108
82// File 109// File
@@ -120,6 +147,7 @@ impl<R: TreeRoot> AstNode<R> for FnDef<R> {
120} 147}
121 148
122impl<R: TreeRoot> ast::NameOwner<R> for FnDef<R> {} 149impl<R: TreeRoot> ast::NameOwner<R> for FnDef<R> {}
150impl<R: TreeRoot> ast::AttrsOwner<R> for FnDef<R> {}
123impl<R: TreeRoot> FnDef<R> {} 151impl<R: TreeRoot> FnDef<R> {}
124 152
125// FnPointerType 153// FnPointerType
@@ -211,6 +239,7 @@ impl<R: TreeRoot> AstNode<R> for Module<R> {
211} 239}
212 240
213impl<R: TreeRoot> ast::NameOwner<R> for Module<R> {} 241impl<R: TreeRoot> ast::NameOwner<R> for Module<R> {}
242impl<R: TreeRoot> ast::AttrsOwner<R> for Module<R> {}
214impl<R: TreeRoot> Module<R> {} 243impl<R: TreeRoot> Module<R> {}
215 244
216// Name 245// Name
@@ -266,6 +295,7 @@ impl<R: TreeRoot> AstNode<R> for NamedField<R> {
266} 295}
267 296
268impl<R: TreeRoot> ast::NameOwner<R> for NamedField<R> {} 297impl<R: TreeRoot> ast::NameOwner<R> for NamedField<R> {}
298impl<R: TreeRoot> ast::AttrsOwner<R> for NamedField<R> {}
269impl<R: TreeRoot> NamedField<R> {} 299impl<R: TreeRoot> NamedField<R> {}
270 300
271// NeverType 301// NeverType
@@ -436,6 +466,7 @@ impl<R: TreeRoot> AstNode<R> for StaticDef<R> {
436} 466}
437 467
438impl<R: TreeRoot> ast::NameOwner<R> for StaticDef<R> {} 468impl<R: TreeRoot> ast::NameOwner<R> for StaticDef<R> {}
469impl<R: TreeRoot> ast::AttrsOwner<R> for StaticDef<R> {}
439impl<R: TreeRoot> StaticDef<R> {} 470impl<R: TreeRoot> StaticDef<R> {}
440 471
441// StructDef 472// StructDef
@@ -455,6 +486,7 @@ impl<R: TreeRoot> AstNode<R> for StructDef<R> {
455} 486}
456 487
457impl<R: TreeRoot> ast::NameOwner<R> for StructDef<R> {} 488impl<R: TreeRoot> ast::NameOwner<R> for StructDef<R> {}
489impl<R: TreeRoot> ast::AttrsOwner<R> for StructDef<R> {}
458impl<R: TreeRoot> StructDef<R> { 490impl<R: TreeRoot> StructDef<R> {
459 pub fn fields<'a>(&'a self) -> impl Iterator<Item = NamedField<R>> + 'a { 491 pub fn fields<'a>(&'a self) -> impl Iterator<Item = NamedField<R>> + 'a {
460 self.syntax() 492 self.syntax()
@@ -463,6 +495,24 @@ impl<R: TreeRoot> StructDef<R> {
463 } 495 }
464} 496}
465 497
498// TokenTree
499#[derive(Debug, Clone, Copy)]
500pub struct TokenTree<R: TreeRoot = Arc<SyntaxRoot>> {
501 syntax: SyntaxNode<R>,
502}
503
504impl<R: TreeRoot> AstNode<R> for TokenTree<R> {
505 fn cast(syntax: SyntaxNode<R>) -> Option<Self> {
506 match syntax.kind() {
507 TOKEN_TREE => Some(TokenTree { syntax }),
508 _ => None,
509 }
510 }
511 fn syntax(&self) -> &SyntaxNode<R> { &self.syntax }
512}
513
514impl<R: TreeRoot> TokenTree<R> {}
515
466// TraitDef 516// TraitDef
467#[derive(Debug, Clone, Copy)] 517#[derive(Debug, Clone, Copy)]
468pub struct TraitDef<R: TreeRoot = Arc<SyntaxRoot>> { 518pub struct TraitDef<R: TreeRoot = Arc<SyntaxRoot>> {
@@ -480,6 +530,7 @@ impl<R: TreeRoot> AstNode<R> for TraitDef<R> {
480} 530}
481 531
482impl<R: TreeRoot> ast::NameOwner<R> for TraitDef<R> {} 532impl<R: TreeRoot> ast::NameOwner<R> for TraitDef<R> {}
533impl<R: TreeRoot> ast::AttrsOwner<R> for TraitDef<R> {}
483impl<R: TreeRoot> TraitDef<R> {} 534impl<R: TreeRoot> TraitDef<R> {}
484 535
485// TupleType 536// TupleType
@@ -517,6 +568,7 @@ impl<R: TreeRoot> AstNode<R> for TypeDef<R> {
517} 568}
518 569
519impl<R: TreeRoot> ast::NameOwner<R> for TypeDef<R> {} 570impl<R: TreeRoot> ast::NameOwner<R> for TypeDef<R> {}
571impl<R: TreeRoot> ast::AttrsOwner<R> for TypeDef<R> {}
520impl<R: TreeRoot> TypeDef<R> {} 572impl<R: TreeRoot> TypeDef<R> {}
521 573
522// TypeRef 574// TypeRef
diff --git a/crates/libsyntax2/src/ast/mod.rs b/crates/libsyntax2/src/ast/mod.rs
index 679e292a2..fe8f91d15 100644
--- a/crates/libsyntax2/src/ast/mod.rs
+++ b/crates/libsyntax2/src/ast/mod.rs
@@ -2,10 +2,11 @@ mod generated;
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use itertools::Itertools;
5use smol_str::SmolStr; 6use smol_str::SmolStr;
6 7
7use { 8use {
8 SyntaxNode, SyntaxRoot, TreeRoot, SyntaxError, 9 SyntaxNode, SyntaxNodeRef, SyntaxRoot, TreeRoot, SyntaxError,
9 SyntaxKind::*, 10 SyntaxKind::*,
10}; 11};
11pub use self::generated::*; 12pub use self::generated::*;
@@ -14,6 +15,9 @@ pub trait AstNode<R: TreeRoot> {
14 fn cast(syntax: SyntaxNode<R>) -> Option<Self> 15 fn cast(syntax: SyntaxNode<R>) -> Option<Self>
15 where Self: Sized; 16 where Self: Sized;
16 fn syntax(&self) -> &SyntaxNode<R>; 17 fn syntax(&self) -> &SyntaxNode<R>;
18 fn syntax_ref<'a>(&'a self) -> SyntaxNodeRef<'a> where R: 'a {
19 self.syntax().as_ref()
20 }
17} 21}
18 22
19pub trait NameOwner<R: TreeRoot>: AstNode<R> { 23pub trait NameOwner<R: TreeRoot>: AstNode<R> {
@@ -25,6 +29,14 @@ pub trait NameOwner<R: TreeRoot>: AstNode<R> {
25 } 29 }
26} 30}
27 31
32pub trait AttrsOwner<R: TreeRoot>: AstNode<R> {
33 fn attrs<'a>(&'a self) -> Box<Iterator<Item=Attr<R>> + 'a> where R: 'a {
34 let it = self.syntax().children()
35 .filter_map(Attr::cast);
36 Box::new(it)
37 }
38}
39
28impl File<Arc<SyntaxRoot>> { 40impl File<Arc<SyntaxRoot>> {
29 pub fn parse(text: &str) -> Self { 41 pub fn parse(text: &str) -> Self {
30 File::cast(::parse(text)).unwrap() 42 File::cast(::parse(text)).unwrap()
@@ -39,31 +51,20 @@ impl<R: TreeRoot> File<R> {
39 51
40impl<R: TreeRoot> FnDef<R> { 52impl<R: TreeRoot> FnDef<R> {
41 pub fn has_atom_attr(&self, atom: &str) -> bool { 53 pub fn has_atom_attr(&self, atom: &str) -> bool {
42 self.syntax() 54 self.attrs()
43 .children() 55 .filter_map(|x| x.value())
44 .filter(|node| node.kind() == ATTR) 56 .filter_map(|x| as_atom(x))
45 .any(|attr| { 57 .any(|x| x == atom)
46 let mut metas = attr.children().filter(|node| node.kind() == META_ITEM); 58 }
47 let meta = match metas.next() { 59}
48 None => return false, 60
49 Some(meta) => { 61fn as_atom<R: TreeRoot>(tt: TokenTree<R>) -> Option<SmolStr> {
50 if metas.next().is_some() { 62 let syntax = tt.syntax_ref();
51 return false; 63 let (_bra, attr, _ket) = syntax.children().collect_tuple()?;
52 } 64 if attr.kind() == IDENT {
53 meta 65 Some(attr.leaf_text().unwrap())
54 } 66 } else {
55 }; 67 None
56 let mut children = meta.children();
57 match children.next() {
58 None => false,
59 Some(child) => {
60 if children.next().is_some() {
61 return false;
62 }
63 child.kind() == IDENT && child.text() == atom
64 }
65 }
66 })
67 } 68 }
68} 69}
69 70
diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron
index aa28ab922..4e523da9a 100644
--- a/crates/libsyntax2/src/grammar.ron
+++ b/crates/libsyntax2/src/grammar.ron
@@ -221,24 +221,26 @@ Grammar(
221 ["functions", "FnDef"] 221 ["functions", "FnDef"]
222 ] 222 ]
223 ), 223 ),
224 "FnDef": ( traits: ["NameOwner"] ), 224 "FnDef": ( traits: ["NameOwner", "AttrsOwner"] ),
225 "StructDef": ( 225 "StructDef": (
226 traits: ["NameOwner"], 226 traits: ["NameOwner", "AttrsOwner"],
227 collections: [ 227 collections: [
228 ["fields", "NamedField"] 228 ["fields", "NamedField"]
229 ] 229 ]
230 ), 230 ),
231 "NamedField": ( traits: ["NameOwner"] ), 231 "NamedField": ( traits: ["NameOwner", "AttrsOwner"] ),
232 "EnumDef": ( traits: ["NameOwner"] ), 232 "EnumDef": ( traits: ["NameOwner", "AttrsOwner"] ),
233 "TraitDef": ( traits: ["NameOwner"] ), 233 "TraitDef": ( traits: ["NameOwner", "AttrsOwner"] ),
234 "Module": ( traits: ["NameOwner"] ), 234 "Module": ( traits: ["NameOwner", "AttrsOwner"] ),
235 "ConstDef": ( traits: ["NameOwner"] ), 235 "ConstDef": ( traits: ["NameOwner", "AttrsOwner"] ),
236 "StaticDef": ( traits: ["NameOwner"] ), 236 "StaticDef": ( traits: ["NameOwner", "AttrsOwner"] ),
237 "TypeDef": ( traits: ["NameOwner"] ), 237 "TypeDef": ( traits: ["NameOwner", "AttrsOwner"] ),
238 "ImplItem": (), 238 "ImplItem": (),
239 239
240 "Name": (), 240 "Name": (),
241 "NameRef": (), 241 "NameRef": (),
242 "Attr": ( options: [ ["value", "TokenTree"] ] ),
243 "TokenTree": (),
242 244
243 "ParenType": (), 245 "ParenType": (),
244 "TupleType": (), 246 "TupleType": (),
diff --git a/crates/libsyntax2/src/grammar/attributes.rs b/crates/libsyntax2/src/grammar/attributes.rs
index c411d4d7f..cd30e8a45 100644
--- a/crates/libsyntax2/src/grammar/attributes.rs
+++ b/crates/libsyntax2/src/grammar/attributes.rs
@@ -22,58 +22,10 @@ fn attribute(p: &mut Parser, inner: bool) {
22 p.bump(); 22 p.bump();
23 } 23 }
24 24
25 if p.expect(L_BRACK) { 25 if p.at(L_BRACK) {
26 meta_item(p); 26 items::token_tree(p);
27 p.expect(R_BRACK);
28 }
29 attr.complete(p, ATTR);
30}
31
32fn meta_item(p: &mut Parser) {
33 if p.at(IDENT) {
34 let meta_item = p.start();
35 p.bump();
36 match p.current() {
37 EQ => {
38 p.bump();
39 if expressions::literal(p).is_none() {
40 p.error("expected literal");
41 }
42 }
43 L_PAREN => meta_item_arg_list(p),
44 _ => (),
45 }
46 meta_item.complete(p, META_ITEM);
47 } else { 27 } else {
48 p.error("expected attribute value"); 28 p.error("expected `[`");
49 }
50}
51
52fn meta_item_arg_list(p: &mut Parser) {
53 assert!(p.at(L_PAREN));
54 p.bump();
55 loop {
56 match p.current() {
57 EOF | R_PAREN => break,
58 IDENT => meta_item(p),
59 c => if expressions::literal(p).is_none() {
60 let message = "expected attribute";
61
62 if items::ITEM_FIRST.contains(c) {
63 p.error(message);
64 return;
65 }
66
67 let err = p.start();
68 p.error(message);
69 p.bump();
70 err.complete(p, ERROR);
71 continue;
72 },
73 }
74 if !p.at(R_PAREN) {
75 p.expect(COMMA);
76 }
77 } 29 }
78 p.expect(R_PAREN); 30 attr.complete(p, ATTR);
79} 31}
diff --git a/crates/libsyntax2/src/grammar/items/mod.rs b/crates/libsyntax2/src/grammar/items/mod.rs
index fc02f0c5c..84cb47748 100644
--- a/crates/libsyntax2/src/grammar/items/mod.rs
+++ b/crates/libsyntax2/src/grammar/items/mod.rs
@@ -55,9 +55,6 @@ pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemF
55 } 55 }
56} 56}
57 57
58pub(super) const ITEM_FIRST: TokenSet =
59 token_set![EXTERN_KW, MOD_KW, USE_KW, STRUCT_KW, ENUM_KW, FN_KW, PUB_KW, POUND];
60
61pub(super) enum MaybeItem { 58pub(super) enum MaybeItem {
62 None, 59 None,
63 Item(SyntaxKind), 60 Item(SyntaxKind),
@@ -322,13 +319,14 @@ pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike {
322 flavor 319 flavor
323} 320}
324 321
325fn token_tree(p: &mut Parser) { 322pub(super) fn token_tree(p: &mut Parser) {
326 let closing_paren_kind = match p.current() { 323 let closing_paren_kind = match p.current() {
327 L_CURLY => R_CURLY, 324 L_CURLY => R_CURLY,
328 L_PAREN => R_PAREN, 325 L_PAREN => R_PAREN,
329 L_BRACK => R_BRACK, 326 L_BRACK => R_BRACK,
330 _ => unreachable!(), 327 _ => unreachable!(),
331 }; 328 };
329 let m = p.start();
332 p.bump(); 330 p.bump();
333 while !p.at(EOF) && !p.at(closing_paren_kind) { 331 while !p.at(EOF) && !p.at(closing_paren_kind) {
334 match p.current() { 332 match p.current() {
@@ -338,4 +336,5 @@ fn token_tree(p: &mut Parser) {
338 } 336 }
339 }; 337 };
340 p.expect(closing_paren_kind); 338 p.expect(closing_paren_kind);
339 m.complete(p, TOKEN_TREE);
341} 340}
diff --git a/crates/libsyntax2/tests/data/parser/err/0005_attribute_recover.txt b/crates/libsyntax2/tests/data/parser/err/0005_attribute_recover.txt
index 219352859..12451c892 100644
--- a/crates/libsyntax2/tests/data/parser/err/0005_attribute_recover.txt
+++ b/crates/libsyntax2/tests/data/parser/err/0005_attribute_recover.txt
@@ -2,25 +2,20 @@ FILE@[0; 54)
2 FN_DEF@[0; 31) 2 FN_DEF@[0; 31)
3 ATTR@[0; 18) 3 ATTR@[0; 18)
4 POUND@[0; 1) 4 POUND@[0; 1)
5 L_BRACK@[1; 2) 5 TOKEN_TREE@[1; 18)
6 META_ITEM@[2; 17) 6 L_BRACK@[1; 2)
7 IDENT@[2; 5) "foo" 7 IDENT@[2; 5) "foo"
8 L_PAREN@[5; 6) 8 TOKEN_TREE@[5; 17)
9 META_ITEM@[6; 9) 9 L_PAREN@[5; 6)
10 IDENT@[6; 9) "foo" 10 IDENT@[6; 9) "foo"
11 COMMA@[9; 10) 11 COMMA@[9; 10)
12 WHITESPACE@[10; 11) 12 WHITESPACE@[10; 11)
13 err: `expected attribute`
14 ERROR@[11; 12)
15 PLUS@[11; 12) 13 PLUS@[11; 12)
16 err: `expected attribute`
17 ERROR@[12; 13)
18 COMMA@[12; 13) 14 COMMA@[12; 13)
19 WHITESPACE@[13; 14) 15 WHITESPACE@[13; 14)
20 LITERAL@[14; 16)
21 INT_NUMBER@[14; 16) "92" 16 INT_NUMBER@[14; 16) "92"
22 R_PAREN@[16; 17) 17 R_PAREN@[16; 17)
23 R_BRACK@[17; 18) 18 R_BRACK@[17; 18)
24 WHITESPACE@[18; 19) 19 WHITESPACE@[18; 19)
25 FN_KW@[19; 21) 20 FN_KW@[19; 21)
26 WHITESPACE@[21; 22) 21 WHITESPACE@[21; 22)
@@ -35,26 +30,26 @@ FILE@[0; 54)
35 WHITESPACE@[29; 30) 30 WHITESPACE@[29; 30)
36 R_CURLY@[30; 31) 31 R_CURLY@[30; 31)
37 WHITESPACE@[31; 34) 32 WHITESPACE@[31; 34)
38 FN_DEF@[34; 53) 33 ATTR@[34; 53)
39 ATTR@[34; 40) 34 POUND@[34; 35)
40 POUND@[34; 35) 35 TOKEN_TREE@[35; 53)
41 L_BRACK@[35; 36) 36 L_BRACK@[35; 36)
42 META_ITEM@[36; 40) 37 IDENT@[36; 39) "foo"
43 IDENT@[36; 39) "foo" 38 TOKEN_TREE@[39; 53)
44 L_PAREN@[39; 40) 39 L_PAREN@[39; 40)
45 err: `expected attribute` 40 WHITESPACE@[40; 41)
46 err: `expected R_BRACK` 41 FN_KW@[41; 43)
47 WHITESPACE@[40; 41) 42 WHITESPACE@[43; 44)
48 FN_KW@[41; 43) 43 IDENT@[44; 47) "foo"
49 WHITESPACE@[43; 44) 44 TOKEN_TREE@[47; 49)
50 NAME@[44; 47) 45 L_PAREN@[47; 48)
51 IDENT@[44; 47) "foo" 46 R_PAREN@[48; 49)
52 PARAM_LIST@[47; 49) 47 WHITESPACE@[49; 50)
53 L_PAREN@[47; 48) 48 TOKEN_TREE@[50; 53)
54 R_PAREN@[48; 49) 49 L_CURLY@[50; 51)
55 WHITESPACE@[49; 50) 50 WHITESPACE@[51; 52)
56 BLOCK_EXPR@[50; 53) 51 R_CURLY@[52; 53)
57 L_CURLY@[50; 51) 52 err: `expected R_PAREN`
58 WHITESPACE@[51; 52) 53 err: `expected R_BRACK`
59 R_CURLY@[52; 53) 54 err: `expected an item`
60 WHITESPACE@[53; 54) 55 WHITESPACE@[53; 54)
diff --git a/crates/libsyntax2/tests/data/parser/err/0008_item_block_recovery.txt b/crates/libsyntax2/tests/data/parser/err/0008_item_block_recovery.txt
index 5b46be079..68f2b8aa5 100644
--- a/crates/libsyntax2/tests/data/parser/err/0008_item_block_recovery.txt
+++ b/crates/libsyntax2/tests/data/parser/err/0008_item_block_recovery.txt
@@ -19,9 +19,10 @@ FILE@[0; 95)
19 NAME_REF@[14; 17) 19 NAME_REF@[14; 17)
20 IDENT@[14; 17) "bar" 20 IDENT@[14; 17) "bar"
21 err: `expected EXCL` 21 err: `expected EXCL`
22 L_PAREN@[17; 18) 22 TOKEN_TREE@[17; 19)
23 R_PAREN@[18; 19) 23 L_PAREN@[17; 18)
24 err: `expected SEMI` 24 R_PAREN@[18; 19)
25 err: `expected SEMI`
25 WHITESPACE@[19; 20) 26 WHITESPACE@[19; 20)
26 err: `expected an item` 27 err: `expected an item`
27 ERROR@[20; 80) 28 ERROR@[20; 80)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0039_path_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0039_path_expr.txt
index 876dd068c..629a8ec9b 100644
--- a/crates/libsyntax2/tests/data/parser/inline/0039_path_expr.txt
+++ b/crates/libsyntax2/tests/data/parser/inline/0039_path_expr.txt
@@ -86,8 +86,9 @@ FILE@[0; 91)
86 NAME_REF@[78; 84) 86 NAME_REF@[78; 84)
87 IDENT@[78; 84) "format" 87 IDENT@[78; 84) "format"
88 EXCL@[84; 85) 88 EXCL@[84; 85)
89 L_PAREN@[85; 86) 89 TOKEN_TREE@[85; 87)
90 R_PAREN@[86; 87) 90 L_PAREN@[85; 86)
91 R_PAREN@[86; 87)
91 SEMI@[87; 88) 92 SEMI@[87; 88)
92 WHITESPACE@[88; 89) 93 WHITESPACE@[88; 89)
93 R_CURLY@[89; 90) 94 R_CURLY@[89; 90)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0078_mod_contents.txt b/crates/libsyntax2/tests/data/parser/inline/0078_mod_contents.txt
index c6be58e75..696695eba 100644
--- a/crates/libsyntax2/tests/data/parser/inline/0078_mod_contents.txt
+++ b/crates/libsyntax2/tests/data/parser/inline/0078_mod_contents.txt
@@ -21,8 +21,9 @@ FILE@[0; 70)
21 WHITESPACE@[24; 25) 21 WHITESPACE@[24; 25)
22 IDENT@[25; 28) "foo" 22 IDENT@[25; 28) "foo"
23 WHITESPACE@[28; 29) 23 WHITESPACE@[28; 29)
24 L_CURLY@[29; 30) 24 TOKEN_TREE@[29; 31)
25 R_CURLY@[30; 31) 25 L_CURLY@[29; 30)
26 R_CURLY@[30; 31)
26 WHITESPACE@[31; 32) 27 WHITESPACE@[31; 32)
27 MACRO_CALL@[32; 44) 28 MACRO_CALL@[32; 44)
28 PATH@[32; 40) 29 PATH@[32; 40)
@@ -35,8 +36,9 @@ FILE@[0; 70)
35 NAME_REF@[37; 40) 36 NAME_REF@[37; 40)
36 IDENT@[37; 40) "bar" 37 IDENT@[37; 40) "bar"
37 EXCL@[40; 41) 38 EXCL@[40; 41)
38 L_PAREN@[41; 42) 39 TOKEN_TREE@[41; 43)
39 R_PAREN@[42; 43) 40 L_PAREN@[41; 42)
41 R_PAREN@[42; 43)
40 SEMI@[43; 44) 42 SEMI@[43; 44)
41 WHITESPACE@[44; 45) 43 WHITESPACE@[44; 45)
42 MACRO_CALL@[45; 59) 44 MACRO_CALL@[45; 59)
@@ -50,8 +52,9 @@ FILE@[0; 70)
50 IDENT@[52; 55) "baz" 52 IDENT@[52; 55) "baz"
51 EXCL@[55; 56) 53 EXCL@[55; 56)
52 WHITESPACE@[56; 57) 54 WHITESPACE@[56; 57)
53 L_CURLY@[57; 58) 55 TOKEN_TREE@[57; 59)
54 R_CURLY@[58; 59) 56 L_CURLY@[57; 58)
57 R_CURLY@[58; 59)
55 WHITESPACE@[59; 60) 58 WHITESPACE@[59; 60)
56 STRUCT_DEF@[60; 69) 59 STRUCT_DEF@[60; 69)
57 STRUCT_KW@[60; 66) 60 STRUCT_KW@[60; 66)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0006_inner_attributes.txt b/crates/libsyntax2/tests/data/parser/ok/0006_inner_attributes.txt
index 562c8d917..d5a170144 100644
--- a/crates/libsyntax2/tests/data/parser/ok/0006_inner_attributes.txt
+++ b/crates/libsyntax2/tests/data/parser/ok/0006_inner_attributes.txt
@@ -2,175 +2,163 @@ FILE@[0; 236)
2 ATTR@[0; 8) 2 ATTR@[0; 8)
3 POUND@[0; 1) 3 POUND@[0; 1)
4 EXCL@[1; 2) 4 EXCL@[1; 2)
5 L_BRACK@[2; 3) 5 TOKEN_TREE@[2; 8)
6 META_ITEM@[3; 7) 6 L_BRACK@[2; 3)
7 IDENT@[3; 7) "attr" 7 IDENT@[3; 7) "attr"
8 R_BRACK@[7; 8) 8 R_BRACK@[7; 8)
9 WHITESPACE@[8; 9) 9 WHITESPACE@[8; 9)
10 ATTR@[9; 23) 10 ATTR@[9; 23)
11 POUND@[9; 10) 11 POUND@[9; 10)
12 EXCL@[10; 11) 12 EXCL@[10; 11)
13 L_BRACK@[11; 12) 13 TOKEN_TREE@[11; 23)
14 META_ITEM@[12; 22) 14 L_BRACK@[11; 12)
15 IDENT@[12; 16) "attr" 15 IDENT@[12; 16) "attr"
16 L_PAREN@[16; 17) 16 TOKEN_TREE@[16; 22)
17 LITERAL@[17; 21) 17 L_PAREN@[16; 17)
18 TRUE_KW@[17; 21) 18 TRUE_KW@[17; 21)
19 R_PAREN@[21; 22) 19 R_PAREN@[21; 22)
20 R_BRACK@[22; 23) 20 R_BRACK@[22; 23)
21 WHITESPACE@[23; 24) 21 WHITESPACE@[23; 24)
22 ATTR@[24; 39) 22 ATTR@[24; 39)
23 POUND@[24; 25) 23 POUND@[24; 25)
24 EXCL@[25; 26) 24 EXCL@[25; 26)
25 L_BRACK@[26; 27) 25 TOKEN_TREE@[26; 39)
26 META_ITEM@[27; 38) 26 L_BRACK@[26; 27)
27 IDENT@[27; 31) "attr" 27 IDENT@[27; 31) "attr"
28 L_PAREN@[31; 32) 28 TOKEN_TREE@[31; 38)
29 META_ITEM@[32; 37) 29 L_PAREN@[31; 32)
30 IDENT@[32; 37) "ident" 30 IDENT@[32; 37) "ident"
31 R_PAREN@[37; 38) 31 R_PAREN@[37; 38)
32 R_BRACK@[38; 39) 32 R_BRACK@[38; 39)
33 WHITESPACE@[39; 40) 33 WHITESPACE@[39; 40)
34 ATTR@[40; 116) 34 ATTR@[40; 116)
35 POUND@[40; 41) 35 POUND@[40; 41)
36 EXCL@[41; 42) 36 EXCL@[41; 42)
37 L_BRACK@[42; 43) 37 TOKEN_TREE@[42; 116)
38 META_ITEM@[43; 115) 38 L_BRACK@[42; 43)
39 IDENT@[43; 47) "attr" 39 IDENT@[43; 47) "attr"
40 L_PAREN@[47; 48) 40 TOKEN_TREE@[47; 115)
41 META_ITEM@[48; 53) 41 L_PAREN@[47; 48)
42 IDENT@[48; 53) "ident" 42 IDENT@[48; 53) "ident"
43 COMMA@[53; 54) 43 COMMA@[53; 54)
44 WHITESPACE@[54; 55) 44 WHITESPACE@[54; 55)
45 LITERAL@[55; 58)
46 INT_NUMBER@[55; 58) "100" 45 INT_NUMBER@[55; 58) "100"
47 COMMA@[58; 59) 46 COMMA@[58; 59)
48 WHITESPACE@[59; 60) 47 WHITESPACE@[59; 60)
49 LITERAL@[60; 64)
50 TRUE_KW@[60; 64) 48 TRUE_KW@[60; 64)
51 COMMA@[64; 65) 49 COMMA@[64; 65)
52 WHITESPACE@[65; 66) 50 WHITESPACE@[65; 66)
53 LITERAL@[66; 72)
54 STRING@[66; 72) 51 STRING@[66; 72)
55 COMMA@[72; 73) 52 COMMA@[72; 73)
56 WHITESPACE@[73; 74) 53 WHITESPACE@[73; 74)
57 META_ITEM@[74; 85)
58 IDENT@[74; 79) "ident" 54 IDENT@[74; 79) "ident"
59 WHITESPACE@[79; 80) 55 WHITESPACE@[79; 80)
60 EQ@[80; 81) 56 EQ@[80; 81)
61 WHITESPACE@[81; 82) 57 WHITESPACE@[81; 82)
62 LITERAL@[82; 85) 58 INT_NUMBER@[82; 85) "100"
63 INT_NUMBER@[82; 85) "100" 59 COMMA@[85; 86)
64 COMMA@[85; 86) 60 WHITESPACE@[86; 87)
65 WHITESPACE@[86; 87)
66 META_ITEM@[87; 102)
67 IDENT@[87; 92) "ident" 61 IDENT@[87; 92) "ident"
68 WHITESPACE@[92; 93) 62 WHITESPACE@[92; 93)
69 EQ@[93; 94) 63 EQ@[93; 94)
70 WHITESPACE@[94; 95) 64 WHITESPACE@[94; 95)
71 LITERAL@[95; 102) 65 STRING@[95; 102)
72 STRING@[95; 102) 66 COMMA@[102; 103)
73 COMMA@[102; 103) 67 WHITESPACE@[103; 104)
74 WHITESPACE@[103; 104)
75 META_ITEM@[104; 114)
76 IDENT@[104; 109) "ident" 68 IDENT@[104; 109) "ident"
77 L_PAREN@[109; 110) 69 TOKEN_TREE@[109; 114)
78 LITERAL@[110; 113) 70 L_PAREN@[109; 110)
79 INT_NUMBER@[110; 113) "100" 71 INT_NUMBER@[110; 113) "100"
80 R_PAREN@[113; 114) 72 R_PAREN@[113; 114)
81 R_PAREN@[114; 115) 73 R_PAREN@[114; 115)
82 R_BRACK@[115; 116) 74 R_BRACK@[115; 116)
83 WHITESPACE@[116; 117) 75 WHITESPACE@[116; 117)
84 ATTR@[117; 130) 76 ATTR@[117; 130)
85 POUND@[117; 118) 77 POUND@[117; 118)
86 EXCL@[118; 119) 78 EXCL@[118; 119)
87 L_BRACK@[119; 120) 79 TOKEN_TREE@[119; 130)
88 META_ITEM@[120; 129) 80 L_BRACK@[119; 120)
89 IDENT@[120; 124) "attr" 81 IDENT@[120; 124) "attr"
90 L_PAREN@[124; 125) 82 TOKEN_TREE@[124; 129)
91 LITERAL@[125; 128) 83 L_PAREN@[124; 125)
92 INT_NUMBER@[125; 128) "100" 84 INT_NUMBER@[125; 128) "100"
93 R_PAREN@[128; 129) 85 R_PAREN@[128; 129)
94 R_BRACK@[129; 130) 86 R_BRACK@[129; 130)
95 WHITESPACE@[130; 131) 87 WHITESPACE@[130; 131)
96 ATTR@[131; 155) 88 ATTR@[131; 155)
97 POUND@[131; 132) 89 POUND@[131; 132)
98 EXCL@[132; 133) 90 EXCL@[132; 133)
99 L_BRACK@[133; 134) 91 TOKEN_TREE@[133; 155)
100 META_ITEM@[134; 154) 92 L_BRACK@[133; 134)
101 IDENT@[134; 138) "attr" 93 IDENT@[134; 138) "attr"
102 L_PAREN@[138; 139) 94 TOKEN_TREE@[138; 154)
103 META_ITEM@[139; 153) 95 L_PAREN@[138; 139)
104 IDENT@[139; 146) "enabled" 96 IDENT@[139; 146) "enabled"
105 WHITESPACE@[146; 147) 97 WHITESPACE@[146; 147)
106 EQ@[147; 148) 98 EQ@[147; 148)
107 WHITESPACE@[148; 149) 99 WHITESPACE@[148; 149)
108 LITERAL@[149; 153) 100 TRUE_KW@[149; 153)
109 TRUE_KW@[149; 153) 101 R_PAREN@[153; 154)
110 R_PAREN@[153; 154) 102 R_BRACK@[154; 155)
111 R_BRACK@[154; 155)
112 WHITESPACE@[155; 156) 103 WHITESPACE@[155; 156)
113 ATTR@[156; 173) 104 ATTR@[156; 173)
114 POUND@[156; 157) 105 POUND@[156; 157)
115 EXCL@[157; 158) 106 EXCL@[157; 158)
116 L_BRACK@[158; 159) 107 TOKEN_TREE@[158; 173)
117 META_ITEM@[159; 172) 108 L_BRACK@[158; 159)
118 IDENT@[159; 166) "enabled" 109 IDENT@[159; 166) "enabled"
119 L_PAREN@[166; 167) 110 TOKEN_TREE@[166; 172)
120 LITERAL@[167; 171) 111 L_PAREN@[166; 167)
121 TRUE_KW@[167; 171) 112 TRUE_KW@[167; 171)
122 R_PAREN@[171; 172) 113 R_PAREN@[171; 172)
123 R_BRACK@[172; 173) 114 R_BRACK@[172; 173)
124 WHITESPACE@[173; 174) 115 WHITESPACE@[173; 174)
125 ATTR@[174; 191) 116 ATTR@[174; 191)
126 POUND@[174; 175) 117 POUND@[174; 175)
127 EXCL@[175; 176) 118 EXCL@[175; 176)
128 L_BRACK@[176; 177) 119 TOKEN_TREE@[176; 191)
129 META_ITEM@[177; 190) 120 L_BRACK@[176; 177)
130 IDENT@[177; 181) "attr" 121 IDENT@[177; 181) "attr"
131 L_PAREN@[181; 182) 122 TOKEN_TREE@[181; 190)
132 LITERAL@[182; 189) 123 L_PAREN@[181; 182)
133 STRING@[182; 189) 124 STRING@[182; 189)
134 R_PAREN@[189; 190) 125 R_PAREN@[189; 190)
135 R_BRACK@[190; 191) 126 R_BRACK@[190; 191)
136 WHITESPACE@[191; 192) 127 WHITESPACE@[191; 192)
137 ATTR@[192; 214) 128 ATTR@[192; 214)
138 POUND@[192; 193) 129 POUND@[192; 193)
139 EXCL@[193; 194) 130 EXCL@[193; 194)
140 L_BRACK@[194; 195) 131 TOKEN_TREE@[194; 214)
141 META_ITEM@[195; 213) 132 L_BRACK@[194; 195)
142 IDENT@[195; 199) "repr" 133 IDENT@[195; 199) "repr"
143 L_PAREN@[199; 200) 134 TOKEN_TREE@[199; 213)
144 META_ITEM@[200; 201) 135 L_PAREN@[199; 200)
145 IDENT@[200; 201) "C" 136 IDENT@[200; 201) "C"
146 COMMA@[201; 202) 137 COMMA@[201; 202)
147 WHITESPACE@[202; 203) 138 WHITESPACE@[202; 203)
148 META_ITEM@[203; 212)
149 IDENT@[203; 208) "align" 139 IDENT@[203; 208) "align"
150 WHITESPACE@[208; 209) 140 WHITESPACE@[208; 209)
151 EQ@[209; 210) 141 EQ@[209; 210)
152 WHITESPACE@[210; 211) 142 WHITESPACE@[210; 211)
153 LITERAL@[211; 212) 143 INT_NUMBER@[211; 212) "4"
154 INT_NUMBER@[211; 212) "4" 144 R_PAREN@[212; 213)
155 R_PAREN@[212; 213) 145 R_BRACK@[213; 214)
156 R_BRACK@[213; 214)
157 WHITESPACE@[214; 215) 146 WHITESPACE@[214; 215)
158 ATTR@[215; 236) 147 ATTR@[215; 236)
159 POUND@[215; 216) 148 POUND@[215; 216)
160 EXCL@[216; 217) 149 EXCL@[216; 217)
161 L_BRACK@[217; 218) 150 TOKEN_TREE@[217; 236)
162 META_ITEM@[218; 235) 151 L_BRACK@[217; 218)
163 IDENT@[218; 222) "repr" 152 IDENT@[218; 222) "repr"
164 L_PAREN@[222; 223) 153 TOKEN_TREE@[222; 235)
165 META_ITEM@[223; 224) 154 L_PAREN@[222; 223)
166 IDENT@[223; 224) "C" 155 IDENT@[223; 224) "C"
167 COMMA@[224; 225) 156 COMMA@[224; 225)
168 WHITESPACE@[225; 226) 157 WHITESPACE@[225; 226)
169 META_ITEM@[226; 234)
170 IDENT@[226; 231) "align" 158 IDENT@[226; 231) "align"
171 L_PAREN@[231; 232) 159 TOKEN_TREE@[231; 234)
172 LITERAL@[232; 233) 160 L_PAREN@[231; 232)
173 INT_NUMBER@[232; 233) "4" 161 INT_NUMBER@[232; 233) "4"
174 R_PAREN@[233; 234) 162 R_PAREN@[233; 234)
175 R_PAREN@[234; 235) 163 R_PAREN@[234; 235)
176 R_BRACK@[235; 236) 164 R_BRACK@[235; 236)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0008_mod_item.txt b/crates/libsyntax2/tests/data/parser/ok/0008_mod_item.txt
index abd2f8d61..54fe69baf 100644
--- a/crates/libsyntax2/tests/data/parser/ok/0008_mod_item.txt
+++ b/crates/libsyntax2/tests/data/parser/ok/0008_mod_item.txt
@@ -60,10 +60,10 @@ FILE@[0; 118)
60 ATTR@[79; 87) 60 ATTR@[79; 87)
61 POUND@[79; 80) 61 POUND@[79; 80)
62 EXCL@[80; 81) 62 EXCL@[80; 81)
63 L_BRACK@[81; 82) 63 TOKEN_TREE@[81; 87)
64 META_ITEM@[82; 86) 64 L_BRACK@[81; 82)
65 IDENT@[82; 86) "attr" 65 IDENT@[82; 86) "attr"
66 R_BRACK@[86; 87) 66 R_BRACK@[86; 87)
67 WHITESPACE@[87; 92) 67 WHITESPACE@[87; 92)
68 MODULE@[92; 98) 68 MODULE@[92; 98)
69 MOD_KW@[92; 95) 69 MOD_KW@[92; 95)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0011_outer_attribute.txt b/crates/libsyntax2/tests/data/parser/ok/0011_outer_attribute.txt
index eae432fe2..24647fb06 100644
--- a/crates/libsyntax2/tests/data/parser/ok/0011_outer_attribute.txt
+++ b/crates/libsyntax2/tests/data/parser/ok/0011_outer_attribute.txt
@@ -2,21 +2,21 @@ FILE@[0; 35)
2 FN_DEF@[0; 34) 2 FN_DEF@[0; 34)
3 ATTR@[0; 12) 3 ATTR@[0; 12)
4 POUND@[0; 1) 4 POUND@[0; 1)
5 L_BRACK@[1; 2) 5 TOKEN_TREE@[1; 12)
6 META_ITEM@[2; 11) 6 L_BRACK@[1; 2)
7 IDENT@[2; 5) "cfg" 7 IDENT@[2; 5) "cfg"
8 L_PAREN@[5; 6) 8 TOKEN_TREE@[5; 11)
9 META_ITEM@[6; 10) 9 L_PAREN@[5; 6)
10 IDENT@[6; 10) "test" 10 IDENT@[6; 10) "test"
11 R_PAREN@[10; 11) 11 R_PAREN@[10; 11)
12 R_BRACK@[11; 12) 12 R_BRACK@[11; 12)
13 WHITESPACE@[12; 13) 13 WHITESPACE@[12; 13)
14 ATTR@[13; 22) 14 ATTR@[13; 22)
15 POUND@[13; 14) 15 POUND@[13; 14)
16 L_BRACK@[14; 15) 16 TOKEN_TREE@[14; 22)
17 META_ITEM@[15; 21) 17 L_BRACK@[14; 15)
18 IDENT@[15; 21) "ignore" 18 IDENT@[15; 21) "ignore"
19 R_BRACK@[21; 22) 19 R_BRACK@[21; 22)
20 WHITESPACE@[22; 23) 20 WHITESPACE@[22; 23)
21 FN_KW@[23; 25) 21 FN_KW@[23; 25)
22 WHITESPACE@[25; 26) 22 WHITESPACE@[25; 26)
diff --git a/crates/libsyntax2/tests/data/parser/ok/0017_attr_trailing_comma.txt b/crates/libsyntax2/tests/data/parser/ok/0017_attr_trailing_comma.txt
index 993cdcdec..6acd842c6 100644
--- a/crates/libsyntax2/tests/data/parser/ok/0017_attr_trailing_comma.txt
+++ b/crates/libsyntax2/tests/data/parser/ok/0017_attr_trailing_comma.txt
@@ -2,15 +2,15 @@ FILE@[0; 23)
2 FN_DEF@[0; 22) 2 FN_DEF@[0; 22)
3 ATTR@[0; 10) 3 ATTR@[0; 10)
4 POUND@[0; 1) 4 POUND@[0; 1)
5 L_BRACK@[1; 2) 5 TOKEN_TREE@[1; 10)
6 META_ITEM@[2; 9) 6 L_BRACK@[1; 2)
7 IDENT@[2; 5) "foo" 7 IDENT@[2; 5) "foo"
8 L_PAREN@[5; 6) 8 TOKEN_TREE@[5; 9)
9 META_ITEM@[6; 7) 9 L_PAREN@[5; 6)
10 IDENT@[6; 7) "a" 10 IDENT@[6; 7) "a"
11 COMMA@[7; 8) 11 COMMA@[7; 8)
12 R_PAREN@[8; 9) 12 R_PAREN@[8; 9)
13 R_BRACK@[9; 10) 13 R_BRACK@[9; 10)
14 WHITESPACE@[10; 11) 14 WHITESPACE@[10; 11)
15 FN_KW@[11; 13) 15 FN_KW@[11; 13)
16 WHITESPACE@[13; 14) 16 WHITESPACE@[13; 14)
diff --git a/crates/libsyntax2/tests/test/main.rs b/crates/libsyntax2/tests/test/main.rs
index 6b0a44d0c..802dba0e9 100644
--- a/crates/libsyntax2/tests/test/main.rs
+++ b/crates/libsyntax2/tests/test/main.rs
@@ -70,19 +70,19 @@ fn assert_equal_text(expected: &str, actual: &str, path: &Path) {
70 return; 70 return;
71 } 71 }
72 let dir = project_dir(); 72 let dir = project_dir();
73 let path = path.strip_prefix(&dir).unwrap_or_else(|_| path); 73 let pretty_path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
74 if expected.trim() == actual.trim() { 74 if expected.trim() == actual.trim() {
75 println!("whitespace difference, rewriting"); 75 println!("whitespace difference, rewriting");
76 println!("file: {}\n", path.display()); 76 println!("file: {}\n", pretty_path.display());
77 fs::write(path, actual).unwrap(); 77 fs::write(path, actual).unwrap();
78 return; 78 return;
79 } 79 }
80 if REWRITE { 80 if REWRITE {
81 println!("rewriting {}", path.display()); 81 println!("rewriting {}", pretty_path.display());
82 fs::write(path, actual).unwrap(); 82 fs::write(path, actual).unwrap();
83 return; 83 return;
84 } 84 }
85 assert_eq_text!(expected, actual, "file: {}", path.display()); 85 assert_eq_text!(expected, actual, "file: {}", pretty_path.display());
86} 86}
87 87
88fn collect_tests(paths: &[&str]) -> Vec<PathBuf> { 88fn collect_tests(paths: &[&str]) -> Vec<PathBuf> {