rustc_hir/attrs/
pretty_printing.rs

1use std::num::NonZero;
2
3use rustc_abi::Align;
4use rustc_ast::token::CommentKind;
5use rustc_ast::{AttrStyle, IntTy, UintTy};
6use rustc_ast_pretty::pp::Printer;
7use rustc_span::hygiene::Transparency;
8use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
9use thin_vec::ThinVec;
10
11/// This trait is used to print attributes in `rustc_hir_pretty`.
12///
13/// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`].
14/// The output will look a lot like a `Debug` implementation, but fields of several types
15/// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the
16/// representation much.
17pub trait PrintAttribute {
18    /// Whether or not this will render as something meaningful, or if it's skipped
19    /// (which will force the containing struct to also skip printing a comma
20    /// and the field name).
21    fn should_render(&self) -> bool;
22
23    fn print_attribute(&self, p: &mut Printer);
24}
25
26impl PrintAttribute for u128 {
27    fn should_render(&self) -> bool {
28        true
29    }
30
31    fn print_attribute(&self, p: &mut Printer) {
32        p.word(self.to_string())
33    }
34}
35
36impl<T: PrintAttribute> PrintAttribute for &T {
37    fn should_render(&self) -> bool {
38        T::should_render(self)
39    }
40
41    fn print_attribute(&self, p: &mut Printer) {
42        T::print_attribute(self, p)
43    }
44}
45impl<T: PrintAttribute> PrintAttribute for Option<T> {
46    fn should_render(&self) -> bool {
47        self.as_ref().is_some_and(|x| x.should_render())
48    }
49
50    fn print_attribute(&self, p: &mut Printer) {
51        if let Some(i) = self {
52            T::print_attribute(i, p)
53        }
54    }
55}
56impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
57    fn should_render(&self) -> bool {
58        self.is_empty() || self[0].should_render()
59    }
60
61    fn print_attribute(&self, p: &mut Printer) {
62        let mut last_printed = false;
63        p.word("[");
64        for i in self {
65            if last_printed {
66                p.word_space(",");
67            }
68            i.print_attribute(p);
69            last_printed = i.should_render();
70        }
71        p.word("]");
72    }
73}
74macro_rules! print_skip {
75    ($($t: ty),* $(,)?) => {$(
76        impl PrintAttribute for $t {
77            fn should_render(&self) -> bool { false }
78            fn print_attribute(&self, _: &mut Printer) { }
79        })*
80    };
81}
82
83macro_rules! print_disp {
84    ($($t: ty),* $(,)?) => {$(
85        impl PrintAttribute for $t {
86            fn should_render(&self) -> bool { true }
87            fn print_attribute(&self, p: &mut Printer) {
88                p.word(format!("{}", self));
89            }
90        }
91    )*};
92}
93macro_rules! print_debug {
94    ($($t: ty),* $(,)?) => {$(
95        impl PrintAttribute for $t {
96            fn should_render(&self) -> bool { true }
97            fn print_attribute(&self, p: &mut Printer) {
98                p.word(format!("{:?}", self));
99            }
100        }
101    )*};
102}
103
104macro_rules! print_tup {
105    (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* };
106    () => {};
107    ($t: ident $($ts: ident)*) => {
108        #[allow(non_snake_case, unused)]
109        impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) {
110            fn should_render(&self) -> bool {
111                let ($t, $($ts),*) = self;
112                print_tup!(num_should_render $t $($ts)*) != 0
113            }
114
115            fn print_attribute(&self, p: &mut Printer) {
116                let ($t, $($ts),*) = self;
117                let parens = print_tup!(num_should_render $t $($ts)*) > 1;
118                if parens {
119                    p.popen();
120                }
121
122                let mut printed_anything = $t.should_render();
123
124                $t.print_attribute(p);
125
126                $(
127                    if $ts.should_render() {
128                        if printed_anything {
129                            p.word_space(",");
130                        }
131                        printed_anything = true;
132                    }
133                    $ts.print_attribute(p);
134                )*
135
136                if parens {
137                    p.pclose();
138                }
139            }
140        }
141
142        print_tup!($($ts)*);
143    };
144}
145
146print_tup!(A B C D E F G H);
147print_skip!(Span, (), ErrorGuaranteed);
148print_disp!(u16, bool, NonZero<u32>);
149print_debug!(Symbol, Ident, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);