blob: be8e1d22c9dbfc0d2512b82b5955ed3b6c3283c0 [file] [log] [blame]
//! A `MutVisitor` represents an AST modification; it accepts an AST piece and
//! mutates it in place. So, for instance, macro expansion is a `MutVisitor`
//! that walks over an AST and modifies it.
//!
//! Note: using a `MutVisitor` (other than the `MacroExpander` `MutVisitor`) on
//! an AST before macro expansion is probably a bad idea. For instance,
//! a `MutVisitor` renaming item names in a module will miss all of those
//! that are created by the expansion of a macro.
use std::ops::DerefMut;
use std::panic;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_span::source_map::Spanned;
use rustc_span::{Ident, Span, Symbol};
use smallvec::{SmallVec, smallvec};
use thin_vec::ThinVec;
use crate::ast::*;
use crate::tokenstream::*;
use crate::visit::{AssocCtxt, BoundKind, FnCtxt, LifetimeCtxt, VisitorResult, try_visit};
mod sealed {
use rustc_ast_ir::visit::VisitorResult;
/// This is for compatibility with the regular `Visitor`.
pub trait MutVisitorResult {
type Result: VisitorResult;
}
impl<T> MutVisitorResult for T {
type Result = ();
}
}
use sealed::MutVisitorResult;
pub(crate) trait MutVisitable<V: MutVisitor> {
type Extra: Copy;
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra);
}
impl<V: MutVisitor, T: ?Sized> MutVisitable<V> for Box<T>
where
T: MutVisitable<V>,
{
type Extra = T::Extra;
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
(**self).visit_mut(visitor, extra)
}
}
impl<V: MutVisitor, T> MutVisitable<V> for Option<T>
where
T: MutVisitable<V>,
{
type Extra = T::Extra;
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
if let Some(this) = self {
this.visit_mut(visitor, extra)
}
}
}
impl<V: MutVisitor, T> MutVisitable<V> for Spanned<T>
where
T: MutVisitable<V>,
{
type Extra = T::Extra;
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
let Spanned { span, node } = self;
span.visit_mut(visitor, ());
node.visit_mut(visitor, extra);
}
}
impl<V: MutVisitor, T> MutVisitable<V> for [T]
where
T: MutVisitable<V>,
{
type Extra = T::Extra;
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
for item in self {
item.visit_mut(visitor, extra);
}
}
}
impl<V: MutVisitor, T> MutVisitable<V> for Vec<T>
where
T: MutVisitable<V>,
{
type Extra = T::Extra;
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
for item in self {
item.visit_mut(visitor, extra);
}
}
}
impl<V: MutVisitor, T> MutVisitable<V> for (T,)
where
T: MutVisitable<V>,
{
type Extra = T::Extra;
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
self.0.visit_mut(visitor, extra);
}
}
impl<V: MutVisitor, T1, T2> MutVisitable<V> for (T1, T2)
where
T1: MutVisitable<V, Extra = ()>,
T2: MutVisitable<V, Extra = ()>,
{
type Extra = ();
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
self.0.visit_mut(visitor, extra);
self.1.visit_mut(visitor, extra);
}
}
impl<V: MutVisitor, T1, T2, T3> MutVisitable<V> for (T1, T2, T3)
where
T1: MutVisitable<V, Extra = ()>,
T2: MutVisitable<V, Extra = ()>,
T3: MutVisitable<V, Extra = ()>,
{
type Extra = ();
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
self.0.visit_mut(visitor, extra);
self.1.visit_mut(visitor, extra);
self.2.visit_mut(visitor, extra);
}
}
impl<V: MutVisitor, T1, T2, T3, T4> MutVisitable<V> for (T1, T2, T3, T4)
where
T1: MutVisitable<V, Extra = ()>,
T2: MutVisitable<V, Extra = ()>,
T3: MutVisitable<V, Extra = ()>,
T4: MutVisitable<V, Extra = ()>,
{
type Extra = ();
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
self.0.visit_mut(visitor, extra);
self.1.visit_mut(visitor, extra);
self.2.visit_mut(visitor, extra);
self.3.visit_mut(visitor, extra);
}
}
pub trait MutWalkable<V: MutVisitor> {
fn walk_mut(&mut self, visitor: &mut V);
}
macro_rules! visit_visitable {
(mut $visitor:expr, $($expr:expr),* $(,)?) => {{
$(MutVisitable::visit_mut($expr, $visitor, ());)*
}};
}
macro_rules! visit_visitable_with {
(mut $visitor:expr, $expr:expr, $extra:expr $(,)?) => {
MutVisitable::visit_mut($expr, $visitor, $extra)
};
}
macro_rules! walk_walkable {
($visitor:expr, $expr:expr, mut) => {
MutWalkable::walk_mut($expr, $visitor)
};
}
macro_rules! impl_visitable {
(|&mut $self:ident: $self_ty:ty,
$vis:ident: &mut $vis_ty:ident,
$extra:ident: $extra_ty:ty| $block:block) => {
#[allow(unused_parens, non_local_definitions)]
impl<$vis_ty: MutVisitor> MutVisitable<$vis_ty> for $self_ty {
type Extra = $extra_ty;
fn visit_mut(&mut $self, $vis: &mut $vis_ty, $extra: Self::Extra) -> V::Result {
$block
}
}
};
}
macro_rules! impl_walkable {
($(<$K:ident: $Kb:ident>)? |&mut $self:ident: $self_ty:ty,
$vis:ident: &mut $vis_ty:ident| $block:block) => {
#[allow(unused_parens, non_local_definitions)]
impl<$($K: $Kb,)? $vis_ty: MutVisitor> MutWalkable<$vis_ty> for $self_ty {
fn walk_mut(&mut $self, $vis: &mut $vis_ty) -> V::Result {
$block
}
}
};
}
macro_rules! impl_visitable_noop {
(<mut> $($ty:ty,)*) => {
$(
impl_visitable!(|&mut self: $ty, _vis: &mut V, _extra: ()| {});
)*
};
}
macro_rules! impl_visitable_list {
(<mut> $($ty:ty,)*) => {
$(impl<V: MutVisitor, T> MutVisitable<V> for $ty
where
for<'a> &'a mut $ty: IntoIterator<Item = &'a mut T>,
T: MutVisitable<V>,
{
type Extra = <T as MutVisitable<V>>::Extra;
#[inline]
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra) {
for i in self {
i.visit_mut(visitor, extra);
}
}
})*
}
}
macro_rules! impl_visitable_direct {
(<mut> $($ty:ty,)*) => {
$(impl_visitable!(
|&mut self: $ty, visitor: &mut V, _extra: ()| {
MutWalkable::walk_mut(self, visitor)
}
);)*
}
}
macro_rules! impl_visitable_calling_walkable {
(<mut>
$( fn $method:ident($ty:ty $(, $extra_name:ident: $extra_ty:ty)?); )*
) => {
$(fn $method(&mut self, node: &mut $ty $(, $extra_name:$extra_ty)?) {
impl_visitable!(|&mut self: $ty, visitor: &mut V, extra: ($($extra_ty)?)| {
let ($($extra_name)?) = extra;
visitor.$method(self $(, $extra_name)?);
});
walk_walkable!(self, node, mut)
})*
}
}
macro_rules! define_named_walk {
((mut) $Visitor:ident
$( pub fn $method:ident($ty:ty); )*
) => {
$(pub fn $method<V: $Visitor>(visitor: &mut V, node: &mut $ty) {
walk_walkable!(visitor, node, mut)
})*
};
}
super::common_visitor_and_walkers!((mut) MutVisitor);
macro_rules! generate_flat_map_visitor_fns {
($($name:ident, $Ty:ty, $flat_map_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => {
$(
#[allow(unused_parens)]
impl<V: MutVisitor> MutVisitable<V> for ThinVec<$Ty> {
type Extra = ($($ParamTy),*);
#[inline]
fn visit_mut(
&mut self,
visitor: &mut V,
($($param),*): Self::Extra,
) -> V::Result {
$name(visitor, self $(, $param)*)
}
}
fn $name<V: MutVisitor>(
vis: &mut V,
values: &mut ThinVec<$Ty>,
$(
$param: $ParamTy,
)*
) {
values.flat_map_in_place(|value| vis.$flat_map_fn(value$(,$param)*));
}
)+
}
}
generate_flat_map_visitor_fns! {
visit_items, Box<Item>, flat_map_item;
visit_foreign_items, Box<ForeignItem>, flat_map_foreign_item;
visit_generic_params, GenericParam, flat_map_generic_param;
visit_stmts, Stmt, flat_map_stmt;
visit_exprs, Box<Expr>, filter_map_expr;
visit_expr_fields, ExprField, flat_map_expr_field;
visit_pat_fields, PatField, flat_map_pat_field;
visit_variants, Variant, flat_map_variant;
visit_assoc_items, Box<AssocItem>, flat_map_assoc_item, ctxt: AssocCtxt;
visit_where_predicates, WherePredicate, flat_map_where_predicate;
visit_params, Param, flat_map_param;
visit_field_defs, FieldDef, flat_map_field_def;
visit_arms, Arm, flat_map_arm;
}
pub fn walk_flat_map_pat_field<T: MutVisitor>(
vis: &mut T,
mut fp: PatField,
) -> SmallVec<[PatField; 1]> {
vis.visit_pat_field(&mut fp);
smallvec![fp]
}
macro_rules! generate_walk_flat_map_fns {
($($fn_name:ident($Ty:ty$(,$extra_name:ident: $ExtraTy:ty)*) => $visit_fn_name:ident;)+) => {$(
pub fn $fn_name<V: MutVisitor>(vis: &mut V, mut value: $Ty$(,$extra_name: $ExtraTy)*) -> SmallVec<[$Ty; 1]> {
vis.$visit_fn_name(&mut value$(,$extra_name)*);
smallvec![value]
}
)+};
}
generate_walk_flat_map_fns! {
walk_flat_map_arm(Arm) => visit_arm;
walk_flat_map_variant(Variant) => visit_variant;
walk_flat_map_param(Param) => visit_param;
walk_flat_map_generic_param(GenericParam) => visit_generic_param;
walk_flat_map_where_predicate(WherePredicate) => visit_where_predicate;
walk_flat_map_field_def(FieldDef) => visit_field_def;
walk_flat_map_expr_field(ExprField) => visit_expr_field;
walk_flat_map_item(Box<Item>) => visit_item;
walk_flat_map_foreign_item(Box<ForeignItem>) => visit_foreign_item;
walk_flat_map_assoc_item(Box<AssocItem>, ctxt: AssocCtxt) => visit_assoc_item;
}
pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: Box<Expr>) -> Option<Box<Expr>> {
vis.visit_expr(&mut e);
Some(e)
}
pub fn walk_flat_map_stmt<T: MutVisitor>(
vis: &mut T,
Stmt { kind, span, mut id }: Stmt,
) -> SmallVec<[Stmt; 1]> {
vis.visit_id(&mut id);
let mut stmts: SmallVec<[Stmt; 1]> = walk_flat_map_stmt_kind(vis, kind)
.into_iter()
.map(|kind| Stmt { id, kind, span })
.collect();
match &mut stmts[..] {
[] => {}
[stmt] => vis.visit_span(&mut stmt.span),
_ => panic!(
"cloning statement `NodeId`s is prohibited by default, \
the visitor should implement custom statement visiting"
),
}
stmts
}
fn walk_flat_map_stmt_kind<T: MutVisitor>(vis: &mut T, kind: StmtKind) -> SmallVec<[StmtKind; 1]> {
match kind {
StmtKind::Let(mut local) => smallvec![StmtKind::Let({
vis.visit_local(&mut local);
local
})],
StmtKind::Item(item) => vis.flat_map_item(item).into_iter().map(StmtKind::Item).collect(),
StmtKind::Expr(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Expr).collect(),
StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(),
StmtKind::Empty => smallvec![StmtKind::Empty],
StmtKind::MacCall(mut mac) => {
let MacCallStmt { mac: mac_, style: _, attrs, tokens: _ } = mac.deref_mut();
for attr in attrs {
vis.visit_attribute(attr);
}
vis.visit_mac_call(mac_);
smallvec![StmtKind::MacCall(mac)]
}
}
}