mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Make sure we don't walk into the expansion of a body macro if the AST walker is configured not to walk macro expansions.
2485 lines
62 KiB
C++
2485 lines
62 KiB
C++
//===--- ASTWalker.cpp - AST Traversal ------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements a recursive traversal of every node in an AST.
|
|
//
|
|
// It's important to update this traversal whenever the AST is
|
|
// changed, whether by adding a new node class or adding a new child
|
|
// to an existing node. Many walker implementations rely on being
|
|
// invoked with every node in the AST.
|
|
//
|
|
// Please follow these general rules when implementing traversal for
|
|
// a node:
|
|
//
|
|
// - Every node should be walked. If a node has both syntactic and
|
|
// semantic components, you should make sure you visit every node
|
|
// in both.
|
|
//
|
|
// - Nodes should only be walked once. So if a node has both
|
|
// syntactic and semantic components, but the type-checker builds
|
|
// the semantic components directly on top of the syntactic
|
|
// components, walking the semantic components will be sufficient
|
|
// to visit all the nodes in both.
|
|
//
|
|
// - Explicitly-written nodes should be walked in left-to-right
|
|
// syntactic order. The ordering of implicit nodes isn't
|
|
// particularly important.
|
|
//
|
|
// Note that semantic components will generally preserve the
|
|
// syntactic order of their children because doing something else
|
|
// could illegally change order of evaluation. This is why, for
|
|
// example, shuffling a TupleExpr creates a DestructureTupleExpr
|
|
// instead of just making a new TupleExpr with the elements in
|
|
// different order.
|
|
//
|
|
// - Sub-expressions and sub-statements should be replaceable.
|
|
// It's reasonable to expect that the replacement won't be
|
|
// completely unrelated to the original, but try to avoid making
|
|
// assumptions about the exact representation type. For example,
|
|
// assuming that a child expression is literally a TupleExpr may
|
|
// only be a reasonable assumption in an unchecked parse tree.
|
|
//
|
|
// - Avoid relying on the AST being type-checked or even
|
|
// well-formed during traversal.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/AST/ASTWalker.h"
|
|
#include "swift/AST/ASTVisitor.h"
|
|
#include "swift/AST/GenericParamList.h"
|
|
#include "swift/AST/ParameterList.h"
|
|
#include "swift/AST/PrettyStackTrace.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
|
|
using namespace swift;
|
|
|
|
void ASTWalker::anchor() {}
|
|
|
|
bool ASTWalker::isDeclInMacroExpansion(Decl *decl) const {
|
|
return decl->isInMacroExpansionInContext();
|
|
}
|
|
|
|
namespace {
|
|
|
|
/// Traversal - This class implements a simple expression/statement
|
|
/// recursive traverser which queries a user-provided walker class
|
|
/// on every node in an AST.
|
|
class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
|
|
/*Decl*/ bool,
|
|
Pattern *, /*TypeRepr*/ bool>
|
|
{
|
|
friend class ASTVisitor<Traversal, Expr*, Stmt*, bool, Pattern*, bool>;
|
|
typedef ASTVisitor<Traversal, Expr*, Stmt*, bool, Pattern*, bool> inherited;
|
|
|
|
ASTWalker &Walker;
|
|
|
|
/// RAII object that sets the parent of the walk context
|
|
/// appropriately.
|
|
class SetParentRAII {
|
|
ASTWalker &Walker;
|
|
decltype(ASTWalker::Parent) PriorParent;
|
|
|
|
public:
|
|
template<typename T>
|
|
SetParentRAII(ASTWalker &walker, T *newParent)
|
|
: Walker(walker), PriorParent(walker.Parent) {
|
|
walker.Parent = newParent;
|
|
}
|
|
|
|
~SetParentRAII() {
|
|
Walker.Parent = PriorParent;
|
|
}
|
|
};
|
|
|
|
[[nodiscard]]
|
|
Expr *visit(Expr *E) {
|
|
SetParentRAII SetParent(Walker, E);
|
|
return inherited::visit(E);
|
|
}
|
|
|
|
[[nodiscard]]
|
|
Stmt *visit(Stmt *S) {
|
|
SetParentRAII SetParent(Walker, S);
|
|
return inherited::visit(S);
|
|
}
|
|
|
|
[[nodiscard]]
|
|
Pattern *visit(Pattern *P) {
|
|
SetParentRAII SetParent(Walker, P);
|
|
return inherited::visit(P);
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool visit(Decl *D) {
|
|
SetParentRAII SetParent(Walker, D);
|
|
if (visitDeclCommon(D))
|
|
return true;
|
|
return inherited::visit(D);
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool visit(TypeRepr *T) {
|
|
SetParentRAII SetParent(Walker, T);
|
|
return inherited::visit(T);
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool visit(ParameterList *PL) {
|
|
return inherited::visit(PL);
|
|
}
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Decls
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
[[nodiscard]]
|
|
bool visitCustomAttr(CustomAttr *CA) {
|
|
auto *newTypeExpr = doIt(CA->getTypeExpr());
|
|
if (!newTypeExpr)
|
|
return true;
|
|
|
|
ASSERT(newTypeExpr == CA->getTypeExpr() &&
|
|
"Cannot change CustomAttr TypeExpr");
|
|
|
|
if (auto *args = CA->getArgs()) {
|
|
auto *newArgs = doIt(args);
|
|
if (!newArgs)
|
|
return true;
|
|
|
|
CA->setArgs(newArgs);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool visitDeclCommon(Decl *D) {
|
|
if (Walker.shouldWalkIntoCustomAttrs()) {
|
|
for (auto *attr : D->getAttrs()) {
|
|
auto *CA = dyn_cast<CustomAttr>(attr);
|
|
if (!CA)
|
|
continue;
|
|
|
|
if (visitCustomAttr(CA))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool visitGenericParamListIfNeeded(GenericContext *GC) {
|
|
// Must check this first in case extensions have not been bound yet
|
|
if (Walker.shouldWalkIntoGenericParams()) {
|
|
if (auto *params = GC->getParsedGenericParams()) {
|
|
if (doIt(params))
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool visitTrailingRequirements(GenericContext *GC) {
|
|
if (const auto Where = GC->getTrailingWhereClause()) {
|
|
for (auto &Req: Where->getRequirements())
|
|
if (doIt(Req))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool visitImportDecl(ImportDecl *ID) {
|
|
return false;
|
|
}
|
|
|
|
bool visitUsingDecl(UsingDecl *UD) {
|
|
return false;
|
|
}
|
|
|
|
bool visitExtensionDecl(ExtensionDecl *ED) {
|
|
if (auto *typeRepr = ED->getExtendedTypeRepr())
|
|
if (doIt(typeRepr))
|
|
return true;
|
|
auto inheritedTypes = ED->getInherited();
|
|
for (auto i : inheritedTypes.getIndices()) {
|
|
if (auto *const TyR = inheritedTypes.getTypeRepr(i))
|
|
if (doIt(TyR))
|
|
return true;
|
|
}
|
|
if (visitTrailingRequirements(ED))
|
|
return true;
|
|
|
|
for (Decl *M : ED->getMembers()) {
|
|
if (doIt(M))
|
|
return true;
|
|
|
|
if (Walker.shouldWalkAccessorsTheOldWay()) {
|
|
// Pretend that accessors share a parent with the storage.
|
|
//
|
|
// FIXME: Update existing ASTWalkers to deal with accessors appearing as
|
|
// children of the storage instead.
|
|
if (auto *ASD = dyn_cast<AbstractStorageDecl>(M)) {
|
|
for (auto AD : ASD->getAllAccessors()) {
|
|
if (doIt(AD))
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool visitPatternBindingDecl(PatternBindingDecl *PBD) {
|
|
auto *singleVar = PBD->getSingleVar();
|
|
|
|
for (auto idx : range(PBD->getNumPatternEntries())) {
|
|
if (Pattern *Pat = doIt(PBD->getPattern(idx)))
|
|
PBD->setPattern(idx, Pat);
|
|
else
|
|
return true;
|
|
|
|
if (!PBD->getInit(idx))
|
|
continue;
|
|
|
|
if (singleVar && singleVar->getOriginalWrappedProperty())
|
|
continue;
|
|
|
|
if (PBD->isInitializerSubsumed(idx) && singleVar &&
|
|
singleVar->getAttrs().hasAttribute<LazyAttr>() &&
|
|
Walker.getLazyInitializerWalkingBehavior() !=
|
|
LazyInitializerWalking::InPatternBinding) {
|
|
break;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
PrettyStackTraceDecl debugStack("walking into initializer for", PBD);
|
|
#endif
|
|
if (Expr *E2 = doIt(PBD->getInit(idx)))
|
|
PBD->setInit(idx, E2);
|
|
else
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool visitEnumCaseDecl(EnumCaseDecl *ECD) {
|
|
// We'll visit the EnumElementDecls separately.
|
|
return false;
|
|
}
|
|
|
|
bool visitTopLevelCodeDecl(TopLevelCodeDecl *TLCD) {
|
|
if (BraceStmt *S = cast_or_null<BraceStmt>(doIt(TLCD->getBody()))) {
|
|
TLCD->setBody(S);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool visitOperatorDecl(OperatorDecl *OD) {
|
|
return false;
|
|
}
|
|
|
|
bool visitPrecedenceGroupDecl(PrecedenceGroupDecl *PGD) {
|
|
return false;
|
|
}
|
|
|
|
bool visitTypeAliasDecl(TypeAliasDecl *TAD) {
|
|
bool WalkGenerics = visitGenericParamListIfNeeded(TAD);
|
|
|
|
if (auto typerepr = TAD->getUnderlyingTypeRepr())
|
|
if (doIt(typerepr))
|
|
return true;
|
|
|
|
return WalkGenerics && visitTrailingRequirements(TAD);
|
|
}
|
|
|
|
bool visitOpaqueTypeDecl(OpaqueTypeDecl *OTD) {
|
|
if (Walker.shouldWalkIntoGenericParams() && OTD->getGenericParams()) {
|
|
if (doIt(OTD->getGenericParams()))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool visitGenericTypeParamDecl(GenericTypeParamDecl *GTPD) {
|
|
for (const auto &Inherit : GTPD->getInherited().getEntries()) {
|
|
if (auto *const TyR = Inherit.getTypeRepr())
|
|
if (doIt(TyR))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool visitAssociatedTypeDecl(AssociatedTypeDecl *ATD) {
|
|
for (const auto &Inherit : ATD->getInherited().getEntries()) {
|
|
if (auto *const TyR = Inherit.getTypeRepr())
|
|
if (doIt(TyR))
|
|
return true;
|
|
}
|
|
if (const auto DefaultTy = ATD->getDefaultDefinitionTypeRepr())
|
|
if (doIt(DefaultTy))
|
|
return true;
|
|
|
|
if (auto *WhereClause = ATD->getTrailingWhereClause()) {
|
|
for (auto &Req: WhereClause->getRequirements()) {
|
|
if (doIt(Req))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool visitNominalTypeDecl(NominalTypeDecl *NTD) {
|
|
#ifndef NDEBUG
|
|
PrettyStackTraceDecl debugStack("walking into", NTD);
|
|
#endif
|
|
|
|
bool WalkGenerics = visitGenericParamListIfNeeded(NTD);
|
|
|
|
auto inheritedTypes = NTD->getInherited();
|
|
for (auto i : inheritedTypes.getIndices()) {
|
|
if (auto *const TyR = inheritedTypes.getTypeRepr(i))
|
|
if (doIt(TyR))
|
|
return true;
|
|
}
|
|
|
|
// Visit requirements
|
|
if (WalkGenerics && visitTrailingRequirements(NTD))
|
|
return true;
|
|
|
|
for (Decl *Member : NTD->getMembers()) {
|
|
if (doIt(Member))
|
|
return true;
|
|
|
|
if (Walker.shouldWalkAccessorsTheOldWay()) {
|
|
// Pretend that accessors share a parent with the storage.
|
|
//
|
|
// FIXME: Update existing ASTWalkers to deal with accessors appearing as
|
|
// children of the storage instead.
|
|
if (auto *ASD = dyn_cast<AbstractStorageDecl>(Member)) {
|
|
for (auto AD : ASD->getAllAccessors()) {
|
|
if (doIt(AD))
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool visitModuleDecl(ModuleDecl *MD) {
|
|
// TODO: should we recurse within the module?
|
|
return false;
|
|
}
|
|
|
|
bool visitVarDecl(VarDecl *VD) {
|
|
if (!Walker.shouldWalkAccessorsTheOldWay()) {
|
|
for (auto *AD : VD->getAllAccessors())
|
|
if (doIt(AD))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool visitParamDecl(ParamDecl *P) {
|
|
// Don't walk into the type if the decl is implicit, or if the type is
|
|
// implicit.
|
|
if (!P->isImplicit()) {
|
|
if (auto *repr = P->getTypeRepr()) {
|
|
if (doIt(repr)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
if (auto *E = P->getStructuralDefaultExpr()) {
|
|
auto res = doIt(E);
|
|
if (!res) return true;
|
|
P->setDefaultExpr(res);
|
|
}
|
|
|
|
if (!Walker.shouldWalkAccessorsTheOldWay()) {
|
|
for (auto *AD : P->getAllAccessors())
|
|
if (doIt(AD))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool visitSubscriptDecl(SubscriptDecl *SD) {
|
|
bool WalkGenerics = visitGenericParamListIfNeeded(SD);
|
|
|
|
if (visit(SD->getIndices()))
|
|
return true;
|
|
|
|
if (auto *const TyR = SD->getElementTypeRepr())
|
|
if (doIt(TyR))
|
|
return true;
|
|
|
|
// Visit trailing requirements
|
|
if (WalkGenerics && visitTrailingRequirements(SD))
|
|
return true;
|
|
|
|
if (!Walker.shouldWalkAccessorsTheOldWay()) {
|
|
for (auto *AD : SD->getAllAccessors())
|
|
if (doIt(AD))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool visitMissingDecl(MissingDecl *missing) {
|
|
return false;
|
|
}
|
|
|
|
bool visitMissingMemberDecl(MissingMemberDecl *MMD) {
|
|
return false;
|
|
}
|
|
|
|
bool visitMacroDecl(MacroDecl *MD) {
|
|
bool WalkGenerics = visitGenericParamListIfNeeded(MD);
|
|
|
|
if (MD->parameterList && visit(MD->parameterList))
|
|
return true;
|
|
|
|
if (auto resultTypeRepr = MD->resultType.getTypeRepr()) {
|
|
if (doIt(resultTypeRepr))
|
|
return true;
|
|
}
|
|
|
|
if (auto def = MD->definition) {
|
|
// Don't walk into unchecked definitions.
|
|
if (auto expansion = dyn_cast<MacroExpansionExpr>(def)) {
|
|
if (!expansion->getType().isNull() ||
|
|
Walker.shouldWalkIntoUncheckedMacroDefinitions()) {
|
|
if (auto newDef = doIt(def))
|
|
MD->definition = newDef;
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Visit trailing requirements
|
|
if (WalkGenerics && visitTrailingRequirements(MD))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool visitFreestandingMacroArgs(FreestandingMacroExpansion *ME) {
|
|
for (TypeRepr *genArg : ME->getGenericArgs()) {
|
|
if (doIt(genArg))
|
|
return true;
|
|
}
|
|
|
|
if (ME->getArgs()) {
|
|
ArgumentList *args = doIt(ME->getArgs());
|
|
if (!args)
|
|
return true;
|
|
ME->setArgs(args);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool visitMacroExpansionDecl(MacroExpansionDecl *MED) {
|
|
#ifndef NDEBUG
|
|
PrettyStackTraceDecl debugStack("walking into", MED);
|
|
#endif
|
|
|
|
bool shouldWalkArguments, shouldWalkExpansion;
|
|
std::tie(shouldWalkArguments, shouldWalkExpansion) =
|
|
Walker.shouldWalkMacroArgumentsAndExpansion();
|
|
|
|
if (shouldWalkArguments && visitFreestandingMacroArgs(MED))
|
|
return true;
|
|
|
|
bool alreadyFailed = false;
|
|
if (shouldWalkExpansion) {
|
|
MED->forEachExpandedNode([&](ASTNode expandedNode) {
|
|
if (alreadyFailed) return;
|
|
|
|
if (auto *expr = expandedNode.dyn_cast<Expr *>()) {
|
|
alreadyFailed = doIt(expr) == nullptr;
|
|
} else if (auto *stmt = expandedNode.dyn_cast<Stmt *>()) {
|
|
alreadyFailed = doIt(stmt) == nullptr;
|
|
} else {
|
|
auto decl = cast<Decl *>(expandedNode);
|
|
if (!isa<VarDecl>(decl))
|
|
alreadyFailed = doIt(decl);
|
|
}
|
|
});
|
|
}
|
|
return alreadyFailed;
|
|
}
|
|
|
|
bool visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) {
|
|
#ifndef NDEBUG
|
|
PrettyStackTraceDecl debugStack("walking into body of", AFD);
|
|
#endif
|
|
|
|
bool WalkGenerics =
|
|
// accessor generics are visited from the storage decl
|
|
!isa<AccessorDecl>(AFD) && visitGenericParamListIfNeeded(AFD);
|
|
|
|
if (auto *PD = AFD->getImplicitSelfDecl(/*createIfNeeded=*/false)) {
|
|
if (visit(PD))
|
|
return true;
|
|
}
|
|
if (visit(AFD->getParameters()))
|
|
return true;
|
|
|
|
if (auto *const ThrownTyR = AFD->getThrownTypeRepr()) {
|
|
if (doIt(ThrownTyR))
|
|
return true;
|
|
}
|
|
|
|
if (auto *FD = dyn_cast<FuncDecl>(AFD)) {
|
|
if (!isa<AccessorDecl>(FD))
|
|
if (auto *const TyR = FD->getResultTypeRepr())
|
|
if (doIt(TyR))
|
|
return true;
|
|
}
|
|
|
|
// Visit trailing requirements
|
|
if (WalkGenerics && visitTrailingRequirements(AFD))
|
|
return true;
|
|
|
|
// If we're not walking macro expansions, avoid walking into a body if it
|
|
// was expanded from a macro.
|
|
auto SkipBody = !Walker.shouldWalkMacroArgumentsAndExpansion().second &&
|
|
AFD->isBodyMacroExpanded();
|
|
|
|
if (!SkipBody && AFD->getBody(/*canSynthesize=*/false)) {
|
|
AbstractFunctionDecl::BodyKind PreservedKind = AFD->getBodyKind();
|
|
if (BraceStmt *S = cast_or_null<BraceStmt>(doIt(AFD->getBody())))
|
|
AFD->setBody(S, PreservedKind);
|
|
else
|
|
return true;
|
|
}
|
|
|
|
if (auto ctor = dyn_cast<ConstructorDecl>(AFD)) {
|
|
if (auto superInit = ctor->getSuperInitCall()) {
|
|
if ((superInit = doIt(superInit)))
|
|
ctor->setSuperInitCall(superInit);
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool visitEnumElementDecl(EnumElementDecl *ED) {
|
|
if (auto *PL = ED->getParameterList()) {
|
|
if (visit(PL))
|
|
return true;
|
|
}
|
|
|
|
if (auto *rawLiteralExpr = ED->getRawValueUnchecked()) {
|
|
if (Expr *newRawExpr = doIt(rawLiteralExpr)) {
|
|
auto *newLiteralRawExpr = cast<LiteralExpr>(newRawExpr);
|
|
ED->setRawValueExpr(newLiteralRawExpr);
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Exprs
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
Expr *visitErrorExpr(ErrorExpr *E) {
|
|
if (auto *origExpr = E->getOriginalExpr()) {
|
|
auto *newOrigExpr = doIt(origExpr);
|
|
if (!newOrigExpr)
|
|
return nullptr;
|
|
E->setOriginalExpr(newOrigExpr);
|
|
}
|
|
return E;
|
|
}
|
|
Expr *visitCodeCompletionExpr(CodeCompletionExpr *E) {
|
|
if (Expr *baseExpr = E->getBase()) {
|
|
Expr *newBaseExpr = doIt(baseExpr);
|
|
if (!newBaseExpr)
|
|
return nullptr;
|
|
E->setBase(newBaseExpr);
|
|
}
|
|
return E;
|
|
}
|
|
Expr *visitLiteralExpr(LiteralExpr *E) { return E; }
|
|
Expr *visitDiscardAssignmentExpr(DiscardAssignmentExpr *E) { return E; }
|
|
Expr *visitTypeExpr(TypeExpr *E) {
|
|
if (!E->isImplicit())
|
|
if (auto *typerepr = E->getTypeRepr())
|
|
if (doIt(typerepr))
|
|
return nullptr;
|
|
|
|
return E;
|
|
}
|
|
Expr *visitSuperRefExpr(SuperRefExpr *E) { return E; }
|
|
Expr *visitOtherConstructorDeclRefExpr(OtherConstructorDeclRefExpr *E) {
|
|
return E;
|
|
}
|
|
|
|
Expr *visitOverloadedDeclRefExpr(OverloadedDeclRefExpr *E) { return E; }
|
|
Expr *visitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *E) { return E; }
|
|
|
|
Expr *visitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { return E; }
|
|
|
|
Expr *visitOpaqueValueExpr(OpaqueValueExpr *E) { return E; }
|
|
|
|
Expr *visitPropertyWrapperValuePlaceholderExpr(
|
|
PropertyWrapperValuePlaceholderExpr *E) {
|
|
if (E->getOpaqueValuePlaceholder()) {
|
|
if (auto *placeholder = doIt(E->getOpaqueValuePlaceholder()))
|
|
E->setOpaqueValuePlaceholder(dyn_cast<OpaqueValueExpr>(placeholder));
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
if (Walker.shouldWalkIntoPropertyWrapperPlaceholderValue()) {
|
|
if (E->getOriginalWrappedValue()) {
|
|
if (auto *newValue = doIt(E->getOriginalWrappedValue()))
|
|
E->setOriginalWrappedValue(newValue);
|
|
else
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitAppliedPropertyWrapperExpr(AppliedPropertyWrapperExpr *E) {
|
|
if (auto *newValue = doIt(E->getValue())) {
|
|
E->setValue(newValue);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitDefaultArgumentExpr(DefaultArgumentExpr *E) { return E; }
|
|
|
|
Expr *visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *E) {
|
|
if (auto oldAppendingExpr = E->getAppendingExpr()) {
|
|
if (auto appendingExpr = doIt(oldAppendingExpr))
|
|
E->setAppendingExpr(dyn_cast<TapExpr>(appendingExpr));
|
|
else
|
|
return nullptr;
|
|
}
|
|
return E;
|
|
}
|
|
|
|
Expr *visitObjectLiteralExpr(ObjectLiteralExpr *E) {
|
|
if (auto *args = doIt(E->getArgs())) {
|
|
E->setArgs(args);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
return E;
|
|
}
|
|
|
|
Expr *visitCollectionExpr(CollectionExpr *E) {
|
|
for (auto &elt : E->getElements())
|
|
if (Expr *Sub = doIt(elt))
|
|
elt = Sub;
|
|
else
|
|
return nullptr;
|
|
return E;
|
|
}
|
|
|
|
Expr *visitDeclRefExpr(DeclRefExpr *E) {
|
|
return E;
|
|
}
|
|
|
|
Expr *visitMemberRefExpr(MemberRefExpr *E) {
|
|
if (Expr *Base = doIt(E->getBase())) {
|
|
E->setBase(Base);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitDynamicMemberRefExpr(DynamicMemberRefExpr *E) {
|
|
if (Expr *Base = doIt(E->getBase())) {
|
|
E->setBase(Base);
|
|
return E;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitAnyTryExpr(AnyTryExpr *E) {
|
|
if (Expr *subExpr = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(subExpr);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitIdentityExpr(IdentityExpr *E) {
|
|
if (Expr *subExpr = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(subExpr);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitCopyExpr(CopyExpr *E) {
|
|
if (Expr *subExpr = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(subExpr);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitConsumeExpr(ConsumeExpr *E) {
|
|
if (Expr *subExpr = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(subExpr);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitTupleExpr(TupleExpr *E) {
|
|
for (unsigned i = 0, e = E->getNumElements(); i != e; ++i)
|
|
if (E->getElement(i)) {
|
|
if (Expr *Elt = doIt(E->getElement(i)))
|
|
E->setElement(i, Elt);
|
|
else
|
|
return nullptr;
|
|
}
|
|
return E;
|
|
}
|
|
Expr *visitSubscriptExpr(SubscriptExpr *E) {
|
|
if (Expr *Base = doIt(E->getBase()))
|
|
E->setBase(Base);
|
|
else
|
|
return nullptr;
|
|
|
|
if (auto *args = doIt(E->getArgs())) {
|
|
E->setArgs(args);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
return E;
|
|
}
|
|
Expr *visitKeyPathApplicationExpr(KeyPathApplicationExpr *E) {
|
|
if (Expr *Base = doIt(E->getBase()))
|
|
E->setBase(Base);
|
|
else
|
|
return nullptr;
|
|
|
|
if (Expr *KeyPath = doIt(E->getKeyPath()))
|
|
E->setKeyPath(KeyPath);
|
|
else
|
|
return nullptr;
|
|
|
|
return E;
|
|
}
|
|
Expr *visitDynamicSubscriptExpr(DynamicSubscriptExpr *E) {
|
|
if (Expr *Base = doIt(E->getBase()))
|
|
E->setBase(Base);
|
|
else
|
|
return nullptr;
|
|
|
|
if (auto *args = doIt(E->getArgs())) {
|
|
E->setArgs(args);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
return E;
|
|
}
|
|
Expr *visitUnresolvedDotExpr(UnresolvedDotExpr *E) {
|
|
if (!E->getBase())
|
|
return E;
|
|
|
|
if (Expr *E2 = doIt(E->getBase())) {
|
|
E->setBase(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
Expr *visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *E) {
|
|
if (!E->getSubExpr())
|
|
return E;
|
|
|
|
if (Expr *Sub = doIt(E->getSubExpr()))
|
|
E->setSubExpr(Sub);
|
|
else
|
|
return nullptr;
|
|
|
|
for (auto &TyLoc : E->getUnresolvedParams()) {
|
|
if (doIt(TyLoc))
|
|
return nullptr;
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitTupleElementExpr(TupleElementExpr *E) {
|
|
if (Expr *E2 = doIt(E->getBase())) {
|
|
E->setBase(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitImplicitConversionExpr(ImplicitConversionExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitErasureExpr(ErasureExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
for (unsigned i = 0; i < E->getArgumentConversions().size(); ++i) {
|
|
const auto &conv = E->getArgumentConversions()[i];
|
|
auto kConv = conv.Conversion;
|
|
if (!kConv) {
|
|
return nullptr;
|
|
} else if (Expr *E2 = doIt(kConv)) {
|
|
E->setArgumentConversion(i, {conv.OrigValue, E2});
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitCollectionUpcastConversionExpr(CollectionUpcastConversionExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
if (auto &keyConv = E->getKeyConversion()) {
|
|
auto kConv = keyConv.Conversion;
|
|
if (!kConv) {
|
|
return nullptr;
|
|
} else if (Expr *E2 = doIt(kConv)) {
|
|
E->setKeyConversion({keyConv.OrigValue, E2});
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
if (auto &valueConv = E->getValueConversion()) {
|
|
auto vConv = valueConv.Conversion;
|
|
if (!vConv) {
|
|
return nullptr;
|
|
} else if (Expr *E2 = doIt(vConv)) {
|
|
E->setValueConversion({valueConv.OrigValue, E2});
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitDestructureTupleExpr(DestructureTupleExpr *E) {
|
|
if (auto *src = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(src);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
if (auto *dst = doIt(E->getResultExpr())) {
|
|
E->setResultExpr(dst);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitTryExpr(TryExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitForceTryExpr(ForceTryExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitOptionalTryExpr(OptionalTryExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitInOutExpr(InOutExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitVarargExpansionExpr(VarargExpansionExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSubExpr())) {
|
|
E->setSubExpr(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitPackExpansionExpr(PackExpansionExpr *E) {
|
|
if (Expr *pattern = doIt(E->getPatternExpr())) {
|
|
E->setPatternExpr(pattern);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitPackElementExpr(PackElementExpr *E) {
|
|
if (Expr *pattern = doIt(E->getPackRefExpr())) {
|
|
E->setPackRefExpr(pattern);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitMaterializePackExpr(MaterializePackExpr *E) {
|
|
if (Expr *fromExpr = doIt(E->getFromExpr())) {
|
|
E->setFromExpr(fromExpr);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitSequenceExpr(SequenceExpr *E) {
|
|
// After folding, the SequenceExpr elements can contain a broken mess of
|
|
// partially folded and/or duplicate nodes (since folding can mutate nodes
|
|
// in-place). We remove the SequenceExpr from the AST after folding, but
|
|
// there's still a period of time during pre-checking when it's still in the
|
|
// AST. To avoid issues for e.g ASTScope and availability scope
|
|
// construction, only walk the folded expression if we have it.
|
|
if (auto *foldedExpr = E->getFoldedExpr()) {
|
|
auto *newExpr = doIt(foldedExpr);
|
|
if (!newExpr)
|
|
return nullptr;
|
|
|
|
E->setFoldedExpr(newExpr);
|
|
return E;
|
|
}
|
|
|
|
for (unsigned i = 0, e = E->getNumElements(); i != e; ++i)
|
|
if (Expr *Elt = doIt(E->getElement(i)))
|
|
E->setElement(i, Elt);
|
|
else
|
|
return nullptr;
|
|
return E;
|
|
}
|
|
|
|
Expr *visitDynamicTypeExpr(DynamicTypeExpr *E) {
|
|
Expr *base = E->getBase();
|
|
if ((base = doIt(base)))
|
|
E->setBase(base);
|
|
else
|
|
return nullptr;
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitCaptureListExpr(CaptureListExpr *expr) {
|
|
for (auto c : expr->getCaptureList()) {
|
|
if (doIt(c.PBD))
|
|
return nullptr;
|
|
}
|
|
|
|
AbstractClosureExpr *body = expr->getClosureBody();
|
|
if ((body = cast_or_null<AbstractClosureExpr>(doIt(body))))
|
|
expr->setClosureBody(body);
|
|
else
|
|
return nullptr;
|
|
return expr;
|
|
}
|
|
|
|
Expr *visitClosureExpr(ClosureExpr *expr) {
|
|
if (visit(expr->getParameters()))
|
|
return nullptr;
|
|
|
|
if (auto thrownTypeRepr = expr->getExplicitThrownTypeRepr()) {
|
|
if (doIt(thrownTypeRepr))
|
|
return nullptr;
|
|
}
|
|
|
|
if (expr->hasExplicitResultType()) {
|
|
if (doIt(expr->getExplicitResultTypeRepr()))
|
|
return nullptr;
|
|
}
|
|
|
|
// Handle other closures.
|
|
if (BraceStmt *body = cast_or_null<BraceStmt>(doIt(expr->getBody()))) {
|
|
expr->setBody(body);
|
|
return expr;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitAutoClosureExpr(AutoClosureExpr *E) {
|
|
if (Expr *E2 = doIt(E->getSingleExpressionBody())) {
|
|
E->setBody(E2);
|
|
return E;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Expr *visitApplyExpr(ApplyExpr *E) {
|
|
if (E->getFn()) {
|
|
Expr *E2 = doIt(E->getFn());
|
|
if (E2 == nullptr) return nullptr;
|
|
E->setFn(E2);
|
|
}
|
|
|
|
if (auto *args = doIt(E->getArgs())) {
|
|
E->setArgs(args);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitSelfApplyExpr(SelfApplyExpr *E) {
|
|
if (E->getBase()) {
|
|
Expr *E2 = doIt(E->getBase());
|
|
if (E2 == nullptr) return nullptr;
|
|
E->setBase(E2);
|
|
}
|
|
|
|
if (E->getFn()) {
|
|
Expr *E2 = doIt(E->getFn());
|
|
if (E2 == nullptr) return nullptr;
|
|
E->setFn(E2);
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *E) {
|
|
Expr *E2 = doIt(E->getLHS());
|
|
if (E2 == nullptr) return nullptr;
|
|
E->setLHS(E2);
|
|
|
|
E2 = doIt(E->getRHS());
|
|
if (E2 == nullptr) return nullptr;
|
|
E->setRHS(E2);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitExplicitCastExpr(ExplicitCastExpr *E) {
|
|
if (Expr *Sub = E->getSubExpr()) {
|
|
Sub = doIt(Sub);
|
|
if (!Sub) return nullptr;
|
|
E->setSubExpr(Sub);
|
|
}
|
|
|
|
if (auto *const tyRepr = E->getCastTypeRepr())
|
|
if (doIt(tyRepr))
|
|
return nullptr;
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitArrowExpr(ArrowExpr *E) {
|
|
if (Expr *Args = E->getArgsExpr()) {
|
|
Args = doIt(Args);
|
|
if (!Args) return nullptr;
|
|
E->setArgsExpr(Args);
|
|
}
|
|
if (Expr *Thrown = E->getThrownTypeExpr()) {
|
|
Thrown = doIt(Thrown);
|
|
if (!Thrown) return nullptr;
|
|
E->setThrownTypeExpr(Thrown);
|
|
}
|
|
if (Expr *Result = E->getResultExpr()) {
|
|
Result = doIt(Result);
|
|
if (!Result) return nullptr;
|
|
E->setResultExpr(Result);
|
|
}
|
|
return E;
|
|
}
|
|
|
|
Expr *visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) {
|
|
Expr *Sub = doIt(E->getSubExpr());
|
|
if (!Sub) return nullptr;
|
|
E->setSubExpr(Sub);
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitAssignExpr(AssignExpr *AE) {
|
|
if (Expr *Dest = AE->getDest()) {
|
|
if (!(Dest = doIt(Dest)))
|
|
return nullptr;
|
|
AE->setDest(Dest);
|
|
}
|
|
|
|
if (Expr *Src = AE->getSrc()) {
|
|
if (!(Src = doIt(AE->getSrc())))
|
|
return nullptr;
|
|
AE->setSrc(Src);
|
|
}
|
|
|
|
return AE;
|
|
}
|
|
|
|
Expr *visitEnumIsCaseExpr(EnumIsCaseExpr *E) {
|
|
if (Expr *Sub = E->getSubExpr()) {
|
|
if (!(Sub = doIt(Sub)))
|
|
return nullptr;
|
|
E->setSubExpr(Sub);
|
|
}
|
|
|
|
if (auto *typerepr = E->getCaseTypeRepr())
|
|
if (doIt(typerepr))
|
|
return nullptr;
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitTernaryExpr(TernaryExpr *E) {
|
|
if (Expr *Cond = E->getCondExpr()) {
|
|
Cond = doIt(Cond);
|
|
if (!Cond) return nullptr;
|
|
E->setCondExpr(Cond);
|
|
}
|
|
|
|
Expr *Then = doIt(E->getThenExpr());
|
|
if (!Then) return nullptr;
|
|
E->setThenExpr(Then);
|
|
|
|
if (Expr *Else = E->getElseExpr()) {
|
|
Else = doIt(Else);
|
|
if (!Else) return nullptr;
|
|
E->setElseExpr(Else);
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitUnresolvedPatternExpr(UnresolvedPatternExpr *E) {
|
|
Pattern *sub = doIt(E->getSubPattern());
|
|
if (!sub) return nullptr;
|
|
|
|
E->setSubPattern(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitBindOptionalExpr(BindOptionalExpr *E) {
|
|
Expr *sub = doIt(E->getSubExpr());
|
|
if (!sub) return nullptr;
|
|
|
|
E->setSubExpr(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitOptionalEvaluationExpr(OptionalEvaluationExpr *E) {
|
|
Expr *sub = doIt(E->getSubExpr());
|
|
if (!sub) return nullptr;
|
|
|
|
E->setSubExpr(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitForceValueExpr(ForceValueExpr *E) {
|
|
Expr *sub = doIt(E->getSubExpr());
|
|
if (!sub) return nullptr;
|
|
|
|
E->setSubExpr(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitOpenExistentialExpr(OpenExistentialExpr *E) {
|
|
Expr *existential = doIt(E->getExistentialValue());
|
|
if (!existential) return nullptr;
|
|
|
|
Expr *sub = doIt(E->getSubExpr());
|
|
if (!sub) return nullptr;
|
|
|
|
E->setExistentialValue(existential);
|
|
E->setSubExpr(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitMakeTemporarilyEscapableExpr(MakeTemporarilyEscapableExpr *E) {
|
|
Expr *closure = doIt(E->getNonescapingClosureValue());
|
|
if (!closure) return nullptr;
|
|
|
|
Expr *sub = doIt(E->getSubExpr());
|
|
if (!sub) return nullptr;
|
|
|
|
E->setNonescapingClosureValue(closure);
|
|
E->setSubExpr(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitEditorPlaceholderExpr(EditorPlaceholderExpr *E) {
|
|
return E;
|
|
}
|
|
|
|
Expr *visitLazyInitializerExpr(LazyInitializerExpr *E) {
|
|
// The initializer is opaque unless we specifically want to visit it as part
|
|
// of the accessor body.
|
|
if (Walker.getLazyInitializerWalkingBehavior() !=
|
|
LazyInitializerWalking::InAccessor) {
|
|
return E;
|
|
}
|
|
auto *sub = doIt(E->getSubExpr());
|
|
if (!sub)
|
|
return nullptr;
|
|
|
|
E->setSubExpr(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitObjCSelectorExpr(ObjCSelectorExpr *E) {
|
|
Expr *sub = doIt(E->getSubExpr());
|
|
if (!sub) return nullptr;
|
|
|
|
E->setSubExpr(sub);
|
|
return E;
|
|
}
|
|
|
|
Expr *visitKeyPathExpr(KeyPathExpr *E) {
|
|
// For an ObjC key path, the string literal expr serves as the semantic
|
|
// expression.
|
|
if (auto objcStringLiteral = E->getObjCStringLiteralExpr()) {
|
|
Expr *sub = doIt(objcStringLiteral);
|
|
if (!sub) return nullptr;
|
|
E->setObjCStringLiteralExpr(sub);
|
|
}
|
|
|
|
auto components = E->getComponents();
|
|
if (components.empty()) {
|
|
// No components means a parsed-only/pre-resolution Swift key path.
|
|
assert(!E->isObjC());
|
|
if (auto parsedRoot = E->getParsedRoot()) {
|
|
Expr *newRoot = doIt(parsedRoot);
|
|
if (!newRoot)
|
|
return nullptr;
|
|
E->setParsedRoot(newRoot);
|
|
}
|
|
if (auto parsedPath = E->getParsedPath()) {
|
|
Expr *newPath = doIt(parsedPath);
|
|
if (!newPath)
|
|
return nullptr;
|
|
E->setParsedPath(newPath);
|
|
}
|
|
return E;
|
|
}
|
|
|
|
if (!E->isObjC()) {
|
|
auto rootType = E->getExplicitRootType();
|
|
if (rootType && doIt(rootType))
|
|
return nullptr;
|
|
}
|
|
|
|
for (auto &origComponent : components) {
|
|
auto component = origComponent;
|
|
switch (component.getKind()) {
|
|
case KeyPathExpr::Component::Kind::Subscript:
|
|
case KeyPathExpr::Component::Kind::UnresolvedSubscript:
|
|
case KeyPathExpr::Component::Kind::Apply:
|
|
case KeyPathExpr::Component::Kind::UnresolvedApply: {
|
|
if (auto *newArgs = doIt(component.getArgs())) {
|
|
component.setArgs(newArgs);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case KeyPathExpr::Component::Kind::OptionalChain:
|
|
case KeyPathExpr::Component::Kind::OptionalWrap:
|
|
case KeyPathExpr::Component::Kind::OptionalForce:
|
|
case KeyPathExpr::Component::Kind::Member:
|
|
case KeyPathExpr::Component::Kind::UnresolvedMember:
|
|
case KeyPathExpr::Component::Kind::Invalid:
|
|
case KeyPathExpr::Component::Kind::Identity:
|
|
case KeyPathExpr::Component::Kind::TupleElement:
|
|
case KeyPathExpr::Component::Kind::DictionaryKey:
|
|
case KeyPathExpr::Component::Kind::CodeCompletion:
|
|
// No subexpr to visit.
|
|
break;
|
|
}
|
|
}
|
|
return E;
|
|
}
|
|
|
|
Expr *visitCurrentContextIsolationExpr(CurrentContextIsolationExpr *E) {
|
|
if (auto actor = E->getActor()) {
|
|
if (auto newActor = doIt(actor))
|
|
E->setActor(newActor);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitExtractFunctionIsolationExpr(ExtractFunctionIsolationExpr *E) {
|
|
if (auto fn = E->getFunctionExpr()) {
|
|
if (auto newFn = doIt(fn))
|
|
E->setFunctionExpr(newFn);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitKeyPathDotExpr(KeyPathDotExpr *E) { return E; }
|
|
|
|
Expr *visitSingleValueStmtExpr(SingleValueStmtExpr *E) {
|
|
if (auto preamble = E->getForExpressionPreamble()) {
|
|
if (doIt(preamble->ForAccumulatorDecl)) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (doIt(preamble->ForAccumulatorBinding)) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
if (auto *S = doIt(E->getStmt())) {
|
|
E->setStmt(S);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
return E;
|
|
}
|
|
|
|
Expr *visitTapExpr(TapExpr *E) {
|
|
if (auto oldSubExpr = E->getSubExpr()) {
|
|
if (auto subExpr = doIt(oldSubExpr)) {
|
|
E->setSubExpr(subExpr);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
if (!Walker.shouldWalkIntoTapExpression())
|
|
return E;
|
|
|
|
if (auto oldBody = E->getBody()) {
|
|
if (auto body = doIt(oldBody)) {
|
|
E->setBody(dyn_cast<BraceStmt>(body));
|
|
}
|
|
else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitRegexLiteralExpr(RegexLiteralExpr *E) {
|
|
return E;
|
|
}
|
|
|
|
Expr *visitTypeJoinExpr(TypeJoinExpr *E) {
|
|
if (auto *var = E->getVar()) {
|
|
if (auto *newVar = dyn_cast<DeclRefExpr>(doIt(var))) {
|
|
E->setVar(newVar);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
for (unsigned i = 0, e = E->getNumElements(); i != e; ++i) {
|
|
if (auto *origElt = E->getElement(i)) {
|
|
if (Expr *Elt = doIt(origElt))
|
|
E->setElement(i, Elt);
|
|
else
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
return E;
|
|
}
|
|
|
|
Expr *visitMacroExpansionExpr(MacroExpansionExpr *E) {
|
|
bool shouldWalkArguments, shouldWalkExpansion;
|
|
std::tie(shouldWalkArguments, shouldWalkExpansion) =
|
|
Walker.shouldWalkMacroArgumentsAndExpansion();
|
|
|
|
if (auto *substituteDecl = E->getSubstituteDecl()) {
|
|
if (doIt(substituteDecl))
|
|
return nullptr;
|
|
// Visiting the substitute macro expansion decl will visit the same
|
|
// argument list. Skip visiting it again.
|
|
shouldWalkArguments = false;
|
|
}
|
|
|
|
if (shouldWalkArguments && visitFreestandingMacroArgs(E))
|
|
return nullptr;
|
|
|
|
if (shouldWalkExpansion) {
|
|
Expr *rewritten = nullptr;
|
|
if (E->getRewritten()) {
|
|
rewritten = doIt(E->getRewritten());
|
|
if (!rewritten) return nullptr;
|
|
}
|
|
E->setRewritten(rewritten);
|
|
}
|
|
return E;
|
|
}
|
|
|
|
Expr *visitTypeValueExpr(TypeValueExpr *E) {
|
|
if (auto *TR = E->getRepr()) {
|
|
if (doIt(TR))
|
|
return nullptr;
|
|
}
|
|
return E;
|
|
}
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Everything Else
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
#define STMT(Id, Parent) Stmt *visit##Id##Stmt(Id##Stmt *S);
|
|
#include "swift/AST/StmtNodes.def"
|
|
|
|
#define PATTERN(Id, Parent) Pattern *visit##Id##Pattern(Id##Pattern *P);
|
|
#include "swift/AST/PatternNodes.def"
|
|
|
|
#define TYPEREPR(Id, Parent) bool visit##Id##TypeRepr(Id##TypeRepr *T);
|
|
#include "swift/AST/TypeReprNodes.def"
|
|
|
|
bool visitDeclRefTypeRepr(DeclRefTypeRepr *T);
|
|
|
|
using Action = ASTWalker::Action;
|
|
|
|
using PreWalkAction = ASTWalker::PreWalkAction;
|
|
using PostWalkAction = ASTWalker::PostWalkAction;
|
|
|
|
template <typename T>
|
|
using PreWalkResult = ASTWalker::PreWalkResult<T>;
|
|
|
|
template <typename T>
|
|
using PostWalkResult = ASTWalker::PostWalkResult<T>;
|
|
|
|
[[nodiscard]]
|
|
bool traverse(PreWalkAction Pre, llvm::function_ref<bool(void)> VisitChildren,
|
|
llvm::function_ref<PostWalkAction(void)> WalkPost) {
|
|
switch (Pre.Action) {
|
|
case PreWalkAction::Stop:
|
|
return true;
|
|
case PreWalkAction::SkipNode:
|
|
return false;
|
|
case PreWalkAction::SkipChildren:
|
|
break;
|
|
case PreWalkAction::Continue:
|
|
if (VisitChildren())
|
|
return true;
|
|
break;
|
|
}
|
|
switch (WalkPost().Action) {
|
|
case PostWalkAction::Stop:
|
|
return true;
|
|
case PostWalkAction::Continue:
|
|
return false;
|
|
}
|
|
llvm_unreachable("Unhandled case in switch!");
|
|
}
|
|
|
|
template <typename T>
|
|
[[nodiscard]]
|
|
T *traverse(PreWalkResult<T *> Pre,
|
|
llvm::function_ref<T *(T *)> VisitChildren,
|
|
llvm::function_ref<PostWalkResult<T *>(T *)> WalkPost) {
|
|
auto Node = Pre.Value;
|
|
assert(!Node || *Node && "Use Action::Stop instead of returning nullptr");
|
|
switch (Pre.Action.Action) {
|
|
case PreWalkAction::Stop:
|
|
return nullptr;
|
|
case PreWalkAction::SkipNode:
|
|
return *Node;
|
|
case PreWalkAction::SkipChildren:
|
|
break;
|
|
case PreWalkAction::Continue: {
|
|
auto NewNode = VisitChildren(*Node);
|
|
if (!NewNode)
|
|
return nullptr;
|
|
|
|
Node = NewNode;
|
|
break;
|
|
}
|
|
}
|
|
auto Post = WalkPost(*Node);
|
|
switch (Post.Action.Action) {
|
|
case PostWalkAction::Stop:
|
|
return nullptr;
|
|
case PostWalkAction::Continue:
|
|
assert(*Post.Value && "Use Action::Stop instead of returning nullptr");
|
|
return *Post.Value;
|
|
}
|
|
llvm_unreachable("Unhandled case in switch!");
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool visitParameterList(ParameterList *PL) {
|
|
return traverse(
|
|
Walker.walkToParameterListPre(PL),
|
|
[&]() {
|
|
for (auto P : *PL) {
|
|
// Walk each parameter's decl and typeloc and default value.
|
|
if (doIt(P))
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
[&]() { return Walker.walkToParameterListPost(PL); });
|
|
}
|
|
|
|
public:
|
|
Traversal(ASTWalker &walker) : Walker(walker) {}
|
|
|
|
[[nodiscard]]
|
|
Expr *doIt(Expr *E) {
|
|
return traverse<Expr>(
|
|
Walker.walkToExprPre(E),
|
|
[&](Expr *E) { return visit(E); },
|
|
[&](Expr *E) { return Walker.walkToExprPost(E); });
|
|
}
|
|
|
|
[[nodiscard]]
|
|
Stmt *doIt(Stmt *S) {
|
|
return traverse<Stmt>(
|
|
Walker.walkToStmtPre(S),
|
|
[&](Stmt *S) { return visit(S); },
|
|
[&](Stmt *S) { return Walker.walkToStmtPost(S); });
|
|
}
|
|
|
|
bool shouldSkip(Decl *D) {
|
|
if (!Walker.shouldWalkMacroArgumentsAndExpansion().second &&
|
|
Walker.isDeclInMacroExpansion(D) && !Walker.Parent.isNull())
|
|
return true;
|
|
|
|
if (auto *VD = dyn_cast<VarDecl>(D)) {
|
|
// VarDecls are walked via their NamedPattern, ignore them if we encounter
|
|
// then in the few cases where they are also pushed outside as members.
|
|
// In all those cases we can walk them via the pattern binding decl.
|
|
// This is used for when vising VarDecls from source, when visiting a
|
|
// module file we walk them as we encounter them.
|
|
if (Walker.Parent.getAsModule() &&
|
|
D->getDeclContext()->getParentSourceFile())
|
|
return true;
|
|
if (Walker.Parent.getAsDecl() && VD->getParentPatternBinding())
|
|
return true;
|
|
auto walkerParentAsStmt = Walker.Parent.getAsStmt();
|
|
if (isa_and_nonnull<BraceStmt>(walkerParentAsStmt))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Returns true on failure.
|
|
[[nodiscard]]
|
|
bool doIt(Decl *D) {
|
|
if (shouldSkip(D))
|
|
return false;
|
|
|
|
return traverse(
|
|
Walker.walkToDeclPre(D),
|
|
[&]() { return visit(D); },
|
|
[&]() { return Walker.walkToDeclPost(D); });
|
|
}
|
|
|
|
[[nodiscard]]
|
|
Pattern *doIt(Pattern *P) {
|
|
return traverse<Pattern>(
|
|
Walker.walkToPatternPre(P),
|
|
[&](Pattern *P) { return visit(P); },
|
|
[&](Pattern *P) { return Walker.walkToPatternPost(P); });
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool doIt(const StmtCondition &C) {
|
|
for (auto &elt : C) {
|
|
switch (elt.getKind()) {
|
|
case StmtConditionElement::CK_Availability:
|
|
break;
|
|
case StmtConditionElement::CK_HasSymbol: {
|
|
auto E = elt.getHasSymbolInfo()->getSymbolExpr();
|
|
if (!E)
|
|
return true;
|
|
E = doIt(E);
|
|
if (!E)
|
|
return true;
|
|
elt.getHasSymbolInfo()->setSymbolExpr(E);
|
|
break;
|
|
}
|
|
case StmtConditionElement::CK_Boolean: {
|
|
auto E = elt.getBoolean();
|
|
// Walk an expression condition normally.
|
|
E = doIt(E);
|
|
if (!E)
|
|
return true;
|
|
elt.setBoolean(E);
|
|
break;
|
|
}
|
|
|
|
case StmtConditionElement::CK_PatternBinding: {
|
|
auto *P = doIt(elt.getPattern());
|
|
if (!P) return true;
|
|
elt.setPattern(P);
|
|
|
|
auto *I = doIt(elt.getInitializer());
|
|
if (!I) return true;
|
|
elt.setInitializer(I);
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
/// Walk a `QualifiedIdentTypeRepr` in source order such that each subsequent
|
|
/// dot-separated component is a child of the previous one
|
|
[[nodiscard]] bool doItInSourceOrderRecursive(QualifiedIdentTypeRepr *T);
|
|
|
|
public:
|
|
/// Returns true on failure.
|
|
[[nodiscard]]
|
|
bool doIt(TypeRepr *T) {
|
|
if (auto *QualIdentTR = dyn_cast<QualifiedIdentTypeRepr>(T)) {
|
|
switch (Walker.getQualifiedIdentTypeReprWalkingScheme()) {
|
|
case QualifiedIdentTypeReprWalkingScheme::SourceOrderRecursive:
|
|
return doItInSourceOrderRecursive(QualIdentTR);
|
|
case QualifiedIdentTypeReprWalkingScheme::ASTOrderRecursive:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return traverse(
|
|
Walker.walkToTypeReprPre(T),
|
|
[&]() { return visit(T); },
|
|
[&]() { return Walker.walkToTypeReprPost(T); });
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool doIt(RequirementRepr &Req) {
|
|
switch (Req.getKind()) {
|
|
case RequirementReprKind::SameType:
|
|
if (doIt(Req.getFirstTypeRepr()) || doIt(Req.getSecondTypeRepr()))
|
|
return true;
|
|
break;
|
|
case RequirementReprKind::TypeConstraint:
|
|
if (doIt(Req.getSubjectRepr()) || doIt(Req.getConstraintRepr()))
|
|
return true;
|
|
break;
|
|
case RequirementReprKind::LayoutConstraint:
|
|
if (doIt(Req.getSubjectRepr()))
|
|
return true;
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool doIt(GenericParamList *GPL) {
|
|
// Visit generic params
|
|
for (auto &P : GPL->getParams()) {
|
|
if (doIt(P))
|
|
return true;
|
|
}
|
|
|
|
// Visit param conformance
|
|
for (auto Req : GPL->getRequirements()) {
|
|
if (doIt(Req))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
bool doIt(ArgumentList *ArgList, unsigned Idx) {
|
|
auto Arg = ArgList->get(Idx);
|
|
return traverse(
|
|
Walker.walkToArgumentPre(Arg),
|
|
[&]() {
|
|
auto *E = doIt(Arg.getExpr());
|
|
if (!E)
|
|
return true;
|
|
ArgList->setExpr(Idx, E);
|
|
return false;
|
|
},
|
|
[&]() { return Walker.walkToArgumentPost(Arg); });
|
|
}
|
|
|
|
[[nodiscard]]
|
|
ArgumentList *visit(ArgumentList *ArgList) {
|
|
for (auto Idx : indices(*ArgList)) {
|
|
if (doIt(ArgList, Idx))
|
|
return nullptr;
|
|
}
|
|
return ArgList;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
ArgumentList *doIt(ArgumentList *ArgList) {
|
|
return traverse<ArgumentList>(
|
|
Walker.walkToArgumentListPre(ArgList),
|
|
[&](ArgumentList *ArgList) { return visit(ArgList); },
|
|
[&](ArgumentList *ArgList) {
|
|
return Walker.walkToArgumentListPost(ArgList);
|
|
});
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
bool Traversal::doItInSourceOrderRecursive(QualifiedIdentTypeRepr *T) {
|
|
// Qualified types are modeled resursively such that each previous
|
|
// dot-separated component is a child of the next one. To walk a member type
|
|
// representation according to
|
|
// `QualifiedIdentTypeReprWalkingScheme::SourceOrderRecursive`:
|
|
|
|
// 1. Pre-walk the dot-separated components in source order. If asked to skip
|
|
// the children of a given component:
|
|
// 1. Set the depth at which to start post-walking later.
|
|
// 2. Skip its generic arguments and subsequent components.
|
|
std::function<bool(TypeRepr *, std::optional<unsigned> &, unsigned)>
|
|
doItInSourceOrderPre = [&](TypeRepr *T,
|
|
std::optional<unsigned> &StartPostWalkDepth,
|
|
unsigned Depth) {
|
|
if (auto *QualIdentTR = dyn_cast<QualifiedIdentTypeRepr>(T)) {
|
|
if (doItInSourceOrderPre(QualIdentTR->getBase(), StartPostWalkDepth,
|
|
Depth + 1)) {
|
|
return true;
|
|
}
|
|
|
|
if (StartPostWalkDepth.has_value()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
switch (this->Walker.walkToTypeReprPre(T).Action) {
|
|
case PreWalkAction::Stop:
|
|
return true;
|
|
case PreWalkAction::SkipChildren:
|
|
StartPostWalkDepth = Depth;
|
|
return false;
|
|
case PreWalkAction::SkipNode:
|
|
StartPostWalkDepth = Depth + 1;
|
|
return false;
|
|
case PreWalkAction::Continue:
|
|
break;
|
|
}
|
|
|
|
if (auto *DeclRefTR = dyn_cast<DeclRefTypeRepr>(T)) {
|
|
for (auto *Arg : DeclRefTR->getGenericArgs()) {
|
|
if (doIt(Arg)) {
|
|
return true;
|
|
}
|
|
}
|
|
} else if (visit(T)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
// 2. Post-walk the components in reverse order, respecting the depth at which
|
|
// to start post-walking if set.
|
|
std::function<bool(TypeRepr *, std::optional<unsigned>, unsigned)>
|
|
doItInSourceOrderPost = [&](TypeRepr *T,
|
|
std::optional<unsigned> StartPostWalkDepth,
|
|
unsigned Depth) {
|
|
if (!StartPostWalkDepth.has_value() || Depth >= *StartPostWalkDepth) {
|
|
switch (this->Walker.walkToTypeReprPost(T).Action) {
|
|
case PostWalkAction::Continue:
|
|
break;
|
|
case PostWalkAction::Stop:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (auto *QualIdentTR = dyn_cast<QualifiedIdentTypeRepr>(T)) {
|
|
return doItInSourceOrderPost(QualIdentTR->getBase(),
|
|
StartPostWalkDepth, Depth + 1);
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
std::optional<unsigned> StartPostWalkDepth;
|
|
|
|
if (doItInSourceOrderPre(T, StartPostWalkDepth, 0)) {
|
|
return true;
|
|
}
|
|
|
|
return doItInSourceOrderPost(T, StartPostWalkDepth, 0);
|
|
}
|
|
|
|
#pragma mark Statement traversal
|
|
Stmt *Traversal::visitBreakStmt(BreakStmt *BS) {
|
|
return BS;
|
|
}
|
|
|
|
Stmt *Traversal::visitContinueStmt(ContinueStmt *CS) {
|
|
return CS;
|
|
}
|
|
|
|
Stmt *Traversal::visitFallthroughStmt(FallthroughStmt *CS) {
|
|
return CS;
|
|
}
|
|
|
|
Stmt *Traversal::visitFailStmt(FailStmt *FS) {
|
|
return FS;
|
|
}
|
|
Stmt *Traversal::visitThrowStmt(ThrowStmt *TS) {
|
|
if (Expr *E = doIt(TS->getSubExpr())) {
|
|
TS->setSubExpr(E);
|
|
return TS;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Stmt *Traversal::visitDiscardStmt(DiscardStmt *DS) {
|
|
if (Expr *E = doIt(DS->getSubExpr())) {
|
|
DS->setSubExpr(E);
|
|
return DS;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Stmt *Traversal::visitPoundAssertStmt(PoundAssertStmt *S) {
|
|
if (auto *condition = doIt(S->getCondition())) {
|
|
S->setCondition(condition);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
return S;
|
|
}
|
|
|
|
Stmt *Traversal::visitBraceStmt(BraceStmt *BS) {
|
|
for (auto &Elem : BS->getElements()) {
|
|
if (auto *SubExpr = Elem.dyn_cast<Expr*>()) {
|
|
if (Expr *E2 = doIt(SubExpr))
|
|
Elem = E2;
|
|
else
|
|
return nullptr;
|
|
continue;
|
|
}
|
|
|
|
if (auto *S = Elem.dyn_cast<Stmt*>()) {
|
|
if (Stmt *S2 = doIt(S))
|
|
Elem = S2;
|
|
else
|
|
return nullptr;
|
|
continue;
|
|
}
|
|
|
|
auto *D = cast<Decl *>(Elem);
|
|
if (doIt(D))
|
|
return nullptr;
|
|
|
|
if (Walker.shouldWalkAccessorsTheOldWay()) {
|
|
// Pretend that accessors share a parent with the storage.
|
|
//
|
|
// FIXME: Update existing ASTWalkers to deal with accessors appearing as
|
|
// children of the storage instead.
|
|
if (auto *ASD = dyn_cast<AbstractStorageDecl>(D)) {
|
|
for (auto AD : ASD->getAllAccessors()) {
|
|
if (doIt(AD))
|
|
return nullptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return BS;
|
|
}
|
|
|
|
Stmt *Traversal::visitReturnStmt(ReturnStmt *RS) {
|
|
if (!RS->hasResult())
|
|
return RS;
|
|
if (Expr *E = doIt(RS->getResult()))
|
|
RS->setResult(E);
|
|
else
|
|
return nullptr;
|
|
return RS;
|
|
}
|
|
|
|
Stmt *Traversal::visitYieldStmt(YieldStmt *YS) {
|
|
for (auto &yield : YS->getMutableYields()) {
|
|
if (Expr *E = doIt(yield))
|
|
yield = E;
|
|
else
|
|
return nullptr;
|
|
}
|
|
return YS;
|
|
}
|
|
|
|
Stmt *Traversal::visitThenStmt(ThenStmt *TS) {
|
|
auto *E = doIt(TS->getResult());
|
|
if (!E)
|
|
return nullptr;
|
|
|
|
TS->setResult(E);
|
|
return TS;
|
|
}
|
|
|
|
Stmt *Traversal::visitDeferStmt(DeferStmt *DS) {
|
|
if (doIt(DS->getTempDecl()))
|
|
return nullptr;
|
|
|
|
if (Expr *Call = doIt(DS->getCallExpr()))
|
|
DS->setCallExpr(Call);
|
|
else
|
|
return nullptr;
|
|
return DS;
|
|
}
|
|
|
|
Stmt *Traversal::visitIfStmt(IfStmt *IS) {
|
|
if (doIt(IS->getCond()))
|
|
return nullptr;
|
|
|
|
if (auto *S2 = doIt(IS->getThenStmt()))
|
|
IS->setThenStmt(cast<BraceStmt>(S2));
|
|
else
|
|
return nullptr;
|
|
|
|
if (IS->getElseStmt()) {
|
|
if (Stmt *S2 = doIt(IS->getElseStmt()))
|
|
IS->setElseStmt(S2);
|
|
else
|
|
return nullptr;
|
|
}
|
|
return IS;
|
|
}
|
|
|
|
Stmt *Traversal::visitGuardStmt(GuardStmt *US) {
|
|
if (doIt(US->getCond()))
|
|
return nullptr;
|
|
|
|
if (BraceStmt *S2 = cast_or_null<BraceStmt>(doIt(US->getBody())))
|
|
US->setBody(S2);
|
|
else
|
|
return nullptr;
|
|
return US;
|
|
}
|
|
|
|
Stmt *Traversal::visitDoStmt(DoStmt *DS) {
|
|
if (BraceStmt *S2 = cast_or_null<BraceStmt>(doIt(DS->getBody())))
|
|
DS->setBody(S2);
|
|
else
|
|
return nullptr;
|
|
|
|
return DS;
|
|
}
|
|
|
|
Stmt *Traversal::visitDoCatchStmt(DoCatchStmt *stmt) {
|
|
// Transform the body of the 'do'.
|
|
if (Stmt *newBody = doIt(stmt->getBody())) {
|
|
stmt->setBody(newBody);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
|
|
// Transform each of the catch clauses:
|
|
for (CaseStmt *&clause : stmt->getMutableCatches()) {
|
|
if (auto newClause = doIt(clause)) {
|
|
clause = cast<CaseStmt>(newClause);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
return stmt;
|
|
}
|
|
|
|
Stmt *Traversal::visitWhileStmt(WhileStmt *WS) {
|
|
if (doIt(WS->getCond()))
|
|
return nullptr;
|
|
|
|
if (Stmt *S2 = doIt(WS->getBody()))
|
|
WS->setBody(S2);
|
|
else
|
|
return nullptr;
|
|
return WS;
|
|
}
|
|
|
|
Stmt *Traversal::visitRepeatWhileStmt(RepeatWhileStmt *RWS) {
|
|
if (Stmt *S2 = doIt(RWS->getBody()))
|
|
RWS->setBody(S2);
|
|
else
|
|
return nullptr;
|
|
|
|
if (Expr *E2 = doIt(RWS->getCond()))
|
|
RWS->setCond(E2);
|
|
else
|
|
return nullptr;
|
|
|
|
return RWS;
|
|
}
|
|
|
|
Stmt *Traversal::visitForEachStmt(ForEachStmt *S) {
|
|
if (Pattern *P = S->getPattern()) {
|
|
if ((P = doIt(P)))
|
|
assert(P == S->getPattern() && "cannot change pattern of ForEachStmt");
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
// The iterator decl is built directly on top of the sequence
|
|
// expression, so don't visit both.
|
|
//
|
|
// If for-in is already type-checked, the type-checked version
|
|
// of the sequence is going to be visited as part of `iteratorVar`.
|
|
if (auto IteratorVar = S->getIteratorVar()) {
|
|
if (doIt(IteratorVar))
|
|
return nullptr;
|
|
|
|
if (auto NextCall = S->getNextCall()) {
|
|
if ((NextCall = doIt(NextCall)))
|
|
S->setNextCall(NextCall);
|
|
else
|
|
return nullptr;
|
|
}
|
|
} else {
|
|
if (Expr *Sequence = S->getParsedSequence()) {
|
|
if ((Sequence = doIt(Sequence)))
|
|
S->setParsedSequence(Sequence);
|
|
else
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
if (Expr *Where = S->getWhere()) {
|
|
if ((Where = doIt(Where)))
|
|
S->setWhere(Where);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
if (auto IteratorNext = S->getConvertElementExpr()) {
|
|
if ((IteratorNext = doIt(IteratorNext)))
|
|
S->setConvertElementExpr(IteratorNext);
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
if (Stmt *Body = S->getBody()) {
|
|
if ((Body = doIt(Body)))
|
|
S->setBody(cast<BraceStmt>(Body));
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
return S;
|
|
}
|
|
|
|
Stmt *Traversal::visitSwitchStmt(SwitchStmt *S) {
|
|
if (Expr *newSubject = doIt(S->getSubjectExpr()))
|
|
S->setSubjectExpr(newSubject);
|
|
else
|
|
return nullptr;
|
|
|
|
for (auto *aCase : S->getCases()) {
|
|
if (Stmt *aStmt = doIt(aCase)) {
|
|
assert(aCase == aStmt && "switch case remap not supported");
|
|
(void)aStmt;
|
|
} else
|
|
return nullptr;
|
|
}
|
|
|
|
return S;
|
|
}
|
|
|
|
Stmt *Traversal::visitCaseStmt(CaseStmt *S) {
|
|
for (auto &CLI : S->getMutableCaseLabelItems()) {
|
|
if (auto *newPattern = doIt(CLI.getPattern()))
|
|
CLI.setPattern(newPattern, /*resolved=*/CLI.isPatternResolved());
|
|
else
|
|
return nullptr;
|
|
if (CLI.getGuardExpr()) {
|
|
if (auto *newGuard = doIt(CLI.getGuardExpr()))
|
|
CLI.setGuardExpr(newGuard);
|
|
else
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
if (BraceStmt *newBody = cast_or_null<BraceStmt>(doIt(S->getBody())))
|
|
S->setBody(newBody);
|
|
else
|
|
return nullptr;
|
|
|
|
return S;
|
|
}
|
|
|
|
#pragma mark Pattern traversal
|
|
Pattern *Traversal::visitParenPattern(ParenPattern *P) {
|
|
if (Pattern *newSub = doIt(P->getSubPattern()))
|
|
P->setSubPattern(newSub);
|
|
else
|
|
return nullptr;
|
|
return P;
|
|
}
|
|
|
|
Pattern *Traversal::visitTuplePattern(TuplePattern *P) {
|
|
for (auto &element : P->getElements()) {
|
|
if (Pattern *newField = doIt(element.getPattern()))
|
|
element.setPattern(newField);
|
|
else
|
|
return nullptr;
|
|
}
|
|
return P;
|
|
}
|
|
|
|
Pattern *Traversal::visitNamedPattern(NamedPattern *P) {
|
|
if (doIt(P->getDecl()))
|
|
return nullptr;
|
|
return P;
|
|
}
|
|
|
|
Pattern *Traversal::visitAnyPattern(AnyPattern *P) {
|
|
return P;
|
|
}
|
|
|
|
Pattern *Traversal::visitTypedPattern(TypedPattern *P) {
|
|
if (Pattern *newSub = doIt(P->getSubPattern()))
|
|
P->setSubPattern(newSub);
|
|
else
|
|
return nullptr;
|
|
if (!P->isImplicit())
|
|
if (auto *TR = P->getTypeRepr())
|
|
if (doIt(TR))
|
|
return nullptr;
|
|
return P;
|
|
}
|
|
|
|
Pattern *Traversal::visitIsPattern(IsPattern *P) {
|
|
if (auto sub = P->getSubPattern()) {
|
|
if (Pattern *newSub = doIt(sub)) {
|
|
P->setSubPattern(newSub);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
if (!P->isImplicit())
|
|
if (auto *TR = P->getCastTypeRepr())
|
|
if (doIt(TR))
|
|
return nullptr;
|
|
return P;
|
|
}
|
|
|
|
Pattern *Traversal::visitEnumElementPattern(EnumElementPattern *P) {
|
|
if (auto *TR = P->getParentTypeRepr())
|
|
if (doIt(TR))
|
|
return nullptr;
|
|
|
|
if (!P->hasSubPattern())
|
|
return P;
|
|
|
|
if (Pattern *newSub = doIt(P->getSubPattern())) {
|
|
P->setSubPattern(newSub);
|
|
return P;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Pattern *Traversal::visitExprPattern(ExprPattern *P) {
|
|
// If the pattern has been type-checked, walk the match expression, which
|
|
// includes the explicit subexpression.
|
|
if (auto *match = P->getCachedMatchExpr()) {
|
|
if (Expr *newMatch = doIt(match)) {
|
|
P->setMatchExpr(newMatch);
|
|
return P;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
if (Expr *newSub = doIt(P->getSubExpr())) {
|
|
P->setSubExpr(newSub);
|
|
return P;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Pattern *Traversal::visitBindingPattern(BindingPattern *P) {
|
|
if (Pattern *newSub = doIt(P->getSubPattern())) {
|
|
P->setSubPattern(newSub);
|
|
return P;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Pattern *Traversal::visitOptionalSomePattern(OptionalSomePattern *P) {
|
|
if (Pattern *newSub = doIt(P->getSubPattern())) {
|
|
P->setSubPattern(newSub);
|
|
return P;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Pattern *Traversal::visitBoolPattern(BoolPattern *P) {
|
|
return P;
|
|
}
|
|
|
|
#pragma mark Type representation traversal
|
|
bool Traversal::visitErrorTypeRepr(ErrorTypeRepr *T) {
|
|
if (auto *originalExpr = T->getOriginalExpr()) {
|
|
auto *newExpr = doIt(originalExpr);
|
|
if (!newExpr)
|
|
return true;
|
|
T->setOriginalExpr(newExpr);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitAttributedTypeRepr(AttributedTypeRepr *T) {
|
|
if (Walker.shouldWalkIntoCustomAttrs()) {
|
|
for (auto attr : T->getAttrs()) {
|
|
auto *CA = attr.dyn_cast<CustomAttr *>();
|
|
if (!CA)
|
|
continue;
|
|
if (visitCustomAttr(CA))
|
|
return true;
|
|
}
|
|
}
|
|
return doIt(T->getTypeRepr());
|
|
}
|
|
|
|
bool Traversal::visitDeclRefTypeRepr(DeclRefTypeRepr *T) {
|
|
if (auto *qualIdentTR = dyn_cast<QualifiedIdentTypeRepr>(T)) {
|
|
if (doIt(qualIdentTR->getBase())) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
for (auto *genericArg : T->getGenericArgs()) {
|
|
if (doIt(genericArg)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitUnqualifiedIdentTypeRepr(UnqualifiedIdentTypeRepr *T) {
|
|
return visitDeclRefTypeRepr(T);
|
|
}
|
|
|
|
bool Traversal::visitQualifiedIdentTypeRepr(QualifiedIdentTypeRepr *T) {
|
|
return visitDeclRefTypeRepr(T);
|
|
}
|
|
|
|
bool Traversal::visitFunctionTypeRepr(FunctionTypeRepr *T) {
|
|
return doIt(T->getArgsTypeRepr()) || doIt(T->getResultTypeRepr());
|
|
}
|
|
|
|
bool Traversal::visitArrayTypeRepr(ArrayTypeRepr *T) {
|
|
return doIt(T->getBase());
|
|
}
|
|
|
|
bool Traversal::visitInlineArrayTypeRepr(InlineArrayTypeRepr *T) {
|
|
return doIt(T->getCount()) || doIt(T->getElement());
|
|
}
|
|
|
|
bool Traversal::visitDictionaryTypeRepr(DictionaryTypeRepr *T) {
|
|
return doIt(T->getKey()) || doIt(T->getValue());
|
|
}
|
|
|
|
bool Traversal::visitOptionalTypeRepr(OptionalTypeRepr *T) {
|
|
return doIt(T->getBase());
|
|
}
|
|
|
|
bool Traversal::visitImplicitlyUnwrappedOptionalTypeRepr(ImplicitlyUnwrappedOptionalTypeRepr *T) {
|
|
return doIt(T->getBase());
|
|
}
|
|
|
|
bool Traversal::visitVarargTypeRepr(VarargTypeRepr *T) {
|
|
return doIt(T->getElementType());
|
|
}
|
|
|
|
bool Traversal::visitPackTypeRepr(PackTypeRepr *T) {
|
|
for (auto &elem : T->getMutableElements())
|
|
if (doIt(elem))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitPackExpansionTypeRepr(PackExpansionTypeRepr *T) {
|
|
return doIt(T->getPatternType());
|
|
}
|
|
|
|
bool Traversal::visitPackElementTypeRepr(PackElementTypeRepr *T) {
|
|
return doIt(T->getPackType());
|
|
}
|
|
|
|
bool Traversal::visitTupleTypeRepr(TupleTypeRepr *T) {
|
|
for (auto &elem : T->getElements()) {
|
|
if (doIt(elem.Type))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitCompositionTypeRepr(CompositionTypeRepr *T) {
|
|
for (auto elem : T->getTypes()) {
|
|
if (doIt(elem))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitMetatypeTypeRepr(MetatypeTypeRepr *T) {
|
|
return doIt(T->getBase());
|
|
}
|
|
|
|
bool Traversal::visitProtocolTypeRepr(ProtocolTypeRepr *T) {
|
|
return doIt(T->getBase());
|
|
}
|
|
|
|
bool Traversal::visitOwnershipTypeRepr(OwnershipTypeRepr *T) {
|
|
return doIt(T->getBase());
|
|
}
|
|
|
|
bool Traversal::visitIsolatedTypeRepr(IsolatedTypeRepr *T) {
|
|
return doIt(T->getBase());
|
|
}
|
|
|
|
bool Traversal::visitSendingTypeRepr(SendingTypeRepr *T) {
|
|
return doIt(T->getBase());
|
|
}
|
|
|
|
bool Traversal::visitCallerIsolatedTypeRepr(CallerIsolatedTypeRepr *T) {
|
|
return doIt(T->getBase());
|
|
}
|
|
|
|
bool Traversal::visitCompileTimeLiteralTypeRepr(CompileTimeLiteralTypeRepr *T) {
|
|
return doIt(T->getBase());
|
|
}
|
|
|
|
bool Traversal::visitConstValueTypeRepr(ConstValueTypeRepr *T) {
|
|
return doIt(T->getBase());
|
|
}
|
|
|
|
bool Traversal::visitOpaqueReturnTypeRepr(OpaqueReturnTypeRepr *T) {
|
|
return doIt(T->getConstraint());
|
|
}
|
|
|
|
bool Traversal::visitNamedOpaqueReturnTypeRepr(NamedOpaqueReturnTypeRepr *T) {
|
|
return doIt(T->getBase());
|
|
}
|
|
|
|
bool Traversal::visitExistentialTypeRepr(ExistentialTypeRepr *T) {
|
|
return doIt(T->getConstraint());
|
|
}
|
|
|
|
bool Traversal::visitInverseTypeRepr(InverseTypeRepr *T) {
|
|
return doIt(T->getConstraint());
|
|
}
|
|
|
|
bool Traversal::visitPlaceholderTypeRepr(PlaceholderTypeRepr *T) {
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitFixedTypeRepr(FixedTypeRepr *T) {
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitSelfTypeRepr(SelfTypeRepr *T) {
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitSILBoxTypeRepr(SILBoxTypeRepr *T) {
|
|
for (auto &field : T->getFields()) {
|
|
if (doIt(field.getFieldType()))
|
|
return true;
|
|
}
|
|
for (auto &arg : T->getGenericArguments()) {
|
|
if (doIt(arg))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Traversal::visitLifetimeDependentTypeRepr(LifetimeDependentTypeRepr *T) {
|
|
return doIt(T->getBase());
|
|
}
|
|
|
|
bool Traversal::visitIntegerTypeRepr(IntegerTypeRepr *T) {
|
|
return false;
|
|
}
|
|
|
|
Expr *Expr::walk(ASTWalker &walker) {
|
|
return Traversal(walker).doIt(this);
|
|
}
|
|
|
|
Stmt *Stmt::walk(ASTWalker &walker) {
|
|
return Traversal(walker).doIt(this);
|
|
}
|
|
|
|
Pattern *Pattern::walk(ASTWalker &walker) {
|
|
return Traversal(walker).doIt(this);
|
|
}
|
|
|
|
TypeRepr *TypeRepr::walk(ASTWalker &walker) {
|
|
(void)Traversal(walker).doIt(this);
|
|
return this;
|
|
}
|
|
|
|
StmtConditionElement *StmtConditionElement::walk(ASTWalker &walker) {
|
|
(void)Traversal(walker).doIt(*this);
|
|
return this;
|
|
}
|
|
|
|
bool Decl::walk(ASTWalker &walker) {
|
|
return Traversal(walker).doIt(this);
|
|
}
|
|
|
|
bool GenericParamList::walk(ASTWalker &walker) {
|
|
return Traversal(walker).doIt(this);
|
|
}
|
|
|
|
ArgumentList *ArgumentList::walk(ASTWalker &walker) {
|
|
return Traversal(walker).doIt(this);
|
|
}
|