use super::ptr::P;
+use super::token::Nonterminal;
use super::tokenstream::LazyTokenStream;
use super::{Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
-use super::{AssocItem, Expr, ForeignItem, Item, Local};
+use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt};
use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
use super::{AttrVec, Attribute, Stmt, StmtKind};
+use std::fmt::Debug;
+
/// An `AstLike` represents an AST node (or some wrapper around
/// and AST node) which stores some combination of attributes
/// and tokens.
-pub trait AstLike: Sized {
+pub trait AstLike: Sized + Debug {
+ /// This is `true` if this `AstLike` might support 'custom' (proc-macro) inner
+ /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not
+ /// considered 'custom' attributes
+ ///
+ /// If this is `false`, then this `AstLike` definitely does
+ /// not support 'custom' inner attributes, which enables some optimizations
+ /// during token collection.
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool;
fn attrs(&self) -> &[Attribute];
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>>;
}
impl<T: AstLike + 'static> AstLike for P<T> {
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
fn attrs(&self) -> &[Attribute] {
(**self).attrs()
}
}
}
+impl AstLike for crate::token::Nonterminal {
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
+ fn attrs(&self) -> &[Attribute] {
+ match self {
+ Nonterminal::NtItem(item) => item.attrs(),
+ Nonterminal::NtStmt(stmt) => stmt.attrs(),
+ Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.attrs(),
+ Nonterminal::NtPat(_)
+ | Nonterminal::NtTy(_)
+ | Nonterminal::NtMeta(_)
+ | Nonterminal::NtPath(_)
+ | Nonterminal::NtVis(_)
+ | Nonterminal::NtTT(_)
+ | Nonterminal::NtBlock(_)
+ | Nonterminal::NtIdent(..)
+ | Nonterminal::NtLifetime(_) => &[],
+ }
+ }
+ fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+ match self {
+ Nonterminal::NtItem(item) => item.visit_attrs(f),
+ Nonterminal::NtStmt(stmt) => stmt.visit_attrs(f),
+ Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.visit_attrs(f),
+ Nonterminal::NtPat(_)
+ | Nonterminal::NtTy(_)
+ | Nonterminal::NtMeta(_)
+ | Nonterminal::NtPath(_)
+ | Nonterminal::NtVis(_)
+ | Nonterminal::NtTT(_)
+ | Nonterminal::NtBlock(_)
+ | Nonterminal::NtIdent(..)
+ | Nonterminal::NtLifetime(_) => {}
+ }
+ }
+ fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
+ match self {
+ Nonterminal::NtItem(item) => item.tokens_mut(),
+ Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
+ Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
+ Nonterminal::NtPat(pat) => pat.tokens_mut(),
+ Nonterminal::NtTy(ty) => ty.tokens_mut(),
+ Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
+ Nonterminal::NtPath(path) => path.tokens_mut(),
+ Nonterminal::NtVis(vis) => vis.tokens_mut(),
+ _ => panic!("Called tokens_mut on {:?}", self),
+ }
+ }
+}
+
fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
crate::mut_visit::visit_clobber(attrs, |attrs| {
let mut vec = attrs.into();
}
impl AstLike for StmtKind {
+ // This might be an `StmtKind::Item`, which contains
+ // an item that supports inner attrs
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
+
fn attrs(&self) -> &[Attribute] {
match self {
StmtKind::Local(local) => local.attrs(),
}
impl AstLike for Stmt {
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool = StmtKind::SUPPORTS_CUSTOM_INNER_ATTRS;
+
fn attrs(&self) -> &[Attribute] {
self.kind.attrs()
}
}
impl AstLike for Attribute {
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
+
fn attrs(&self) -> &[Attribute] {
&[]
}
}
impl<T: AstLike> AstLike for Option<T> {
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
+
fn attrs(&self) -> &[Attribute] {
self.as_ref().map(|inner| inner.attrs()).unwrap_or(&[])
}
}
macro_rules! derive_has_tokens_and_attrs {
- ($($ty:path),*) => { $(
+ (
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner_attrs:literal;
+ $($ty:path),*
+ ) => { $(
impl AstLike for $ty {
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner_attrs;
+
fn attrs(&self) -> &[Attribute] {
&self.attrs
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
Some(&mut self.tokens)
}
+
}
)* }
}
macro_rules! derive_has_attrs_no_tokens {
($($ty:path),*) => { $(
impl AstLike for $ty {
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
+
fn attrs(&self) -> &[Attribute] {
&self.attrs
}
macro_rules! derive_has_tokens_no_attrs {
($($ty:path),*) => { $(
impl AstLike for $ty {
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
+
fn attrs(&self) -> &[Attribute] {
&[]
}
fn visit_attrs(&mut self, _f: impl FnOnce(&mut Vec<Attribute>)) {}
-
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
Some(&mut self.tokens)
}
)* }
}
-// These AST nodes support both inert and active
-// attributes, so they also have tokens.
+// These ast nodes support both active and inert attributes,
+// so they have tokens collected to pass to proc macros
+derive_has_tokens_and_attrs! {
+ // Both `Item` and `AssocItem` can have bodies, which
+ // can contain inner attributes
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool = true;
+ Item, AssocItem, ForeignItem
+}
+
derive_has_tokens_and_attrs! {
- Item, Expr, Local, AssocItem, ForeignItem
+ const SUPPORTS_CUSTOM_INNER_ATTRS: bool = false;
+ Local, MacCallStmt, Expr
}
// These ast nodes only support inert attributes, so they don't