2 use super::tokenstream::LazyTokenStream;
3 use super::{Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
4 use super::{AssocItem, Expr, ForeignItem, Item, Local};
5 use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
6 use super::{AttrVec, Attribute, Stmt, StmtKind};
8 /// An `AstLike` represents an AST node (or some wrapper around
9 /// and AST node) which stores some combination of attributes
11 pub trait AstLike: Sized {
12 fn attrs(&self) -> &[Attribute];
13 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
14 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>>;
17 impl<T: AstLike + 'static> AstLike for P<T> {
18 fn attrs(&self) -> &[Attribute] {
21 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
22 (**self).visit_attrs(f);
24 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
29 fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
30 crate::mut_visit::visit_clobber(attrs, |attrs| {
31 let mut vec = attrs.into();
37 impl AstLike for StmtKind {
38 fn attrs(&self) -> &[Attribute] {
40 StmtKind::Local(local) => local.attrs(),
41 StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(),
42 StmtKind::Item(item) => item.attrs(),
43 StmtKind::Empty => &[],
44 StmtKind::MacCall(mac) => &mac.attrs,
48 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
50 StmtKind::Local(local) => local.visit_attrs(f),
51 StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
52 StmtKind::Item(item) => item.visit_attrs(f),
54 StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f),
57 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
59 StmtKind::Local(local) => &mut local.tokens,
60 StmtKind::Item(item) => &mut item.tokens,
61 StmtKind::Expr(expr) | StmtKind::Semi(expr) => &mut expr.tokens,
62 StmtKind::Empty => return None,
63 StmtKind::MacCall(mac) => &mut mac.tokens,
68 impl AstLike for Stmt {
69 fn attrs(&self) -> &[Attribute] {
73 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
74 self.kind.visit_attrs(f);
76 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
77 self.kind.tokens_mut()
81 impl AstLike for Attribute {
82 fn attrs(&self) -> &[Attribute] {
85 fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
86 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
87 Some(match &mut self.kind {
88 AttrKind::Normal(_, tokens) => tokens,
89 kind @ AttrKind::DocComment(..) => {
90 panic!("Called tokens_mut on doc comment attr {:?}", kind)
96 impl<T: AstLike> AstLike for Option<T> {
97 fn attrs(&self) -> &[Attribute] {
98 self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
100 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
101 if let Some(inner) = self.as_mut() {
102 inner.visit_attrs(f);
105 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
106 self.as_mut().and_then(|inner| inner.tokens_mut())
110 /// Helper trait for the macros below. Abstracts over
111 /// the two types of attribute fields that AST nodes
112 /// may have (`Vec<Attribute>` or `AttrVec`)
114 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
117 impl VecOrAttrVec for Vec<Attribute> {
118 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
123 impl VecOrAttrVec for AttrVec {
124 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
125 visit_attrvec(self, f)
129 macro_rules! derive_has_tokens_and_attrs {
130 ($($ty:path),*) => { $(
131 impl AstLike for $ty {
132 fn attrs(&self) -> &[Attribute] {
136 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
137 VecOrAttrVec::visit(&mut self.attrs, f)
140 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
141 Some(&mut self.tokens)
147 macro_rules! derive_has_attrs_no_tokens {
148 ($($ty:path),*) => { $(
149 impl AstLike for $ty {
150 fn attrs(&self) -> &[Attribute] {
154 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
155 VecOrAttrVec::visit(&mut self.attrs, f)
158 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
165 macro_rules! derive_has_tokens_no_attrs {
166 ($($ty:path),*) => { $(
167 impl AstLike for $ty {
168 fn attrs(&self) -> &[Attribute] {
172 fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
174 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
175 Some(&mut self.tokens)
181 // These AST nodes support both inert and active
182 // attributes, so they also have tokens.
183 derive_has_tokens_and_attrs! {
184 Item, Expr, Local, AssocItem, ForeignItem
187 // These ast nodes only support inert attributes, so they don't
188 // store tokens (since nothing can observe them)
189 derive_has_attrs_no_tokens! {
190 FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam
193 // These AST nodes don't support attributes, but can
194 // be captured by a `macro_rules!` matcher. Therefore,
195 // they need to store tokens.
196 derive_has_tokens_no_attrs! {
197 Ty, Block, AttrItem, Pat, Path, Visibility