rustc_hir/attrs/
pretty_printing.rs1use 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
20pub trait PrintAttribute {
27 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);