Skip to main content

rustc_hir/attrs/
pretty_printing.rs

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