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