Files
swift-mirror/include/swift/AST/ASTWalker.h
John McCall 9bee3cac5a Generalize storage implementations to support generalized accessors.
The storage kind has been replaced with three separate "impl kinds",
one for each of the basic access kinds (read, write, and read/write).
This makes it far easier to mix-and-match implementations of different
accessors, as well as subtleties like implementing both a setter
and an independent read/write operation.

AccessStrategy has become a bit more explicit about how exactly the
access should be implemented.  For example, the accessor-based kinds
now carry the exact accessor intended to be used.  Also, I've shifted
responsibilities slightly between AccessStrategy and AccessSemantics
so that AccessSemantics::Ordinary can be used except in the sorts of
semantic-bypasses that accessor synthesis wants.  This requires
knowing the correct DC of the access when computing the access strategy;
the upshot is that SILGenFunction now needs a DC.

Accessor synthesis has been reworked so that only the declarations are
built immediately; body synthesis can be safely delayed out of the main
decl-checking path.  This caused a large number of ramifications,
especially for lazy properties, and greatly inflated the size of this
patch.  That is... really regrettable.  The impetus for changing this
was necessity: I needed to rework accessor synthesis to end its reliance
on distinctions like Stored vs. StoredWithTrivialAccessors, and those
fixes were exposing serious re-entrancy problems, and fixing that... well.
Breaking the fixes apart at this point would be a serious endeavor.
2018-06-30 05:19:03 -04:00

237 lines
8.2 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 "llvm/ADT/PointerUnion.h"
#include <utility>
namespace swift {
class Decl;
class Expr;
class ModuleDecl;
class Stmt;
class Pattern;
class TypeRepr;
struct TypeLoc;
class ParameterList;
enum class AccessKind: unsigned char;
enum class SemaReferenceKind : uint8_t {
ModuleRef = 0,
DeclRef,
DeclMemberRef,
DeclConstructorRef,
TypeRef,
EnumElementRef,
SubscriptRef,
};
struct ReferenceMetaData {
SemaReferenceKind Kind;
llvm::Optional<AccessKind> AccKind;
ReferenceMetaData(SemaReferenceKind Kind, llvm::Optional<AccessKind> AccKind) :
Kind(Kind), AccKind(AccKind) {}
};
/// \brief 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;
}
};
/// \brief 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; }
/// \brief This method is called when first visiting a TypeLoc, before
/// walking into its TypeRepr children. If it returns false, the subtree is
/// skipped.
///
/// \param TL The TypeLoc to check.
virtual bool walkToTypeLocPre(TypeLoc &TL) { return true; }
/// \brief This method is called after visiting the children of a TypeLoc.
/// If it returns false, the remaining traversal is terminated and returns
/// failure.
virtual bool walkToTypeLocPost(TypeLoc &TL) { return true; }
/// \brief 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; }
/// \brief 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; }
/// 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