1 //! A set of traits implemented for various AST nodes,
2 //! typically those used in AST fragments during macro expansion.
3 //! The traits are not implemented exhaustively, only when actually necessary.
6 use crate::token::Nonterminal;
7 use crate::tokenstream::LazyTokenStream;
8 use crate::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
9 use crate::{AssocItem, Expr, ForeignItem, Item, NodeId};
10 use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
11 use crate::{AttrVec, Attribute, Stmt, StmtKind};
16 use std::marker::PhantomData;
18 /// A utility trait to reduce boilerplate.
19 /// Standard `Deref(Mut)` cannot be reused due to coherence.
22 fn ast_deref(&self) -> &Self::Target;
23 fn ast_deref_mut(&mut self) -> &mut Self::Target;
26 macro_rules! impl_not_ast_deref {
27 ($($T:ty),+ $(,)?) => {
29 impl !AstDeref for $T {}
34 impl_not_ast_deref!(AssocItem, Expr, ForeignItem, Item, Stmt);
36 impl<T> AstDeref for P<T> {
38 fn ast_deref(&self) -> &Self::Target {
41 fn ast_deref_mut(&mut self) -> &mut Self::Target {
46 /// A trait for AST nodes having an ID.
48 fn node_id(&self) -> NodeId;
49 fn node_id_mut(&mut self) -> &mut NodeId;
52 macro_rules! impl_has_node_id {
53 ($($T:ty),+ $(,)?) => {
55 impl HasNodeId for $T {
56 fn node_id(&self) -> NodeId {
59 fn node_id_mut(&mut self) -> &mut NodeId {
85 impl<T: AstDeref<Target: HasNodeId>> HasNodeId for T {
86 fn node_id(&self) -> NodeId {
87 self.ast_deref().node_id()
89 fn node_id_mut(&mut self) -> &mut NodeId {
90 self.ast_deref_mut().node_id_mut()
94 /// A trait for AST nodes having a span.
96 fn span(&self) -> Span;
99 macro_rules! impl_has_span {
100 ($($T:ty),+ $(,)?) => {
102 impl HasSpan for $T {
103 fn span(&self) -> Span {
111 impl_has_span!(AssocItem, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility);
113 impl<T: AstDeref<Target: HasSpan>> HasSpan for T {
114 fn span(&self) -> Span {
115 self.ast_deref().span()
119 impl HasSpan for AttrItem {
120 fn span(&self) -> Span {
125 /// A trait for AST nodes having (or not having) collected tokens.
126 pub trait HasTokens {
127 fn tokens(&self) -> Option<&LazyTokenStream>;
128 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>>;
131 macro_rules! impl_has_tokens {
132 ($($T:ty),+ $(,)?) => {
134 impl HasTokens for $T {
135 fn tokens(&self) -> Option<&LazyTokenStream> {
138 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
139 Some(&mut self.tokens)
146 macro_rules! impl_has_tokens_none {
147 ($($T:ty),+ $(,)?) => {
149 impl HasTokens for $T {
150 fn tokens(&self) -> Option<&LazyTokenStream> {
153 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
161 impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path, Ty, Visibility);
162 impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant);
164 impl<T: AstDeref<Target: HasTokens>> HasTokens for T {
165 fn tokens(&self) -> Option<&LazyTokenStream> {
166 self.ast_deref().tokens()
168 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
169 self.ast_deref_mut().tokens_mut()
173 impl<T: HasTokens> HasTokens for Option<T> {
174 fn tokens(&self) -> Option<&LazyTokenStream> {
175 self.as_ref().and_then(|inner| inner.tokens())
177 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
178 self.as_mut().and_then(|inner| inner.tokens_mut())
182 impl HasTokens for StmtKind {
183 fn tokens(&self) -> Option<&LazyTokenStream> {
185 StmtKind::Local(local) => local.tokens.as_ref(),
186 StmtKind::Item(item) => item.tokens(),
187 StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens(),
188 StmtKind::Empty => return None,
189 StmtKind::MacCall(mac) => mac.tokens.as_ref(),
192 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
194 StmtKind::Local(local) => Some(&mut local.tokens),
195 StmtKind::Item(item) => item.tokens_mut(),
196 StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.tokens_mut(),
197 StmtKind::Empty => return None,
198 StmtKind::MacCall(mac) => Some(&mut mac.tokens),
203 impl HasTokens for Stmt {
204 fn tokens(&self) -> Option<&LazyTokenStream> {
207 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
208 self.kind.tokens_mut()
212 impl HasTokens for Attribute {
213 fn tokens(&self) -> Option<&LazyTokenStream> {
215 AttrKind::Normal(_, tokens) => tokens.as_ref(),
216 kind @ AttrKind::DocComment(..) => {
217 panic!("Called tokens on doc comment attr {:?}", kind)
221 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
222 Some(match &mut self.kind {
223 AttrKind::Normal(_, tokens) => tokens,
224 kind @ AttrKind::DocComment(..) => {
225 panic!("Called tokens_mut on doc comment attr {:?}", kind)
231 impl HasTokens for Nonterminal {
232 fn tokens(&self) -> Option<&LazyTokenStream> {
234 Nonterminal::NtItem(item) => item.tokens(),
235 Nonterminal::NtStmt(stmt) => stmt.tokens(),
236 Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(),
237 Nonterminal::NtPat(pat) => pat.tokens(),
238 Nonterminal::NtTy(ty) => ty.tokens(),
239 Nonterminal::NtMeta(attr_item) => attr_item.tokens(),
240 Nonterminal::NtPath(path) => path.tokens(),
241 Nonterminal::NtVis(vis) => vis.tokens(),
242 Nonterminal::NtBlock(block) => block.tokens(),
243 Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
246 fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
248 Nonterminal::NtItem(item) => item.tokens_mut(),
249 Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
250 Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
251 Nonterminal::NtPat(pat) => pat.tokens_mut(),
252 Nonterminal::NtTy(ty) => ty.tokens_mut(),
253 Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
254 Nonterminal::NtPath(path) => path.tokens_mut(),
255 Nonterminal::NtVis(vis) => vis.tokens_mut(),
256 Nonterminal::NtBlock(block) => block.tokens_mut(),
257 Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
262 /// A trait for AST nodes having (or not having) attributes.
264 /// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner
265 /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not
266 /// considered 'custom' attributes.
268 /// If this is `false`, then this `HasAttrs` definitely does
269 /// not support 'custom' inner attributes, which enables some optimizations
270 /// during token collection.
271 const SUPPORTS_CUSTOM_INNER_ATTRS: bool;
272 fn attrs(&self) -> &[Attribute];
273 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
276 macro_rules! impl_has_attrs {
277 (const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner:literal, $($T:ty),+ $(,)?) => {
279 impl HasAttrs for $T {
280 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner;
282 fn attrs(&self) -> &[Attribute] {
286 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
287 VecOrAttrVec::visit(&mut self.attrs, f)
294 macro_rules! impl_has_attrs_none {
295 ($($T:ty),+ $(,)?) => {
297 impl HasAttrs for $T {
298 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
299 fn attrs(&self) -> &[Attribute] {
302 fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
309 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true,
315 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false,
326 impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility);
328 impl<T: AstDeref<Target: HasAttrs>> HasAttrs for T {
329 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::Target::SUPPORTS_CUSTOM_INNER_ATTRS;
330 fn attrs(&self) -> &[Attribute] {
331 self.ast_deref().attrs()
333 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
334 self.ast_deref_mut().visit_attrs(f)
338 impl<T: HasAttrs> HasAttrs for Option<T> {
339 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
340 fn attrs(&self) -> &[Attribute] {
341 self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
343 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
344 if let Some(inner) = self.as_mut() {
345 inner.visit_attrs(f);
350 impl HasAttrs for StmtKind {
351 // This might be a `StmtKind::Item`, which contains
352 // an item that supports inner attrs.
353 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
355 fn attrs(&self) -> &[Attribute] {
357 StmtKind::Local(local) => &local.attrs,
358 StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.attrs(),
359 StmtKind::Item(item) => item.attrs(),
360 StmtKind::Empty => &[],
361 StmtKind::MacCall(mac) => &mac.attrs,
365 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
367 StmtKind::Local(local) => visit_attrvec(&mut local.attrs, f),
368 StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
369 StmtKind::Item(item) => item.visit_attrs(f),
370 StmtKind::Empty => {}
371 StmtKind::MacCall(mac) => visit_attrvec(&mut mac.attrs, f),
376 impl HasAttrs for Stmt {
377 const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS;
378 fn attrs(&self) -> &[Attribute] {
381 fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
382 self.kind.visit_attrs(f);
386 /// Helper trait for the impls above. Abstracts over
387 /// the two types of attribute fields that AST nodes
388 /// may have (`Vec<Attribute>` or `AttrVec`).
390 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
393 impl VecOrAttrVec for Vec<Attribute> {
394 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
399 impl VecOrAttrVec for AttrVec {
400 fn visit(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
401 visit_attrvec(self, f)
405 fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
406 crate::mut_visit::visit_clobber(attrs, |attrs| {
407 let mut vec = attrs.into();
413 /// A newtype around an AST node that implements the traits above if the node implements them.
414 pub struct AstNodeWrapper<Wrapped, Tag> {
415 pub wrapped: Wrapped,
416 pub tag: PhantomData<Tag>,
419 impl<Wrapped, Tag> AstNodeWrapper<Wrapped, Tag> {
420 pub fn new(wrapped: Wrapped, _tag: Tag) -> AstNodeWrapper<Wrapped, Tag> {
421 AstNodeWrapper { wrapped, tag: Default::default() }
425 impl<Wrapped, Tag> AstDeref for AstNodeWrapper<Wrapped, Tag> {
426 type Target = Wrapped;
427 fn ast_deref(&self) -> &Self::Target {
430 fn ast_deref_mut(&mut self) -> &mut Self::Target {
435 impl<Wrapped: fmt::Debug, Tag> fmt::Debug for AstNodeWrapper<Wrapped, Tag> {
436 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
437 f.debug_struct("AstNodeWrapper")
438 .field("wrapped", &self.wrapped)
439 .field("tag", &self.tag)