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::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::Limit;
14use rustc_data_structures::fx::FxIndexMap;
15use rustc_span::def_id::DefId;
16use rustc_span::hygiene::Transparency;
17use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
18use rustc_target::spec::SanitizerSet;
19use thin_vec::ThinVec;
20
21pub trait PrintAttribute {
28 fn should_render(&self) -> bool;
32
33 fn print_attribute(&self, p: &mut Printer);
34}
35
36impl<T: PrintAttribute> PrintAttribute for &T {
37 fn should_render(&self) -> bool {
38 T::should_render(self)
39 }
40
41 fn print_attribute(&self, p: &mut Printer) {
42 T::print_attribute(self, p)
43 }
44}
45impl<T: PrintAttribute> PrintAttribute for Box<T> {
46 fn should_render(&self) -> bool {
47 self.deref().should_render()
48 }
49
50 fn print_attribute(&self, p: &mut Printer) {
51 T::print_attribute(self.deref(), p)
52 }
53}
54impl<T: PrintAttribute> PrintAttribute for Option<T> {
55 fn should_render(&self) -> bool {
56 self.as_ref().is_some_and(|x| x.should_render())
57 }
58
59 fn print_attribute(&self, p: &mut Printer) {
60 if let Some(i) = self {
61 T::print_attribute(i, p)
62 }
63 }
64}
65impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
66 fn should_render(&self) -> bool {
67 self.is_empty() || self[0].should_render()
68 }
69
70 fn print_attribute(&self, p: &mut Printer) {
71 let mut last_printed = false;
72 p.word("[");
73 for i in self {
74 if last_printed {
75 p.word_space(",");
76 }
77 i.print_attribute(p);
78 last_printed = i.should_render();
79 }
80 p.word("]");
81 }
82}
83impl<T: PrintAttribute, T2: PrintAttribute> PrintAttribute for FxIndexMap<T, T2> {
84 fn should_render(&self) -> bool {
85 self.is_empty() || self[0].should_render()
86 }
87
88 fn print_attribute(&self, p: &mut Printer) {
89 let mut last_printed = false;
90 p.word("[");
91 for (i, _) in self {
92 if last_printed {
93 p.word_space(",");
94 }
95 i.print_attribute(p);
96 last_printed = i.should_render();
97 }
98 p.word("]");
99 }
100}
101impl PrintAttribute for PathBuf {
102 fn should_render(&self) -> bool {
103 true
104 }
105
106 fn print_attribute(&self, p: &mut Printer) {
107 p.word(self.display().to_string());
108 }
109}
110impl PrintAttribute for Path {
111 fn should_render(&self) -> bool {
112 true
113 }
114
115 fn print_attribute(&self, p: &mut Printer) {
116 p.word(join_path_idents(self.segments.iter().map(|seg| seg.ident)));
117 }
118}
119
120macro_rules! print_skip {
121 ($($t: ty),* $(,)?) => {$(
122 impl PrintAttribute for $t {
123 fn should_render(&self) -> bool { false }
124 fn print_attribute(&self, _: &mut Printer) { }
125 })*
126 };
127}
128
129macro_rules! print_disp {
130 ($($t: ty),* $(,)?) => {$(
131 impl PrintAttribute for $t {
132 fn should_render(&self) -> bool { true }
133 fn print_attribute(&self, p: &mut Printer) {
134 p.word(format!("{}", self));
135 }
136 }
137 )*};
138}
139macro_rules! print_debug {
140 ($($t: ty),* $(,)?) => {$(
141 impl PrintAttribute for $t {
142 fn should_render(&self) -> bool { true }
143 fn print_attribute(&self, p: &mut Printer) {
144 p.word(format!("{:?}", self));
145 }
146 }
147 )*};
148}
149
150macro_rules! print_tup {
151 (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* };
152 () => {};
153 ($t: ident $($ts: ident)*) => {
154 #[allow(non_snake_case, unused)]
155 impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) {
156 fn should_render(&self) -> bool {
157 let ($t, $($ts),*) = self;
158 print_tup!(num_should_render $t $($ts)*) != 0
159 }
160
161 fn print_attribute(&self, p: &mut Printer) {
162 let ($t, $($ts),*) = self;
163 let parens = print_tup!(num_should_render $t $($ts)*) > 1;
164 if parens {
165 p.popen();
166 }
167
168 let mut printed_anything = $t.should_render();
169
170 $t.print_attribute(p);
171
172 $(
173 if $ts.should_render() {
174 if printed_anything {
175 p.word_space(",");
176 }
177 printed_anything = true;
178 }
179 $ts.print_attribute(p);
180 )*
181
182 if parens {
183 p.pclose();
184 }
185 }
186 }
187
188 print_tup!($($ts)*);
189 };
190}
191
192#[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);
193impl PrintAttribute for AttrId {
fn should_render(&self) -> bool { false }
fn print_attribute(&self, _: &mut Printer) {}
}print_skip!(Span, (), ErrorGuaranteed, AttrId);
194impl 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);
195impl 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))
}));
}
}print_debug!(
196 Symbol,
197 Ident,
198 UintTy,
199 IntTy,
200 Align,
201 AttrStyle,
202 CommentKind,
203 DocFragmentKind,
204 Transparency,
205 SanitizerSet,
206 DefId,
207 RustcVersion,
208 CfgEntry,
209 DiffActivity,
210 DiffMode,
211);