| //! 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::{Ident, Span, Spanned, 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)] | |
| } | |
| } | |
| } |