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, LocalModId};
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)
    }
    hir::ItemKind::TestBinderConstraints { .. } => {
        self.record_variant("Item", "TestBinderConstraints", 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                TestBinderConstraints
270            ]
271        );
272        hir_visit::walk_item(self, i)
273    }
274
275    fn visit_body(&mut self, b: &hir::Body<'v>) {
276        self.record("Body", None, b);
277        hir_visit::walk_body(self, b);
278    }
279
280    fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, _id: LocalModId) {
281        self.record("Mod", None, m);
282        hir_visit::walk_mod(self, m)
283    }
284
285    fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) {
286        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!(
287            (self, i, i.kind, Some(i.hir_id()), hir, ForeignItem, ForeignItemKind),
288            [Fn, Static, Type]
289        );
290        hir_visit::walk_foreign_item(self, i)
291    }
292
293    fn visit_local(&mut self, l: &'v hir::LetStmt<'v>) {
294        self.record("Local", Some(l.hir_id), l);
295        hir_visit::walk_local(self, l)
296    }
297
298    fn visit_block(&mut self, b: &'v hir::Block<'v>) {
299        self.record("Block", Some(b.hir_id), b);
300        hir_visit::walk_block(self, b)
301    }
302
303    fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
304        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!(
305            (self, s, s.kind, Some(s.hir_id), hir, Stmt, StmtKind),
306            [Let, Item, Expr, Semi]
307        );
308        hir_visit::walk_stmt(self, s)
309    }
310
311    fn visit_arm(&mut self, a: &'v hir::Arm<'v>) {
312        self.record("Arm", Some(a.hir_id), a);
313        hir_visit::walk_arm(self, a)
314    }
315
316    fn visit_pat(&mut self, p: &'v hir::Pat<'v>) {
317        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::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!(
318            (self, p, p.kind, Some(p.hir_id), hir, Pat, PatKind),
319            [
320                Missing,
321                Wild,
322                Binding,
323                Struct,
324                TupleStruct,
325                Or,
326                Never,
327                Tuple,
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::View { .. } => {
        self.record_variant("Ty", "View", 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                View,
415                Err
416            ]
417        );
418        hir_visit::walk_ty(self, t)
419    }
420
421    fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
422        self.record("GenericParam", Some(p.hir_id), p);
423        hir_visit::walk_generic_param(self, p)
424    }
425
426    fn visit_generics(&mut self, g: &'v hir::Generics<'v>) {
427        self.record("Generics", None, g);
428        hir_visit::walk_generics(self, g)
429    }
430
431    fn visit_where_predicate(&mut self, p: &'v hir::WherePredicate<'v>) {
432        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)
    }
};record_variants!(
433            (self, p, p.kind, Some(p.hir_id), hir, WherePredicate, WherePredicateKind),
434            [BoundPredicate, RegionPredicate]
435        );
436        hir_visit::walk_where_predicate(self, p)
437    }
438
439    fn visit_fn(
440        &mut self,
441        fk: hir_visit::FnKind<'v>,
442        fd: &'v hir::FnDecl<'v>,
443        b: hir::BodyId,
444        _: Span,
445        id: LocalDefId,
446    ) {
447        self.record("FnDecl", None, fd);
448        hir_visit::walk_fn(self, fk, fd, b, id)
449    }
450
451    fn visit_use(&mut self, tree: &'v hir::UseTree<'v>, _hir_id: HirId, _def_id: LocalDefId) {
452        // This is `visit_use`, but the type is `Path` so record it that way.
453        self.record("Path", None, tree);
454        // Don't call `hir_visit::walk_use(self, p, hir_id)`: it calls
455        // `visit_path` up to three times, once for each namespace result in
456        // `p.res`, by building temporary `Path`s that are not part of the real
457        // HIR, which causes `p` to be double- or triple-counted. Instead just
458        // walk the path internals (i.e. the segments) directly.
459        let hir::Path { span: _, res: _, segments } = *tree.prefix;
460        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);
461        match tree.kind {
462            hir::UseKind::Single(_) | hir::UseKind::Glob => {}
463            hir::UseKind::Nested { items } => {
464                for (tree, id, def_id) in items {
465                    self.visit_use(tree, *id, *def_id);
466                }
467            }
468        }
469    }
470
471    fn visit_trait_item(&mut self, ti: &'v hir::TraitItem<'v>) {
472        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!(
473            (self, ti, ti.kind, Some(ti.hir_id()), hir, TraitItem, TraitItemKind),
474            [Const, Fn, Type]
475        );
476        hir_visit::walk_trait_item(self, ti)
477    }
478
479    fn visit_trait_item_ref(&mut self, ti: &'v hir::TraitItemId) {
480        self.record("TraitItemId", Some(ti.hir_id()), ti);
481        hir_visit::walk_trait_item_ref(self, *ti)
482    }
483
484    fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) {
485        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!(
486            (self, ii, ii.kind, Some(ii.hir_id()), hir, ImplItem, ImplItemKind),
487            [Const, Fn, Type]
488        );
489        hir_visit::walk_impl_item(self, ii)
490    }
491
492    fn visit_foreign_item_ref(&mut self, fi: &'v hir::ForeignItemId) {
493        self.record("ForeignItemId", Some(fi.hir_id()), fi);
494        hir_visit::walk_foreign_item_ref(self, *fi)
495    }
496
497    fn visit_impl_item_ref(&mut self, ii: &'v hir::ImplItemId) {
498        self.record("ImplItemId", Some(ii.hir_id()), ii);
499        hir_visit::walk_impl_item_ref(self, *ii)
500    }
501
502    fn visit_param_bound(&mut self, b: &'v hir::GenericBound<'v>) {
503        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!(
504            (self, b, b, None, hir, GenericBound, GenericBound),
505            [Trait, Outlives, Use]
506        );
507        hir_visit::walk_param_bound(self, b)
508    }
509
510    fn visit_field_def(&mut self, s: &'v hir::FieldDef<'v>) {
511        self.record("FieldDef", Some(s.hir_id), s);
512        hir_visit::walk_field_def(self, s)
513    }
514
515    fn visit_variant(&mut self, v: &'v hir::Variant<'v>) {
516        self.record("Variant", None, v);
517        hir_visit::walk_variant(self, v)
518    }
519
520    fn visit_generic_arg(&mut self, ga: &'v hir::GenericArg<'v>) {
521        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!(
522            (self, ga, ga, Some(ga.hir_id()), hir, GenericArg, GenericArg),
523            [Lifetime, Type, Const, Infer]
524        );
525        match ga {
526            hir::GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
527            hir::GenericArg::Type(ty) => self.visit_ty(ty),
528            hir::GenericArg::Const(ct) => self.visit_const_arg(ct),
529            hir::GenericArg::Infer(inf) => self.visit_id(inf.hir_id),
530        }
531    }
532
533    fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
534        self.record("Lifetime", Some(lifetime.hir_id), lifetime);
535        hir_visit::walk_lifetime(self, lifetime)
536    }
537
538    fn visit_path(&mut self, path: &hir::Path<'v>, _id: HirId) {
539        self.record("Path", None, path);
540        hir_visit::walk_path(self, path)
541    }
542
543    fn visit_path_segment(&mut self, path_segment: &'v hir::PathSegment<'v>) {
544        self.record("PathSegment", None, path_segment);
545        hir_visit::walk_path_segment(self, path_segment)
546    }
547
548    fn visit_generic_args(&mut self, ga: &'v hir::GenericArgs<'v>) {
549        self.record("GenericArgs", None, ga);
550        hir_visit::walk_generic_args(self, ga)
551    }
552
553    fn visit_assoc_item_constraint(&mut self, constraint: &'v hir::AssocItemConstraint<'v>) {
554        self.record("AssocItemConstraint", Some(constraint.hir_id), constraint);
555        hir_visit::walk_assoc_item_constraint(self, constraint)
556    }
557
558    fn visit_attribute(&mut self, attr: &'v rustc_attr_ir::Attribute) {
559        self.record("Attribute", None, attr);
560    }
561
562    fn visit_inline_asm(&mut self, asm: &'v hir::InlineAsm<'v>, id: HirId) {
563        self.record("InlineAsm", None, asm);
564        hir_visit::walk_inline_asm(self, asm, id);
565    }
566}
567
568impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
569    fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
570        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!(
571            (self, i, i.kind, None, ast, ForeignItem, ForeignItemKind),
572            [Static, Fn, TyAlias, MacCall]
573        );
574        ast_visit::walk_item(self, i)
575    }
576
577    fn visit_item(&mut self, i: &'v ast::Item) {
578        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)
    }
    ast::ItemKind::TestBinderConstraints { .. } => {
        self.record_variant("Item", "TestBinderConstraints", None, i)
    }
};record_variants!(
579            (self, i, i.kind, None, ast, Item, ItemKind),
580            [
581                ExternCrate,
582                Use,
583                Static,
584                Const,
585                ConstBlock,
586                Fn,
587                Mod,
588                ForeignMod,
589                GlobalAsm,
590                TyAlias,
591                Enum,
592                Struct,
593                Union,
594                Trait,
595                TraitAlias,
596                Impl,
597                MacCall,
598                MacroDef,
599                Delegation,
600                DelegationMac,
601                TestBinderConstraints
602            ]
603        );
604        ast_visit::walk_item(self, i)
605    }
606
607    fn visit_local(&mut self, l: &'v ast::Local) {
608        self.record("Local", None, l);
609        ast_visit::walk_local(self, l)
610    }
611
612    fn visit_block(&mut self, b: &'v ast::Block) {
613        self.record("Block", None, b);
614        ast_visit::walk_block(self, b)
615    }
616
617    fn visit_stmt(&mut self, s: &'v ast::Stmt) {
618        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!(
619            (self, s, s.kind, None, ast, Stmt, StmtKind),
620            [Let, Item, Expr, Semi, Empty, MacCall]
621        );
622        ast_visit::walk_stmt(self, s)
623    }
624
625    fn visit_param(&mut self, p: &'v ast::Param) {
626        self.record("Param", None, p);
627        ast_visit::walk_param(self, p)
628    }
629
630    fn visit_arm(&mut self, a: &'v ast::Arm) {
631        self.record("Arm", None, a);
632        ast_visit::walk_arm(self, a)
633    }
634
635    fn visit_pat(&mut self, p: &'v ast::Pat) {
636        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::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!(
637            (self, p, p.kind, None, ast, Pat, PatKind),
638            [
639                Missing,
640                Wild,
641                Ident,
642                Struct,
643                TupleStruct,
644                Or,
645                Path,
646                Tuple,
647                Deref,
648                Ref,
649                Expr,
650                Range,
651                Slice,
652                Rest,
653                Never,
654                Guard,
655                Paren,
656                MacCall,
657                Err
658            ]
659        );
660        ast_visit::walk_pat(self, p)
661    }
662
663    fn visit_expr(&mut self, e: &'v ast::Expr) {
664        #[rustfmt::skip]
665        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::Move { .. } => {
        self.record_variant("Expr", "Move", 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::GcaMacro { .. } => {
        self.record_variant("Expr", "GcaMacro", None, e)
    }
    ast::ExprKind::Err { .. } => {
        self.record_variant("Expr", "Err", None, e)
    }
    ast::ExprKind::Dummy { .. } => {
        self.record_variant("Expr", "Dummy", None, e)
    }
};record_variants!(
666            (self, e, e.kind, None, ast, Expr, ExprKind),
667            [
668                Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
669                If, While, ForLoop, Loop, Match, Closure, Block, Await, Move, Use, TryBlock, Assign,
670                AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
671                InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet,
672                Become, IncludedBytes, Gen, UnsafeBinderCast, GcaMacro, Err, Dummy
673            ]
674        );
675        ast_visit::walk_expr(self, e)
676    }
677
678    fn visit_ty(&mut self, t: &'v ast::Ty) {
679        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::FieldOf { .. } => {
        self.record_variant("Ty", "FieldOf", None, t)
    }
    ast::TyKind::View { .. } => { self.record_variant("Ty", "View", None, t) }
    ast::TyKind::GcaMacro { .. } => {
        self.record_variant("Ty", "GcaMacro", None, t)
    }
    ast::TyKind::Dummy { .. } => {
        self.record_variant("Ty", "Dummy", None, t)
    }
    ast::TyKind::Err { .. } => { self.record_variant("Ty", "Err", None, t) }
};record_variants!(
680            (self, t, t.kind, None, ast, Ty, TyKind),
681            [
682                Slice,
683                Array,
684                Ptr,
685                Ref,
686                PinnedRef,
687                FnPtr,
688                UnsafeBinder,
689                Never,
690                Tup,
691                Path,
692                Pat,
693                TraitObject,
694                ImplTrait,
695                Paren,
696                Infer,
697                ImplicitSelf,
698                MacCall,
699                CVarArgs,
700                FieldOf,
701                View,
702                GcaMacro,
703                Dummy,
704                Err
705            ]
706        );
707
708        ast_visit::walk_ty(self, t)
709    }
710
711    fn visit_generic_param(&mut self, g: &'v ast::GenericParam) {
712        self.record("GenericParam", None, g);
713        ast_visit::walk_generic_param(self, g)
714    }
715
716    fn visit_where_predicate(&mut self, p: &'v ast::WherePredicate) {
717        match &p.kind {
    ast::WherePredicateKind::BoundPredicate { .. } => {
        self.record_variant("WherePredicate", "BoundPredicate", None, p)
    }
    ast::WherePredicateKind::RegionPredicate { .. } => {
        self.record_variant("WherePredicate", "RegionPredicate", None, p)
    }
};record_variants!(
718            (self, p, &p.kind, None, ast, WherePredicate, WherePredicateKind),
719            [BoundPredicate, RegionPredicate]
720        );
721        ast_visit::walk_where_predicate(self, p)
722    }
723
724    fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, _: &AttrVec, _: Span, _: NodeId) {
725        self.record("FnDecl", None, fk.decl());
726        ast_visit::walk_fn(self, fk)
727    }
728
729    fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
730        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!(
731            (self, i, i.kind, None, ast, AssocItem, AssocItemKind),
732            [Const, Fn, Type, MacCall, Delegation, DelegationMac]
733        );
734        ast_visit::walk_assoc_item(self, i, ctxt);
735    }
736
737    fn visit_param_bound(&mut self, b: &'v ast::GenericBound, _ctxt: BoundKind) {
738        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!(
739            (self, b, b, None, ast, GenericBound, GenericBound),
740            [Trait, Outlives, Use]
741        );
742        ast_visit::walk_param_bound(self, b)
743    }
744
745    fn visit_field_def(&mut self, s: &'v ast::FieldDef) {
746        self.record("FieldDef", None, s);
747        ast_visit::walk_field_def(self, s)
748    }
749
750    fn visit_variant(&mut self, v: &'v ast::Variant) {
751        self.record("Variant", None, v);
752        ast_visit::walk_variant(self, v)
753    }
754
755    // `UseTree` has one inline use (in `ast::ItemKind::Use`) and one
756    // non-inline use (in `ast::UseTreeKind::Nested`). The former case is more
757    // common, so we don't implement `visit_use_tree` and tolerate the missed
758    // coverage in the latter case.
759
760    // `PathSegment` has one inline use (in `ast::ExprKind::MethodCall`) and
761    // one non-inline use (in `ast::Path::segments`). The latter case is more
762    // common than the former case, so we implement this visitor and tolerate
763    // the double counting in the former case.
764    fn visit_path_segment(&mut self, path_segment: &'v ast::PathSegment) {
765        self.record("PathSegment", None, path_segment);
766        ast_visit::walk_path_segment(self, path_segment)
767    }
768
769    // `GenericArgs` has one inline use (in `ast::AssocItemConstraint::gen_args`) and one
770    // non-inline use (in `ast::PathSegment::args`). The latter case is more
771    // common, so we implement `visit_generic_args` and tolerate the double
772    // counting in the former case.
773    fn visit_generic_args(&mut self, g: &'v ast::GenericArgs) {
774        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!(
775            (self, g, g, None, ast, GenericArgs, GenericArgs),
776            [AngleBracketed, Parenthesized, ParenthesizedElided]
777        );
778        ast_visit::walk_generic_args(self, g)
779    }
780
781    fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
782        match attr.kind {
    ast::AttrKind::Normal { .. } => {
        self.record_variant("Attribute", "Normal", None, attr)
    }
    ast::AttrKind::Synthetic { .. } => {
        self.record_variant("Attribute", "Synthetic", None, attr)
    }
    ast::AttrKind::DocComment { .. } => {
        self.record_variant("Attribute", "DocComment", None, attr)
    }
};record_variants!(
783            (self, attr, attr.kind, None, ast, Attribute, AttrKind),
784            [Normal, Synthetic, DocComment]
785        );
786        ast_visit::walk_attribute(self, attr)
787    }
788
789    fn visit_expr_field(&mut self, f: &'v ast::ExprField) {
790        self.record("ExprField", None, f);
791        ast_visit::walk_expr_field(self, f)
792    }
793
794    fn visit_crate(&mut self, krate: &'v ast::Crate) {
795        self.record("Crate", None, krate);
796        ast_visit::walk_crate(self, krate)
797    }
798
799    fn visit_inline_asm(&mut self, asm: &'v ast::InlineAsm) {
800        self.record("InlineAsm", None, asm);
801        ast_visit::walk_inline_asm(self, asm)
802    }
803}