]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast/src/ast_like.rs
Remove rustfmt tests from top-level .gitattributes
[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, 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::Debug;
10
11 /// An `AstLike` represents an AST node (or some wrapper around
12 /// and AST node) which stores some combination of attributes
13 /// and tokens.
14 pub trait AstLike: Sized + Debug {
15     /// This is `true` if this `AstLike` might support 'custom' (proc-macro) inner
16     /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not
17     /// considered 'custom' attributes
18     ///
19     /// If this is `false`, then this `AstLike` definitely does
20     /// not support 'custom' inner attributes, which enables some optimizations
21     /// during token collection.
22     const SUPPORTS_CUSTOM_INNER_ATTRS: bool;
23     fn attrs(&self) -> &[Attribute];
24     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
25     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>>;
26 }
27
28 impl<T: AstLike + 'static> AstLike for P<T> {
29     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
30     fn attrs(&self) -> &[Attribute] {
31         (**self).attrs()
32     }
33     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
34         (**self).visit_attrs(f);
35     }
36     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
37         (**self).tokens_mut()
38     }
39 }
40
41 impl AstLike for crate::token::Nonterminal {
42     const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
43     fn attrs(&self) -> &[Attribute] {
44         match self {
45             Nonterminal::NtItem(item) => item.attrs(),
46             Nonterminal::NtStmt(stmt) => stmt.attrs(),
47             Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.attrs(),
48             Nonterminal::NtPat(_)
49             | Nonterminal::NtTy(_)
50             | Nonterminal::NtMeta(_)
51             | Nonterminal::NtPath(_)
52             | Nonterminal::NtVis(_)
53             | Nonterminal::NtTT(_)
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::NtTT(_)
70             | Nonterminal::NtBlock(_)
71             | Nonterminal::NtIdent(..)
72             | Nonterminal::NtLifetime(_) => {}
73         }
74     }
75     fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
76         match self {
77             Nonterminal::NtItem(item) => item.tokens_mut(),
78             Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
79             Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
80             Nonterminal::NtPat(pat) => pat.tokens_mut(),
81             Nonterminal::NtTy(ty) => ty.tokens_mut(),
82             Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
83             Nonterminal::NtPath(path) => path.tokens_mut(),
84             Nonterminal::NtVis(vis) => vis.tokens_mut(),
85             _ => panic!("Called tokens_mut on {:?}", self),
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
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 }