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};
11 /// An `AstLike` represents an AST node (or some wrapper around
12 /// and AST node) which stores some combination of attributes
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
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>>;
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] {
33 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
34 (**self).visit_attrs(f);
36 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
41 impl AstLike for crate::token::Nonterminal {
42 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
43 fn attrs(&self) -> &[Attribute] {
45 Nonterminal::NtItem(item) => item.attrs(),
46 Nonterminal::NtStmt(stmt) => stmt.attrs(),
47 Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.attrs(),
49 | Nonterminal::NtTy(_)
50 | Nonterminal::NtMeta(_)
51 | Nonterminal::NtPath(_)
52 | Nonterminal::NtVis(_)
53 | Nonterminal::NtTT(_)
54 | Nonterminal::NtBlock(_)
55 | Nonterminal::NtIdent(..)
56 | Nonterminal::NtLifetime(_) => &[],
59 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
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),
65 | Nonterminal::NtTy(_)
66 | Nonterminal::NtMeta(_)
67 | Nonterminal::NtPath(_)
68 | Nonterminal::NtVis(_)
69 | Nonterminal::NtTT(_)
70 | Nonterminal::NtBlock(_)
71 | Nonterminal::NtIdent(..)
72 | Nonterminal::NtLifetime(_) => {}
75 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
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 Nonterminal::NtBlock(block) => block.tokens_mut(),
86 Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) | Nonterminal::NtTT(..) => None,
91 fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
92 crate::mut_visit::visit_clobber(attrs, |attrs| {
93 let mut vec = attrs.into();
99 impl AstLike for StmtKind {
100 // This might be an `StmtKind::Item`, which contains
101 // an item that supports inner attrs
102 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
104 fn attrs(&self) -> &[Attribute] {
106 StmtKind::Local(local) => local.attrs(),
107 StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(),
108 StmtKind::Item(item) => item.attrs(),
109 StmtKind::Empty => &[],
110 StmtKind::MacCall(mac) => &mac.attrs,
114 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
116 StmtKind::Local(local) => local.visit_attrs(f),
117 StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
118 StmtKind::Item(item) => item.visit_attrs(f),
119 StmtKind::Empty => {}
120 StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f),
123 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
125 StmtKind::Local(local) => &mut local.tokens,
126 StmtKind::Item(item) => &mut item.tokens,
127 StmtKind::Expr(expr) | StmtKind::Semi(expr) => &mut expr.tokens,
128 StmtKind::Empty => return None,
129 StmtKind::MacCall(mac) => &mut mac.tokens,
134 impl AstLike for Stmt {
135 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS;
137 fn attrs(&self) -> &[Attribute] {
141 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
142 self.kind.visit_attrs(f);
144 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
145 self.kind.tokens_mut()
149 impl AstLike for Attribute {
150 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
152 fn attrs(&self) -> &[Attribute] {
155 fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
156 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
157 Some(match &mut self.kind {
158 AttrKind::Normal(_, tokens) => tokens,
159 kind @ AttrKind::DocComment(..) => {
160 panic!("Called tokens_mut on doc comment attr {:?}", kind)
166 impl<T: AstLike> AstLike for Option<T> {
167 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
169 fn attrs(&self) -> &[Attribute] {
170 self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
172 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
173 if let Some(inner) = self.as_mut() {
174 inner.visit_attrs(f);
177 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
178 self.as_mut().and_then(|inner| inner.tokens_mut())
182 /// Helper trait for the macros below. Abstracts over
183 /// the two types of attribute fields that AST nodes
184 /// may have (`Vec<Attribute>` or `AttrVec`)
186 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
189 impl VecOrAttrVec for Vec<Attribute> {
190 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
195 impl VecOrAttrVec for AttrVec {
196 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
197 visit_attrvec(self, f)
201 macro_rules! derive_has_tokens_and_attrs {
203 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner_attrs:literal;
206 impl AstLike for $ty {
207 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner_attrs;
209 fn attrs(&self) -> &[Attribute] {
213 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
214 VecOrAttrVec::visit(&mut self.attrs, f)
217 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
218 Some(&mut self.tokens)
225 macro_rules! derive_has_attrs_no_tokens {
226 ($($ty:path),*) => { $(
227 impl AstLike for $ty {
228 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
230 fn attrs(&self) -> &[Attribute] {
234 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
235 VecOrAttrVec::visit(&mut self.attrs, f)
238 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
245 macro_rules! derive_has_tokens_no_attrs {
246 ($($ty:path),*) => { $(
247 impl AstLike for $ty {
248 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
250 fn attrs(&self) -> &[Attribute] {
254 fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
255 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
256 Some(&mut self.tokens)
262 // These ast nodes support both active and inert attributes,
263 // so they have tokens collected to pass to proc macros
264 derive_has_tokens_and_attrs! {
265 // Both `Item` and `AssocItem` can have bodies, which
266 // can contain inner attributes
267 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
268 Item, AssocItem, ForeignItem
271 derive_has_tokens_and_attrs! {
272 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
273 Local, MacCallStmt, Expr
276 // These ast nodes only support inert attributes, so they don't
277 // store tokens (since nothing can observe them)
278 derive_has_attrs_no_tokens! {
279 FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam
282 // These AST nodes don't support attributes, but can
283 // be captured by a `macro_rules!` matcher. Therefore,
284 // they need to store tokens.
285 derive_has_tokens_no_attrs! {
286 Ty, Block, AttrItem, Pat, Path, Visibility