@@ -5,7 +5,7 @@ use std::sync::Arc;
5
5
use base_db:: { salsa, SourceDatabase } ;
6
6
use itertools:: Itertools ;
7
7
use limit:: Limit ;
8
- use mbe:: { ExpandError , ExpandResult } ;
8
+ use mbe:: { syntax_node_to_token_tree , ExpandError , ExpandResult } ;
9
9
use syntax:: {
10
10
algo:: diff,
11
11
ast:: { self , AttrsOwner , NameOwner } ,
@@ -141,27 +141,72 @@ pub trait AstDatabase: SourceDatabase {
141
141
pub fn expand_speculative (
142
142
db : & dyn AstDatabase ,
143
143
actual_macro_call : MacroCallId ,
144
- speculative_args : & ast :: TokenTree ,
144
+ speculative_args : & SyntaxNode ,
145
145
token_to_map : SyntaxToken ,
146
146
) -> Option < ( SyntaxNode , SyntaxToken ) > {
147
- let ( tt, tmap_1) = mbe:: syntax_node_to_token_tree ( speculative_args. syntax ( ) ) ;
148
- let range =
149
- token_to_map. text_range ( ) . checked_sub ( speculative_args. syntax ( ) . text_range ( ) . start ( ) ) ?;
150
- let token_id = tmap_1. token_by_range ( range) ?;
151
-
152
- let macro_def = {
153
- let loc: MacroCallLoc = db. lookup_intern_macro ( actual_macro_call) ;
154
- db. macro_def ( loc. def ) ?
147
+ let loc = db. lookup_intern_macro ( actual_macro_call) ;
148
+ let macro_def = db. macro_def ( loc. def ) ?;
149
+ let token_range = token_to_map. text_range ( ) ;
150
+
151
+ // Build the subtree and token mapping for the speculative args
152
+ let censor = censor_for_macro_input ( & loc, & speculative_args) ;
153
+ let ( mut tt, spec_args_tmap) =
154
+ mbe:: syntax_node_to_token_tree_censored ( & speculative_args, censor) ;
155
+
156
+ let ( attr_arg, token_id) = match loc. kind {
157
+ MacroCallKind :: Attr { invoc_attr_index, .. } => {
158
+ // Attributes may have an input token tree, build the subtree and map for this as well
159
+ // then try finding a token id for our token if it is inside this input subtree.
160
+ let item = ast:: Item :: cast ( speculative_args. clone ( ) ) ?;
161
+ let attr = item. attrs ( ) . nth ( invoc_attr_index as usize ) ?;
162
+ match attr. token_tree ( ) {
163
+ Some ( token_tree) => {
164
+ let ( mut tree, map) = syntax_node_to_token_tree ( attr. token_tree ( ) ?. syntax ( ) ) ;
165
+ tree. delimiter = None ;
166
+
167
+ let shift = mbe:: Shift :: new ( & tt) ;
168
+ shift. shift_all ( & mut tree) ;
169
+
170
+ let token_id = if token_tree. syntax ( ) . text_range ( ) . contains_range ( token_range) {
171
+ let attr_input_start =
172
+ token_tree. left_delimiter_token ( ) ?. text_range ( ) . start ( ) ;
173
+ let range = token_range. checked_sub ( attr_input_start) ?;
174
+ let token_id = shift. shift ( map. token_by_range ( range) ?) ;
175
+ Some ( token_id)
176
+ } else {
177
+ None
178
+ } ;
179
+ ( Some ( tree) , token_id)
180
+ }
181
+ _ => ( None , None ) ,
182
+ }
183
+ }
184
+ _ => ( None , None ) ,
185
+ } ;
186
+ let token_id = match token_id {
187
+ Some ( token_id) => token_id,
188
+ // token wasn't inside an attribute input so it has to be in the general macro input
189
+ None => {
190
+ let range = token_range. checked_sub ( speculative_args. text_range ( ) . start ( ) ) ?;
191
+ let token_id = spec_args_tmap. token_by_range ( range) ?;
192
+ macro_def. map_id_down ( token_id)
193
+ }
155
194
} ;
156
195
157
- let speculative_expansion = macro_def. expand ( db, actual_macro_call, & tt) ;
196
+ // Do the actual expansion, we need to directly expand the proc macro due to the attribute args
197
+ // Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
198
+ let speculative_expansion = if let MacroDefKind :: ProcMacro ( expander, ..) = loc. def . kind {
199
+ tt. delimiter = None ;
200
+ expander. expand ( db, loc. krate , & tt, attr_arg. as_ref ( ) )
201
+ } else {
202
+ macro_def. expand ( db, actual_macro_call, & tt)
203
+ } ;
158
204
159
205
let expand_to = macro_expand_to ( db, actual_macro_call) ;
206
+ let ( node, rev_tmap) =
207
+ token_tree_to_syntax_node ( & speculative_expansion. value , expand_to) . ok ( ) ?;
160
208
161
- let ( node, tmap_2) = token_tree_to_syntax_node ( & speculative_expansion. value , expand_to) . ok ( ) ?;
162
-
163
- let token_id = macro_def. map_id_down ( token_id) ;
164
- let range = tmap_2. first_range_by_token ( token_id, token_to_map. kind ( ) ) ?;
209
+ let range = rev_tmap. first_range_by_token ( token_id, token_to_map. kind ( ) ) ?;
165
210
let token = node. syntax_node ( ) . covering_element ( range) . into_token ( ) ?;
166
211
Some ( ( node. syntax_node ( ) , token) )
167
212
}
@@ -259,7 +304,19 @@ fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree,
259
304
let loc = db. lookup_intern_macro ( id) ;
260
305
261
306
let node = SyntaxNode :: new_root ( arg) ;
262
- let censor = match loc. kind {
307
+ let censor = censor_for_macro_input ( & loc, & node) ;
308
+ let ( mut tt, tmap) = mbe:: syntax_node_to_token_tree_censored ( & node, censor) ;
309
+
310
+ if loc. def . is_proc_macro ( ) {
311
+ // proc macros expect their inputs without parentheses, MBEs expect it with them included
312
+ tt. delimiter = None ;
313
+ }
314
+
315
+ Some ( Arc :: new ( ( tt, tmap) ) )
316
+ }
317
+
318
+ fn censor_for_macro_input ( loc : & MacroCallLoc , node : & SyntaxNode ) -> Option < TextRange > {
319
+ match loc. kind {
263
320
MacroCallKind :: FnLike { .. } => None ,
264
321
MacroCallKind :: Derive { derive_attr_index, .. } => match ast:: Item :: cast ( node. clone ( ) ) {
265
322
Some ( item) => item
@@ -275,15 +332,7 @@ fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree,
275
332
}
276
333
None => None ,
277
334
} ,
278
- } ;
279
- let ( mut tt, tmap) = mbe:: syntax_node_to_token_tree_censored ( & node, censor) ;
280
-
281
- if loc. def . is_proc_macro ( ) {
282
- // proc macros expect their inputs without parentheses, MBEs expect it with them included
283
- tt. delimiter = None ;
284
335
}
285
-
286
- Some ( Arc :: new ( ( tt, tmap) ) )
287
336
}
288
337
289
338
fn macro_arg_text ( db : & dyn AstDatabase , id : MacroCallId ) -> Option < GreenNode > {
@@ -367,11 +416,11 @@ fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Ar
367
416
None => return ExpandResult :: str_err ( "Failed to lower macro args to token tree" . into ( ) ) ,
368
417
} ;
369
418
370
- let macro_rules = match db. macro_def ( loc. def ) {
419
+ let expander = match db. macro_def ( loc. def ) {
371
420
Some ( it) => it,
372
421
None => return ExpandResult :: str_err ( "Failed to find macro definition" . into ( ) ) ,
373
422
} ;
374
- let ExpandResult { value : tt, err } = macro_rules . expand ( db, id, & macro_arg. 0 ) ;
423
+ let ExpandResult { value : tt, err } = expander . expand ( db, id, & macro_arg. 0 ) ;
375
424
// Set a hard limit for the expanded tt
376
425
let count = tt. count ( ) ;
377
426
// XXX: Make ExpandResult a real error and use .map_err instead?
0 commit comments