]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast/src/ast_like.rs
Rollup merge of #82563 - lucas-deangelis:issue-82209-fix, r=jyn514
[rust.git] / compiler / rustc_ast / src / ast_like.rs
1 use super::ptr::P;
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};
7
8 /// An `AstLike` represents an AST node (or some wrapper around
9 /// and AST node) which stores some combination of attributes
10 /// and tokens.
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!")
20     }
21 }
22
23 impl<T: AstLike + 'static> AstLike for P<T> {
24     fn attrs(&self) -> &[Attribute] {
25         (**self).attrs()
26     }
27     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
28         (**self).visit_attrs(f);
29     }
30     fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
31         (**self).finalize_tokens(tokens)
32     }
33 }
34
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();
38         f(&mut vec);
39         vec.into()
40     });
41 }
42
43 impl AstLike for StmtKind {
44     fn attrs(&self) -> &[Attribute] {
45         match *self {
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,
51         }
52     }
53
54     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
55         match self {
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),
59             StmtKind::Empty => {}
60             StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f),
61         }
62     }
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,
70         };
71         if stmt_tokens.is_none() {
72             *stmt_tokens = Some(tokens);
73         }
74     }
75 }
76
77 impl AstLike for Stmt {
78     fn attrs(&self) -> &[Attribute] {
79         self.kind.attrs()
80     }
81
82     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
83         self.kind.visit_attrs(f);
84     }
85     fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
86         self.kind.finalize_tokens(tokens)
87     }
88 }
89
90 impl AstLike for Attribute {
91     fn attrs(&self) -> &[Attribute] {
92         &[]
93     }
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);
100                 }
101             }
102             AttrKind::DocComment(..) => {
103                 panic!("Called finalize_tokens on doc comment attr {:?}", self)
104             }
105         }
106     }
107 }
108
109 impl<T: AstLike> AstLike for Option<T> {
110     fn attrs(&self) -> &[Attribute] {
111         self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
112     }
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);
116         }
117     }
118     fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
119         if let Some(inner) = self {
120             inner.finalize_tokens(tokens);
121         }
122     }
123 }
124
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`)
128 trait VecOrAttrVec {
129     fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
130 }
131
132 impl VecOrAttrVec for Vec<Attribute> {
133     fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
134         f(self)
135     }
136 }
137
138 impl VecOrAttrVec for AttrVec {
139     fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
140         visit_attrvec(self, f)
141     }
142 }
143
144 macro_rules! derive_has_tokens_and_attrs {
145     ($($ty:path),*) => { $(
146         impl AstLike for $ty {
147             fn attrs(&self) -> &[Attribute] {
148                 &self.attrs
149             }
150
151             fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
152                 VecOrAttrVec::visit(&mut self.attrs, f)
153             }
154
155             fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
156                 if self.tokens.is_none() {
157                     self.tokens = Some(tokens);
158                 }
159
160             }
161         }
162     )* }
163 }
164
165 macro_rules! derive_has_attrs_no_tokens {
166     ($($ty:path),*) => { $(
167         impl AstLike for $ty {
168             fn attrs(&self) -> &[Attribute] {
169                 &self.attrs
170             }
171
172             fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
173                 VecOrAttrVec::visit(&mut self.attrs, f)
174             }
175
176             fn finalize_tokens(&mut self, _tokens: LazyTokenStream) {}
177         }
178     )* }
179 }
180
181 macro_rules! derive_has_tokens_no_attrs {
182     ($($ty:path),*) => { $(
183         impl AstLike for $ty {
184             fn attrs(&self) -> &[Attribute] {
185                 &[]
186             }
187
188             fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {
189             }
190
191             fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
192                 if self.tokens.is_none() {
193                     self.tokens = Some(tokens);
194                 }
195
196             }
197         }
198     )* }
199 }
200
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
205 }
206
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! {
210     StructField, Arm,
211     Field, FieldPat, Variant, Param, GenericParam
212 }
213
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
219 }