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