rustc_hir/attrs/
pretty_printing.rs1use std::num::NonZero;
2use std::ops::Deref;
3
4use rustc_abi::Align;
5use rustc_ast::attr::data_structures::CfgEntry;
6use rustc_ast::attr::version::RustcVersion;
7use rustc_ast::token::{CommentKind, DocFragmentKind};
8use rustc_ast::{AttrStyle, IntTy, UintTy};
9use rustc_ast_pretty::pp::Printer;
10use rustc_data_structures::fx::FxIndexMap;
11use rustc_span::def_id::DefId;
12use rustc_span::hygiene::Transparency;
13use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
14use rustc_target::spec::SanitizerSet;
15use thin_vec::ThinVec;
16
17use crate::limit::Limit;
18
19pub trait PrintAttribute {
26 fn should_render(&self) -> bool;
30
31 fn print_attribute(&self, p: &mut Printer);
32}
33
34impl<T: PrintAttribute> PrintAttribute for &T {
35 fn should_render(&self) -> bool {
36 T::should_render(self)
37 }
38
39 fn print_attribute(&self, p: &mut Printer) {
40 T::print_attribute(self, p)
41 }
42}
43impl<T: PrintAttribute> PrintAttribute for Box<T> {
44 fn should_render(&self) -> bool {
45 self.deref().should_render()
46 }
47
48 fn print_attribute(&self, p: &mut Printer) {
49 T::print_attribute(self.deref(), p)
50 }
51}
52impl<T: PrintAttribute> PrintAttribute for Option<T> {
53 fn should_render(&self) -> bool {
54 self.as_ref().is_some_and(|x| x.should_render())
55 }
56
57 fn print_attribute(&self, p: &mut Printer) {
58 if let Some(i) = self {
59 T::print_attribute(i, p)
60 }
61 }
62}
63impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
64 fn should_render(&self) -> bool {
65 self.is_empty() || self[0].should_render()
66 }
67
68 fn print_attribute(&self, p: &mut Printer) {
69 let mut last_printed = false;
70 p.word("[");
71 for i in self {
72 if last_printed {
73 p.word_space(",");
74 }
75 i.print_attribute(p);
76 last_printed = i.should_render();
77 }
78 p.word("]");
79 }
80}
81impl<T: PrintAttribute> PrintAttribute for FxIndexMap<T, Span> {
82 fn should_render(&self) -> bool {
83 self.is_empty() || self[0].should_render()
84 }
85
86 fn print_attribute(&self, p: &mut Printer) {
87 let mut last_printed = false;
88 p.word("[");
89 for (i, _) in self {
90 if last_printed {
91 p.word_space(",");
92 }
93 i.print_attribute(p);
94 last_printed = i.should_render();
95 }
96 p.word("]");
97 }
98}
99
100macro_rules! print_skip {
101 ($($t: ty),* $(,)?) => {$(
102 impl PrintAttribute for $t {
103 fn should_render(&self) -> bool { false }
104 fn print_attribute(&self, _: &mut Printer) { }
105 })*
106 };
107}
108
109macro_rules! print_disp {
110 ($($t: ty),* $(,)?) => {$(
111 impl PrintAttribute for $t {
112 fn should_render(&self) -> bool { true }
113 fn print_attribute(&self, p: &mut Printer) {
114 p.word(format!("{}", self));
115 }
116 }
117 )*};
118}
119macro_rules! print_debug {
120 ($($t: ty),* $(,)?) => {$(
121 impl PrintAttribute for $t {
122 fn should_render(&self) -> bool { true }
123 fn print_attribute(&self, p: &mut Printer) {
124 p.word(format!("{:?}", self));
125 }
126 }
127 )*};
128}
129
130macro_rules! print_tup {
131 (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* };
132 () => {};
133 ($t: ident $($ts: ident)*) => {
134 #[allow(non_snake_case, unused)]
135 impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) {
136 fn should_render(&self) -> bool {
137 let ($t, $($ts),*) = self;
138 print_tup!(num_should_render $t $($ts)*) != 0
139 }
140
141 fn print_attribute(&self, p: &mut Printer) {
142 let ($t, $($ts),*) = self;
143 let parens = print_tup!(num_should_render $t $($ts)*) > 1;
144 if parens {
145 p.popen();
146 }
147
148 let mut printed_anything = $t.should_render();
149
150 $t.print_attribute(p);
151
152 $(
153 if $ts.should_render() {
154 if printed_anything {
155 p.word_space(",");
156 }
157 printed_anything = true;
158 }
159 $ts.print_attribute(p);
160 )*
161
162 if parens {
163 p.pclose();
164 }
165 }
166 }
167
168 print_tup!($($ts)*);
169 };
170}
171
172#[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);
173impl PrintAttribute for ErrorGuaranteed {
fn should_render(&self) -> bool { false }
fn print_attribute(&self, _: &mut Printer) {}
}print_skip!(Span, (), ErrorGuaranteed);
174impl 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!(u16, u128, usize, bool, NonZero<u32>, Limit);
175impl 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!(
176 Symbol,
177 Ident,
178 UintTy,
179 IntTy,
180 Align,
181 AttrStyle,
182 CommentKind,
183 DocFragmentKind,
184 Transparency,
185 SanitizerSet,
186 DefId,
187 RustcVersion,
188 CfgEntry,
189);