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