Skip to main content

rustc_attr_ir/
pretty_printing.rs

1use std::num::NonZero;
2use std::ops::Deref;
3use std::path::PathBuf;
4
5use rustc_abi::Align;
6use rustc_ast::ast::{Path, join_path_idents};
7use rustc_ast::attr::data_structures::CfgEntry;
8use rustc_ast::attr::version::RustcVersion;
9use rustc_ast::expand::autodiff_attrs::{DiffActivity, DiffMode};
10use rustc_ast::token::{CommentKind, DocFragmentKind};
11use rustc_ast::{AttrId, AttrStyle, IntTy, UintTy};
12use rustc_ast_pretty::pp::Printer;
13use rustc_data_structures::fx::FxIndexMap;
14use rustc_span::def_id::DefId;
15use rustc_span::hygiene::Transparency;
16use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
17use rustc_structures::{CollapseMacroDebuginfo, CrateType, Limit, NativeLibKind, SanitizerSet};
18use thin_vec::ThinVec;
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, T2: PrintAttribute> PrintAttribute for FxIndexMap<T, T2> {
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}
109impl PrintAttribute for Path {
110    fn should_render(&self) -> bool {
111        true
112    }
113
114    fn print_attribute(&self, p: &mut Printer) {
115        p.word(join_path_idents(self.segments.iter().map(|seg| seg.ident)));
116    }
117}
118
119macro_rules! print_skip {
120    ($($t: ty),* $(,)?) => {$(
121        impl PrintAttribute for $t {
122            fn should_render(&self) -> bool { false }
123            fn print_attribute(&self, _: &mut Printer) { }
124        })*
125    };
126}
127
128macro_rules! print_disp {
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}
138macro_rules! print_debug {
139    ($($t: ty),* $(,)?) => {$(
140        impl PrintAttribute for $t {
141            fn should_render(&self) -> bool { true }
142            fn print_attribute(&self, p: &mut Printer) {
143                p.word(format!("{:?}", self));
144            }
145        }
146    )*};
147}
148
149macro_rules! print_tup {
150    (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* };
151    () => {};
152    ($t: ident $($ts: ident)*) => {
153        #[allow(non_snake_case, unused)]
154        impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) {
155            fn should_render(&self) -> bool {
156                let ($t, $($ts),*) = self;
157                print_tup!(num_should_render $t $($ts)*) != 0
158            }
159
160            fn print_attribute(&self, p: &mut Printer) {
161                let ($t, $($ts),*) = self;
162                let parens = print_tup!(num_should_render $t $($ts)*) > 1;
163                if parens {
164                    p.popen();
165                }
166
167                let mut printed_anything = $t.should_render();
168
169                $t.print_attribute(p);
170
171                $(
172                    if $ts.should_render() {
173                        if printed_anything {
174                            p.word_space(",");
175                        }
176                        printed_anything = true;
177                    }
178                    $ts.print_attribute(p);
179                )*
180
181                if parens {
182                    p.pclose();
183                }
184            }
185        }
186
187        print_tup!($($ts)*);
188    };
189}
190
191#[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);
192impl PrintAttribute for Span {
    fn should_render(&self) -> bool { false }
    fn print_attribute(&self, _: &mut Printer) {}
}
impl PrintAttribute for () {
    fn should_render(&self) -> bool { false }
    fn print_attribute(&self, _: &mut Printer) {}
}
impl PrintAttribute for ErrorGuaranteed {
    fn should_render(&self) -> bool { false }
    fn print_attribute(&self, _: &mut Printer) {}
}
impl PrintAttribute for AttrId {
    fn should_render(&self) -> bool { false }
    fn print_attribute(&self, _: &mut Printer) {}
}print_skip!(Span, (), ErrorGuaranteed, AttrId);
193impl PrintAttribute for u8 {
    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))
                }));
    }
}
impl PrintAttribute for u16 {
    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))
                }));
    }
}
impl PrintAttribute for u32 {
    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))
                }));
    }
}
impl PrintAttribute for u128 {
    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))
                }));
    }
}
impl PrintAttribute for usize {
    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))
                }));
    }
}
impl PrintAttribute for bool {
    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))
                }));
    }
}
impl PrintAttribute for NonZero<u32> {
    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))
                }));
    }
}
impl 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, u32, u128, usize, bool, NonZero<u32>, Limit);
194impl PrintAttribute for Symbol {
    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))
                }));
    }
}
impl PrintAttribute for Ident {
    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))
                }));
    }
}
impl PrintAttribute for UintTy {
    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))
                }));
    }
}
impl PrintAttribute for IntTy {
    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))
                }));
    }
}
impl PrintAttribute for Align {
    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))
                }));
    }
}
impl PrintAttribute for AttrStyle {
    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))
                }));
    }
}
impl PrintAttribute for CommentKind {
    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))
                }));
    }
}
impl PrintAttribute for DocFragmentKind {
    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))
                }));
    }
}
impl PrintAttribute for Transparency {
    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))
                }));
    }
}
impl PrintAttribute for SanitizerSet {
    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))
                }));
    }
}
impl PrintAttribute for DefId {
    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))
                }));
    }
}
impl PrintAttribute for RustcVersion {
    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))
                }));
    }
}
impl 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))
                }));
    }
}
impl PrintAttribute for DiffActivity {
    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))
                }));
    }
}
impl PrintAttribute for DiffMode {
    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))
                }));
    }
}
impl PrintAttribute for CrateType {
    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))
                }));
    }
}
impl PrintAttribute for NativeLibKind {
    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))
                }));
    }
}
impl PrintAttribute for CollapseMacroDebuginfo {
    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!(
195    Symbol,
196    Ident,
197    UintTy,
198    IntTy,
199    Align,
200    AttrStyle,
201    CommentKind,
202    DocFragmentKind,
203    Transparency,
204    SanitizerSet,
205    DefId,
206    RustcVersion,
207    CfgEntry,
208    DiffActivity,
209    DiffMode,
210    CrateType,
211    NativeLibKind,
212    CollapseMacroDebuginfo,
213);