rustc_attr_data_structures/
lib.rs

1// tidy-alphabetical-start
2#![allow(internal_features)]
3#![doc(rust_logo)]
4#![feature(let_chains)]
5#![feature(rustdoc_internals)]
6// tidy-alphabetical-end
7
8mod attributes;
9mod stability;
10mod version;
11
12use std::num::NonZero;
13
14pub use attributes::*;
15use rustc_abi::Align;
16use rustc_ast::token::CommentKind;
17use rustc_ast::{AttrStyle, IntTy, UintTy};
18use rustc_ast_pretty::pp::Printer;
19use rustc_span::hygiene::Transparency;
20use rustc_span::{Span, Symbol};
21pub use stability::*;
22use thin_vec::ThinVec;
23pub use version::*;
24
25/// Requirements for a `StableHashingContext` to be used in this crate.
26/// This is a hack to allow using the `HashStable_Generic` derive macro
27/// instead of implementing everything in `rustc_middle`.
28pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {}
29
30/// This trait is used to print attributes in `rustc_hir_pretty`.
31///
32/// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`].
33/// The output will look a lot like a `Debug` implementation, but fields of several types
34/// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the
35/// representation much.
36pub trait PrintAttribute {
37    /// Whether or not this will render as something meaningful, or if it's skipped
38    /// (which will force the containing struct to also skip printing a comma
39    /// and the field name).
40    fn should_render(&self) -> bool;
41
42    fn print_attribute(&self, p: &mut Printer);
43}
44
45impl<T: PrintAttribute> PrintAttribute for &T {
46    fn should_render(&self) -> bool {
47        T::should_render(self)
48    }
49
50    fn print_attribute(&self, p: &mut Printer) {
51        T::print_attribute(self, p)
52    }
53}
54impl<T: PrintAttribute> PrintAttribute for Option<T> {
55    fn should_render(&self) -> bool {
56        self.as_ref().is_some_and(|x| x.should_render())
57    }
58
59    fn print_attribute(&self, p: &mut Printer) {
60        if let Some(i) = self {
61            T::print_attribute(i, p)
62        }
63    }
64}
65impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
66    fn should_render(&self) -> bool {
67        self.is_empty() || self[0].should_render()
68    }
69
70    fn print_attribute(&self, p: &mut Printer) {
71        let mut last_printed = false;
72        p.word("[");
73        for i in self {
74            if last_printed {
75                p.word_space(",");
76            }
77            i.print_attribute(p);
78            last_printed = i.should_render();
79        }
80        p.word("]");
81    }
82}
83macro_rules! print_skip {
84    ($($t: ty),* $(,)?) => {$(
85        impl PrintAttribute for $t {
86            fn should_render(&self) -> bool { false }
87            fn print_attribute(&self, _: &mut Printer) { }
88        })*
89    };
90}
91
92macro_rules! print_disp {
93    ($($t: ty),* $(,)?) => {$(
94        impl PrintAttribute for $t {
95            fn should_render(&self) -> bool { true }
96            fn print_attribute(&self, p: &mut Printer) {
97                p.word(format!("{}", self));
98            }
99        }
100    )*};
101}
102macro_rules! print_debug {
103    ($($t: ty),* $(,)?) => {$(
104        impl PrintAttribute for $t {
105            fn should_render(&self) -> bool { true }
106            fn print_attribute(&self, p: &mut Printer) {
107                p.word(format!("{:?}", self));
108            }
109        }
110    )*};
111}
112
113macro_rules! print_tup {
114    (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* };
115    () => {};
116    ($t: ident $($ts: ident)*) => {
117        #[allow(non_snake_case, unused)]
118        impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) {
119            fn should_render(&self) -> bool {
120                let ($t, $($ts),*) = self;
121                print_tup!(num_should_render $t $($ts)*) != 0
122            }
123
124            fn print_attribute(&self, p: &mut Printer) {
125                let ($t, $($ts),*) = self;
126                let parens = print_tup!(num_should_render $t $($ts)*) > 1;
127                if parens {
128                    p.popen();
129                }
130
131                let mut printed_anything = $t.should_render();
132
133                $t.print_attribute(p);
134
135                $(
136                    if $ts.should_render() {
137                        if printed_anything {
138                            p.word_space(",");
139                        }
140                        printed_anything = true;
141                    }
142                    $ts.print_attribute(p);
143                )*
144
145                if parens {
146                    p.pclose();
147                }
148            }
149        }
150
151        print_tup!($($ts)*);
152    };
153}
154
155print_tup!(A B C D E F G H);
156print_skip!(Span, ());
157print_disp!(u16, bool, NonZero<u32>);
158print_debug!(Symbol, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
159
160/// Finds attributes in sequences of attributes by pattern matching.
161///
162/// A little like `matches` but for attributes.
163///
164/// ```rust,ignore (illustrative)
165/// // finds the repr attribute
166/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) {
167///
168/// }
169///
170/// // checks if one has matched
171/// if find_attr!(attrs, AttributeKind::Repr(_)) {
172///
173/// }
174/// ```
175///
176/// Often this requires you to first end up with a list of attributes.
177/// A common way to get those is through `tcx.get_all_attrs(did)`
178#[macro_export]
179macro_rules! find_attr {
180    ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{
181        $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some()
182    }};
183
184    ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{
185        'done: {
186            for i in $attributes_list {
187                let i: &rustc_hir::Attribute = i;
188                match i {
189                    rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => {
190                        break 'done Some($e);
191                    }
192                    _ => {}
193                }
194            }
195
196            None
197        }
198    }};
199}