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