blob: f45f84681616c7a7f408a0ac5f1d95b358c239c4 [file] [log] [blame]
//===--- 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 "llvm/ADT/PointerUnion.h"
#include <utility>
namespace swift {
class Decl;
class Expr;
class ClosureExpr;
class ModuleDecl;
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;
llvm::Optional<AccessKind> AccKind;
bool isImplicit = false;
ReferenceMetaData(SemaReferenceKind Kind, llvm::Optional<AccessKind> AccKind,
bool isImplicit = false)
: Kind(Kind), AccKind(AccKind), isImplicit(isImplicit) {}
};
/// An abstract class used to traverse an AST.
class ASTWalker {
public:
enum class ParentKind {
Module, Decl, Stmt, Expr, Pattern, TypeRepr
};
class ParentTy {
ParentKind Kind;
void *Ptr = nullptr;
public:
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;
}
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;
/// This method is called when first visiting an expression
/// before walking into its children.
///
/// \param E The expression to check.
///
/// \returns a pair indicating whether to visit the children along with
/// the expression that should replace this expression in the tree. If the
/// latter is null, the traversal will be terminated.
///
/// The default implementation returns \c {true, E}.
virtual std::pair<bool, Expr *> walkToExprPre(Expr *E) {
return { true, E };
}
/// This method is called after visiting an expression's children.
/// If it returns null, the walk is terminated; otherwise, the
/// returned expression is spliced in where the old expression
/// previously appeared.
///
/// The default implementation always returns its argument.
virtual Expr *walkToExprPost(Expr *E) { return E; }
/// This method is called when first visiting a statement before
/// walking into its children.
///
/// \param S The statement to check.
///
/// \returns a pair indicating whether to visit the children along with
/// the statement that should replace this statement in the tree. If the
/// latter is null, the traversal will be terminated.
///
/// The default implementation returns \c {true, S}.
virtual std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) {
return { true, S };
}
/// This method is called after visiting a statement's children. If
/// it returns null, the walk is terminated; otherwise, the returned
/// statement is spliced in where the old statement previously
/// appeared.
///
/// The default implementation always returns its argument.
virtual Stmt *walkToStmtPost(Stmt *S) { return S; }
/// This method is called when first visiting a pattern before walking into
/// its children.
///
/// \param P The statement to check.
///
/// \returns a pair indicating whether to visit the children along with
/// the statement that should replace this statement in the tree. If the
/// latter is null, the traversal will be terminated.
///
/// The default implementation returns \c {true, P}.
virtual std::pair<bool, Pattern*> walkToPatternPre(Pattern *P) {
return { true, P };
}
/// This method is called after visiting a pattern's children. If
/// it returns null, the walk is terminated; otherwise, the returned
/// pattern is spliced in where the old statement previously
/// appeared.
///
/// The default implementation always returns its argument.
virtual Pattern *walkToPatternPost(Pattern *P) { return P; }
/// walkToDeclPre - This method is called when first visiting a decl, before
/// walking into its children. If it returns false, the subtree is skipped.
///
/// \param D The declaration to check. The callee may update this declaration
/// in-place.
virtual bool walkToDeclPre(Decl *D) { return true; }
/// walkToDeclPost - This method is called after visiting the children of a
/// decl. If it returns false, the remaining traversal is terminated and
/// returns failure.
virtual bool walkToDeclPost(Decl *D) { return true; }
/// This method is called when first visiting a TypeRepr, before
/// walking into its children. If it returns false, the subtree is skipped.
///
/// \param T The TypeRepr to check.
virtual bool walkToTypeReprPre(TypeRepr *T) { return true; }
/// This method is called after visiting the children of a TypeRepr.
/// If it returns false, the remaining traversal is terminated and returns
/// failure.
virtual bool walkToTypeReprPost(TypeRepr *T) { return true; }
/// This method configures whether the walker should explore into the generic
/// params in AbstractFunctionDecl and NominalTypeDecl.
virtual bool shouldWalkIntoGenericParams() { return false; }
/// This method configures whether the walker should walk into the
/// initializers of lazy variables. These initializers are semantically
/// different from other initializers in their context and so sometimes
/// should not be visited.
///
/// Note that visiting the body of the lazy getter will find a
/// LazyInitializerExpr with the initializer as its sub-expression.
/// However, ASTWalker does not walk into LazyInitializerExprs on its own.
virtual bool shouldWalkIntoLazyInitializers() { return true; }
/// This method configures whether the walker should visit the body of a
/// closure that was checked separately from its enclosing expression.
///
/// For work that is performed for every top-level expression, this should
/// be overridden to return false, to avoid duplicating work or visiting
/// bodies of closures that have not yet been type checked.
virtual bool shouldWalkIntoSeparatelyCheckedClosure(ClosureExpr *) {
return true;
}
/// 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 capture
/// initializer expressions within a capture list directly, rather than
/// walking the declarations.
virtual bool shouldWalkCaptureInitializerExpressions() { return false; }
/// 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; }
/// walkToParameterListPre - This method is called when first visiting a
/// ParameterList, before walking into its parameters. If it returns false,
/// the subtree is skipped.
///
virtual bool walkToParameterListPre(ParameterList *PL) { return true; }
/// walkToParameterListPost - This method is called after visiting the
/// children of a parameter list. If it returns false, the remaining
/// traversal is terminated and returns failure.
virtual bool walkToParameterListPost(ParameterList *PL) { return true; }
protected:
ASTWalker() = default;
ASTWalker(const ASTWalker &) = default;
virtual ~ASTWalker() = default;
virtual void anchor();
};
} // end namespace swift
#endif