Skip to main content

rustc_passes/
input_stats.rs

1// The visitors in this module collect sizes and counts of the most important
2// pieces of AST and HIR. The resulting numbers are good approximations but not
3// completely accurate (some things might be counted twice, others missed).
4
5use rustc_ast::visit::BoundKind;
6use rustc_ast::{self as ast, AttrVec, NodeId, visit as ast_visit};
7use rustc_data_structures::fx::{FxHashMap, FxHashSet};
8use rustc_data_structures::thousands::usize_with_underscores;
9use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit};
10use rustc_middle::ty::TyCtxt;
11use rustc_span::Span;
12use rustc_span::def_id::LocalDefId;
13
14struct NodeStats {
15    count: usize,
16    size: usize,
17}
18
19impl NodeStats {
20    fn new() -> NodeStats {
21        NodeStats { count: 0, size: 0 }
22    }
23
24    fn accum_size(&self) -> usize {
25        self.count * self.size
26    }
27}
28
29struct Node {
30    stats: NodeStats,
31    subnodes: FxHashMap<&'static str, NodeStats>,
32}
33
34impl Node {
35    fn new() -> Node {
36        Node { stats: NodeStats::new(), subnodes: FxHashMap::default() }
37    }
38}
39
40/// This type measures the size of AST and HIR nodes, by implementing the AST
41/// and HIR `Visitor` traits. But we don't measure every visited type because
42/// that could cause double counting.
43///
44/// For example, `ast::Visitor` has `visit_ident`, but `Ident`s are always
45/// stored inline within other AST nodes, so we don't implement `visit_ident`
46/// here. In contrast, we do implement `visit_expr` because `ast::Expr` is
47/// always stored as `Box<ast::Expr>`, and every such expression should be
48/// measured separately.
49///
50/// In general, a `visit_foo` method should be implemented here if the
51/// corresponding `Foo` type is always stored on its own, e.g.: `Box<Foo>`,
52/// `Box<Foo>`, `Vec<Foo>`, `Box<[Foo]>`.
53///
54/// There are some types in the AST and HIR tree that the visitors do not have
55/// a `visit_*` method for, and so we cannot measure these, which is
56/// unfortunate.
57struct StatCollector<'k> {
58    tcx: Option<TyCtxt<'k>>,
59    nodes: FxHashMap<&'static str, Node>,
60    seen: FxHashSet<HirId>,
61}
62
63pub fn print_hir_stats(tcx: TyCtxt<'_>) {
64    let mut collector =
65        StatCollector { tcx: Some(tcx), nodes: FxHashMap::default(), seen: FxHashSet::default() };
66    tcx.hir_walk_toplevel_module(&mut collector);
67    tcx.hir_walk_attributes(&mut collector);
68    collector.print(tcx, "HIR STATS", "hir-stats");
69}
70
71pub fn print_ast_stats(tcx: TyCtxt<'_>, krate: &ast::Crate) {
72    use rustc_ast::visit::Visitor;
73
74    let mut collector =
75        StatCollector { tcx: None, nodes: FxHashMap::default(), seen: FxHashSet::default() };
76    collector.visit_crate(krate);
77    collector.print(tcx, "POST EXPANSION AST STATS", "ast-stats");
78}
79
80impl<'k> StatCollector<'k> {
81    // Record a top-level node.
82    fn record<T>(&mut self, label: &'static str, id: Option<HirId>, val: &T) {
83        self.record_inner(label, None, id, val);
84    }
85
86    // Record a two-level entry, with a top-level enum type and a variant.
87    fn record_variant<T>(
88        &mut self,
89        label1: &'static str,
90        label2: &'static str,
91        id: Option<HirId>,
92        val: &T,
93    ) {
94        self.record_inner(label1, Some(label2), id, val);
95    }
96
97    fn record_inner<T>(
98        &mut self,
99        label1: &'static str,
100        label2: Option<&'static str>,
101        id: Option<HirId>,
102        val: &T,
103    ) {
104        if id.is_some_and(|x| !self.seen.insert(x)) {
105            return;
106        }
107
108        let node = self.nodes.entry(label1).or_insert(Node::new());
109        node.stats.count += 1;
110        node.stats.size = size_of_val(val);
111
112        if let Some(label2) = label2 {
113            let subnode = node.subnodes.entry(label2).or_insert(NodeStats::new());
114            subnode.count += 1;
115            subnode.size = size_of_val(val);
116        }
117    }
118
119    fn print(&self, tcx: TyCtxt<'_>, title: &str, prefix: &str) {
120        use std::fmt::Write;
121
122        // We will soon sort, so the initial order does not matter.
123        #[allow(rustc::potential_query_instability)]
124        let mut nodes: Vec<_> = self.nodes.iter().collect();
125        nodes.sort_by_cached_key(|(label, node)| (node.stats.accum_size(), label.to_owned()));
126        nodes.reverse(); // bigger items first
127
128        let name_w = 18;
129        let acc_size1_w = 10;
130        let acc_size2_w = 8; // " (NN.N%)"
131        let acc_size_w = acc_size1_w + acc_size2_w;
132        let count_w = 14;
133        let item_size_w = 14;
134        let banner_w = name_w + acc_size_w + count_w + item_size_w;
135
136        let total_size = nodes.iter().map(|(_, node)| node.stats.accum_size()).sum();
137        let total_count = nodes.iter().map(|(_, node)| node.stats.count).sum();
138
139        // We write all the text into a string and print it with a single
140        // `eprint!`. This is an attempt to minimize interleaved text if multiple
141        // rustc processes are printing macro-stats at the same time (e.g. with
142        // `RUSTFLAGS='-Zinput-stats' cargo build`). It still doesn't guarantee
143        // non-interleaving, though.
144        let mut s = String::new();
145        _ = s.write_fmt(format_args!("{1} {0}\n", "=".repeat(banner_w), prefix))writeln!(s, "{prefix} {}", "=".repeat(banner_w));
146        _ = s.write_fmt(format_args!("{1} {2}: {0}\n",
        tcx.crate_name(hir::def_id::LOCAL_CRATE), prefix, title))writeln!(s, "{prefix} {title}: {}", tcx.crate_name(hir::def_id::LOCAL_CRATE));
147        _ = s.write_fmt(format_args!("{4} {0:<5$}{1:>6$}{2:>7$}{3:>8$}\n", "Name",
        "Accumulated Size", "Count", "Item Size", prefix, name_w, acc_size_w,
        count_w, item_size_w))writeln!(
148            s,
149            "{prefix} {:<name_w$}{:>acc_size_w$}{:>count_w$}{:>item_size_w$}",
150            "Name", "Accumulated Size", "Count", "Item Size"
151        );
152        _ = s.write_fmt(format_args!("{1} {0}\n", "-".repeat(banner_w), prefix))writeln!(s, "{prefix} {}", "-".repeat(banner_w));
153
154        let percent = |m, n| (m * 100) as f64 / n as f64;
155
156        for (label, node) in nodes {
157            let size = node.stats.accum_size();
158            _ = s.write_fmt(format_args!("{5} {0:<6$}{1:>7$} ({2:4.1}%){3:>8$}{4:>9$}\n",
        label, usize_with_underscores(size), percent(size, total_size),
        usize_with_underscores(node.stats.count),
        usize_with_underscores(node.stats.size), prefix, name_w, acc_size1_w,
        count_w, item_size_w))writeln!(
159                s,
160                "{prefix} {:<name_w$}{:>acc_size1_w$} ({:4.1}%){:>count_w$}{:>item_size_w$}",
161                label,
162                usize_with_underscores(size),
163                percent(size, total_size),
164                usize_with_underscores(node.stats.count),
165                usize_with_underscores(node.stats.size)
166            );
167            if !node.subnodes.is_empty() {
168                // We will soon sort, so the initial order does not matter.
169                #[allow(rustc::potential_query_instability)]
170                let mut subnodes: Vec<_> = node.subnodes.iter().collect();
171                subnodes.sort_by_cached_key(|(label, subnode)| {
172                    (subnode.accum_size(), label.to_owned())
173                });
174
175                for (label, subnode) in subnodes {
176                    let size = subnode.accum_size();
177                    _ = s.write_fmt(format_args!("{4} - {0:<5$}{1:>6$} ({2:4.1}%){3:>7$}\n", label,
        usize_with_underscores(size), percent(size, total_size),
        usize_with_underscores(subnode.count), prefix, name_w, acc_size1_w,
        count_w))writeln!(
178                        s,
179                        "{prefix} - {:<name_w$}{:>acc_size1_w$} ({:4.1}%){:>count_w$}",
180                        label,
181                        usize_with_underscores(size),
182                        percent(size, total_size),
183                        usize_with_underscores(subnode.count),
184                    );
185                }
186            }
187        }
188        _ = s.write_fmt(format_args!("{1} {0}\n", "-".repeat(banner_w), prefix))writeln!(s, "{prefix} {}", "-".repeat(banner_w));
189        _ = s.write_fmt(format_args!("{4} {0:<5$}{1:>6$}{2:>7$}{3:>8$}\n", "Total",
        usize_with_underscores(total_size), "",
        usize_with_underscores(total_count), prefix, name_w, acc_size1_w,
        acc_size2_w, count_w))writeln!(
190            s,
191            "{prefix} {:<name_w$}{:>acc_size1_w$}{:>acc_size2_w$}{:>count_w$}",
192            "Total",
193            usize_with_underscores(total_size),
194            "",
195            usize_with_underscores(total_count),
196        );
197        _ = s.write_fmt(format_args!("{1} {0}\n", "=".repeat(banner_w), prefix))writeln!(s, "{prefix} {}", "=".repeat(banner_w));
198        { ::std::io::_eprint(format_args!("{0}", s)); };eprint!("{s}");
199    }
200}
201
202// Used to avoid boilerplate for types with many variants.
203macro_rules! record_variants {
204    (
205        ($self:ident, $val:expr, $kind:expr, $id:expr, $mod:ident, $ty:ty, $tykind:ident),
206        [$($variant:ident),*]
207    ) => {
208        match $kind {
209            $(
210                $mod::$tykind::$variant { .. } => {
211                    $self.record_variant(stringify!($ty), stringify!($variant), $id, $val)
212                }
213            )*
214        }
215    };
216}
217
218impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
219    fn visit_param(&mut self, param: &'v hir::Param<'v>) {
220        self.record("Param", Some(param.hir_id), param);
221        hir_visit::walk_param(self, param)
222    }
223
224    fn visit_nested_item(&mut self, id: hir::ItemId) {
225        let nested_item = self.tcx.unwrap().hir_item(id);
226        self.visit_item(nested_item)
227    }
228
229    fn visit_nested_trait_item(&mut self, trait_item_id: hir::TraitItemId) {
230        let nested_trait_item = self.tcx.unwrap().hir_trait_item(trait_item_id);
231        self.visit_trait_item(nested_trait_item)
232    }
233
234    fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) {
235        let nested_impl_item = self.tcx.unwrap().hir_impl_item(impl_item_id);
236        self.visit_impl_item(nested_impl_item)
237    }
238
239    fn visit_nested_foreign_item(&mut self, id: hir::ForeignItemId) {
240        let nested_foreign_item = self.tcx.unwrap().hir_foreign_item(id);
241        self.visit_foreign_item(nested_foreign_item);
242    }
243
244    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
245        let nested_body = self.tcx.unwrap().hir_body(body_id);
246        self.visit_body(nested_body)
247    }
248
249    fn visit_item(&mut self, i: &'v hir::Item<'v>) {
250        match i.kind {
    hir::ItemKind::ExternCrate { .. } => {
        self.record_variant("Item", "ExternCrate", Some(i.hir_id()), i)
    }
    hir::ItemKind::Use { .. } => {
        self.record_variant("Item", "Use", Some(i.hir_id()), i)
    }
    hir::ItemKind::Static { .. } => {
        self.record_variant("Item", "Static", Some(i.hir_id()), i)
    }
    hir::ItemKind::Const { .. } => {
        self.record_variant("Item", "Const", Some(i.hir_id()), i)
    }
    hir::ItemKind::Fn { .. } => {
        self.record_variant("Item", "Fn", Some(i.hir_id()), i)
    }
    hir::ItemKind::Macro { .. } => {
        self.record_variant("Item", "Macro", Some(i.hir_id()), i)
    }
    hir::ItemKind::Mod { .. } => {
        self.record_variant("Item", "Mod", Some(i.hir_id()), i)
    }
    hir::ItemKind::ForeignMod { .. } => {
        self.record_variant("Item", "ForeignMod", Some(i.hir_id()), i)
    }
    hir::ItemKind::GlobalAsm { .. } => {
        self.record_variant("Item", "GlobalAsm", Some(i.hir_id()), i)
    }
    hir::ItemKind::TyAlias { .. } => {
        self.record_variant("Item", "TyAlias", Some(i.hir_id()), i)
    }
    hir::ItemKind::Enum { .. } => {
        self.record_variant("Item", "Enum", Some(i.hir_id()), i)
    }
    hir::ItemKind::Struct { .. } => {
        self.record_variant("Item", "Struct", Some(i.hir_id()), i)
    }
    hir::ItemKind::Union { .. } => {
        self.record_variant("Item", "Union", Some(i.hir_id()), i)
    }
    hir::ItemKind::Trait { .. } => {
        self.record_variant("Item", "Trait", Some(i.hir_id()), i)
    }
    hir::ItemKind::TraitAlias { .. } => {
        self.record_variant("Item", "TraitAlias", Some(i.hir_id()), i)
    }
    hir::ItemKind::Impl { .. } => {
        self.record_variant("Item", "Impl", Some(i.hir_id()), i)
    }
};record_variants!(
251            (self, i, i.kind, Some(i.hir_id()), hir, Item, ItemKind),
252            [
253                ExternCrate,
254                Use,
255                Static,
256                Const,
257                Fn,
258                Macro,
259                Mod,
260                ForeignMod,
261                GlobalAsm,
262                TyAlias,
263                Enum,
264                Struct,
265                Union,
266                Trait,
267                TraitAlias,
268                Impl
269            ]
270        );
271        hir_visit::walk_item(self, i)
272    }
273
274    fn visit_body(&mut self, b: &hir::Body<'v>) {
275        self.record("Body", None, b);
276        hir_visit::walk_body(self, b);
277    }
278
279    fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, _n: HirId) {
280        self.record("Mod", None, m);
281        hir_visit::walk_mod(self, m)
282    }
283
284    fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) {
285        match i.kind {
    hir::ForeignItemKind::Fn { .. } => {
        self.record_variant("ForeignItem", "Fn", Some(i.hir_id()), i)
    }
    hir::ForeignItemKind::Static { .. } => {
        self.record_variant("ForeignItem", "Static", Some(i.hir_id()), i)
    }
    hir::ForeignItemKind::Type { .. } => {
        self.record_variant("ForeignItem", "Type", Some(i.hir_id()), i)
    }
};record_variants!(
286            (self, i, i.kind, Some(i.hir_id()), hir, ForeignItem, ForeignItemKind),
287            [Fn, Static, Type]
288        );
289        hir_visit::walk_foreign_item(self, i)
290    }
291
292    fn visit_local(&mut self, l: &'v hir::LetStmt<'v>) {
293        self.record("Local", Some(l.hir_id), l);
294        hir_visit::walk_local(self, l)
295    }
296
297    fn visit_block(&mut self, b: &'v hir::Block<'v>) {
298        self.record("Block", Some(b.hir_id), b);
299        hir_visit::walk_block(self, b)
300    }
301
302    fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
303        match s.kind {
    hir::StmtKind::Let { .. } => {
        self.record_variant("Stmt", "Let", Some(s.hir_id), s)
    }
    hir::StmtKind::Item { .. } => {
        self.record_variant("Stmt", "Item", Some(s.hir_id), s)
    }
    hir::StmtKind::Expr { .. } => {
        self.record_variant("Stmt", "Expr", Some(s.hir_id), s)
    }
    hir::StmtKind::Semi { .. } => {
        self.record_variant("Stmt", "Semi", Some(s.hir_id), s)
    }
};record_variants!(
304            (self, s, s.kind, Some(s.hir_id), hir, Stmt, StmtKind),
305            [Let, Item, Expr, Semi]
306        );
307        hir_visit::walk_stmt(self, s)
308    }
309
310    fn visit_arm(&mut self, a: &'v hir::Arm<'v>) {
311        self.record("Arm", Some(a.hir_id), a);
312        hir_visit::walk_arm(self, a)
313    }
314
315    fn visit_pat(&mut self, p: &'v hir::Pat<'v>) {
316        match p.kind {
    hir::PatKind::Missing { .. } => {
        self.record_variant("Pat", "Missing", Some(p.hir_id), p)
    }
    hir::PatKind::Wild { .. } => {
        self.record_variant("Pat", "Wild", Some(p.hir_id), p)
    }
    hir::PatKind::Binding { .. } => {
        self.record_variant("Pat", "Binding", Some(p.hir_id), p)
    }
    hir::PatKind::Struct { .. } => {
        self.record_variant("Pat", "Struct", Some(p.hir_id), p)
    }
    hir::PatKind::TupleStruct { .. } => {
        self.record_variant("Pat", "TupleStruct", Some(p.hir_id), p)
    }
    hir::PatKind::Or { .. } => {
        self.record_variant("Pat", "Or", Some(p.hir_id), p)
    }
    hir::PatKind::Never { .. } => {
        self.record_variant("Pat", "Never", Some(p.hir_id), p)
    }
    hir::PatKind::Tuple { .. } => {
        self.record_variant("Pat", "Tuple", Some(p.hir_id), p)
    }
    hir::PatKind::Box { .. } => {
        self.record_variant("Pat", "Box", Some(p.hir_id), p)
    }
    hir::PatKind::Deref { .. } => {
        self.record_variant("Pat", "Deref", Some(p.hir_id), p)
    }
    hir::PatKind::Ref { .. } => {
        self.record_variant("Pat", "Ref", Some(p.hir_id), p)
    }
    hir::PatKind::Expr { .. } => {
        self.record_variant("Pat", "Expr", Some(p.hir_id), p)
    }
    hir::PatKind::Guard { .. } => {
        self.record_variant("Pat", "Guard", Some(p.hir_id), p)
    }
    hir::PatKind::Range { .. } => {
        self.record_variant("Pat", "Range", Some(p.hir_id), p)
    }
    hir::PatKind::Slice { .. } => {
        self.record_variant("Pat", "Slice", Some(p.hir_id), p)
    }
    hir::PatKind::Err { .. } => {
        self.record_variant("Pat", "Err", Some(p.hir_id), p)
    }
};record_variants!(
317            (self, p, p.kind, Some(p.hir_id), hir, Pat, PatKind),
318            [
319                Missing,
320                Wild,
321                Binding,
322                Struct,
323                TupleStruct,
324                Or,
325                Never,
326                Tuple,
327                Box,
328                Deref,
329                Ref,
330                Expr,
331                Guard,
332                Range,
333                Slice,
334                Err
335            ]
336        );
337        hir_visit::walk_pat(self, p)
338    }
339
340    fn visit_pat_field(&mut self, f: &'v hir::PatField<'v>) {
341        self.record("PatField", Some(f.hir_id), f);
342        hir_visit::walk_pat_field(self, f)
343    }
344
345    fn visit_expr(&mut self, e: &'v hir::Expr<'v>) {
346        match e.kind {
    hir::ExprKind::ConstBlock { .. } => {
        self.record_variant("Expr", "ConstBlock", Some(e.hir_id), e)
    }
    hir::ExprKind::Array { .. } => {
        self.record_variant("Expr", "Array", Some(e.hir_id), e)
    }
    hir::ExprKind::Call { .. } => {
        self.record_variant("Expr", "Call", Some(e.hir_id), e)
    }
    hir::ExprKind::MethodCall { .. } => {
        self.record_variant("Expr", "MethodCall", Some(e.hir_id), e)
    }
    hir::ExprKind::Use { .. } => {
        self.record_variant("Expr", "Use", Some(e.hir_id), e)
    }
    hir::ExprKind::Tup { .. } => {
        self.record_variant("Expr", "Tup", Some(e.hir_id), e)
    }
    hir::ExprKind::Binary { .. } => {
        self.record_variant("Expr", "Binary", Some(e.hir_id), e)
    }
    hir::ExprKind::Unary { .. } => {
        self.record_variant("Expr", "Unary", Some(e.hir_id), e)
    }
    hir::ExprKind::Lit { .. } => {
        self.record_variant("Expr", "Lit", Some(e.hir_id), e)
    }
    hir::ExprKind::Cast { .. } => {
        self.record_variant("Expr", "Cast", Some(e.hir_id), e)
    }
    hir::ExprKind::Type { .. } => {
        self.record_variant("Expr", "Type", Some(e.hir_id), e)
    }
    hir::ExprKind::DropTemps { .. } => {
        self.record_variant("Expr", "DropTemps", Some(e.hir_id), e)
    }
    hir::ExprKind::Let { .. } => {
        self.record_variant("Expr", "Let", Some(e.hir_id), e)
    }
    hir::ExprKind::If { .. } => {
        self.record_variant("Expr", "If", Some(e.hir_id), e)
    }
    hir::ExprKind::Loop { .. } => {
        self.record_variant("Expr", "Loop", Some(e.hir_id), e)
    }
    hir::ExprKind::Match { .. } => {
        self.record_variant("Expr", "Match", Some(e.hir_id), e)
    }
    hir::ExprKind::Closure { .. } => {
        self.record_variant("Expr", "Closure", Some(e.hir_id), e)
    }
    hir::ExprKind::Block { .. } => {
        self.record_variant("Expr", "Block", Some(e.hir_id), e)
    }
    hir::ExprKind::Assign { .. } => {
        self.record_variant("Expr", "Assign", Some(e.hir_id), e)
    }
    hir::ExprKind::AssignOp { .. } => {
        self.record_variant("Expr", "AssignOp", Some(e.hir_id), e)
    }
    hir::ExprKind::Field { .. } => {
        self.record_variant("Expr", "Field", Some(e.hir_id), e)
    }
    hir::ExprKind::Index { .. } => {
        self.record_variant("Expr", "Index", Some(e.hir_id), e)
    }
    hir::ExprKind::Path { .. } => {
        self.record_variant("Expr", "Path", Some(e.hir_id), e)
    }
    hir::ExprKind::AddrOf { .. } => {
        self.record_variant("Expr", "AddrOf", Some(e.hir_id), e)
    }
    hir::ExprKind::Break { .. } => {
        self.record_variant("Expr", "Break", Some(e.hir_id), e)
    }
    hir::ExprKind::Continue { .. } => {
        self.record_variant("Expr", "Continue", Some(e.hir_id), e)
    }
    hir::ExprKind::Ret { .. } => {
        self.record_variant("Expr", "Ret", Some(e.hir_id), e)
    }
    hir::ExprKind::Become { .. } => {
        self.record_variant("Expr", "Become", Some(e.hir_id), e)
    }
    hir::ExprKind::InlineAsm { .. } => {
        self.record_variant("Expr", "InlineAsm", Some(e.hir_id), e)
    }
    hir::ExprKind::OffsetOf { .. } => {
        self.record_variant("Expr", "OffsetOf", Some(e.hir_id), e)
    }
    hir::ExprKind::Struct { .. } => {
        self.record_variant("Expr", "Struct", Some(e.hir_id), e)
    }
    hir::ExprKind::Repeat { .. } => {
        self.record_variant("Expr", "Repeat", Some(e.hir_id), e)
    }
    hir::ExprKind::Yield { .. } => {
        self.record_variant("Expr", "Yield", Some(e.hir_id), e)
    }
    hir::ExprKind::UnsafeBinderCast { .. } => {
        self.record_variant("Expr", "UnsafeBinderCast", Some(e.hir_id), e)
    }
    hir::ExprKind::Err { .. } => {
        self.record_variant("Expr", "Err", Some(e.hir_id), e)
    }
};record_variants!(
347            (self, e, e.kind, Some(e.hir_id), hir, Expr, ExprKind),
348            [
349                ConstBlock,
350                Array,
351                Call,
352                MethodCall,
353                Use,
354                Tup,
355                Binary,
356                Unary,
357                Lit,
358                Cast,
359                Type,
360                DropTemps,
361                Let,
362                If,
363                Loop,
364                Match,
365                Closure,
366                Block,
367                Assign,
368                AssignOp,
369                Field,
370                Index,
371                Path,
372                AddrOf,
373                Break,
374                Continue,
375                Ret,
376                Become,
377                InlineAsm,
378                OffsetOf,
379                Struct,
380                Repeat,
381                Yield,
382                UnsafeBinderCast,
383                Err
384            ]
385        );
386        hir_visit::walk_expr(self, e)
387    }
388
389    fn visit_expr_field(&mut self, f: &'v hir::ExprField<'v>) {
390        self.record("ExprField", Some(f.hir_id), f);
391        hir_visit::walk_expr_field(self, f)
392    }
393
394    fn visit_ty(&mut self, t: &'v hir::Ty<'v, AmbigArg>) {
395        match t.kind {
    hir::TyKind::InferDelegation { .. } => {
        self.record_variant("Ty", "InferDelegation", Some(t.hir_id), t)
    }
    hir::TyKind::Slice { .. } => {
        self.record_variant("Ty", "Slice", Some(t.hir_id), t)
    }
    hir::TyKind::Array { .. } => {
        self.record_variant("Ty", "Array", Some(t.hir_id), t)
    }
    hir::TyKind::Ptr { .. } => {
        self.record_variant("Ty", "Ptr", Some(t.hir_id), t)
    }
    hir::TyKind::Ref { .. } => {
        self.record_variant("Ty", "Ref", Some(t.hir_id), t)
    }
    hir::TyKind::FnPtr { .. } => {
        self.record_variant("Ty", "FnPtr", Some(t.hir_id), t)
    }
    hir::TyKind::UnsafeBinder { .. } => {
        self.record_variant("Ty", "UnsafeBinder", Some(t.hir_id), t)
    }
    hir::TyKind::Never { .. } => {
        self.record_variant("Ty", "Never", Some(t.hir_id), t)
    }
    hir::TyKind::Tup { .. } => {
        self.record_variant("Ty", "Tup", Some(t.hir_id), t)
    }
    hir::TyKind::Path { .. } => {
        self.record_variant("Ty", "Path", Some(t.hir_id), t)
    }
    hir::TyKind::OpaqueDef { .. } => {
        self.record_variant("Ty", "OpaqueDef", Some(t.hir_id), t)
    }
    hir::TyKind::TraitAscription { .. } => {
        self.record_variant("Ty", "TraitAscription", Some(t.hir_id), t)
    }
    hir::TyKind::TraitObject { .. } => {
        self.record_variant("Ty", "TraitObject", Some(t.hir_id), t)
    }
    hir::TyKind::Infer { .. } => {
        self.record_variant("Ty", "Infer", Some(t.hir_id), t)
    }
    hir::TyKind::Pat { .. } => {
        self.record_variant("Ty", "Pat", Some(t.hir_id), t)
    }
    hir::TyKind::FieldOf { .. } => {
        self.record_variant("Ty", "FieldOf", Some(t.hir_id), t)
    }
    hir::TyKind::Err { .. } => {
        self.record_variant("Ty", "Err", Some(t.hir_id), t)
    }
};record_variants!(
396            (self, t, t.kind, Some(t.hir_id), hir, Ty, TyKind),
397            [
398                InferDelegation,
399                Slice,
400                Array,
401                Ptr,
402                Ref,
403                FnPtr,
404                UnsafeBinder,
405                Never,
406                Tup,
407                Path,
408                OpaqueDef,
409                TraitAscription,
410                TraitObject,
411                Infer,
412                Pat,
413                FieldOf,
414                Err
415            ]
416        );
417        hir_visit::walk_ty(self, t)
418    }
419
420    fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
421        self.record("GenericParam", Some(p.hir_id), p);
422        hir_visit::walk_generic_param(self, p)
423    }
424
425    fn visit_generics(&mut self, g: &'v hir::Generics<'v>) {
426        self.record("Generics", None, g);
427        hir_visit::walk_generics(self, g)
428    }
429
430    fn visit_where_predicate(&mut self, p: &'v hir::WherePredicate<'v>) {
431        match p.kind {
    hir::WherePredicateKind::BoundPredicate { .. } => {
        self.record_variant("WherePredicate", "BoundPredicate",
            Some(p.hir_id), p)
    }
    hir::WherePredicateKind::RegionPredicate { .. } => {
        self.record_variant("WherePredicate", "RegionPredicate",
            Some(p.hir_id), p)
    }
    hir::WherePredicateKind::EqPredicate { .. } => {
        self.record_variant("WherePredicate", "EqPredicate", Some(p.hir_id),
            p)
    }
};record_variants!(
432            (self, p, p.kind, Some(p.hir_id), hir, WherePredicate, WherePredicateKind),
433            [BoundPredicate, RegionPredicate, EqPredicate]
434        );
435        hir_visit::walk_where_predicate(self, p)
436    }
437
438    fn visit_fn(
439        &mut self,
440        fk: hir_visit::FnKind<'v>,
441        fd: &'v hir::FnDecl<'v>,
442        b: hir::BodyId,
443        _: Span,
444        id: LocalDefId,
445    ) {
446        self.record("FnDecl", None, fd);
447        hir_visit::walk_fn(self, fk, fd, b, id)
448    }
449
450    fn visit_use(&mut self, p: &'v hir::UsePath<'v>, _hir_id: HirId) {
451        // This is `visit_use`, but the type is `Path` so record it that way.
452        self.record("Path", None, p);
453        // Don't call `hir_visit::walk_use(self, p, hir_id)`: it calls
454        // `visit_path` up to three times, once for each namespace result in
455        // `p.res`, by building temporary `Path`s that are not part of the real
456        // HIR, which causes `p` to be double- or triple-counted. Instead just
457        // walk the path internals (i.e. the segments) directly.
458        let hir::Path { span: _, res: _, segments } = *p;
459        for elem in segments {
    match ::rustc_ast_ir::visit::VisitorResult::branch(self.visit_path_segment(elem))
        {
        core::ops::ControlFlow::Continue(()) =>
            (),
            #[allow(unreachable_code)]
            core::ops::ControlFlow::Break(r) => {
            return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
        }
    };
};ast_visit::walk_list!(self, visit_path_segment, segments);
460    }
461
462    fn visit_trait_item(&mut self, ti: &'v hir::TraitItem<'v>) {
463        match ti.kind {
    hir::TraitItemKind::Const { .. } => {
        self.record_variant("TraitItem", "Const", Some(ti.hir_id()), ti)
    }
    hir::TraitItemKind::Fn { .. } => {
        self.record_variant("TraitItem", "Fn", Some(ti.hir_id()), ti)
    }
    hir::TraitItemKind::Type { .. } => {
        self.record_variant("TraitItem", "Type", Some(ti.hir_id()), ti)
    }
};record_variants!(
464            (self, ti, ti.kind, Some(ti.hir_id()), hir, TraitItem, TraitItemKind),
465            [Const, Fn, Type]
466        );
467        hir_visit::walk_trait_item(self, ti)
468    }
469
470    fn visit_trait_item_ref(&mut self, ti: &'v hir::TraitItemId) {
471        self.record("TraitItemId", Some(ti.hir_id()), ti);
472        hir_visit::walk_trait_item_ref(self, *ti)
473    }
474
475    fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) {
476        match ii.kind {
    hir::ImplItemKind::Const { .. } => {
        self.record_variant("ImplItem", "Const", Some(ii.hir_id()), ii)
    }
    hir::ImplItemKind::Fn { .. } => {
        self.record_variant("ImplItem", "Fn", Some(ii.hir_id()), ii)
    }
    hir::ImplItemKind::Type { .. } => {
        self.record_variant("ImplItem", "Type", Some(ii.hir_id()), ii)
    }
};record_variants!(
477            (self, ii, ii.kind, Some(ii.hir_id()), hir, ImplItem, ImplItemKind),
478            [Const, Fn, Type]
479        );
480        hir_visit::walk_impl_item(self, ii)
481    }
482
483    fn visit_foreign_item_ref(&mut self, fi: &'v hir::ForeignItemId) {
484        self.record("ForeignItemId", Some(fi.hir_id()), fi);
485        hir_visit::walk_foreign_item_ref(self, *fi)
486    }
487
488    fn visit_impl_item_ref(&mut self, ii: &'v hir::ImplItemId) {
489        self.record("ImplItemId", Some(ii.hir_id()), ii);
490        hir_visit::walk_impl_item_ref(self, *ii)
491    }
492
493    fn visit_param_bound(&mut self, b: &'v hir::GenericBound<'v>) {
494        match b {
    hir::GenericBound::Trait { .. } => {
        self.record_variant("GenericBound", "Trait", None, b)
    }
    hir::GenericBound::Outlives { .. } => {
        self.record_variant("GenericBound", "Outlives", None, b)
    }
    hir::GenericBound::Use { .. } => {
        self.record_variant("GenericBound", "Use", None, b)
    }
};record_variants!(
495            (self, b, b, None, hir, GenericBound, GenericBound),
496            [Trait, Outlives, Use]
497        );
498        hir_visit::walk_param_bound(self, b)
499    }
500
501    fn visit_field_def(&mut self, s: &'v hir::FieldDef<'v>) {
502        self.record("FieldDef", Some(s.hir_id), s);
503        hir_visit::walk_field_def(self, s)
504    }
505
506    fn visit_variant(&mut self, v: &'v hir::Variant<'v>) {
507        self.record("Variant", None, v);
508        hir_visit::walk_variant(self, v)
509    }
510
511    fn visit_generic_arg(&mut self, ga: &'v hir::GenericArg<'v>) {
512        match ga {
    hir::GenericArg::Lifetime { .. } => {
        self.record_variant("GenericArg", "Lifetime", Some(ga.hir_id()), ga)
    }
    hir::GenericArg::Type { .. } => {
        self.record_variant("GenericArg", "Type", Some(ga.hir_id()), ga)
    }
    hir::GenericArg::Const { .. } => {
        self.record_variant("GenericArg", "Const", Some(ga.hir_id()), ga)
    }
    hir::GenericArg::Infer { .. } => {
        self.record_variant("GenericArg", "Infer", Some(ga.hir_id()), ga)
    }
};record_variants!(
513            (self, ga, ga, Some(ga.hir_id()), hir, GenericArg, GenericArg),
514            [Lifetime, Type, Const, Infer]
515        );
516        match ga {
517            hir::GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
518            hir::GenericArg::Type(ty) => self.visit_ty(ty),
519            hir::GenericArg::Const(ct) => self.visit_const_arg(ct),
520            hir::GenericArg::Infer(inf) => self.visit_id(inf.hir_id),
521        }
522    }
523
524    fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
525        self.record("Lifetime", Some(lifetime.hir_id), lifetime);
526        hir_visit::walk_lifetime(self, lifetime)
527    }
528
529    fn visit_path(&mut self, path: &hir::Path<'v>, _id: HirId) {
530        self.record("Path", None, path);
531        hir_visit::walk_path(self, path)
532    }
533
534    fn visit_path_segment(&mut self, path_segment: &'v hir::PathSegment<'v>) {
535        self.record("PathSegment", None, path_segment);
536        hir_visit::walk_path_segment(self, path_segment)
537    }
538
539    fn visit_generic_args(&mut self, ga: &'v hir::GenericArgs<'v>) {
540        self.record("GenericArgs", None, ga);
541        hir_visit::walk_generic_args(self, ga)
542    }
543
544    fn visit_assoc_item_constraint(&mut self, constraint: &'v hir::AssocItemConstraint<'v>) {
545        self.record("AssocItemConstraint", Some(constraint.hir_id), constraint);
546        hir_visit::walk_assoc_item_constraint(self, constraint)
547    }
548
549    fn visit_attribute(&mut self, attr: &'v hir::Attribute) {
550        self.record("Attribute", None, attr);
551    }
552
553    fn visit_inline_asm(&mut self, asm: &'v hir::InlineAsm<'v>, id: HirId) {
554        self.record("InlineAsm", None, asm);
555        hir_visit::walk_inline_asm(self, asm, id);
556    }
557}
558
559impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
560    fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
561        match i.kind {
    ast::ForeignItemKind::Static { .. } => {
        self.record_variant("ForeignItem", "Static", None, i)
    }
    ast::ForeignItemKind::Fn { .. } => {
        self.record_variant("ForeignItem", "Fn", None, i)
    }
    ast::ForeignItemKind::TyAlias { .. } => {
        self.record_variant("ForeignItem", "TyAlias", None, i)
    }
    ast::ForeignItemKind::MacCall { .. } => {
        self.record_variant("ForeignItem", "MacCall", None, i)
    }
};record_variants!(
562            (self, i, i.kind, None, ast, ForeignItem, ForeignItemKind),
563            [Static, Fn, TyAlias, MacCall]
564        );
565        ast_visit::walk_item(self, i)
566    }
567
568    fn visit_item(&mut self, i: &'v ast::Item) {
569        match i.kind {
    ast::ItemKind::ExternCrate { .. } => {
        self.record_variant("Item", "ExternCrate", None, i)
    }
    ast::ItemKind::Use { .. } => {
        self.record_variant("Item", "Use", None, i)
    }
    ast::ItemKind::Static { .. } => {
        self.record_variant("Item", "Static", None, i)
    }
    ast::ItemKind::Const { .. } => {
        self.record_variant("Item", "Const", None, i)
    }
    ast::ItemKind::ConstBlock { .. } => {
        self.record_variant("Item", "ConstBlock", None, i)
    }
    ast::ItemKind::Fn { .. } => { self.record_variant("Item", "Fn", None, i) }
    ast::ItemKind::Mod { .. } => {
        self.record_variant("Item", "Mod", None, i)
    }
    ast::ItemKind::ForeignMod { .. } => {
        self.record_variant("Item", "ForeignMod", None, i)
    }
    ast::ItemKind::GlobalAsm { .. } => {
        self.record_variant("Item", "GlobalAsm", None, i)
    }
    ast::ItemKind::TyAlias { .. } => {
        self.record_variant("Item", "TyAlias", None, i)
    }
    ast::ItemKind::Enum { .. } => {
        self.record_variant("Item", "Enum", None, i)
    }
    ast::ItemKind::Struct { .. } => {
        self.record_variant("Item", "Struct", None, i)
    }
    ast::ItemKind::Union { .. } => {
        self.record_variant("Item", "Union", None, i)
    }
    ast::ItemKind::Trait { .. } => {
        self.record_variant("Item", "Trait", None, i)
    }
    ast::ItemKind::TraitAlias { .. } => {
        self.record_variant("Item", "TraitAlias", None, i)
    }
    ast::ItemKind::Impl { .. } => {
        self.record_variant("Item", "Impl", None, i)
    }
    ast::ItemKind::MacCall { .. } => {
        self.record_variant("Item", "MacCall", None, i)
    }
    ast::ItemKind::MacroDef { .. } => {
        self.record_variant("Item", "MacroDef", None, i)
    }
    ast::ItemKind::Delegation { .. } => {
        self.record_variant("Item", "Delegation", None, i)
    }
    ast::ItemKind::DelegationMac { .. } => {
        self.record_variant("Item", "DelegationMac", None, i)
    }
};record_variants!(
570            (self, i, i.kind, None, ast, Item, ItemKind),
571            [
572                ExternCrate,
573                Use,
574                Static,
575                Const,
576                ConstBlock,
577                Fn,
578                Mod,
579                ForeignMod,
580                GlobalAsm,
581                TyAlias,
582                Enum,
583                Struct,
584                Union,
585                Trait,
586                TraitAlias,
587                Impl,
588                MacCall,
589                MacroDef,
590                Delegation,
591                DelegationMac
592            ]
593        );
594        ast_visit::walk_item(self, i)
595    }
596
597    fn visit_local(&mut self, l: &'v ast::Local) {
598        self.record("Local", None, l);
599        ast_visit::walk_local(self, l)
600    }
601
602    fn visit_block(&mut self, b: &'v ast::Block) {
603        self.record("Block", None, b);
604        ast_visit::walk_block(self, b)
605    }
606
607    fn visit_stmt(&mut self, s: &'v ast::Stmt) {
608        match s.kind {
    ast::StmtKind::Let { .. } => {
        self.record_variant("Stmt", "Let", None, s)
    }
    ast::StmtKind::Item { .. } => {
        self.record_variant("Stmt", "Item", None, s)
    }
    ast::StmtKind::Expr { .. } => {
        self.record_variant("Stmt", "Expr", None, s)
    }
    ast::StmtKind::Semi { .. } => {
        self.record_variant("Stmt", "Semi", None, s)
    }
    ast::StmtKind::Empty { .. } => {
        self.record_variant("Stmt", "Empty", None, s)
    }
    ast::StmtKind::MacCall { .. } => {
        self.record_variant("Stmt", "MacCall", None, s)
    }
};record_variants!(
609            (self, s, s.kind, None, ast, Stmt, StmtKind),
610            [Let, Item, Expr, Semi, Empty, MacCall]
611        );
612        ast_visit::walk_stmt(self, s)
613    }
614
615    fn visit_param(&mut self, p: &'v ast::Param) {
616        self.record("Param", None, p);
617        ast_visit::walk_param(self, p)
618    }
619
620    fn visit_arm(&mut self, a: &'v ast::Arm) {
621        self.record("Arm", None, a);
622        ast_visit::walk_arm(self, a)
623    }
624
625    fn visit_pat(&mut self, p: &'v ast::Pat) {
626        match p.kind {
    ast::PatKind::Missing { .. } => {
        self.record_variant("Pat", "Missing", None, p)
    }
    ast::PatKind::Wild { .. } => {
        self.record_variant("Pat", "Wild", None, p)
    }
    ast::PatKind::Ident { .. } => {
        self.record_variant("Pat", "Ident", None, p)
    }
    ast::PatKind::Struct { .. } => {
        self.record_variant("Pat", "Struct", None, p)
    }
    ast::PatKind::TupleStruct { .. } => {
        self.record_variant("Pat", "TupleStruct", None, p)
    }
    ast::PatKind::Or { .. } => { self.record_variant("Pat", "Or", None, p) }
    ast::PatKind::Path { .. } => {
        self.record_variant("Pat", "Path", None, p)
    }
    ast::PatKind::Tuple { .. } => {
        self.record_variant("Pat", "Tuple", None, p)
    }
    ast::PatKind::Box { .. } => { self.record_variant("Pat", "Box", None, p) }
    ast::PatKind::Deref { .. } => {
        self.record_variant("Pat", "Deref", None, p)
    }
    ast::PatKind::Ref { .. } => { self.record_variant("Pat", "Ref", None, p) }
    ast::PatKind::Expr { .. } => {
        self.record_variant("Pat", "Expr", None, p)
    }
    ast::PatKind::Range { .. } => {
        self.record_variant("Pat", "Range", None, p)
    }
    ast::PatKind::Slice { .. } => {
        self.record_variant("Pat", "Slice", None, p)
    }
    ast::PatKind::Rest { .. } => {
        self.record_variant("Pat", "Rest", None, p)
    }
    ast::PatKind::Never { .. } => {
        self.record_variant("Pat", "Never", None, p)
    }
    ast::PatKind::Guard { .. } => {
        self.record_variant("Pat", "Guard", None, p)
    }
    ast::PatKind::Paren { .. } => {
        self.record_variant("Pat", "Paren", None, p)
    }
    ast::PatKind::MacCall { .. } => {
        self.record_variant("Pat", "MacCall", None, p)
    }
    ast::PatKind::Err { .. } => { self.record_variant("Pat", "Err", None, p) }
};record_variants!(
627            (self, p, p.kind, None, ast, Pat, PatKind),
628            [
629                Missing,
630                Wild,
631                Ident,
632                Struct,
633                TupleStruct,
634                Or,
635                Path,
636                Tuple,
637                Box,
638                Deref,
639                Ref,
640                Expr,
641                Range,
642                Slice,
643                Rest,
644                Never,
645                Guard,
646                Paren,
647                MacCall,
648                Err
649            ]
650        );
651        ast_visit::walk_pat(self, p)
652    }
653
654    fn visit_expr(&mut self, e: &'v ast::Expr) {
655        #[rustfmt::skip]
656        match e.kind {
    ast::ExprKind::Array { .. } => {
        self.record_variant("Expr", "Array", None, e)
    }
    ast::ExprKind::ConstBlock { .. } => {
        self.record_variant("Expr", "ConstBlock", None, e)
    }
    ast::ExprKind::Call { .. } => {
        self.record_variant("Expr", "Call", None, e)
    }
    ast::ExprKind::MethodCall { .. } => {
        self.record_variant("Expr", "MethodCall", None, e)
    }
    ast::ExprKind::Tup { .. } => {
        self.record_variant("Expr", "Tup", None, e)
    }
    ast::ExprKind::Binary { .. } => {
        self.record_variant("Expr", "Binary", None, e)
    }
    ast::ExprKind::Unary { .. } => {
        self.record_variant("Expr", "Unary", None, e)
    }
    ast::ExprKind::Lit { .. } => {
        self.record_variant("Expr", "Lit", None, e)
    }
    ast::ExprKind::Cast { .. } => {
        self.record_variant("Expr", "Cast", None, e)
    }
    ast::ExprKind::Type { .. } => {
        self.record_variant("Expr", "Type", None, e)
    }
    ast::ExprKind::Let { .. } => {
        self.record_variant("Expr", "Let", None, e)
    }
    ast::ExprKind::If { .. } => { self.record_variant("Expr", "If", None, e) }
    ast::ExprKind::While { .. } => {
        self.record_variant("Expr", "While", None, e)
    }
    ast::ExprKind::ForLoop { .. } => {
        self.record_variant("Expr", "ForLoop", None, e)
    }
    ast::ExprKind::Loop { .. } => {
        self.record_variant("Expr", "Loop", None, e)
    }
    ast::ExprKind::Match { .. } => {
        self.record_variant("Expr", "Match", None, e)
    }
    ast::ExprKind::Closure { .. } => {
        self.record_variant("Expr", "Closure", None, e)
    }
    ast::ExprKind::Block { .. } => {
        self.record_variant("Expr", "Block", None, e)
    }
    ast::ExprKind::Await { .. } => {
        self.record_variant("Expr", "Await", None, e)
    }
    ast::ExprKind::Use { .. } => {
        self.record_variant("Expr", "Use", None, e)
    }
    ast::ExprKind::TryBlock { .. } => {
        self.record_variant("Expr", "TryBlock", None, e)
    }
    ast::ExprKind::Assign { .. } => {
        self.record_variant("Expr", "Assign", None, e)
    }
    ast::ExprKind::AssignOp { .. } => {
        self.record_variant("Expr", "AssignOp", None, e)
    }
    ast::ExprKind::Field { .. } => {
        self.record_variant("Expr", "Field", None, e)
    }
    ast::ExprKind::Index { .. } => {
        self.record_variant("Expr", "Index", None, e)
    }
    ast::ExprKind::Range { .. } => {
        self.record_variant("Expr", "Range", None, e)
    }
    ast::ExprKind::Underscore { .. } => {
        self.record_variant("Expr", "Underscore", None, e)
    }
    ast::ExprKind::Path { .. } => {
        self.record_variant("Expr", "Path", None, e)
    }
    ast::ExprKind::AddrOf { .. } => {
        self.record_variant("Expr", "AddrOf", None, e)
    }
    ast::ExprKind::Break { .. } => {
        self.record_variant("Expr", "Break", None, e)
    }
    ast::ExprKind::Continue { .. } => {
        self.record_variant("Expr", "Continue", None, e)
    }
    ast::ExprKind::Ret { .. } => {
        self.record_variant("Expr", "Ret", None, e)
    }
    ast::ExprKind::InlineAsm { .. } => {
        self.record_variant("Expr", "InlineAsm", None, e)
    }
    ast::ExprKind::FormatArgs { .. } => {
        self.record_variant("Expr", "FormatArgs", None, e)
    }
    ast::ExprKind::OffsetOf { .. } => {
        self.record_variant("Expr", "OffsetOf", None, e)
    }
    ast::ExprKind::MacCall { .. } => {
        self.record_variant("Expr", "MacCall", None, e)
    }
    ast::ExprKind::Struct { .. } => {
        self.record_variant("Expr", "Struct", None, e)
    }
    ast::ExprKind::Repeat { .. } => {
        self.record_variant("Expr", "Repeat", None, e)
    }
    ast::ExprKind::Paren { .. } => {
        self.record_variant("Expr", "Paren", None, e)
    }
    ast::ExprKind::Try { .. } => {
        self.record_variant("Expr", "Try", None, e)
    }
    ast::ExprKind::Yield { .. } => {
        self.record_variant("Expr", "Yield", None, e)
    }
    ast::ExprKind::Yeet { .. } => {
        self.record_variant("Expr", "Yeet", None, e)
    }
    ast::ExprKind::Become { .. } => {
        self.record_variant("Expr", "Become", None, e)
    }
    ast::ExprKind::IncludedBytes { .. } => {
        self.record_variant("Expr", "IncludedBytes", None, e)
    }
    ast::ExprKind::Gen { .. } => {
        self.record_variant("Expr", "Gen", None, e)
    }
    ast::ExprKind::UnsafeBinderCast { .. } => {
        self.record_variant("Expr", "UnsafeBinderCast", None, e)
    }
    ast::ExprKind::Err { .. } => {
        self.record_variant("Expr", "Err", None, e)
    }
    ast::ExprKind::Dummy { .. } => {
        self.record_variant("Expr", "Dummy", None, e)
    }
};record_variants!(
657            (self, e, e.kind, None, ast, Expr, ExprKind),
658            [
659                Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
660                If, While, ForLoop, Loop, Match, Closure, Block, Await, Use, TryBlock, Assign,
661                AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
662                InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet,
663                Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy
664            ]
665        );
666        ast_visit::walk_expr(self, e)
667    }
668
669    fn visit_ty(&mut self, t: &'v ast::Ty) {
670        match t.kind {
    ast::TyKind::Slice { .. } => {
        self.record_variant("Ty", "Slice", None, t)
    }
    ast::TyKind::Array { .. } => {
        self.record_variant("Ty", "Array", None, t)
    }
    ast::TyKind::Ptr { .. } => { self.record_variant("Ty", "Ptr", None, t) }
    ast::TyKind::Ref { .. } => { self.record_variant("Ty", "Ref", None, t) }
    ast::TyKind::PinnedRef { .. } => {
        self.record_variant("Ty", "PinnedRef", None, t)
    }
    ast::TyKind::FnPtr { .. } => {
        self.record_variant("Ty", "FnPtr", None, t)
    }
    ast::TyKind::UnsafeBinder { .. } => {
        self.record_variant("Ty", "UnsafeBinder", None, t)
    }
    ast::TyKind::Never { .. } => {
        self.record_variant("Ty", "Never", None, t)
    }
    ast::TyKind::Tup { .. } => { self.record_variant("Ty", "Tup", None, t) }
    ast::TyKind::Path { .. } => { self.record_variant("Ty", "Path", None, t) }
    ast::TyKind::Pat { .. } => { self.record_variant("Ty", "Pat", None, t) }
    ast::TyKind::TraitObject { .. } => {
        self.record_variant("Ty", "TraitObject", None, t)
    }
    ast::TyKind::ImplTrait { .. } => {
        self.record_variant("Ty", "ImplTrait", None, t)
    }
    ast::TyKind::Paren { .. } => {
        self.record_variant("Ty", "Paren", None, t)
    }
    ast::TyKind::Infer { .. } => {
        self.record_variant("Ty", "Infer", None, t)
    }
    ast::TyKind::ImplicitSelf { .. } => {
        self.record_variant("Ty", "ImplicitSelf", None, t)
    }
    ast::TyKind::MacCall { .. } => {
        self.record_variant("Ty", "MacCall", None, t)
    }
    ast::TyKind::CVarArgs { .. } => {
        self.record_variant("Ty", "CVarArgs", None, t)
    }
    ast::TyKind::Dummy { .. } => {
        self.record_variant("Ty", "Dummy", None, t)
    }
    ast::TyKind::FieldOf { .. } => {
        self.record_variant("Ty", "FieldOf", None, t)
    }
    ast::TyKind::Err { .. } => { self.record_variant("Ty", "Err", None, t) }
};record_variants!(
671            (self, t, t.kind, None, ast, Ty, TyKind),
672            [
673                Slice,
674                Array,
675                Ptr,
676                Ref,
677                PinnedRef,
678                FnPtr,
679                UnsafeBinder,
680                Never,
681                Tup,
682                Path,
683                Pat,
684                TraitObject,
685                ImplTrait,
686                Paren,
687                Infer,
688                ImplicitSelf,
689                MacCall,
690                CVarArgs,
691                Dummy,
692                FieldOf,
693                Err
694            ]
695        );
696
697        ast_visit::walk_ty(self, t)
698    }
699
700    fn visit_generic_param(&mut self, g: &'v ast::GenericParam) {
701        self.record("GenericParam", None, g);
702        ast_visit::walk_generic_param(self, g)
703    }
704
705    fn visit_where_predicate(&mut self, p: &'v ast::WherePredicate) {
706        match &p.kind {
    ast::WherePredicateKind::BoundPredicate { .. } => {
        self.record_variant("WherePredicate", "BoundPredicate", None, p)
    }
    ast::WherePredicateKind::RegionPredicate { .. } => {
        self.record_variant("WherePredicate", "RegionPredicate", None, p)
    }
    ast::WherePredicateKind::EqPredicate { .. } => {
        self.record_variant("WherePredicate", "EqPredicate", None, p)
    }
};record_variants!(
707            (self, p, &p.kind, None, ast, WherePredicate, WherePredicateKind),
708            [BoundPredicate, RegionPredicate, EqPredicate]
709        );
710        ast_visit::walk_where_predicate(self, p)
711    }
712
713    fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, _: &AttrVec, _: Span, _: NodeId) {
714        self.record("FnDecl", None, fk.decl());
715        ast_visit::walk_fn(self, fk)
716    }
717
718    fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
719        match i.kind {
    ast::AssocItemKind::Const { .. } => {
        self.record_variant("AssocItem", "Const", None, i)
    }
    ast::AssocItemKind::Fn { .. } => {
        self.record_variant("AssocItem", "Fn", None, i)
    }
    ast::AssocItemKind::Type { .. } => {
        self.record_variant("AssocItem", "Type", None, i)
    }
    ast::AssocItemKind::MacCall { .. } => {
        self.record_variant("AssocItem", "MacCall", None, i)
    }
    ast::AssocItemKind::Delegation { .. } => {
        self.record_variant("AssocItem", "Delegation", None, i)
    }
    ast::AssocItemKind::DelegationMac { .. } => {
        self.record_variant("AssocItem", "DelegationMac", None, i)
    }
};record_variants!(
720            (self, i, i.kind, None, ast, AssocItem, AssocItemKind),
721            [Const, Fn, Type, MacCall, Delegation, DelegationMac]
722        );
723        ast_visit::walk_assoc_item(self, i, ctxt);
724    }
725
726    fn visit_param_bound(&mut self, b: &'v ast::GenericBound, _ctxt: BoundKind) {
727        match b {
    ast::GenericBound::Trait { .. } => {
        self.record_variant("GenericBound", "Trait", None, b)
    }
    ast::GenericBound::Outlives { .. } => {
        self.record_variant("GenericBound", "Outlives", None, b)
    }
    ast::GenericBound::Use { .. } => {
        self.record_variant("GenericBound", "Use", None, b)
    }
};record_variants!(
728            (self, b, b, None, ast, GenericBound, GenericBound),
729            [Trait, Outlives, Use]
730        );
731        ast_visit::walk_param_bound(self, b)
732    }
733
734    fn visit_field_def(&mut self, s: &'v ast::FieldDef) {
735        self.record("FieldDef", None, s);
736        ast_visit::walk_field_def(self, s)
737    }
738
739    fn visit_variant(&mut self, v: &'v ast::Variant) {
740        self.record("Variant", None, v);
741        ast_visit::walk_variant(self, v)
742    }
743
744    // `UseTree` has one inline use (in `ast::ItemKind::Use`) and one
745    // non-inline use (in `ast::UseTreeKind::Nested`). The former case is more
746    // common, so we don't implement `visit_use_tree` and tolerate the missed
747    // coverage in the latter case.
748
749    // `PathSegment` has one inline use (in `ast::ExprKind::MethodCall`) and
750    // one non-inline use (in `ast::Path::segments`). The latter case is more
751    // common than the former case, so we implement this visitor and tolerate
752    // the double counting in the former case.
753    fn visit_path_segment(&mut self, path_segment: &'v ast::PathSegment) {
754        self.record("PathSegment", None, path_segment);
755        ast_visit::walk_path_segment(self, path_segment)
756    }
757
758    // `GenericArgs` has one inline use (in `ast::AssocItemConstraint::gen_args`) and one
759    // non-inline use (in `ast::PathSegment::args`). The latter case is more
760    // common, so we implement `visit_generic_args` and tolerate the double
761    // counting in the former case.
762    fn visit_generic_args(&mut self, g: &'v ast::GenericArgs) {
763        match g {
    ast::GenericArgs::AngleBracketed { .. } => {
        self.record_variant("GenericArgs", "AngleBracketed", None, g)
    }
    ast::GenericArgs::Parenthesized { .. } => {
        self.record_variant("GenericArgs", "Parenthesized", None, g)
    }
    ast::GenericArgs::ParenthesizedElided { .. } => {
        self.record_variant("GenericArgs", "ParenthesizedElided", None, g)
    }
};record_variants!(
764            (self, g, g, None, ast, GenericArgs, GenericArgs),
765            [AngleBracketed, Parenthesized, ParenthesizedElided]
766        );
767        ast_visit::walk_generic_args(self, g)
768    }
769
770    fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
771        match attr.kind {
    ast::AttrKind::Normal { .. } => {
        self.record_variant("Attribute", "Normal", None, attr)
    }
    ast::AttrKind::DocComment { .. } => {
        self.record_variant("Attribute", "DocComment", None, attr)
    }
};record_variants!(
772            (self, attr, attr.kind, None, ast, Attribute, AttrKind),
773            [Normal, DocComment]
774        );
775        ast_visit::walk_attribute(self, attr)
776    }
777
778    fn visit_expr_field(&mut self, f: &'v ast::ExprField) {
779        self.record("ExprField", None, f);
780        ast_visit::walk_expr_field(self, f)
781    }
782
783    fn visit_crate(&mut self, krate: &'v ast::Crate) {
784        self.record("Crate", None, krate);
785        ast_visit::walk_crate(self, krate)
786    }
787
788    fn visit_inline_asm(&mut self, asm: &'v ast::InlineAsm) {
789        self.record("InlineAsm", None, asm);
790        ast_visit::walk_inline_asm(self, asm)
791    }
792}