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