]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast/src/ast_like.rs
Auto merge of #96080 - nikic:ranlib, r=Mark-Simulacrum
[rust.git] / compiler / rustc_ast / src / ast_like.rs
1 use super::ptr::P;
2 use super::token::Nonterminal;
3 use super::tokenstream::LazyTokenStream;
4 use super::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
5 use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt};
6 use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
7 use super::{AttrVec, Attribute, Stmt, StmtKind};
8
9 use std::fmt;
10 use std::marker::PhantomData;
11
12 /// An `AstLike` represents an AST node (or some wrapper around
13 /// and AST node) which stores some combination of attributes
14 /// and tokens.
15 pub trait AstLike: Sized + fmt::Debug {
16     /// This is `true` if this `AstLike` might support 'custom' (proc-macro) inner
17     /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not
18     /// considered 'custom' attributes
19     ///
20     /// If this is `false`, then this `AstLike` definitely does
21     /// not support 'custom' inner attributes, which enables some optimizations
22     /// during token collection.
23     const SUPPORTS_CUSTOM_INNER_ATTRS: bool;
24     fn attrs(&self) -> &[Attribute];
25     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
26     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>>;
27 }
28
29 impl<T: AstLike + 'static> AstLike for P<T> {
30     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
31     fn attrs(&self) -> &[Attribute] {
32         (**self).attrs()
33     }
34     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
35         (**self).visit_attrs(f);
36     }
37     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
38         (**self).tokens_mut()
39     }
40 }
41
42 impl AstLike for crate::token::Nonterminal {
43     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
44     fn attrs(&self) -> &[Attribute] {
45         match self {
46             Nonterminal::NtItem(item) => item.attrs(),
47             Nonterminal::NtStmt(stmt) => stmt.attrs(),
48             Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.attrs(),
49             Nonterminal::NtPat(_)
50             | Nonterminal::NtTy(_)
51             | Nonterminal::NtMeta(_)
52             | Nonterminal::NtPath(_)
53             | Nonterminal::NtVis(_)
54             | Nonterminal::NtBlock(_)
55             | Nonterminal::NtIdent(..)
56             | Nonterminal::NtLifetime(_) => &[],
57         }
58     }
59     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
60         match self {
61             Nonterminal::NtItem(item) => item.visit_attrs(f),
62             Nonterminal::NtStmt(stmt) => stmt.visit_attrs(f),
63             Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.visit_attrs(f),
64             Nonterminal::NtPat(_)
65             | Nonterminal::NtTy(_)
66             | Nonterminal::NtMeta(_)
67             | Nonterminal::NtPath(_)
68             | Nonterminal::NtVis(_)
69             | Nonterminal::NtBlock(_)
70             | Nonterminal::NtIdent(..)
71             | Nonterminal::NtLifetime(_) => {}
72         }
73     }
74     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
75         match self {
76             Nonterminal::NtItem(item) => item.tokens_mut(),
77             Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
78             Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
79             Nonterminal::NtPat(pat) => pat.tokens_mut(),
80             Nonterminal::NtTy(ty) => ty.tokens_mut(),
81             Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
82             Nonterminal::NtPath(path) => path.tokens_mut(),
83             Nonterminal::NtVis(vis) => vis.tokens_mut(),
84             Nonterminal::NtBlock(block) => block.tokens_mut(),
85             Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
86         }
87     }
88 }
89
90 fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
91     crate::mut_visit::visit_clobber(attrs, |attrs| {
92         let mut vec = attrs.into();
93         f(&mut vec);
94         vec.into()
95     });
96 }
97
98 impl AstLike for StmtKind {
99     // This might be an `StmtKind::Item`, which contains
100     // an item that supports inner attrs
101     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
102
103     fn attrs(&self) -> &[Attribute] {
104         match self {
105             StmtKind::Local(local) => local.attrs(),
106             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(),
107             StmtKind::Item(item) => item.attrs(),
108             StmtKind::Empty => &[],
109             StmtKind::MacCall(mac) => &mac.attrs,
110         }
111     }
112
113     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
114         match self {
115             StmtKind::Local(local) => local.visit_attrs(f),
116             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
117             StmtKind::Item(item) => item.visit_attrs(f),
118             StmtKind::Empty => {}
119             StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f),
120         }
121     }
122     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
123         Some(match self {
124             StmtKind::Local(local) => &mut local.tokens,
125             StmtKind::Item(item) => &mut item.tokens,
126             StmtKind::Expr(expr) | StmtKind::Semi(expr) => &mut expr.tokens,
127             StmtKind::Empty => return None,
128             StmtKind::MacCall(mac) => &mut mac.tokens,
129         })
130     }
131 }
132
133 impl AstLike for Stmt {
134     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS;
135
136     fn attrs(&self) -> &[Attribute] {
137         self.kind.attrs()
138     }
139
140     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
141         self.kind.visit_attrs(f);
142     }
143     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
144         self.kind.tokens_mut()
145     }
146 }
147
148 impl AstLike for Attribute {
149     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
150
151     fn attrs(&self) -> &[Attribute] {
152         &[]
153     }
154     fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
155     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
156         Some(match &mut self.kind {
157             AttrKind::Normal(_, tokens) => tokens,
158             kind @ AttrKind::DocComment(..) => {
159                 panic!("Called tokens_mut on doc comment attr {:?}", kind)
160             }
161         })
162     }
163 }
164
165 impl<T: AstLike> AstLike for Option<T> {
166     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
167
168     fn attrs(&self) -> &[Attribute] {
169         self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
170     }
171     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
172         if let Some(inner) = self.as_mut() {
173             inner.visit_attrs(f);
174         }
175     }
176     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
177         self.as_mut().and_then(|inner| inner.tokens_mut())
178     }
179 }
180
181 /// Helper trait for the macros below. Abstracts over
182 /// the two types of attribute fields that AST nodes
183 /// may have (`Vec<Attribute>` or `AttrVec`)
184 trait VecOrAttrVec {
185     fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
186 }
187
188 impl VecOrAttrVec for Vec<Attribute> {
189     fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
190         f(self)
191     }
192 }
193
194 impl VecOrAttrVec for AttrVec {
195     fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
196         visit_attrvec(self, f)
197     }
198 }
199
200 macro_rules! derive_has_tokens_and_attrs {
201     (
202         const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner_attrs:literal;
203         $($ty:path),*
204     ) => { $(
205         impl AstLike for $ty {
206             const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner_attrs;
207
208             fn attrs(&self) -> &[Attribute] {
209                 &self.attrs
210             }
211
212             fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
213                 VecOrAttrVec::visit(&mut self.attrs, f)
214             }
215
216             fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
217                 Some(&mut self.tokens)
218             }
219
220         }
221     )* }
222 }
223
224 macro_rules! derive_has_attrs_no_tokens {
225     ($($ty:path),*) => { $(
226         impl AstLike for $ty {
227             const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
228
229             fn attrs(&self) -> &[Attribute] {
230                 &self.attrs
231             }
232
233             fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
234                 VecOrAttrVec::visit(&mut self.attrs, f)
235             }
236
237             fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
238                 None
239             }
240         }
241     )* }
242 }
243
244 macro_rules! derive_has_tokens_no_attrs {
245     ($($ty:path),*) => { $(
246         impl AstLike for $ty {
247             const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
248
249             fn attrs(&self) -> &[Attribute] {
250                 &[]
251             }
252
253             fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
254             fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
255                 Some(&mut self.tokens)
256             }
257         }
258     )* }
259 }
260
261 // These ast nodes support both active and inert attributes,
262 // so they have tokens collected to pass to proc macros
263 derive_has_tokens_and_attrs! {
264     // Both `Item` and `AssocItem` can have bodies, which
265     // can contain inner attributes
266     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
267     Item, AssocItem, ForeignItem
268 }
269
270 derive_has_tokens_and_attrs! {
271     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
272     Local, MacCallStmt, Expr
273 }
274
275 // These ast nodes only support inert attributes, so they don't
276 // store tokens (since nothing can observe them)
277 derive_has_attrs_no_tokens! {
278     FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam, Crate
279 }
280
281 // These AST nodes don't support attributes, but can
282 // be captured by a `macro_rules!` matcher. Therefore,
283 // they need to store tokens.
284 derive_has_tokens_no_attrs! {
285     Ty, Block, AttrItem, Pat, Path, Visibility
286 }
287
288 /// A newtype around an `AstLike` node that implements `AstLike` itself.
289 pub struct AstLikeWrapper<Wrapped, Tag> {
290     pub wrapped: Wrapped,
291     pub tag: PhantomData<Tag>,
292 }
293
294 impl<Wrapped, Tag> AstLikeWrapper<Wrapped, Tag> {
295     pub fn new(wrapped: Wrapped, _tag: Tag) -> AstLikeWrapper<Wrapped, Tag> {
296         AstLikeWrapper { wrapped, tag: Default::default() }
297     }
298 }
299
300 impl<Wrapped: fmt::Debug, Tag> fmt::Debug for AstLikeWrapper<Wrapped, Tag> {
301     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302         f.debug_struct("AstLikeWrapper")
303             .field("wrapped", &self.wrapped)
304             .field("tag", &self.tag)
305             .finish()
306     }
307 }
308
309 impl<Wrapped: AstLike, Tag> AstLike for AstLikeWrapper<Wrapped, Tag> {
310     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = Wrapped::SUPPORTS_CUSTOM_INNER_ATTRS;
311     fn attrs(&self) -> &[Attribute] {
312         self.wrapped.attrs()
313     }
314     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
315         self.wrapped.visit_attrs(f)
316     }
317     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
318         self.wrapped.tokens_mut()
319     }
320 }