rustc_attr_data_structures/
lib.rs

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