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