//! 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}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use crate::ast::*; use crate::ptr::P; use crate::tokenstream::*; use crate::visit::{AssocCtxt, BoundKind, FnCtxt, VisitorResult, try_visit, visit_opt, walk_list}; mod sealed { use rustc_ast_ir::visit::VisitorResult; /// This is for compatibility with the regular `Visitor`. pub trait MutVisitorResult { type Result: VisitorResult; } impl MutVisitorResult for T { type Result = (); } } use sealed::MutVisitorResult; 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)*;)+) => { $( fn $name( 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, P, flat_map_item; visit_foreign_items, P, flat_map_foreign_item; visit_generic_params, GenericParam, flat_map_generic_param; visit_stmts, Stmt, flat_map_stmt; visit_exprs, P, 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, P, 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( vis: &mut T, mut fp: PatField, ) -> SmallVec<[PatField; 1]> { vis.visit_pat_field(&mut fp); smallvec![fp] } fn visit_nested_use_tree( vis: &mut V, nested_tree: &mut UseTree, nested_id: &mut NodeId, ) { vis.visit_id(nested_id); vis.visit_use_tree(nested_tree); } 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(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(P) => visit_item; walk_flat_map_foreign_item(P) => visit_foreign_item; walk_flat_map_assoc_item(P, ctxt: AssocCtxt) => visit_assoc_item; } fn walk_ty_alias_where_clauses(vis: &mut T, tawcs: &mut TyAliasWhereClauses) { let TyAliasWhereClauses { before, after, split: _ } = tawcs; let TyAliasWhereClause { has_where_token: _, span: span_before } = before; let TyAliasWhereClause { has_where_token: _, span: span_after } = after; vis.visit_span(span_before); vis.visit_span(span_after); } pub fn walk_filter_map_expr(vis: &mut T, mut e: P) -> Option> { vis.visit_expr(&mut e); Some(e) } pub fn walk_flat_map_stmt( 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(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)] } } }