2 use super::tokenstream::LazyTokenStream;
3 use super::{Arm, Field, FieldPat, GenericParam, Param, StructField, 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 /// Called by `Parser::collect_tokens` to store the collected
15 /// tokens inside an AST node
16 fn finalize_tokens(&mut self, _tokens: LazyTokenStream) {
17 // This default impl makes this trait easier to implement
18 // in tools like `rust-analyzer`
19 panic!("`finalize_tokens` is not supported!")
23 impl<T: AstLike + 'static> AstLike for P<T> {
24 fn attrs(&self) -> &[Attribute] {
27 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
28 (**self).visit_attrs(f);
30 fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
31 (**self).finalize_tokens(tokens)
35 fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
36 crate::mut_visit::visit_clobber(attrs, |attrs| {
37 let mut vec = attrs.into();
43 impl AstLike for StmtKind {
44 fn attrs(&self) -> &[Attribute] {
46 StmtKind::Local(ref local) => local.attrs(),
47 StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(),
48 StmtKind::Item(ref item) => item.attrs(),
49 StmtKind::Empty => &[],
50 StmtKind::MacCall(ref mac) => &*mac.attrs,
54 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
56 StmtKind::Local(local) => local.visit_attrs(f),
57 StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
58 StmtKind::Item(item) => item.visit_attrs(f),
60 StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f),
63 fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
64 let stmt_tokens = match self {
65 StmtKind::Local(ref mut local) => &mut local.tokens,
66 StmtKind::Item(ref mut item) => &mut item.tokens,
67 StmtKind::Expr(ref mut expr) | StmtKind::Semi(ref mut expr) => &mut expr.tokens,
68 StmtKind::Empty => return,
69 StmtKind::MacCall(ref mut mac) => &mut mac.tokens,
71 if stmt_tokens.is_none() {
72 *stmt_tokens = Some(tokens);
77 impl AstLike for Stmt {
78 fn attrs(&self) -> &[Attribute] {
82 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
83 self.kind.visit_attrs(f);
85 fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
86 self.kind.finalize_tokens(tokens)
90 impl AstLike for Attribute {
91 fn attrs(&self) -> &[Attribute] {
94 fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
95 fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
96 match &mut self.kind {
97 AttrKind::Normal(_, attr_tokens) => {
98 if attr_tokens.is_none() {
99 *attr_tokens = Some(tokens);
102 AttrKind::DocComment(..) => {
103 panic!("Called finalize_tokens on doc comment attr {:?}", self)
109 impl<T: AstLike> AstLike for Option<T> {
110 fn attrs(&self) -> &[Attribute] {
111 self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
113 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
114 if let Some(inner) = self.as_mut() {
115 inner.visit_attrs(f);
118 fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
119 if let Some(inner) = self {
120 inner.finalize_tokens(tokens);
125 /// Helper trait for the macros below. Abstracts over
126 /// the two types of attribute fields that AST nodes
127 /// may have (`Vec<Attribute>` or `AttrVec`)
129 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
132 impl VecOrAttrVec for Vec<Attribute> {
133 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
138 impl VecOrAttrVec for AttrVec {
139 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
140 visit_attrvec(self, f)
144 macro_rules! derive_has_tokens_and_attrs {
145 ($($ty:path),*) => { $(
146 impl AstLike for $ty {
147 fn attrs(&self) -> &[Attribute] {
151 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
152 VecOrAttrVec::visit(&mut self.attrs, f)
155 fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
156 if self.tokens.is_none() {
157 self.tokens = Some(tokens);
165 macro_rules! derive_has_attrs_no_tokens {
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>)) {
173 VecOrAttrVec::visit(&mut self.attrs, f)
176 fn finalize_tokens(&mut self, _tokens: LazyTokenStream) {}
181 macro_rules! derive_has_tokens_no_attrs {
182 ($($ty:path),*) => { $(
183 impl AstLike for $ty {
184 fn attrs(&self) -> &[Attribute] {
188 fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {
191 fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
192 if self.tokens.is_none() {
193 self.tokens = Some(tokens);
201 // These AST nodes support both inert and active
202 // attributes, so they also have tokens.
203 derive_has_tokens_and_attrs! {
204 Item, Expr, Local, AssocItem, ForeignItem
207 // These ast nodes only support inert attributes, so they don't
208 // store tokens (since nothing can observe them)
209 derive_has_attrs_no_tokens! {
211 Field, FieldPat, Variant, Param, GenericParam
214 // These AST nodes don't support attributes, but can
215 // be captured by a `macro_rules!` matcher. Therefore,
216 // they need to store tokens.
217 derive_has_tokens_no_attrs! {
218 Ty, Block, AttrItem, Pat, Path, Visibility