1
+ //! To make attribute macros work reliably when typing, we need to take care to
2
+ //! fix up syntax errors in the code we're passing to them.
3
+ use std:: mem;
4
+
1
5
use mbe:: { SyntheticToken , SyntheticTokenId , TokenMap } ;
2
6
use rustc_hash:: FxHashMap ;
3
7
use syntax:: {
@@ -6,16 +10,22 @@ use syntax::{
6
10
} ;
7
11
use tt:: Subtree ;
8
12
13
+ /// The result of calculating fixes for a syntax node -- a bunch of changes
14
+ /// (appending to and replacing nodes), the information that is needed to
15
+ /// reverse those changes afterwards, and a token map.
9
16
#[ derive( Debug ) ]
10
17
pub struct SyntaxFixups {
11
18
pub append : FxHashMap < SyntaxNode , Vec < SyntheticToken > > ,
12
19
pub replace : FxHashMap < SyntaxNode , Vec < SyntheticToken > > ,
13
- pub map : SyntaxFixupMap ,
20
+ pub undo_info : SyntaxFixupUndoInfo ,
21
+ pub token_map : TokenMap ,
22
+ pub next_id : u32 ,
14
23
}
15
24
25
+ /// This is the information needed to reverse the fixups.
16
26
#[ derive( Debug , PartialEq , Eq ) ]
17
- pub struct SyntaxFixupMap {
18
- original : Vec < ( Subtree , TokenMap ) > ,
27
+ pub struct SyntaxFixupUndoInfo {
28
+ original : Vec < Subtree > ,
19
29
}
20
30
21
31
const EMPTY_ID : SyntheticTokenId = SyntheticTokenId ( !0 ) ;
@@ -25,15 +35,26 @@ pub fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups {
25
35
let mut replace = FxHashMap :: default ( ) ;
26
36
let mut preorder = node. preorder ( ) ;
27
37
let mut original = Vec :: new ( ) ;
38
+ let mut token_map = TokenMap :: default ( ) ;
39
+ let mut next_id = 0 ;
28
40
while let Some ( event) = preorder. next ( ) {
29
41
let node = match event {
30
42
syntax:: WalkEvent :: Enter ( node) => node,
31
43
syntax:: WalkEvent :: Leave ( _) => continue ,
32
44
} ;
45
+
33
46
if can_handle_error ( & node) && has_error_to_handle ( & node) {
34
47
// the node contains an error node, we have to completely replace it by something valid
35
- let original_tree = mbe:: syntax_node_to_token_tree ( & node) ;
36
- // TODO handle token ids / token map
48
+ let ( original_tree, new_tmap, new_next_id) =
49
+ mbe:: syntax_node_to_token_tree_with_modifications (
50
+ & node,
51
+ mem:: take ( & mut token_map) ,
52
+ next_id,
53
+ Default :: default ( ) ,
54
+ Default :: default ( ) ,
55
+ ) ;
56
+ token_map = new_tmap;
57
+ next_id = new_next_id;
37
58
let idx = original. len ( ) as u32 ;
38
59
original. push ( original_tree) ;
39
60
let replacement = SyntheticToken {
@@ -46,6 +67,8 @@ pub fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups {
46
67
preorder. skip_subtree ( ) ;
47
68
continue ;
48
69
}
70
+
71
+ // In some other situations, we can fix things by just appending some tokens.
49
72
let end_range = TextRange :: empty ( node. text_range ( ) . end ( ) ) ;
50
73
match_ast ! {
51
74
match node {
@@ -78,7 +101,13 @@ pub fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups {
78
101
}
79
102
}
80
103
}
81
- SyntaxFixups { append, replace, map : SyntaxFixupMap { original } }
104
+ SyntaxFixups {
105
+ append,
106
+ replace,
107
+ token_map,
108
+ next_id,
109
+ undo_info : SyntaxFixupUndoInfo { original } ,
110
+ }
82
111
}
83
112
84
113
fn has_error ( node : & SyntaxNode ) -> bool {
@@ -93,7 +122,7 @@ fn has_error_to_handle(node: &SyntaxNode) -> bool {
93
122
has_error ( node) || node. children ( ) . any ( |c| !can_handle_error ( & c) && has_error_to_handle ( & c) )
94
123
}
95
124
96
- pub fn reverse_fixups ( tt : & mut Subtree , token_map : & TokenMap , fixup_map : & SyntaxFixupMap ) {
125
+ pub fn reverse_fixups ( tt : & mut Subtree , token_map : & TokenMap , undo_info : & SyntaxFixupUndoInfo ) {
97
126
tt. token_trees . retain ( |tt| match tt {
98
127
tt:: TokenTree :: Leaf ( leaf) => {
99
128
token_map. synthetic_token_id ( leaf. id ( ) ) . is_none ( )
@@ -102,10 +131,10 @@ pub fn reverse_fixups(tt: &mut Subtree, token_map: &TokenMap, fixup_map: &Syntax
102
131
_ => true ,
103
132
} ) ;
104
133
tt. token_trees . iter_mut ( ) . for_each ( |tt| match tt {
105
- tt:: TokenTree :: Subtree ( tt) => reverse_fixups ( tt, token_map, fixup_map ) ,
134
+ tt:: TokenTree :: Subtree ( tt) => reverse_fixups ( tt, token_map, undo_info ) ,
106
135
tt:: TokenTree :: Leaf ( leaf) => {
107
136
if let Some ( id) = token_map. synthetic_token_id ( leaf. id ( ) ) {
108
- let ( original, _original_tmap ) = & fixup_map . original [ id. 0 as usize ] ;
137
+ let original = & undo_info . original [ id. 0 as usize ] ;
109
138
* tt = tt:: TokenTree :: Subtree ( original. clone ( ) ) ;
110
139
}
111
140
}
@@ -123,8 +152,10 @@ mod tests {
123
152
let parsed = syntax:: SourceFile :: parse ( ra_fixture) ;
124
153
eprintln ! ( "parse: {:#?}" , parsed. syntax_node( ) ) ;
125
154
let fixups = super :: fixup_syntax ( & parsed. syntax_node ( ) ) ;
126
- let ( mut tt, tmap) = mbe:: syntax_node_to_token_tree_with_modifications (
155
+ let ( mut tt, tmap, _ ) = mbe:: syntax_node_to_token_tree_with_modifications (
127
156
& parsed. syntax_node ( ) ,
157
+ fixups. token_map ,
158
+ fixups. next_id ,
128
159
fixups. replace ,
129
160
fixups. append ,
130
161
) ;
@@ -144,7 +175,7 @@ mod tests {
144
175
parse. syntax_node( )
145
176
) ;
146
177
147
- reverse_fixups ( & mut tt, & tmap, & fixups. map ) ;
178
+ reverse_fixups ( & mut tt, & tmap, & fixups. undo_info ) ;
148
179
149
180
// the fixed-up + reversed version should be equivalent to the original input
150
181
// (but token IDs don't matter)
0 commit comments