Rollup merge of #92573 - petrochenkov:ltrattr3, r=Aaron1011

expand: Refactor InvocationCollector visitor for better code reuse

The refactoring part of https://github.com/rust-lang/rust/pull/92473.

Invocation collector visitor logic now lives in two main functions:
- `fn flat_map_node`, corresponding to "one to many" expansions
- `fn visit_node`, corresponding to "one to one" expansions

All specific mut visitor methods now use one of these functions.

The new `InvocationCollectorNode` trait implemented for all `AstFragment` nodes provides the necessary small pieces of functionality required to implement the `(flat_map,visit)_node` functions.
r? `@Aaron1011`
This commit is contained in:
Matthias Krüger 2022-01-09 13:38:31 +01:00 committed by GitHub
commit b681dc2af4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 782 additions and 561 deletions

View file

@ -6,12 +6,13 @@ 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;
use std::fmt;
use std::marker::PhantomData;
/// 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 + Debug {
pub trait AstLike: Sized + fmt::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
@ -285,3 +286,37 @@ derive_has_attrs_no_tokens! {
derive_has_tokens_no_attrs! {
Ty, Block, AttrItem, Pat, Path, Visibility
}
/// A newtype around an `AstLike` node that implements `AstLike` itself.
pub struct AstLikeWrapper<Wrapped, Tag> {
pub wrapped: Wrapped,
pub tag: PhantomData<Tag>,
}
impl<Wrapped, Tag> AstLikeWrapper<Wrapped, Tag> {
pub fn new(wrapped: Wrapped, _tag: Tag) -> AstLikeWrapper<Wrapped, Tag> {
AstLikeWrapper { wrapped, tag: Default::default() }
}
}
impl<Wrapped: fmt::Debug, Tag> fmt::Debug for AstLikeWrapper<Wrapped, Tag> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AstLikeWrapper")
.field("wrapped", &self.wrapped)
.field("tag", &self.tag)
.finish()
}
}
impl<Wrapped: AstLike, Tag> AstLike for AstLikeWrapper<Wrapped, Tag> {
const SUPPORTS_CUSTOM_INNER_ATTRS: bool = Wrapped::SUPPORTS_CUSTOM_INNER_ATTRS;
fn attrs(&self) -> &[Attribute] {
self.wrapped.attrs()
}
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
self.wrapped.visit_attrs(f)
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
self.wrapped.tokens_mut()
}
}

View file

@ -41,7 +41,7 @@ pub mod tokenstream;
pub mod visit;
pub use self::ast::*;
pub use self::ast_like::AstLike;
pub use self::ast_like::{AstLike, AstLikeWrapper};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};

View file

@ -238,7 +238,7 @@ macro_rules! configure {
}
impl<'a> StripUnconfigured<'a> {
pub fn configure<T: AstLike>(&mut self, mut node: T) -> Option<T> {
pub fn configure<T: AstLike>(&self, mut node: T) -> Option<T> {
self.process_cfg_attrs(&mut node);
if self.in_cfg(node.attrs()) {
self.try_configure_tokens(&mut node);
@ -248,7 +248,7 @@ impl<'a> StripUnconfigured<'a> {
}
}
fn try_configure_tokens<T: AstLike>(&mut self, node: &mut T) {
fn try_configure_tokens<T: AstLike>(&self, node: &mut T) {
if self.config_tokens {
if let Some(Some(tokens)) = node.tokens_mut() {
let attr_annotated_tokens = tokens.create_token_stream();
@ -257,10 +257,7 @@ impl<'a> StripUnconfigured<'a> {
}
}
fn configure_krate_attrs(
&mut self,
mut attrs: Vec<ast::Attribute>,
) -> Option<Vec<ast::Attribute>> {
fn configure_krate_attrs(&self, mut attrs: Vec<ast::Attribute>) -> Option<Vec<ast::Attribute>> {
attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
if self.in_cfg(&attrs) { Some(attrs) } else { None }
}
@ -269,7 +266,7 @@ impl<'a> StripUnconfigured<'a> {
/// This is only used during the invocation of `derive` proc-macros,
/// which require that we cfg-expand their entire input.
/// Normal cfg-expansion operates on parsed AST nodes via the `configure` method
fn configure_tokens(&mut self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream {
fn configure_tokens(&self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream {
fn can_skip(stream: &AttrAnnotatedTokenStream) -> bool {
stream.0.iter().all(|(tree, _spacing)| match tree {
AttrAnnotatedTokenTree::Attributes(_) => false,
@ -325,7 +322,7 @@ impl<'a> StripUnconfigured<'a> {
/// Gives compiler warnings if any `cfg_attr` does not contain any
/// attributes and is in the original source code. Gives compiler errors if
/// the syntax of any `cfg_attr` is incorrect.
fn process_cfg_attrs<T: AstLike>(&mut self, node: &mut T) {
fn process_cfg_attrs<T: AstLike>(&self, node: &mut T) {
node.visit_attrs(|attrs| {
attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
});
@ -338,7 +335,7 @@ impl<'a> StripUnconfigured<'a> {
/// Gives a compiler warning when the `cfg_attr` contains no attributes and
/// is in the original source file. Gives a compiler error if the syntax of
/// the attribute is incorrect.
fn process_cfg_attr(&mut self, attr: Attribute) -> Vec<Attribute> {
fn process_cfg_attr(&self, attr: Attribute) -> Vec<Attribute> {
if !attr.has_name(sym::cfg_attr) {
return vec![attr];
}
@ -461,7 +458,7 @@ impl<'a> StripUnconfigured<'a> {
}
}
pub fn configure_expr(&mut self, expr: &mut P<ast::Expr>) {
pub fn configure_expr(&self, expr: &mut P<ast::Expr>) {
for attr in expr.attrs.iter() {
self.maybe_emit_expr_attr_err(attr);
}

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,5 @@
#![feature(associated_type_bounds)]
#![feature(associated_type_defaults)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![cfg_attr(bootstrap, feature(destructuring_assignment))]

View file

@ -123,7 +123,7 @@ pub fn placeholder(
span,
is_placeholder: true,
}]),
AstFragmentKind::Fields => AstFragment::Fields(smallvec![ast::ExprField {
AstFragmentKind::ExprFields => AstFragment::ExprFields(smallvec![ast::ExprField {
attrs: Default::default(),
expr: expr_placeholder(),
id,
@ -132,7 +132,7 @@ pub fn placeholder(
span,
is_placeholder: true,
}]),
AstFragmentKind::FieldPats => AstFragment::FieldPats(smallvec![ast::PatField {
AstFragmentKind::PatFields => AstFragment::PatFields(smallvec![ast::PatField {
attrs: Default::default(),
id,
ident,
@ -159,7 +159,7 @@ pub fn placeholder(
ty: ty(),
is_placeholder: true,
}]),
AstFragmentKind::StructFields => AstFragment::StructFields(smallvec![ast::FieldDef {
AstFragmentKind::FieldDefs => AstFragment::FieldDefs(smallvec![ast::FieldDef {
attrs: Default::default(),
id,
ident: None,