|  | //! 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)] | 
|  | } | 
|  | } | 
|  | } |