rustc_hir/attrs/
pretty_printing.rs

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