blob: 68b3d2b0368654a69d528efc744e23c11401b31c [file] [log] [blame]
//! AST walker. Each overridden visit method has full control over what
//! happens with its node, it can do its own traversal of the node's children,
//! call `visit::walk_*` to apply the default traversal algorithm, or prevent
//! deeper traversal by doing nothing.
//!
//! Note: it is an important invariant that the default visitor walks the body
//! of a function in "execution order" (more concretely, reverse post-order
//! with respect to the CFG implied by the AST), meaning that if AST node A may
//! execute before AST node B, then A is visited first. The borrow checker in
//! particular relies on this property.
//!
//! Note: walking an AST before macro expansion is probably a bad idea. For
//! instance, a walker looking for item names in a module will miss all of
//! those that are created by the expansion of a macro.
pub use rustc_ast_ir::visit::VisitorResult;
pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list};
use rustc_span::source_map::Spanned;
use rustc_span::{Ident, Span, Symbol};
use thin_vec::ThinVec;
use crate::ast::*;
use crate::tokenstream::DelimSpan;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AssocCtxt {
Trait,
Impl { of_trait: bool },
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum FnCtxt {
Free,
Foreign,
Assoc(AssocCtxt),
}
#[derive(Copy, Clone, Debug)]
pub enum BoundKind {
/// Trait bounds in generics bounds and type/trait alias.
/// E.g., `<T: Bound>`, `type A: Bound`, or `where T: Bound`.
Bound,
/// Trait bounds in `impl` type.
/// E.g., `type Foo = impl Bound1 + Bound2 + Bound3`.
Impl,
/// Trait bounds in trait object type.
/// E.g., `dyn Bound1 + Bound2 + Bound3`.
TraitObject,
/// Super traits of a trait.
/// E.g., `trait A: B`
SuperTraits,
}
impl BoundKind {
pub fn descr(self) -> &'static str {
match self {
BoundKind::Bound => "bounds",
BoundKind::Impl => "`impl Trait`",
BoundKind::TraitObject => "`dyn` trait object bounds",
BoundKind::SuperTraits => "supertrait bounds",
}
}
}
#[derive(Copy, Clone, Debug)]
pub enum LifetimeCtxt {
/// Appears in a reference type.
Ref,
/// Appears as a bound on a type or another lifetime.
Bound,
/// Appears as a generic argument.
GenericArg,
}
pub(crate) trait Visitable<'a, V: Visitor<'a>> {
type Extra: Copy;
#[must_use]
fn visit(&'a self, visitor: &mut V, extra: Self::Extra) -> V::Result;
}
impl<'a, V: Visitor<'a>, T: ?Sized> Visitable<'a, V> for Box<T>
where
T: Visitable<'a, V>,
{
type Extra = T::Extra;
fn visit(&'a self, visitor: &mut V, extra: Self::Extra) -> V::Result {
(**self).visit(visitor, extra)
}
}
impl<'a, V: Visitor<'a>, T> Visitable<'a, V> for Option<T>
where
T: Visitable<'a, V>,
{
type Extra = T::Extra;
fn visit(&'a self, visitor: &mut V, extra: Self::Extra) -> V::Result {
if let Some(this) = self {
try_visit!(this.visit(visitor, extra));
}
V::Result::output()
}
}
impl<'a, V: Visitor<'a>, T> Visitable<'a, V> for Spanned<T>
where
T: Visitable<'a, V>,
{
type Extra = T::Extra;
fn visit(&'a self, visitor: &mut V, extra: Self::Extra) -> V::Result {
let Spanned { span: _, node } = self;
node.visit(visitor, extra)
}
}
impl<'a, V: Visitor<'a>, T> Visitable<'a, V> for [T]
where
T: Visitable<'a, V>,
{
type Extra = T::Extra;
fn visit(&'a self, visitor: &mut V, extra: Self::Extra) -> V::Result {
for item in self {
try_visit!(item.visit(visitor, extra));
}
V::Result::output()
}
}
impl<'a, V: Visitor<'a>, T> Visitable<'a, V> for Vec<T>
where
T: Visitable<'a, V>,
{
type Extra = T::Extra;
fn visit(&'a self, visitor: &mut V, extra: Self::Extra) -> V::Result {
for item in self {
try_visit!(item.visit(visitor, extra));
}
V::Result::output()
}
}
impl<'a, V: Visitor<'a>, T> Visitable<'a, V> for (T,)
where
T: Visitable<'a, V>,
{
type Extra = T::Extra;
fn visit(&'a self, visitor: &mut V, extra: Self::Extra) -> V::Result {
self.0.visit(visitor, extra)
}
}
impl<'a, V: Visitor<'a>, T1, T2> Visitable<'a, V> for (T1, T2)
where
T1: Visitable<'a, V, Extra = ()>,
T2: Visitable<'a, V, Extra = ()>,
{
type Extra = ();
fn visit(&'a self, visitor: &mut V, extra: Self::Extra) -> V::Result {
try_visit!(self.0.visit(visitor, extra));
try_visit!(self.1.visit(visitor, extra));
V::Result::output()
}
}
impl<'a, V: Visitor<'a>, T1, T2, T3> Visitable<'a, V> for (T1, T2, T3)
where
T1: Visitable<'a, V, Extra = ()>,
T2: Visitable<'a, V, Extra = ()>,
T3: Visitable<'a, V, Extra = ()>,
{
type Extra = ();
fn visit(&'a self, visitor: &mut V, extra: Self::Extra) -> V::Result {
try_visit!(self.0.visit(visitor, extra));
try_visit!(self.1.visit(visitor, extra));
try_visit!(self.2.visit(visitor, extra));
V::Result::output()
}
}
impl<'a, V: Visitor<'a>, T1, T2, T3, T4> Visitable<'a, V> for (T1, T2, T3, T4)
where
T1: Visitable<'a, V, Extra = ()>,
T2: Visitable<'a, V, Extra = ()>,
T3: Visitable<'a, V, Extra = ()>,
T4: Visitable<'a, V, Extra = ()>,
{
type Extra = ();
fn visit(&'a self, visitor: &mut V, extra: Self::Extra) -> V::Result {
try_visit!(self.0.visit(visitor, extra));
try_visit!(self.1.visit(visitor, extra));
try_visit!(self.2.visit(visitor, extra));
try_visit!(self.3.visit(visitor, extra));
V::Result::output()
}
}
pub(crate) trait Walkable<'a, V: Visitor<'a>> {
#[must_use]
fn walk_ref(&'a self, visitor: &mut V) -> V::Result;
}
macro_rules! visit_visitable {
($visitor:expr, $($expr:expr),* $(,)?) => {{
$(try_visit!(Visitable::visit($expr, $visitor, ()));)*
}};
}
macro_rules! visit_visitable_with {
($visitor:expr, $expr:expr, $extra:expr $(,)?) => {
try_visit!(Visitable::visit($expr, $visitor, $extra))
};
}
macro_rules! walk_walkable {
($visitor:expr, $expr:expr, ) => {
Walkable::walk_ref($expr, $visitor)
};
}
macro_rules! impl_visitable {
(|&$lt:lifetime $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<$lt, $vis_ty: Visitor<$lt>> Visitable<$lt, $vis_ty> for $self_ty {
type Extra = $extra_ty;
fn visit(&$lt $self, $vis: &mut $vis_ty, $extra: Self::Extra) -> V::Result {
$block
}
}
};
}
macro_rules! impl_walkable {
($(<$K:ident: $Kb:ident>)? |&$lt:lifetime $self:ident: $self_ty:ty,
$vis:ident: &mut $vis_ty:ident| $block:block) => {
#[allow(unused_parens, non_local_definitions)]
impl<$($K: $Kb,)? $lt, $vis_ty: Visitor<$lt>> Walkable<$lt, $vis_ty> for $self_ty {
fn walk_ref(&$lt $self, $vis: &mut $vis_ty) -> V::Result {
$block
}
}
};
}
macro_rules! impl_visitable_noop {
(<$lt:lifetime> $($ty:ty,)*) => {
$(
impl_visitable!(|&$lt self: $ty, _vis: &mut V, _extra: ()| {
V::Result::output()
});
)*
};
}
macro_rules! impl_visitable_list {
(<$lt:lifetime> $($ty:ty,)*) => {
$(impl<$lt, V: Visitor<$lt>, T> Visitable<$lt, V> for $ty
where
&$lt $ty: IntoIterator<Item = &$lt T>,
T: $lt + Visitable<$lt, V>,
{
type Extra = <T as Visitable<$lt, V>>::Extra;
#[inline]
fn visit(&$lt self, visitor: &mut V, extra: Self::Extra) -> V::Result {
for i in self {
try_visit!(i.visit(visitor, extra));
}
V::Result::output()
}
})*
};
}
macro_rules! impl_visitable_direct {
(<$lt:lifetime> $($ty:ty,)*) => {
$(impl_visitable!(
|&$lt self: $ty, visitor: &mut V, _extra: ()| {
Walkable::walk_ref(self, visitor)
}
);)*
};
}
macro_rules! impl_visitable_calling_walkable {
(<$lt:lifetime>
$( fn $method:ident($ty:ty $(, $extra_name:ident: $extra_ty:ty)?); )*
) => {
$(fn $method(&mut self, node: &$lt $ty $(, $extra_name:$extra_ty)?) -> Self::Result {
impl_visitable!(|&$lt self: $ty, visitor: &mut V, extra: ($($extra_ty)?)| {
let ($($extra_name)?) = extra;
visitor.$method(self $(, $extra_name)?)
});
walk_walkable!(self, node, )
})*
};
}
macro_rules! define_named_walk {
($Visitor:ident<$lt:lifetime>
$( pub fn $method:ident($ty:ty); )*
) => {
$(pub fn $method<$lt, V: $Visitor<$lt>>(visitor: &mut V, node: &$lt $ty) -> V::Result {
walk_walkable!(visitor, node,)
})*
};
}
#[macro_export]
macro_rules! common_visitor_and_walkers {
($(($mut: ident))? $Visitor:ident$(<$lt:lifetime>)?) => {
$(${ignore($lt)}
#[derive(Copy, Clone)]
)?
#[derive(Debug)]
pub enum FnKind<'a> {
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
Fn(FnCtxt, &'a $($mut)? Visibility, &'a $($mut)? Fn),
/// E.g., `|x, y| body`.
Closure(&'a $($mut)? ClosureBinder, &'a $($mut)? Option<CoroutineKind>, &'a $($mut)? Box<FnDecl>, &'a $($mut)? Box<Expr>),
}
impl<'a> FnKind<'a> {
pub fn header(&'a $($mut)? self) -> Option<&'a $($mut)? FnHeader> {
match *self {
FnKind::Fn(_, _, Fn { sig, .. }) => Some(&$($mut)? sig.header),
FnKind::Closure(..) => None,
}
}
pub fn ident(&'a $($mut)? self) -> Option<&'a $($mut)? Ident> {
match self {
FnKind::Fn(_, _, Fn { ident, .. }) => Some(ident),
_ => None,
}
}
pub fn decl(&'a $($mut)? self) -> &'a $($mut)? FnDecl {
match self {
FnKind::Fn(_, _, Fn { sig, .. }) => &$($mut)? sig.decl,
FnKind::Closure(_, _, decl, _) => decl,
}
}
pub fn ctxt(&self) -> Option<FnCtxt> {
match self {
FnKind::Fn(ctxt, ..) => Some(*ctxt),
FnKind::Closure(..) => None,
}
}
}
// This macro generates `impl Visitable` and `impl MutVisitable` that do nothing.
impl_visitable_noop!(<$($lt)? $($mut)?>
AttrId,
bool,
rustc_span::ByteSymbol,
char,
crate::token::CommentKind,
crate::token::Delimiter,
crate::token::Lit,
crate::token::LitKind,
crate::tokenstream::LazyAttrTokenStream,
crate::tokenstream::TokenStream,
Movability,
Mutability,
Result<(), rustc_span::ErrorGuaranteed>,
rustc_data_structures::fx::FxHashMap<Symbol, usize>,
rustc_span::ErrorGuaranteed,
std::borrow::Cow<'_, str>,
Symbol,
u8,
usize,
);
// `Span` is only a no-op for the non-mutable visitor.
$(impl_visitable_noop!(<$lt> Span,);)?
// This macro generates `impl Visitable` and `impl MutVisitable` that simply iterate over
// their contents. We do not use a generic impl for `ThinVec` because we want to allow
// custom visits for the `MutVisitor`.
impl_visitable_list!(<$($lt)? $($mut)?>
ThinVec<AngleBracketedArg>,
ThinVec<Attribute>,
ThinVec<(Ident, Option<Ident>)>,
ThinVec<(NodeId, Path)>,
ThinVec<PathSegment>,
ThinVec<PreciseCapturingArg>,
ThinVec<Box<Pat>>,
ThinVec<Box<Ty>>,
ThinVec<Box<TyPat>>,
);
// This macro generates `impl Visitable` and `impl MutVisitable` that forward to `Walkable`
// or `MutWalkable`. By default, all types that do not have a custom visit method in the
// visitor should appear here.
impl_visitable_direct!(<$($lt)? $($mut)?>
AngleBracketedArg,
AngleBracketedArgs,
AsmMacro,
AssignOpKind,
AssocItemConstraintKind,
AttrArgs,
AttrItem,
AttrKind,
AttrStyle,
FnPtrTy,
BindingMode,
GenBlockKind,
RangeLimits,
UnsafeBinderCastKind,
BinOpKind,
BlockCheckMode,
BorrowKind,
BoundAsyncness,
BoundConstness,
BoundPolarity,
ByRef,
Closure,
Const,
ConstItem,
Defaultness,
Delegation,
DelegationMac,
DelimArgs,
DelimSpan,
EnumDef,
Extern,
ForLoopKind,
FormatArgPosition,
FormatArgsPiece,
FormatArgument,
FormatArgumentKind,
FormatArguments,
FormatPlaceholder,
GenericParamKind,
Impl,
ImplPolarity,
Inline,
InlineAsmOperand,
InlineAsmRegOrRegClass,
InlineAsmTemplatePiece,
IsAuto,
LocalKind,
MacCallStmt,
MacStmtStyle,
MatchKind,
MethodCall,
ModKind,
ModSpans,
MutTy,
NormalAttr,
Parens,
ParenthesizedArgs,
PatFieldsRest,
PatKind,
RangeEnd,
RangeSyntax,
Recovered,
Safety,
StaticItem,
StrLit,
StrStyle,
StructExpr,
StructRest,
Term,
Trait,
TraitBoundModifiers,
TraitObjectSyntax,
TyAlias,
TyAliasWhereClause,
TyAliasWhereClauses,
TyKind,
TyPatKind,
UnOp,
UnsafeBinderTy,
UnsafeSource,
UseTreeKind,
VisibilityKind,
WhereBoundPredicate,
WhereClause,
WhereEqPredicate,
WhereRegionPredicate,
YieldKind,
);
/// Each method of this trait is a hook to be potentially
/// overridden. Each method's default implementation recursively visits
/// the substructure of the input via the corresponding `walk` method;
#[doc = concat!(" e.g., the `visit_item` method by default calls `visit"$(, "_", stringify!($mut))?, "::walk_item`.")]
///
/// If you want to ensure that your code handles every variant
/// explicitly, you need to override each method. (And you also need
/// to monitor future changes to this trait in case a new method with a
/// new default implementation gets introduced.)
///
/// Every `walk_*` method uses deconstruction to access fields of structs and
/// enums. This will result in a compile error if a field is added, which makes
/// it more likely the appropriate visit call will be added for it.
pub trait $Visitor<$($lt)?> : Sized $(${ignore($mut)} + MutVisitorResult<Result = ()>)? {
$(
${ignore($lt)}
/// The result type of the `visit_*` methods. Can be either `()`,
/// or `ControlFlow<T>`.
type Result: VisitorResult = ();
)?
// Methods in this trait have one of three forms, with the last two forms
// only occurring on `MutVisitor`:
//
// fn visit_t(&mut self, t: &mut T); // common
// fn flat_map_t(&mut self, t: T) -> SmallVec<[T; 1]>; // rare
// fn filter_map_t(&mut self, t: T) -> Option<T>; // rarest
//
// When writing these methods, it is better to use destructuring like this:
//
// fn visit_abc(&mut self, ABC { a, b, c: _ }: &mut ABC) {
// visit_a(a);
// visit_b(b);
// }
//
// than to use field access like this:
//
// fn visit_abc(&mut self, abc: &mut ABC) {
// visit_a(&mut abc.a);
// visit_b(&mut abc.b);
// // ignore abc.c
// }
//
// As well as being more concise, the former is explicit about which fields
// are skipped. Furthermore, if a new field is added, the destructuring
// version will cause a compile error, which is good. In comparison, the
// field access version will continue working and it would be easy to
// forget to add handling for it.
fn visit_ident(&mut self, Ident { name: _, span }: &$($lt)? $($mut)? Ident) -> Self::Result {
impl_visitable!(|&$($lt)? $($mut)? self: Ident, visitor: &mut V, _extra: ()| {
visitor.visit_ident(self)
});
visit_span(self, span)
}
// This macro defines a custom visit method for each listed type.
// It implements `impl Visitable` and `impl MutVisitable` to call those methods on the
// visitor.
impl_visitable_calling_walkable!(<$($lt)? $($mut)?>
fn visit_anon_const(AnonConst);
fn visit_arm(Arm);
//fn visit_assoc_item(AssocItem, _ctxt: AssocCtxt);
fn visit_assoc_item_constraint(AssocItemConstraint);
fn visit_attribute(Attribute);
fn visit_block(Block);
//fn visit_nested_use_tree((UseTree, NodeId));
fn visit_capture_by(CaptureBy);
fn visit_closure_binder(ClosureBinder);
fn visit_contract(FnContract);
fn visit_coroutine_kind(CoroutineKind);
fn visit_crate(Crate);
fn visit_expr(Expr);
fn visit_expr_field(ExprField);
fn visit_field_def(FieldDef);
fn visit_fn_decl(FnDecl);
fn visit_fn_header(FnHeader);
fn visit_fn_ret_ty(FnRetTy);
//fn visit_foreign_item(ForeignItem);
fn visit_foreign_mod(ForeignMod);
fn visit_format_args(FormatArgs);
fn visit_generic_arg(GenericArg);
fn visit_generic_args(GenericArgs);
fn visit_generic_param(GenericParam);
fn visit_generics(Generics);
fn visit_inline_asm(InlineAsm);
fn visit_inline_asm_sym(InlineAsmSym);
//fn visit_item(Item);
fn visit_label(Label);
fn visit_lifetime(Lifetime, _ctxt: LifetimeCtxt);
fn visit_local(Local);
fn visit_mac_call(MacCall);
fn visit_macro_def(MacroDef);
fn visit_param_bound(GenericBound, _ctxt: BoundKind);
fn visit_param(Param);
fn visit_pat_field(PatField);
fn visit_path(Path);
fn visit_path_segment(PathSegment);
fn visit_pat(Pat);
fn visit_poly_trait_ref(PolyTraitRef);
fn visit_precise_capturing_arg(PreciseCapturingArg);
fn visit_qself(QSelf);
fn visit_trait_ref(TraitRef);
fn visit_ty_pat(TyPat);
fn visit_ty(Ty);
fn visit_use_tree(UseTree);
fn visit_variant_data(VariantData);
fn visit_variant(Variant);
fn visit_vis(Visibility);
fn visit_where_predicate_kind(WherePredicateKind);
fn visit_where_predicate(WherePredicate);
);
// We want `Visitor` to take the `NodeId` by value.
fn visit_id(&mut self, _id: $(&$mut)? NodeId) -> Self::Result {
$(impl_visitable!(
|&$lt self: NodeId, visitor: &mut V, _extra: ()| {
visitor.visit_id(*self)
}
);)?
$(impl_visitable!(
|&$mut self: NodeId, visitor: &mut V, _extra: ()| {
visitor.visit_id(self)
}
);)?
Self::Result::output()
}
/// This method is a hack to workaround unstable of `stmt_expr_attributes`.
/// It can be removed once that feature is stabilized.
fn visit_method_receiver_expr(&mut self, ex: &$($lt)? $($mut)? Expr) -> Self::Result {
self.visit_expr(ex)
}
fn visit_item(&mut self, item: &$($lt)? $($mut)? Item) -> Self::Result {
impl_visitable!(|&$($lt)? $($mut)? self: Item, vis: &mut V, _extra: ()| {
vis.visit_item(self)
});
walk_item(self, item)
}
fn visit_foreign_item(&mut self, item: &$($lt)? $($mut)? ForeignItem) -> Self::Result {
impl_visitable!(|&$($lt)? $($mut)? self: ForeignItem, vis: &mut V, _extra: ()| {
vis.visit_foreign_item(self)
});
walk_item(self, item)
}
fn visit_assoc_item(&mut self, item: &$($lt)? $($mut)? AssocItem, ctxt: AssocCtxt) -> Self::Result {
impl_visitable!(|&$($lt)? $($mut)? self: AssocItem, vis: &mut V, ctxt: AssocCtxt| {
vis.visit_assoc_item(self, ctxt)
});
walk_assoc_item(self, item, ctxt)
}
// for `MutVisitor`: `Span` and `NodeId` are mutated at the caller site.
fn visit_fn(
&mut self,
fk: FnKind<$($lt)? $(${ignore($mut)} '_)?>,
_: Span,
_: NodeId
) -> Self::Result {
walk_fn(self, fk)
}
// (non-mut) `Visitor`-only methods
$(
fn visit_stmt(&mut self, s: &$lt Stmt) -> Self::Result {
walk_stmt(self, s)
}
fn visit_nested_use_tree(&mut self, use_tree: &$lt UseTree, id: NodeId) -> Self::Result {
try_visit!(self.visit_id(id));
self.visit_use_tree(use_tree)
}
)?
// `MutVisitor`-only methods
$(
// Span visiting is no longer used, but we keep it for now,
// in case it's needed for something like #127241.
#[inline]
fn visit_span(&mut self, _sp: &$mut Span) {
impl_visitable!(|&mut self: Span, visitor: &mut V, _extra: ()| {
visitor.visit_span(self)
});
// Do nothing.
}
fn flat_map_foreign_item(&mut self, ni: Box<ForeignItem>) -> SmallVec<[Box<ForeignItem>; 1]> {
walk_flat_map_foreign_item(self, ni)
}
fn flat_map_item(&mut self, i: Box<Item>) -> SmallVec<[Box<Item>; 1]> {
walk_flat_map_item(self, i)
}
fn flat_map_field_def(&mut self, fd: FieldDef) -> SmallVec<[FieldDef; 1]> {
walk_flat_map_field_def(self, fd)
}
fn flat_map_assoc_item(
&mut self,
i: Box<AssocItem>,
ctxt: AssocCtxt,
) -> SmallVec<[Box<AssocItem>; 1]> {
walk_flat_map_assoc_item(self, i, ctxt)
}
fn flat_map_stmt(&mut self, s: Stmt) -> SmallVec<[Stmt; 1]> {
walk_flat_map_stmt(self, s)
}
fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> {
walk_flat_map_arm(self, arm)
}
fn filter_map_expr(&mut self, e: Box<Expr>) -> Option<Box<Expr>> {
walk_filter_map_expr(self, e)
}
fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> {
walk_flat_map_variant(self, v)
}
fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> {
walk_flat_map_param(self, param)
}
fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> {
walk_flat_map_generic_param(self, param)
}
fn flat_map_expr_field(&mut self, f: ExprField) -> SmallVec<[ExprField; 1]> {
walk_flat_map_expr_field(self, f)
}
fn flat_map_where_predicate(
&mut self,
where_predicate: WherePredicate,
) -> SmallVec<[WherePredicate; 1]> {
walk_flat_map_where_predicate(self, where_predicate)
}
fn flat_map_pat_field(&mut self, fp: PatField) -> SmallVec<[PatField; 1]> {
walk_flat_map_pat_field(self, fp)
}
)?
}
pub trait WalkItemKind {
type Ctxt;
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
&$($lt)? $($mut)? self,
span: Span,
id: NodeId,
visibility: &$($lt)? $($mut)? Visibility,
ctxt: Self::Ctxt,
vis: &mut V,
) -> V::Result;
}
// this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier
$(${ignore($lt)}
#[expect(unused, rustc::pass_by_value)]
#[inline]
)?
fn visit_span<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, span: &$($lt)? $($mut)? Span) -> V::Result {
$(${ignore($mut)} vis.visit_span(span))?;
V::Result::output()
}
$(impl_visitable!(|&$lt self: ThinVec<(UseTree, NodeId)>, vis: &mut V, _extra: ()| {
for (nested_tree, nested_id) in self {
try_visit!(vis.visit_nested_use_tree(nested_tree, *nested_id));
}
V::Result::output()
});)?
$(impl_visitable_list!(<$mut> ThinVec<(UseTree, NodeId)>,);)?
fn walk_item_inner<$($lt,)? K: WalkItemKind, V: $Visitor$(<$lt>)?>(
visitor: &mut V,
item: &$($mut)? $($lt)? Item<K>,
ctxt: K::Ctxt,
) -> V::Result {
let Item { attrs, id, kind, vis, span, tokens: _ } = item;
visit_visitable!($($mut)? visitor, id, attrs, vis);
try_visit!(kind.walk(*span, *id, vis, ctxt, visitor));
visit_visitable!($($mut)? visitor, span);
V::Result::output()
}
// Do not implement `Walkable`/`MutWalkable` for *Item to avoid confusion.
pub fn walk_item<$($lt,)? K: WalkItemKind<Ctxt = ()>, V: $Visitor$(<$lt>)?>(
visitor: &mut V,
item: &$($mut)? $($lt)? Item<K>,
) -> V::Result {
walk_item_inner(visitor, item, ())
}
// Do not implement `Walkable`/`MutWalkable` for *Item to avoid confusion.
pub fn walk_assoc_item<$($lt,)? K: WalkItemKind<Ctxt = AssocCtxt>, V: $Visitor$(<$lt>)?>(
visitor: &mut V,
item: &$($mut)? $($lt)? Item<K>,
ctxt: AssocCtxt,
) -> V::Result {
walk_item_inner(visitor, item, ctxt)
}
impl WalkItemKind for ItemKind {
type Ctxt = ();
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
&$($lt)? $($mut)? self,
span: Span,
id: NodeId,
visibility: &$($lt)? $($mut)? Visibility,
_ctxt: Self::Ctxt,
vis: &mut V,
) -> V::Result {
match self {
ItemKind::Fn(func) => {
let kind = FnKind::Fn(FnCtxt::Free, visibility, &$($mut)? *func);
try_visit!(vis.visit_fn(kind, span, id));
}
ItemKind::ExternCrate(orig_name, ident) =>
visit_visitable!($($mut)? vis, orig_name, ident),
ItemKind::Use(use_tree) =>
visit_visitable!($($mut)? vis, use_tree),
ItemKind::Static(item) =>
visit_visitable!($($mut)? vis, item),
ItemKind::Const(item) =>
visit_visitable!($($mut)? vis, item),
ItemKind::Mod(safety, ident, mod_kind) =>
visit_visitable!($($mut)? vis, safety, ident, mod_kind),
ItemKind::ForeignMod(nm) =>
visit_visitable!($($mut)? vis, nm),
ItemKind::GlobalAsm(asm) =>
visit_visitable!($($mut)? vis, asm),
ItemKind::TyAlias(ty_alias) =>
visit_visitable!($($mut)? vis, ty_alias),
ItemKind::Enum(ident, generics, enum_definition) =>
visit_visitable!($($mut)? vis, ident, generics, enum_definition),
ItemKind::Struct(ident, generics, variant_data)
| ItemKind::Union(ident, generics, variant_data) =>
visit_visitable!($($mut)? vis, ident, generics, variant_data),
ItemKind::Impl(impl_) =>
visit_visitable!($($mut)? vis, impl_),
ItemKind::Trait(trait_) =>
visit_visitable!($($mut)? vis, trait_),
ItemKind::TraitAlias(ident, generics, bounds) => {
visit_visitable!($($mut)? vis, ident, generics);
visit_visitable_with!($($mut)? vis, bounds, BoundKind::Bound)
}
ItemKind::MacCall(m) =>
visit_visitable!($($mut)? vis, m),
ItemKind::MacroDef(ident, def) =>
visit_visitable!($($mut)? vis, ident, def),
ItemKind::Delegation(delegation) =>
visit_visitable!($($mut)? vis, delegation),
ItemKind::DelegationMac(dm) =>
visit_visitable!($($mut)? vis, dm),
}
V::Result::output()
}
}
impl WalkItemKind for AssocItemKind {
type Ctxt = AssocCtxt;
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
&$($lt)? $($mut)? self,
span: Span,
id: NodeId,
visibility: &$($lt)? $($mut)? Visibility,
ctxt: Self::Ctxt,
vis: &mut V,
) -> V::Result {
match self {
AssocItemKind::Const(item) =>
visit_visitable!($($mut)? vis, item),
AssocItemKind::Fn(func) => {
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), visibility, &$($mut)? *func);
try_visit!(vis.visit_fn(kind, span, id))
}
AssocItemKind::Type(alias) =>
visit_visitable!($($mut)? vis, alias),
AssocItemKind::MacCall(mac) =>
visit_visitable!($($mut)? vis, mac),
AssocItemKind::Delegation(delegation) =>
visit_visitable!($($mut)? vis, delegation),
AssocItemKind::DelegationMac(dm) =>
visit_visitable!($($mut)? vis, dm),
}
V::Result::output()
}
}
impl WalkItemKind for ForeignItemKind {
type Ctxt = ();
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
&$($lt)? $($mut)? self,
span: Span,
id: NodeId,
visibility: &$($lt)? $($mut)? Visibility,
_ctxt: Self::Ctxt,
vis: &mut V,
) -> V::Result {
match self {
ForeignItemKind::Static(item) =>
visit_visitable!($($mut)? vis, item),
ForeignItemKind::Fn(func) => {
let kind = FnKind::Fn(FnCtxt::Foreign, visibility, &$($mut)?*func);
try_visit!(vis.visit_fn(kind, span, id))
}
ForeignItemKind::TyAlias(alias) =>
visit_visitable!($($mut)? vis, alias),
ForeignItemKind::MacCall(mac) =>
visit_visitable!($($mut)? vis, mac),
}
V::Result::output()
}
}
pub fn walk_fn<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, kind: FnKind<$($lt)? $(${ignore($mut)} '_)?>) -> V::Result {
match kind {
FnKind::Fn(
_ctxt,
// Visibility is visited as a part of the item.
_vis,
Fn { defaultness, ident, sig, generics, contract, body, define_opaque },
) => {
let FnSig { header, decl, span } = sig;
visit_visitable!($($mut)? vis,
defaultness, ident, header, generics, decl,
contract, body, span, define_opaque
)
}
FnKind::Closure(binder, coroutine_kind, decl, body) =>
visit_visitable!($($mut)? vis, binder, coroutine_kind, decl, body),
}
V::Result::output()
}
impl_walkable!(|&$($mut)? $($lt)? self: Impl, vis: &mut V| {
let Impl { generics, of_trait, self_ty, items } = self;
try_visit!(vis.visit_generics(generics));
if let Some(box of_trait) = of_trait {
let TraitImplHeader { defaultness, safety, constness, polarity, trait_ref } = of_trait;
visit_visitable!($($mut)? vis, defaultness, safety, constness, polarity, trait_ref);
}
try_visit!(vis.visit_ty(self_ty));
visit_visitable_with!($($mut)? vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() });
V::Result::output()
});
// Special case to call `visit_method_receiver_expr`.
impl_walkable!(|&$($mut)? $($lt)? self: MethodCall, vis: &mut V| {
let MethodCall { seg, receiver, args, span } = self;
try_visit!(vis.visit_method_receiver_expr(receiver));
visit_visitable!($($mut)? vis, seg, args, span);
V::Result::output()
});
impl_walkable!(|&$($mut)? $($lt)? self: Expr, vis: &mut V| {
let Expr { id, kind, span, attrs, tokens: _ } = self;
visit_visitable!($($mut)? vis, id, attrs);
match kind {
ExprKind::Array(exprs) =>
visit_visitable!($($mut)? vis, exprs),
ExprKind::ConstBlock(anon_const) =>
visit_visitable!($($mut)? vis, anon_const),
ExprKind::Repeat(element, count) =>
visit_visitable!($($mut)? vis, element, count),
ExprKind::Struct(se) =>
visit_visitable!($($mut)? vis, se),
ExprKind::Tup(exprs) =>
visit_visitable!($($mut)? vis, exprs),
ExprKind::Call(callee_expression, arguments) =>
visit_visitable!($($mut)? vis, callee_expression, arguments),
ExprKind::MethodCall(mc) =>
visit_visitable!($($mut)? vis, mc),
ExprKind::Binary(op, lhs, rhs) =>
visit_visitable!($($mut)? vis, op, lhs, rhs),
ExprKind::AddrOf(kind, mutbl, subexpression) =>
visit_visitable!($($mut)? vis, kind, mutbl, subexpression),
ExprKind::Unary(op, subexpression) =>
visit_visitable!($($mut)? vis, op, subexpression),
ExprKind::Cast(subexpression, typ) | ExprKind::Type(subexpression, typ) =>
visit_visitable!($($mut)? vis, subexpression, typ),
ExprKind::Let(pat, expr, span, _recovered) =>
visit_visitable!($($mut)? vis, pat, expr, span),
ExprKind::If(head_expression, if_block, optional_else) =>
visit_visitable!($($mut)? vis, head_expression, if_block, optional_else),
ExprKind::While(subexpression, block, opt_label) =>
visit_visitable!($($mut)? vis, subexpression, block, opt_label),
ExprKind::ForLoop { pat, iter, body, label, kind } =>
visit_visitable!($($mut)? vis, pat, iter, body, label, kind),
ExprKind::Loop(block, opt_label, span) =>
visit_visitable!($($mut)? vis, block, opt_label, span),
ExprKind::Match(subexpression, arms, kind) =>
visit_visitable!($($mut)? vis, subexpression, arms, kind),
ExprKind::Closure(box Closure {
binder,
capture_clause,
coroutine_kind,
constness,
movability,
fn_decl,
body,
fn_decl_span,
fn_arg_span,
}) => {
visit_visitable!($($mut)? vis, constness, movability, capture_clause);
let kind = FnKind::Closure(binder, coroutine_kind, fn_decl, body);
try_visit!(vis.visit_fn(kind, *span, *id));
visit_visitable!($($mut)? vis, fn_decl_span, fn_arg_span);
}
ExprKind::Block(block, opt_label) =>
visit_visitable!($($mut)? vis, block, opt_label),
ExprKind::Gen(capt, body, kind, decl_span) =>
visit_visitable!($($mut)? vis, capt, body, kind, decl_span),
ExprKind::Await(expr, span) | ExprKind::Use(expr, span) =>
visit_visitable!($($mut)? vis, expr, span),
ExprKind::Assign(lhs, rhs, span) =>
visit_visitable!($($mut)? vis, lhs, rhs, span),
ExprKind::AssignOp(op, lhs, rhs) =>
visit_visitable!($($mut)? vis, op, lhs, rhs),
ExprKind::Field(subexpression, ident) =>
visit_visitable!($($mut)? vis, subexpression, ident),
ExprKind::Index(main_expression, index_expression, span) =>
visit_visitable!($($mut)? vis, main_expression, index_expression, span),
ExprKind::Range(start, end, limit) =>
visit_visitable!($($mut)? vis, start, end, limit),
ExprKind::Underscore => {}
ExprKind::Path(maybe_qself, path) =>
visit_visitable!($($mut)? vis, maybe_qself, path),
ExprKind::Break(opt_label, opt_expr) =>
visit_visitable!($($mut)? vis, opt_label, opt_expr),
ExprKind::Continue(opt_label) =>
visit_visitable!($($mut)? vis, opt_label),
ExprKind::Ret(optional_expression) | ExprKind::Yeet(optional_expression) =>
visit_visitable!($($mut)? vis, optional_expression),
ExprKind::Become(expr) =>
visit_visitable!($($mut)? vis, expr),
ExprKind::MacCall(mac) =>
visit_visitable!($($mut)? vis, mac),
ExprKind::Paren(subexpression) =>
visit_visitable!($($mut)? vis, subexpression),
ExprKind::InlineAsm(asm) =>
visit_visitable!($($mut)? vis, asm),
ExprKind::FormatArgs(f) =>
visit_visitable!($($mut)? vis, f),
ExprKind::OffsetOf(container, fields) =>
visit_visitable!($($mut)? vis, container, fields),
ExprKind::Yield(kind) =>
visit_visitable!($($mut)? vis, kind),
ExprKind::Try(subexpression) =>
visit_visitable!($($mut)? vis, subexpression),
ExprKind::TryBlock(body) =>
visit_visitable!($($mut)? vis, body),
ExprKind::Lit(token) =>
visit_visitable!($($mut)? vis, token),
ExprKind::IncludedBytes(bytes) =>
visit_visitable!($($mut)? vis, bytes),
ExprKind::UnsafeBinderCast(kind, expr, ty) =>
visit_visitable!($($mut)? vis, kind, expr, ty),
ExprKind::Err(_guar) => {}
ExprKind::Dummy => {}
}
visit_span(vis, span)
});
define_named_walk!($(($mut))? $Visitor$(<$lt>)?
pub fn walk_anon_const(AnonConst);
pub fn walk_arm(Arm);
//pub fn walk_assoc_item(AssocItem, _ctxt: AssocCtxt);
pub fn walk_assoc_item_constraint(AssocItemConstraint);
pub fn walk_attribute(Attribute);
pub fn walk_block(Block);
//pub fn walk_nested_use_tree((UseTree, NodeId));
pub fn walk_capture_by(CaptureBy);
pub fn walk_closure_binder(ClosureBinder);
pub fn walk_contract(FnContract);
pub fn walk_coroutine_kind(CoroutineKind);
pub fn walk_crate(Crate);
pub fn walk_expr(Expr);
pub fn walk_expr_field(ExprField);
pub fn walk_field_def(FieldDef);
pub fn walk_fn_decl(FnDecl);
pub fn walk_fn_header(FnHeader);
pub fn walk_fn_ret_ty(FnRetTy);
//pub fn walk_foreign_item(ForeignItem);
pub fn walk_foreign_mod(ForeignMod);
pub fn walk_format_args(FormatArgs);
pub fn walk_generic_arg(GenericArg);
pub fn walk_generic_args(GenericArgs);
pub fn walk_generic_param(GenericParam);
pub fn walk_generics(Generics);
pub fn walk_inline_asm(InlineAsm);
pub fn walk_inline_asm_sym(InlineAsmSym);
//pub fn walk_item(Item);
pub fn walk_label(Label);
pub fn walk_lifetime(Lifetime);
pub fn walk_local(Local);
pub fn walk_mac(MacCall);
pub fn walk_macro_def(MacroDef);
pub fn walk_param_bound(GenericBound);
pub fn walk_param(Param);
pub fn walk_pat_field(PatField);
pub fn walk_path(Path);
pub fn walk_path_segment(PathSegment);
pub fn walk_pat(Pat);
pub fn walk_poly_trait_ref(PolyTraitRef);
pub fn walk_precise_capturing_arg(PreciseCapturingArg);
pub fn walk_qself(QSelf);
pub fn walk_trait_ref(TraitRef);
pub fn walk_ty_pat(TyPat);
pub fn walk_ty(Ty);
pub fn walk_use_tree(UseTree);
pub fn walk_variant_data(VariantData);
pub fn walk_variant(Variant);
pub fn walk_vis(Visibility);
pub fn walk_where_predicate_kind(WherePredicateKind);
pub fn walk_where_predicate(WherePredicate);
);
};
}
common_visitor_and_walkers!(Visitor<'a>);
macro_rules! generate_list_visit_fns {
($($name:ident, $Ty:ty, $visit_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => {
$(
#[allow(unused_parens)]
impl<'a, V: Visitor<'a>> Visitable<'a, V> for ThinVec<$Ty> {
type Extra = ($($ParamTy),*);
#[inline]
fn visit(
&'a self,
visitor: &mut V,
($($param),*): Self::Extra,
) -> V::Result {
$name(visitor, self $(, $param)*)
}
}
fn $name<'a, V: Visitor<'a>>(
vis: &mut V,
values: &'a ThinVec<$Ty>,
$(
$param: $ParamTy,
)*
) -> V::Result {
walk_list!(vis, $visit_fn, values$(,$param)*);
V::Result::output()
}
)+
}
}
generate_list_visit_fns! {
visit_items, Box<Item>, visit_item;
visit_foreign_items, Box<ForeignItem>, visit_foreign_item;
visit_generic_params, GenericParam, visit_generic_param;
visit_stmts, Stmt, visit_stmt;
visit_exprs, Box<Expr>, visit_expr;
visit_expr_fields, ExprField, visit_expr_field;
visit_pat_fields, PatField, visit_pat_field;
visit_variants, Variant, visit_variant;
visit_assoc_items, Box<AssocItem>, visit_assoc_item, ctxt: AssocCtxt;
visit_where_predicates, WherePredicate, visit_where_predicate;
visit_params, Param, visit_param;
visit_field_defs, FieldDef, visit_field_def;
visit_arms, Arm, visit_arm;
}
pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result {
let Stmt { id, kind, span: _ } = statement;
try_visit!(visitor.visit_id(*id));
match kind {
StmtKind::Let(local) => try_visit!(visitor.visit_local(local)),
StmtKind::Item(item) => try_visit!(visitor.visit_item(item)),
StmtKind::Expr(expr) | StmtKind::Semi(expr) => try_visit!(visitor.visit_expr(expr)),
StmtKind::Empty => {}
StmtKind::MacCall(mac) => {
let MacCallStmt { mac, attrs, style: _, tokens: _ } = &**mac;
walk_list!(visitor, visit_attribute, attrs);
try_visit!(visitor.visit_mac_call(mac));
}
}
V::Result::output()
}