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