rustc_attr_parsing/attributes/mod.rs
1//! This module defines traits for attribute parsers, little state machines that recognize and parse
2//! attributes out of a longer list of attributes. The main trait is called [`AttributeParser`].
3//! You can find more docs about [`AttributeParser`]s on the trait itself.
4//! However, for many types of attributes, implementing [`AttributeParser`] is not necessary.
5//! It allows for a lot of flexibility you might not want.
6//!
7//! Specifically, you might not care about managing the state of your [`AttributeParser`]
8//! state machine yourself. In this case you can choose to implement:
9//!
10//! - [`SingleAttributeParser`]: makes it easy to implement an attribute which should error if it
11//! appears more than once in a list of attributes
12//! - [`CombineAttributeParser`]: makes it easy to implement an attribute which should combine the
13//! contents of attributes, if an attribute appear multiple times in a list
14//!
15//! Attributes should be added to [`ATTRIBUTE_MAPPING`](crate::context::ATTRIBUTE_MAPPING) to be parsed.
16
17use std::marker::PhantomData;
18
19use rustc_attr_data_structures::AttributeKind;
20use rustc_span::{Span, Symbol};
21use thin_vec::ThinVec;
22
23use crate::context::{AcceptContext, FinalizeContext};
24use crate::parser::ArgParser;
25
26pub(crate) mod allow_unstable;
27pub(crate) mod cfg;
28pub(crate) mod confusables;
29pub(crate) mod deprecation;
30pub(crate) mod repr;
31pub(crate) mod stability;
32pub(crate) mod transparency;
33pub(crate) mod util;
34
35type AcceptFn<T> = fn(&mut T, &AcceptContext<'_>, &ArgParser<'_>);
36type AcceptMapping<T> = &'static [(&'static [Symbol], AcceptFn<T>)];
37
38/// An [`AttributeParser`] is a type which searches for syntactic attributes.
39///
40/// Parsers are often tiny state machines that gets to see all syntactical attributes on an item.
41/// [`Default::default`] creates a fresh instance that sits in some kind of initial state, usually that the
42/// attribute it is looking for was not yet seen.
43///
44/// Then, it defines what paths this group will accept in [`AttributeParser::ATTRIBUTES`].
45/// These are listed as pairs, of symbols and function pointers. The function pointer will
46/// be called when that attribute is found on an item, which can influence the state of the little
47/// state machine.
48///
49/// Finally, after all attributes on an item have been seen, and possibly been accepted,
50/// the [`finalize`](AttributeParser::finalize) functions for all attribute parsers are called. Each can then report
51/// whether it has seen the attribute it has been looking for.
52///
53/// The state machine is automatically reset to parse attributes on the next item.
54pub(crate) trait AttributeParser: Default + 'static {
55 /// The symbols for the attributes that this parser is interested in.
56 ///
57 /// If an attribute has this symbol, the `accept` function will be called on it.
58 const ATTRIBUTES: AcceptMapping<Self>;
59
60 /// The parser has gotten a chance to accept the attributes on an item,
61 /// here it can produce an attribute.
62 fn finalize(self, cx: &FinalizeContext<'_>) -> Option<AttributeKind>;
63}
64
65/// Alternative to [`AttributeParser`] that automatically handles state management.
66/// A slightly simpler and more restricted way to convert attributes.
67/// Assumes that an attribute can only appear a single time on an item,
68/// and errors when it sees more.
69///
70/// [`Single<T> where T: SingleAttributeParser`](Single) implements [`AttributeParser`].
71///
72/// [`SingleAttributeParser`] can only convert attributes one-to-one, and cannot combine multiple
73/// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example.
74pub(crate) trait SingleAttributeParser: 'static {
75 const PATH: &'static [Symbol];
76
77 /// Caled when a duplicate attribute is found.
78 ///
79 /// `first_span` is the span of the first occurrence of this attribute.
80 // FIXME(jdonszelmann): default error
81 fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span);
82
83 /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
84 fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind>;
85}
86
87pub(crate) struct Single<T: SingleAttributeParser>(PhantomData<T>, Option<(AttributeKind, Span)>);
88
89impl<T: SingleAttributeParser> Default for Single<T> {
90 fn default() -> Self {
91 Self(Default::default(), Default::default())
92 }
93}
94
95impl<T: SingleAttributeParser> AttributeParser for Single<T> {
96 const ATTRIBUTES: AcceptMapping<Self> = &[(T::PATH, |group: &mut Single<T>, cx, args| {
97 if let Some((_, s)) = group.1 {
98 T::on_duplicate(cx, s);
99 return;
100 }
101
102 if let Some(pa) = T::convert(cx, args) {
103 group.1 = Some((pa, cx.attr_span));
104 }
105 })];
106
107 fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
108 Some(self.1?.0)
109 }
110}
111
112type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
113
114/// Alternative to [`AttributeParser`] that automatically handles state management.
115/// If multiple attributes appear on an element, combines the values of each into a
116/// [`ThinVec`].
117/// [`Combine<T> where T: CombineAttributeParser`](Combine) implements [`AttributeParser`].
118///
119/// [`CombineAttributeParser`] can only convert a single kind of attribute, and cannot combine multiple
120/// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example.
121pub(crate) trait CombineAttributeParser: 'static {
122 const PATH: &'static [Symbol];
123
124 type Item;
125 const CONVERT: ConvertFn<Self::Item>;
126
127 /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
128 fn extend<'a>(
129 cx: &'a AcceptContext<'a>,
130 args: &'a ArgParser<'a>,
131 ) -> impl IntoIterator<Item = Self::Item> + 'a;
132}
133
134pub(crate) struct Combine<T: CombineAttributeParser>(
135 PhantomData<T>,
136 ThinVec<<T as CombineAttributeParser>::Item>,
137);
138
139impl<T: CombineAttributeParser> Default for Combine<T> {
140 fn default() -> Self {
141 Self(Default::default(), Default::default())
142 }
143}
144
145impl<T: CombineAttributeParser> AttributeParser for Combine<T> {
146 const ATTRIBUTES: AcceptMapping<Self> =
147 &[(T::PATH, |group: &mut Combine<T>, cx, args| group.1.extend(T::extend(cx, args)))];
148
149 fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
150 if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }
151 }
152}