+
+ for macro_ in source_file.syntax().descendants().filter_map(ast::Macro::cast) {
+ let mut show_token_ids = false;
+ for comment in macro_.syntax().children_with_tokens().filter(|it| it.kind() == COMMENT) {
+ show_token_ids |= comment.to_string().contains("+tokenids");
+ }
+ if !show_token_ids {
+ continue;
+ }
+
+ let call_offset = macro_.syntax().text_range().start().into();
+ let file_ast_id = db.ast_id_map(source.file_id).ast_id(¯o_);
+ let ast_id = AstId::new(source.file_id, file_ast_id.upcast());
+ let kind = MacroDefKind::Declarative(ast_id);
+
+ let macro_def = db.macro_def(MacroDefId { krate, kind, local_inner: false }).unwrap();
+ if let TokenExpander::DeclarativeMacro { mac, def_site_token_map } = &*macro_def {
+ let tt = match ¯o_ {
+ ast::Macro::MacroRules(mac) => mac.token_tree().unwrap(),
+ ast::Macro::MacroDef(_) => unimplemented!(""),
+ };
+
+ let tt_start = tt.syntax().text_range().start();
+ tt.syntax().descendants_with_tokens().filter_map(SyntaxElement::into_token).for_each(
+ |token| {
+ let range = token.text_range().checked_sub(tt_start).unwrap();
+ if let Some(id) = def_site_token_map.token_by_range(range) {
+ let offset = (range.end() + tt_start).into();
+ text_edits.push((offset..offset, format!("#{}", id.0)));
+ }
+ },
+ );
+ text_edits.push((
+ call_offset..call_offset,
+ format!("// call ids will be shifted by {:?}\n", mac.shift()),
+ ));
+ }
+ }
+