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
20use crate::HashIgnoredAttrId;
21
22/// This trait is used to print attributes in `rustc_hir_pretty`.
23///
24/// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`].
25/// The output will look a lot like a `Debug` implementation, but fields of several types
26/// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the
27/// representation much.
28pub trait PrintAttribute {
29    /// Whether or not this will render as something meaningful, or if it's skipped
30    /// (which will force the containing struct to also skip printing a comma
31    /// and the field name).
32    fn should_render(&self) -> bool;
33
34    fn print_attribute(&self, p: &mut Printer);
35}
36
37impl<T: ?Sized + PrintAttribute> PrintAttribute for &T {
38    fn should_render(&self) -> bool {
39        T::should_render(self)
40    }
41
42    fn print_attribute(&self, p: &mut Printer) {
43        T::print_attribute(self, p)
44    }
45}
46impl<T: ?Sized + PrintAttribute> PrintAttribute for Box<T> {
47    fn should_render(&self) -> bool {
48        self.deref().should_render()
49    }
50
51    fn print_attribute(&self, p: &mut Printer) {
52        T::print_attribute(self.deref(), p)
53    }
54}
55impl<T: PrintAttribute> PrintAttribute for Option<T> {
56    fn should_render(&self) -> bool {
57        self.as_ref().is_some_and(|x| x.should_render())
58    }
59
60    fn print_attribute(&self, p: &mut Printer) {
61        if let Some(i) = self {
62            T::print_attribute(i, p)
63        }
64    }
65}
66
67impl<T: PrintAttribute> PrintAttribute for [T] {
68    fn should_render(&self) -> bool {
69        self.is_empty() || self[0].should_render()
70    }
71
72    fn print_attribute(&self, p: &mut Printer) {
73        let mut last_printed = false;
74        p.word("[");
75        for i in self {
76            if last_printed {
77                p.word_space(",");
78            }
79            i.print_attribute(p);
80            last_printed = i.should_render();
81        }
82        p.word("]");
83    }
84}
85
86impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
87    fn should_render(&self) -> bool {
88        self.as_slice().should_render()
89    }
90
91    fn print_attribute(&self, p: &mut Printer) {
92        self.as_slice().print_attribute(p)
93    }
94}
95impl<T: PrintAttribute, T2: PrintAttribute> PrintAttribute for FxIndexMap<T, T2> {
96    fn should_render(&self) -> bool {
97        self.is_empty() || self[0].should_render()
98    }
99
100    fn print_attribute(&self, p: &mut Printer) {
101        let mut last_printed = false;
102        p.word("[");
103        for (i, _) in self {
104            if last_printed {
105                p.word_space(",");
106            }
107            i.print_attribute(p);
108            last_printed = i.should_render();
109        }
110        p.word("]");
111    }
112}
113impl PrintAttribute for PathBuf {
114    fn should_render(&self) -> bool {
115        true
116    }
117
118    fn print_attribute(&self, p: &mut Printer) {
119        p.word(self.display().to_string());
120    }
121}
122impl PrintAttribute for Path {
123    fn should_render(&self) -> bool {
124        true
125    }
126
127    fn print_attribute(&self, p: &mut Printer) {
128        p.word(join_path_idents(self.segments.iter().map(|seg| seg.ident)));
129    }
130}
131
132macro_rules! print_skip {
133    ($($t: ty),* $(,)?) => {$(
134        impl PrintAttribute for $t {
135            fn should_render(&self) -> bool { false }
136            fn print_attribute(&self, _: &mut Printer) { }
137        })*
138    };
139}
140
141macro_rules! print_disp {
142    ($($t: ty),* $(,)?) => {$(
143        impl PrintAttribute for $t {
144            fn should_render(&self) -> bool { true }
145            fn print_attribute(&self, p: &mut Printer) {
146                p.word(format!("{}", self));
147            }
148        }
149    )*};
150}
151macro_rules! print_debug {
152    ($($t: ty),* $(,)?) => {$(
153        impl PrintAttribute for $t {
154            fn should_render(&self) -> bool { true }
155            fn print_attribute(&self, p: &mut Printer) {
156                p.word(format!("{:?}", self));
157            }
158        }
159    )*};
160}
161
162macro_rules! print_tup {
163    (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* };
164    () => {};
165    ($t: ident $($ts: ident)*) => {
166        #[allow(non_snake_case, unused)]
167        impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) {
168            fn should_render(&self) -> bool {
169                let ($t, $($ts),*) = self;
170                print_tup!(num_should_render $t $($ts)*) != 0
171            }
172
173            fn print_attribute(&self, p: &mut Printer) {
174                let ($t, $($ts),*) = self;
175                let parens = print_tup!(num_should_render $t $($ts)*) > 1;
176                if parens {
177                    p.popen();
178                }
179
180                let mut printed_anything = $t.should_render();
181
182                $t.print_attribute(p);
183
184                $(
185                    if $ts.should_render() {
186                        if printed_anything {
187                            p.word_space(",");
188                        }
189                        printed_anything = true;
190                    }
191                    $ts.print_attribute(p);
192                )*
193
194                if parens {
195                    p.pclose();
196                }
197            }
198        }
199
200        print_tup!($($ts)*);
201    };
202}
203
204#[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);
205impl 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) {}
}
impl PrintAttribute for HashIgnoredAttrId {
    fn should_render(&self) -> bool { false }
    fn print_attribute(&self, _: &mut Printer) {}
}print_skip!(Span, (), ErrorGuaranteed, AttrId, HashIgnoredAttrId);
206impl 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);
207impl 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!(
208    Symbol,
209    Ident,
210    UintTy,
211    IntTy,
212    Align,
213    AttrStyle,
214    CommentKind,
215    DocFragmentKind,
216    Transparency,
217    SanitizerSet,
218    DefId,
219    RustcVersion,
220    CfgEntry,
221    DiffActivity,
222    DiffMode,
223    CrateType,
224    NativeLibKind,
225    CollapseMacroDebuginfo,
226);