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<T: PrintAttribute> PrintAttribute for &T {
30    fn should_render(&self) -> bool {
31        T::should_render(self)
32    }
33
34    fn print_attribute(&self, p: &mut Printer) {
35        T::print_attribute(self, p)
36    }
37}
38impl<T: PrintAttribute> PrintAttribute for Option<T> {
39    fn should_render(&self) -> bool {
40        self.as_ref().is_some_and(|x| x.should_render())
41    }
42
43    fn print_attribute(&self, p: &mut Printer) {
44        if let Some(i) = self {
45            T::print_attribute(i, p)
46        }
47    }
48}
49impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
50    fn should_render(&self) -> bool {
51        self.is_empty() || self[0].should_render()
52    }
53
54    fn print_attribute(&self, p: &mut Printer) {
55        let mut last_printed = false;
56        p.word("[");
57        for i in self {
58            if last_printed {
59                p.word_space(",");
60            }
61            i.print_attribute(p);
62            last_printed = i.should_render();
63        }
64        p.word("]");
65    }
66}
67macro_rules! print_skip {
68    ($($t: ty),* $(,)?) => {$(
69        impl PrintAttribute for $t {
70            fn should_render(&self) -> bool { false }
71            fn print_attribute(&self, _: &mut Printer) { }
72        })*
73    };
74}
75
76macro_rules! print_disp {
77    ($($t: ty),* $(,)?) => {$(
78        impl PrintAttribute for $t {
79            fn should_render(&self) -> bool { true }
80            fn print_attribute(&self, p: &mut Printer) {
81                p.word(format!("{}", self));
82            }
83        }
84    )*};
85}
86macro_rules! print_debug {
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}
96
97macro_rules! print_tup {
98    (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* };
99    () => {};
100    ($t: ident $($ts: ident)*) => {
101        #[allow(non_snake_case, unused)]
102        impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) {
103            fn should_render(&self) -> bool {
104                let ($t, $($ts),*) = self;
105                print_tup!(num_should_render $t $($ts)*) != 0
106            }
107
108            fn print_attribute(&self, p: &mut Printer) {
109                let ($t, $($ts),*) = self;
110                let parens = print_tup!(num_should_render $t $($ts)*) > 1;
111                if parens {
112                    p.popen();
113                }
114
115                let mut printed_anything = $t.should_render();
116
117                $t.print_attribute(p);
118
119                $(
120                    if $ts.should_render() {
121                        if printed_anything {
122                            p.word_space(",");
123                        }
124                        printed_anything = true;
125                    }
126                    $ts.print_attribute(p);
127                )*
128
129                if parens {
130                    p.pclose();
131                }
132            }
133        }
134
135        print_tup!($($ts)*);
136    };
137}
138
139print_tup!(A B C D E F G H);
140print_skip!(Span, (), ErrorGuaranteed);
141print_disp!(u16, u128, bool, NonZero<u32>, Limit);
142print_debug!(
143    Symbol,
144    Ident,
145    UintTy,
146    IntTy,
147    Align,
148    AttrStyle,
149    CommentKind,
150    Transparency,
151    SanitizerSet,
152);