mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Since availability scopes may be built at arbitrary times, the builder may encounter ASTs where SequenceExprs still exist and have not been folded, or it may encounter folded SequenceExprs that have not been removed from the AST. To avoid a double visit, track whether a SequenceExpr is folded and then customize how ASTVisitor handles folded sequences. Resolves rdar://142824799 and https://github.com/swiftlang/swift/issues/78567.
768 lines
26 KiB
C++
768 lines
26 KiB
C++
//===--- ASTWalker.h - Class for walking the AST ----------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_AST_ASTWALKER_H
|
|
#define SWIFT_AST_ASTWALKER_H
|
|
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "llvm/ADT/PointerUnion.h"
|
|
#include <optional>
|
|
#include <utility>
|
|
|
|
namespace swift {
|
|
|
|
class Argument;
|
|
class ArgumentList;
|
|
class Decl;
|
|
class Expr;
|
|
class ClosureExpr;
|
|
class CustomAttr;
|
|
class ModuleDecl;
|
|
class PackageUnit;
|
|
class Stmt;
|
|
class Pattern;
|
|
class TypeRepr;
|
|
class ParameterList;
|
|
enum class AccessKind: unsigned char;
|
|
|
|
enum class SemaReferenceKind : uint8_t {
|
|
ModuleRef = 0,
|
|
DeclRef,
|
|
DeclMemberRef,
|
|
DeclConstructorRef,
|
|
TypeRef,
|
|
EnumElementRef,
|
|
SubscriptRef,
|
|
DynamicMemberRef,
|
|
};
|
|
|
|
struct ReferenceMetaData {
|
|
SemaReferenceKind Kind;
|
|
std::optional<AccessKind> AccKind;
|
|
bool isImplicit = false;
|
|
bool isImplicitCtorType = false;
|
|
|
|
/// When non-none, this is a custom attribute reference.
|
|
std::optional<std::pair<const CustomAttr *, Decl *>> CustomAttrRef;
|
|
|
|
ReferenceMetaData(SemaReferenceKind Kind, std::optional<AccessKind> AccKind,
|
|
bool isImplicit = false,
|
|
std::optional<std::pair<const CustomAttr *, Decl *>>
|
|
customAttrRef = std::nullopt)
|
|
: Kind(Kind), AccKind(AccKind), isImplicit(isImplicit),
|
|
CustomAttrRef(customAttrRef) {}
|
|
};
|
|
|
|
/// Specifies how the initialization expression of a \c lazy variable should be
|
|
/// walked by the ASTWalker.
|
|
enum class LazyInitializerWalking {
|
|
/// No lazy initialization expressions will be walked.
|
|
None,
|
|
|
|
/// The lazy initialization expression will only be walked as a part of
|
|
/// the variable's pattern binding decl. This is the default behavior, and is
|
|
/// consistent with the initializer being syntactically part of the pattern
|
|
/// binding.
|
|
InPatternBinding,
|
|
|
|
/// The lazy initialization expression will only be walked as part of the
|
|
/// body of the synthesized accessor for the lazy variable. In such an
|
|
/// accessor, the expression is denoted by LazyInitializerExpr. This is mainly
|
|
/// useful for code emission.
|
|
InAccessor
|
|
};
|
|
|
|
/// Specifies the behavior for walking a macro expansion, whether we want to
|
|
/// see the macro arguments, the expansion, or both.
|
|
enum class MacroWalking {
|
|
/// Walk into the expansion of the macro, to see the semantic effect of
|
|
/// the macro expansion.
|
|
Expansion,
|
|
|
|
/// Walk into the arguments of the macro as written in the source code.
|
|
///
|
|
/// The actual arguments walked may not make it into the program itself,
|
|
/// because they can be translated by the macro in arbitrary ways.
|
|
Arguments,
|
|
|
|
/// Walk into both the arguments of the macro as written in the source code
|
|
/// and also the macro expansion.
|
|
ArgumentsAndExpansion,
|
|
|
|
/// Don't walk into macros.
|
|
None
|
|
};
|
|
|
|
/// A scheme for walking a `QualifiedIdentTypeRepr`.
|
|
enum class QualifiedIdentTypeReprWalkingScheme {
|
|
/// Walk in source order, such that each subsequent dot-separated component is
|
|
/// a child of the previous one. For example, walk `A.B<T.U>.C` like so
|
|
/// (top-down order):
|
|
///
|
|
/// ```
|
|
/// A
|
|
/// ╰─B
|
|
/// ├─T
|
|
/// │ ╰─U
|
|
/// ╰─C
|
|
/// ```
|
|
SourceOrderRecursive,
|
|
|
|
/// Walk in AST order (that is, according to how member type
|
|
/// representations are modeled in the AST, such that each previous
|
|
/// dot-separated component is a child of the subsequent one), base before
|
|
/// generic arguments. For example, walk `A.B<T.U>.C` like so
|
|
/// (top-down order):
|
|
///
|
|
/// ```
|
|
/// C
|
|
/// ╰─B
|
|
/// ├─A
|
|
/// ╰─U
|
|
/// ╰─T
|
|
/// ```
|
|
ASTOrderRecursive
|
|
};
|
|
|
|
/// Specifies the behavior for walking SequenceExprs.
|
|
enum class SequenceWalking {
|
|
/// Walk into every element of the sequence, regardless of what state the
|
|
/// sequence is in.
|
|
Default,
|
|
|
|
/// If the sequence has been folded by type checking, only walk into the
|
|
/// elements that represent the operator nodes. This will ensure that the walk
|
|
/// does not visit the same AST nodes twice when it encounters a sequence that
|
|
/// has already been folded but hasn't been removed from the AST.
|
|
OnlyWalkFirstOperatorWhenFolded
|
|
};
|
|
|
|
/// An abstract class used to traverse an AST.
|
|
class ASTWalker {
|
|
public:
|
|
enum class ParentKind {
|
|
Package, Module, Decl, Stmt, Expr, Pattern, TypeRepr
|
|
};
|
|
|
|
class ParentTy {
|
|
ParentKind Kind;
|
|
void *Ptr = nullptr;
|
|
|
|
public:
|
|
ParentTy(PackageUnit *Pkg) : Kind(ParentKind::Package), Ptr(Pkg) {}
|
|
ParentTy(ModuleDecl *Mod) : Kind(ParentKind::Module), Ptr(Mod) {}
|
|
ParentTy(Decl *D) : Kind(ParentKind::Decl), Ptr(D) {}
|
|
ParentTy(Stmt *S) : Kind(ParentKind::Stmt), Ptr(S) {}
|
|
ParentTy(Expr *E) : Kind(ParentKind::Expr), Ptr(E) {}
|
|
ParentTy(Pattern *P) : Kind(ParentKind::Pattern), Ptr(P) {}
|
|
ParentTy(TypeRepr *T) : Kind(ParentKind::TypeRepr), Ptr(T) {}
|
|
ParentTy() : Kind(ParentKind::Module), Ptr(nullptr) { }
|
|
|
|
bool isNull() const { return Ptr == nullptr; }
|
|
ParentKind getKind() const {
|
|
assert(!isNull());
|
|
return Kind;
|
|
}
|
|
|
|
PackageUnit *getAsPackage() const {
|
|
return Kind == ParentKind::Package ? static_cast<PackageUnit*>(Ptr)
|
|
: nullptr;
|
|
}
|
|
ModuleDecl *getAsModule() const {
|
|
return Kind == ParentKind::Module ? static_cast<ModuleDecl*>(Ptr)
|
|
: nullptr;
|
|
}
|
|
Decl *getAsDecl() const {
|
|
return Kind == ParentKind::Decl ? static_cast<Decl*>(Ptr) : nullptr;
|
|
}
|
|
Stmt *getAsStmt() const {
|
|
return Kind == ParentKind::Stmt ? static_cast<Stmt*>(Ptr) : nullptr;
|
|
}
|
|
Expr *getAsExpr() const {
|
|
return Kind == ParentKind::Expr ? static_cast<Expr*>(Ptr) : nullptr;
|
|
}
|
|
Pattern *getAsPattern() const {
|
|
return Kind == ParentKind::Pattern ? static_cast<Pattern*>(Ptr) : nullptr;
|
|
}
|
|
TypeRepr *getAsTypeRepr() const {
|
|
return Kind==ParentKind::TypeRepr ? static_cast<TypeRepr*>(Ptr) : nullptr;
|
|
}
|
|
};
|
|
|
|
/// The parent of the node we are visiting.
|
|
ParentTy Parent;
|
|
|
|
struct _Detail {
|
|
_Detail() = delete;
|
|
|
|
// The 'Action' set of types, which do not take a payload.
|
|
struct ContinueWalkAction {};
|
|
struct SkipChildrenIfWalkAction { bool Cond; bool SkipPostWalk; };
|
|
struct StopIfWalkAction { bool Cond; };
|
|
struct StopWalkAction {};
|
|
|
|
// The 'Result' set of types, which do take a payload.
|
|
template <typename T>
|
|
struct ContinueWalkResult {
|
|
ContinueWalkAction Action;
|
|
T Value;
|
|
};
|
|
template <typename T>
|
|
struct SkipChildrenIfWalkResult {
|
|
SkipChildrenIfWalkAction Action;
|
|
T Value;
|
|
};
|
|
template <typename T>
|
|
struct StopIfWalkResult {
|
|
StopIfWalkAction Action;
|
|
T Value;
|
|
};
|
|
};
|
|
|
|
/// A namespace for ASTWalker actions that may be returned from pre-walk and
|
|
/// post-walk functions.
|
|
///
|
|
/// Only certain AST nodes support being replaced during a walk. The
|
|
/// visitation methods for such nodes use the PreWalkResult/PostWalkResult
|
|
/// types, which store both the action to take, along with the AST node to
|
|
/// splice into the tree in place of the old node. The node must be provided
|
|
/// to \c Action::<action> function, e.g \c Action::Continue(E) or
|
|
/// \c Action::SkipChildren(E). The only exception is \c Action::Stop(),
|
|
/// which never accepts a node.
|
|
///
|
|
/// AST nodes that do not support being replaced during a walk use visitation
|
|
/// methods that return PreWalkAction/PostWalkAction. These just store the
|
|
/// walking action to perform, and you return e.g \c Action::Continue() or
|
|
/// \c Action::SkipChildren().
|
|
///
|
|
/// Each function here returns a separate underscored type, which is then
|
|
/// consumed by PreWalkAction/PreWalkResult/PostWalkAction/PostWalkAction. It
|
|
/// is designed this way to achieve a pseudo form of return type overloading,
|
|
/// where e.g \c Action::Continue() can become either a pre-walk action or a
|
|
/// post-walk action, but \c Action::SkipChildren() can only become a pre-walk
|
|
/// action.
|
|
struct Action {
|
|
Action() = delete;
|
|
|
|
/// Continue the current walk, replacing the current node with \p node.
|
|
template <typename T>
|
|
static _Detail::ContinueWalkResult<T> Continue(T node) {
|
|
return {Continue(), std::move(node)};
|
|
}
|
|
|
|
/// Continue the current walk, replacing the current node with \p node.
|
|
/// However, skip visiting the children of \p node, and resume at its
|
|
/// post-walk.
|
|
template <typename T>
|
|
static _Detail::SkipChildrenIfWalkResult<T> SkipChildren(T node) {
|
|
return SkipChildrenIf(true, std::move(node));
|
|
}
|
|
|
|
/// Similar to \c Action::SkipChildren, but also skips the call to the
|
|
/// post-visitation method.
|
|
template <typename T>
|
|
static _Detail::SkipChildrenIfWalkResult<T>
|
|
SkipNode(T node) {
|
|
return SkipNodeIf(true, std::move(node));
|
|
}
|
|
|
|
/// If \p cond is true, this is equivalent to \c Action::SkipChildren(node).
|
|
/// Otherwise, it is equivalent to \c Action::Continue(node).
|
|
template <typename T>
|
|
static _Detail::SkipChildrenIfWalkResult<T>
|
|
SkipChildrenIf(bool cond, T node) {
|
|
return {SkipChildrenIf(cond), std::move(node)};
|
|
}
|
|
|
|
/// If \p cond is true, this is equivalent to \c Action::SkipNode(node).
|
|
/// Otherwise, it is equivalent to \c Action::Continue(node).
|
|
template <typename T>
|
|
static _Detail::SkipChildrenIfWalkResult<T>
|
|
SkipNodeIf(bool cond, T node) {
|
|
return {SkipNodeIf(cond), std::move(node)};
|
|
}
|
|
|
|
/// If \p cond is true, this is equivalent to \c Action::Continue(node).
|
|
/// Otherwise, it is equivalent to \c Action::SkipChildren(node).
|
|
template <typename T>
|
|
static _Detail::SkipChildrenIfWalkResult<T>
|
|
VisitChildrenIf(bool cond, T node) {
|
|
return SkipChildrenIf(!cond, std::move(node));
|
|
}
|
|
|
|
/// If \p cond is true, this is equivalent to \c Action::Continue(node).
|
|
/// Otherwise, it is equivalent to \c Action::SkipNode(node).
|
|
template <typename T>
|
|
static _Detail::SkipChildrenIfWalkResult<T>
|
|
VisitNodeIf(bool cond, T node) {
|
|
return SkipNodeIf(!cond, std::move(node));
|
|
}
|
|
|
|
/// If \p cond is true, this is equivalent to \c Action::Stop().
|
|
/// Otherwise, it is equivalent to \c Action::Continue(node).
|
|
template <typename T>
|
|
static _Detail::StopIfWalkResult<T> StopIf(bool cond, T node) {
|
|
return {StopIf(cond), std::move(node)};
|
|
}
|
|
|
|
/// Continue the current walk.
|
|
static _Detail::ContinueWalkAction Continue() { return {}; }
|
|
|
|
/// Continue the current walk, but do not visit the children of the current
|
|
/// node, resuming at its post-walk.
|
|
static _Detail::SkipChildrenIfWalkAction SkipChildren() {
|
|
return SkipChildrenIf(true);
|
|
}
|
|
|
|
/// Similar to \c Action::SkipChildren, but also skips the call to the
|
|
/// post-visitation method.
|
|
static _Detail::SkipChildrenIfWalkAction SkipNode() {
|
|
return SkipNodeIf(true);
|
|
}
|
|
|
|
/// If \p cond is true, this is equivalent to \c Action::SkipChildren().
|
|
/// Otherwise, it is equivalent to \c Action::Continue().
|
|
static _Detail::SkipChildrenIfWalkAction SkipChildrenIf(bool cond) {
|
|
return {cond, /*SkipPostWalk*/ false};
|
|
}
|
|
|
|
/// If \p cond is true, this is equivalent to \c Action::SkipNode().
|
|
/// Otherwise, it is equivalent to \c Action::Continue().
|
|
static _Detail::SkipChildrenIfWalkAction
|
|
SkipNodeIf(bool cond) {
|
|
return {cond, /*SkipPostWalk*/ true};
|
|
}
|
|
|
|
/// If \p cond is true, this is equivalent to \c Action::Continue().
|
|
/// Otherwise, it is equivalent to \c Action::SkipChildren().
|
|
static _Detail::SkipChildrenIfWalkAction VisitChildrenIf(bool cond) {
|
|
return SkipChildrenIf(!cond);
|
|
}
|
|
|
|
/// If \p cond is true, this is equivalent to \c Action::Continue().
|
|
/// Otherwise, it is equivalent to \c Action::SkipNode().
|
|
static _Detail::SkipChildrenIfWalkAction
|
|
VisitNodeIf(bool cond) {
|
|
return SkipNodeIf(!cond);
|
|
}
|
|
|
|
/// Terminate the walk, returning without visiting any other nodes.
|
|
static _Detail::StopWalkAction Stop() { return {}; }
|
|
|
|
/// If \p cond is true, this is equivalent to \c Action::Stop().
|
|
/// Otherwise, it is equivalent to \c Action::Continue().
|
|
static _Detail::StopIfWalkAction StopIf(bool cond) { return {cond}; }
|
|
};
|
|
|
|
/// Do not construct directly, use \c Action::<action> instead.
|
|
///
|
|
/// A pre-visitation action for AST nodes that do not support being replaced
|
|
/// while walking.
|
|
struct PreWalkAction {
|
|
enum Kind { Stop, SkipChildren, SkipNode, Continue };
|
|
Kind Action;
|
|
|
|
PreWalkAction(_Detail::ContinueWalkAction) : Action(Continue) {}
|
|
PreWalkAction(_Detail::StopWalkAction) : Action(Stop) {}
|
|
|
|
PreWalkAction(_Detail::SkipChildrenIfWalkAction action) {
|
|
if (action.Cond) {
|
|
Action = action.SkipPostWalk ? SkipNode : SkipChildren;
|
|
} else {
|
|
Action = Continue;
|
|
}
|
|
}
|
|
|
|
PreWalkAction(_Detail::StopIfWalkAction action)
|
|
: Action(action.Cond ? Stop : Continue) {}
|
|
};
|
|
|
|
/// Do not construct directly, use \c Action::<action> instead.
|
|
///
|
|
/// A post-visitation action for AST nodes that do not support being replaced
|
|
/// while walking.
|
|
struct PostWalkAction {
|
|
enum Kind { Stop, Continue };
|
|
Kind Action;
|
|
|
|
PostWalkAction(_Detail::ContinueWalkAction) : Action(Continue) {}
|
|
PostWalkAction(_Detail::StopWalkAction) : Action(Stop) {}
|
|
|
|
PostWalkAction(_Detail::StopIfWalkAction action)
|
|
: Action(action.Cond ? Stop : Continue) {}
|
|
};
|
|
|
|
/// Do not construct directly, use \c Action::<action> instead.
|
|
///
|
|
/// A pre-visitation result for AST nodes that support being replaced while
|
|
/// walking. Stores both the walking action to take, along with the node to
|
|
/// splice into the AST in place of the old node.
|
|
template <typename T>
|
|
struct PreWalkResult {
|
|
PreWalkAction Action;
|
|
std::optional<T> Value;
|
|
|
|
template <typename U,
|
|
typename std::enable_if<std::is_convertible<U, T>::value>::type
|
|
* = nullptr>
|
|
PreWalkResult(const PreWalkResult<U> &Other) : Action(Other.Action) {
|
|
if (Other.Value)
|
|
Value = *Other.Value;
|
|
}
|
|
|
|
template <typename U,
|
|
typename std::enable_if<std::is_convertible<U, T>::value>::type
|
|
* = nullptr>
|
|
PreWalkResult(PreWalkResult<U> &&Other) : Action(Other.Action) {
|
|
if (Other.Value)
|
|
Value = std::move(*Other.Value);
|
|
}
|
|
|
|
template <typename U>
|
|
PreWalkResult(_Detail::ContinueWalkResult<U> Result)
|
|
: Action(Result.Action), Value(std::move(Result.Value)) {}
|
|
|
|
template <typename U>
|
|
PreWalkResult(_Detail::SkipChildrenIfWalkResult<U> Result)
|
|
: Action(Result.Action), Value(std::move(Result.Value)) {}
|
|
|
|
template <typename U>
|
|
PreWalkResult(_Detail::StopIfWalkResult<U> Result)
|
|
: Action(Result.Action), Value(std::move(Result.Value)) {}
|
|
|
|
PreWalkResult(_Detail::StopWalkAction Action)
|
|
: Action(Action), Value(std::nullopt) {}
|
|
};
|
|
|
|
/// Do not construct directly, use \c Action::<action> instead.
|
|
///
|
|
/// A post-visitation result for AST nodes that support being replaced while
|
|
/// walking. Stores both the walking action to take, along with the node to
|
|
/// splice into the AST in place of the old node.
|
|
template <typename T>
|
|
struct PostWalkResult {
|
|
PostWalkAction Action;
|
|
std::optional<T> Value;
|
|
|
|
template <typename U,
|
|
typename std::enable_if<std::is_convertible<U, T>::value>::type
|
|
* = nullptr>
|
|
PostWalkResult(const PostWalkResult<U> &Other) : Action(Other.Action) {
|
|
if (Other.Value)
|
|
Value = *Other.Value;
|
|
}
|
|
|
|
template <typename U,
|
|
typename std::enable_if<std::is_convertible<U, T>::value>::type
|
|
* = nullptr>
|
|
PostWalkResult(PostWalkResult<U> &&Other) : Action(Other.Action) {
|
|
if (Other.Value)
|
|
Value = std::move(*Other.Value);
|
|
}
|
|
|
|
template <typename U>
|
|
PostWalkResult(_Detail::ContinueWalkResult<U> Result)
|
|
: Action(Result.Action), Value(std::move(Result.Value)) {}
|
|
|
|
template <typename U>
|
|
PostWalkResult(_Detail::StopIfWalkResult<U> Result)
|
|
: Action(Result.Action), Value(std::move(Result.Value)) {}
|
|
|
|
PostWalkResult(_Detail::StopWalkAction Action)
|
|
: Action(Action), Value(std::nullopt) {}
|
|
};
|
|
|
|
/// This method is called when first visiting an expression
|
|
/// before walking into its children.
|
|
///
|
|
/// \param E The expression to check.
|
|
///
|
|
/// \returns A result that contains a potentially re-written expression,
|
|
/// along with the walk action to perform. The default implementation
|
|
/// returns \c Action::Continue(E).
|
|
///
|
|
virtual PreWalkResult<Expr *> walkToExprPre(Expr *E) {
|
|
return Action::Continue(E);
|
|
}
|
|
|
|
/// This method is called after visiting an expression's children. If a new
|
|
/// expression is returned, it is spliced in where the old expression
|
|
/// previously appeared.
|
|
///
|
|
/// \param E The expression that was walked.
|
|
///
|
|
/// \returns A result that contains a potentially re-written expression,
|
|
/// along with the walk action to perform. The default implementation
|
|
/// returns \c Action::Continue(E).
|
|
///
|
|
virtual PostWalkResult<Expr *> walkToExprPost(Expr *E) {
|
|
return Action::Continue(E);
|
|
}
|
|
|
|
/// This method is called when first visiting a statement before
|
|
/// walking into its children.
|
|
///
|
|
/// \param S The statement to check.
|
|
///
|
|
/// \returns A result that contains a potentially re-written statement,
|
|
/// along with the walk action to perform. The default implementation
|
|
/// returns \c Action::Continue(S).
|
|
///
|
|
virtual PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) {
|
|
return Action::Continue(S);
|
|
}
|
|
|
|
/// This method is called after visiting an statements's children. If a new
|
|
/// statement is returned, it is spliced in where the old statement
|
|
/// previously appeared.
|
|
///
|
|
/// \param S The statement that was walked.
|
|
///
|
|
/// \returns A result that contains a potentially re-written statement,
|
|
/// along with the walk action to perform. The default implementation
|
|
/// returns \c Action::Continue(S).
|
|
///
|
|
virtual PostWalkResult<Stmt *> walkToStmtPost(Stmt *S) {
|
|
return Action::Continue(S);
|
|
}
|
|
|
|
/// This method is called when first visiting a pattern before walking into
|
|
/// its children.
|
|
///
|
|
/// \param P The statement to check.
|
|
///
|
|
/// \returns A result that contains a potentially re-written pattern,
|
|
/// along with the walk action to perform. The default implementation
|
|
/// returns \c Action::Continue(P).
|
|
///
|
|
virtual PreWalkResult<Pattern *> walkToPatternPre(Pattern *P) {
|
|
return Action::Continue(P);
|
|
}
|
|
|
|
/// This method is called after visiting an pattern's children. If a new
|
|
/// pattern is returned, it is spliced in where the old pattern
|
|
/// previously appeared.
|
|
///
|
|
/// \param P The pattern that was walked.
|
|
///
|
|
/// \returns A result that contains a potentially re-written pattern,
|
|
/// along with the walk action to perform. The default implementation
|
|
/// returns \c Action::Continue(P).
|
|
///
|
|
virtual PostWalkResult<Pattern *> walkToPatternPost(Pattern *P) {
|
|
return Action::Continue(P);
|
|
}
|
|
|
|
/// walkToDeclPre - This method is called when first visiting a decl, before
|
|
/// walking into its children.
|
|
///
|
|
/// \param D The declaration to check. The callee may update this declaration
|
|
/// in-place.
|
|
///
|
|
/// \returns The walking action to perform. By default, this
|
|
/// is \c Action::Continue().
|
|
///
|
|
virtual PreWalkAction walkToDeclPre(Decl *D) { return Action::Continue(); }
|
|
|
|
/// walkToDeclPost - This method is called after visiting the children of a
|
|
/// decl.
|
|
///
|
|
/// \param D The declaration that was walked.
|
|
///
|
|
/// \returns The walking action to perform. By default, this
|
|
/// is \c Action::Continue().
|
|
///
|
|
virtual PostWalkAction walkToDeclPost(Decl *D) { return Action::Continue(); }
|
|
|
|
/// This method is called when first visiting a TypeRepr, before
|
|
/// walking into its children.
|
|
///
|
|
/// \param T The TypeRepr to check.
|
|
///
|
|
/// \returns The walking action to perform. By default, this
|
|
/// is \c Action::Continue().
|
|
///
|
|
virtual PreWalkAction walkToTypeReprPre(TypeRepr *T) {
|
|
return Action::Continue();
|
|
}
|
|
|
|
/// This method is called after visiting the children of a TypeRepr.
|
|
///
|
|
/// \param T The type that was walked.
|
|
///
|
|
/// \returns The walking action to perform. By default, this
|
|
/// is \c Action::Continue().
|
|
///
|
|
virtual PostWalkAction walkToTypeReprPost(TypeRepr *T) {
|
|
return Action::Continue();
|
|
}
|
|
|
|
/// This method configures how to walk `QualifiedIdentTypeRepr` nodes.
|
|
virtual QualifiedIdentTypeReprWalkingScheme
|
|
getQualifiedIdentTypeReprWalkingScheme() const {
|
|
return QualifiedIdentTypeReprWalkingScheme::ASTOrderRecursive;
|
|
}
|
|
|
|
/// This method configures whether the walker should explore into the generic
|
|
/// params in AbstractFunctionDecl and NominalTypeDecl.
|
|
virtual bool shouldWalkIntoGenericParams() { return false; }
|
|
|
|
/// This method configures how the walker should walk the initializers of
|
|
/// lazy variables. These initializers are semantically different from other
|
|
/// initializers in their context and so sometimes should be visited as part
|
|
/// of the synthesized getter, or should not be visited at all.
|
|
virtual LazyInitializerWalking getLazyInitializerWalkingBehavior() {
|
|
return LazyInitializerWalking::InPatternBinding;
|
|
}
|
|
|
|
/// This method configures how the walker should walk into uses of macros.
|
|
virtual MacroWalking getMacroWalkingBehavior() const {
|
|
return MacroWalking::ArgumentsAndExpansion;
|
|
}
|
|
|
|
/// This method configures how the walker should walk into SequenceExprs.
|
|
/// Needing to customize this behavior should be rare, as sequence expressions
|
|
/// are only encountered in un-typechecked ASTs.
|
|
virtual SequenceWalking getSequenceWalkingBehavior() const {
|
|
return SequenceWalking::Default;
|
|
}
|
|
|
|
/// This method determines whether the given declaration should be
|
|
/// considered to be in a macro expansion context. It can be configured
|
|
/// by subclasses.
|
|
virtual bool isDeclInMacroExpansion(Decl *decl) const;
|
|
|
|
/// Determine whether we should walk macro arguments (as they appear in
|
|
/// source) and the expansion (which is semantically part of the program).
|
|
std::pair<bool, bool> shouldWalkMacroArgumentsAndExpansion() const {
|
|
switch (getMacroWalkingBehavior()) {
|
|
case MacroWalking::Expansion:
|
|
return std::make_pair(false, true);
|
|
|
|
case MacroWalking::Arguments:
|
|
return std::make_pair(true, false);
|
|
|
|
case MacroWalking::ArgumentsAndExpansion:
|
|
return std::make_pair(true, true);
|
|
|
|
case MacroWalking::None:
|
|
return std::make_pair(false, false);
|
|
}
|
|
}
|
|
|
|
/// This method configures whether the walker should visit the body of a
|
|
/// TapExpr.
|
|
virtual bool shouldWalkIntoTapExpression() { return true; }
|
|
|
|
/// This method configures whether the walker should visit the underlying
|
|
/// value of a property wrapper placeholder.
|
|
virtual bool shouldWalkIntoPropertyWrapperPlaceholderValue() { return true; }
|
|
|
|
/// This method configures whether the walker should exhibit the legacy
|
|
/// behavior where accessors appear as peers of their storage, rather
|
|
/// than children nested inside of it.
|
|
///
|
|
/// Please don't write new ASTWalker implementations that override this
|
|
/// method to return true; instead, refactor existing code as needed
|
|
/// until eventually we can remove this altogether.
|
|
virtual bool shouldWalkAccessorsTheOldWay() { return false; }
|
|
|
|
/// Whether to walk internal top level decls in serialized modules.
|
|
///
|
|
/// TODO: Consider changing this to false by default.
|
|
virtual bool shouldWalkSerializedTopLevelInternalDecls() { return true; }
|
|
|
|
/// Whether to walk into the definition of a \c MacroDecl if it hasn't been
|
|
/// type-checked yet.
|
|
virtual bool shouldWalkIntoUncheckedMacroDefinitions() { return false; }
|
|
|
|
/// walkToParameterListPre - This method is called when first visiting a
|
|
/// ParameterList, before walking into its parameters.
|
|
///
|
|
/// \param PL The parameter list to walk.
|
|
///
|
|
/// \returns The walking action to perform. By default, this
|
|
/// is \c Action::Continue().
|
|
///
|
|
virtual PreWalkAction walkToParameterListPre(ParameterList *PL) {
|
|
return Action::Continue();
|
|
}
|
|
|
|
/// walkToParameterListPost - This method is called after visiting the
|
|
/// children of a parameter list.
|
|
///
|
|
/// \param PL The parameter list that was walked.
|
|
///
|
|
/// \returns The walking action to perform. By default, this
|
|
/// is \c Action::Continue().
|
|
///
|
|
virtual PostWalkAction walkToParameterListPost(ParameterList *PL) {
|
|
return Action::Continue();
|
|
}
|
|
|
|
/// This method is called when first visiting an argument list before walking
|
|
/// into its arguments.
|
|
///
|
|
/// \param ArgList The argument list to walk.
|
|
///
|
|
/// \returns A result that contains a potentially re-written argument list,
|
|
/// along with the walk action to perform.
|
|
///
|
|
/// The default implementation returns \c Action::Continue(ArgList).
|
|
virtual PreWalkResult<ArgumentList *>
|
|
walkToArgumentListPre(ArgumentList *ArgList) {
|
|
return Action::Continue(ArgList);
|
|
}
|
|
|
|
/// This method is called after visiting the arguments in an argument list.
|
|
/// If a new argument list is returned, it is spliced in where the old
|
|
/// argument list previously appeared.
|
|
///
|
|
/// The default implementation returns \c Action::Continue(ArgList).
|
|
virtual PostWalkResult<ArgumentList *>
|
|
walkToArgumentListPost(ArgumentList *ArgList) {
|
|
return Action::Continue(ArgList);
|
|
}
|
|
|
|
/// This method is called when first visiting an argument in an argument list,
|
|
/// before walking into its expression.
|
|
///
|
|
/// \param Arg The argument to walk.
|
|
///
|
|
/// \returns The walking action to perform.
|
|
///
|
|
/// The default implementation returns \c Action::Continue().
|
|
virtual PreWalkAction walkToArgumentPre(const Argument &Arg) {
|
|
return Action::Continue();
|
|
}
|
|
|
|
/// This method is called after visiting an argument in an argument list.
|
|
///
|
|
/// \returns The walking action to perform.
|
|
///
|
|
/// The default implementation returns \c Action::Continue().
|
|
virtual PostWalkAction walkToArgumentPost(const Argument &Arg) {
|
|
return Action::Continue();
|
|
}
|
|
|
|
protected:
|
|
ASTWalker() = default;
|
|
ASTWalker(const ASTWalker &) = default;
|
|
virtual ~ASTWalker() = default;
|
|
|
|
virtual void anchor();
|
|
};
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|