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::token::{CommentKind, DocFragmentKind};
10use rustc_ast::{AttrId, AttrStyle, IntTy, UintTy};
11use rustc_ast_pretty::pp::Printer;
12use rustc_data_structures::fx::FxIndexMap;
13use rustc_span::def_id::DefId;
14use rustc_span::hygiene::Transparency;
15use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
16use rustc_target::spec::SanitizerSet;
17use thin_vec::ThinVec;
18
19use crate::limit::Limit;
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> PrintAttribute for FxIndexMap<T, Span> {
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, u128, usize, bool, NonZero<u32>, Limit);
195impl 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!(
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);