Viewing file: ConstructionContext.h (27.43 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
//===- ConstructionContext.h - CFG constructor information ------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the ConstructionContext class and its sub-classes, // which represent various different ways of constructing C++ objects // with the additional information the users may want to know about // the constructor. // //===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H #define LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H
#include "clang/Analysis/Support/BumpVector.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h"
namespace clang {
/// Represents a single point (AST node) in the program that requires attention /// during construction of an object. ConstructionContext would be represented /// as a list of such items. class ConstructionContextItem { public: enum ItemKind { VariableKind, NewAllocatorKind, ReturnKind, MaterializationKind, TemporaryDestructorKind, ElidedDestructorKind, ElidableConstructorKind, ArgumentKind, LambdaCaptureKind, STATEMENT_WITH_INDEX_KIND_BEGIN = ArgumentKind, STATEMENT_WITH_INDEX_KIND_END = LambdaCaptureKind, STATEMENT_KIND_BEGIN = VariableKind, STATEMENT_KIND_END = LambdaCaptureKind, InitializerKind, INITIALIZER_KIND_BEGIN = InitializerKind, INITIALIZER_KIND_END = InitializerKind };
LLVM_DUMP_METHOD static StringRef getKindAsString(ItemKind K) { switch (K) { case VariableKind: return "construct into local variable"; case NewAllocatorKind: return "construct into new-allocator"; case ReturnKind: return "construct into return address"; case MaterializationKind: return "materialize temporary"; case TemporaryDestructorKind: return "destroy temporary"; case ElidedDestructorKind: return "elide destructor"; case ElidableConstructorKind: return "elide constructor"; case ArgumentKind: return "construct into argument"; case LambdaCaptureKind: return "construct into lambda captured variable"; case InitializerKind: return "construct into member variable"; }; llvm_unreachable("Unknown ItemKind"); }
private: const void *const Data; const ItemKind Kind; const unsigned Index = 0;
bool hasStatement() const { return Kind >= STATEMENT_KIND_BEGIN && Kind <= STATEMENT_KIND_END; }
bool hasIndex() const { return Kind >= STATEMENT_WITH_INDEX_KIND_BEGIN && Kind <= STATEMENT_WITH_INDEX_KIND_END; }
bool hasInitializer() const { return Kind >= INITIALIZER_KIND_BEGIN && Kind <= INITIALIZER_KIND_END; }
public: // ConstructionContextItem should be simple enough so that it was easy to // re-construct it from the AST node it captures. For that reason we provide // simple implicit conversions from all sorts of supported AST nodes. ConstructionContextItem(const DeclStmt *DS) : Data(DS), Kind(VariableKind) {}
ConstructionContextItem(const CXXNewExpr *NE) : Data(NE), Kind(NewAllocatorKind) {}
ConstructionContextItem(const ReturnStmt *RS) : Data(RS), Kind(ReturnKind) {}
ConstructionContextItem(const MaterializeTemporaryExpr *MTE) : Data(MTE), Kind(MaterializationKind) {}
ConstructionContextItem(const CXXBindTemporaryExpr *BTE, bool IsElided = false) : Data(BTE), Kind(IsElided ? ElidedDestructorKind : TemporaryDestructorKind) {}
ConstructionContextItem(const CXXConstructExpr *CE) : Data(CE), Kind(ElidableConstructorKind) {}
ConstructionContextItem(const CallExpr *CE, unsigned Index) : Data(CE), Kind(ArgumentKind), Index(Index) {}
ConstructionContextItem(const CXXConstructExpr *CE, unsigned Index) : Data(CE), Kind(ArgumentKind), Index(Index) {}
ConstructionContextItem(const CXXInheritedCtorInitExpr *CE, unsigned Index) : Data(CE), Kind(ArgumentKind), Index(Index) {}
ConstructionContextItem(const ObjCMessageExpr *ME, unsigned Index) : Data(ME), Kind(ArgumentKind), Index(Index) {}
// A polymorphic version of the previous calls with dynamic type check. ConstructionContextItem(const Expr *E, unsigned Index) : Data(E), Kind(ArgumentKind), Index(Index) { assert(isa<CallExpr>(E) || isa<CXXConstructExpr>(E) || isa<CXXDeleteExpr>(E) || isa<CXXInheritedCtorInitExpr>(E) || isa<ObjCMessageExpr>(E)); }
ConstructionContextItem(const CXXCtorInitializer *Init) : Data(Init), Kind(InitializerKind), Index(0) {}
ConstructionContextItem(const LambdaExpr *LE, unsigned Index) : Data(LE), Kind(LambdaCaptureKind), Index(Index) {}
ItemKind getKind() const { return Kind; }
LLVM_DUMP_METHOD StringRef getKindAsString() const { return getKindAsString(getKind()); }
/// The construction site - the statement that triggered the construction /// for one of its parts. For instance, stack variable declaration statement /// triggers construction of itself or its elements if it's an array, /// new-expression triggers construction of the newly allocated object(s). const Stmt *getStmt() const { assert(hasStatement()); return static_cast<const Stmt *>(Data); }
const Stmt *getStmtOrNull() const { return hasStatement() ? getStmt() : nullptr; }
/// The construction site is not necessarily a statement. It may also be a /// CXXCtorInitializer, which means that a member variable is being /// constructed during initialization of the object that contains it. const CXXCtorInitializer *getCXXCtorInitializer() const { assert(hasInitializer()); return static_cast<const CXXCtorInitializer *>(Data); }
/// If a single trigger statement triggers multiple constructors, they are /// usually being enumerated. This covers function argument constructors /// triggered by a call-expression and items in an initializer list triggered /// by an init-list-expression. unsigned getIndex() const { // This is a fairly specific request. Let's make sure the user knows // what he's doing. assert(hasIndex()); return Index; }
void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(Data); ID.AddInteger(Kind); ID.AddInteger(Index); }
bool operator==(const ConstructionContextItem &Other) const { // For most kinds the Index comparison is trivially true, but // checking kind separately doesn't seem to be less expensive // than checking Index. Same in operator<(). return std::make_tuple(Data, Kind, Index) == std::make_tuple(Other.Data, Other.Kind, Other.Index); }
bool operator<(const ConstructionContextItem &Other) const { return std::make_tuple(Data, Kind, Index) < std::make_tuple(Other.Data, Other.Kind, Other.Index); } };
/// Construction context can be seen as a linked list of multiple layers. /// Sometimes a single trigger is not enough to describe the construction /// site. That's what causing us to have a chain of "partial" construction /// context layers. Some examples: /// - A constructor within in an aggregate initializer list within a variable /// would have a construction context of the initializer list with /// the parent construction context of a variable. /// - A constructor for a temporary that needs to be both destroyed /// and materialized into an elidable copy constructor would have a /// construction context of a CXXBindTemporaryExpr with the parent /// construction context of a MaterializeTemproraryExpr. /// Not all of these are currently supported. /// Layers are created gradually while traversing the AST, and layers that /// represent the outmost AST nodes are built first, while the node that /// immediately contains the constructor would be built last and capture the /// previous layers as its parents. Construction context captures the last layer /// (which has links to the previous layers) and classifies the seemingly /// arbitrary chain of layers into one of the possible ways of constructing /// an object in C++ for user-friendly experience. class ConstructionContextLayer { const ConstructionContextLayer *Parent = nullptr; ConstructionContextItem Item;
ConstructionContextLayer(ConstructionContextItem Item, const ConstructionContextLayer *Parent) : Parent(Parent), Item(Item) {}
public: static const ConstructionContextLayer * create(BumpVectorContext &C, const ConstructionContextItem &Item, const ConstructionContextLayer *Parent = nullptr);
const ConstructionContextItem &getItem() const { return Item; } const ConstructionContextLayer *getParent() const { return Parent; } bool isLast() const { return !Parent; }
/// See if Other is a proper initial segment of this construction context /// in terms of the parent chain - i.e. a few first parents coincide and /// then the other context terminates but our context goes further - i.e., /// we are providing the same context that the other context provides, /// and a bit more above that. bool isStrictlyMoreSpecificThan(const ConstructionContextLayer *Other) const; };
/// ConstructionContext's subclasses describe different ways of constructing /// an object in C++. The context re-captures the essential parent AST nodes /// of the CXXConstructExpr it is assigned to and presents these nodes /// through easy-to-understand accessor methods. class ConstructionContext { public: enum Kind { SimpleVariableKind, CXX17ElidedCopyVariableKind, VARIABLE_BEGIN = SimpleVariableKind, VARIABLE_END = CXX17ElidedCopyVariableKind, SimpleConstructorInitializerKind, CXX17ElidedCopyConstructorInitializerKind, INITIALIZER_BEGIN = SimpleConstructorInitializerKind, INITIALIZER_END = CXX17ElidedCopyConstructorInitializerKind, NewAllocatedObjectKind, SimpleTemporaryObjectKind, ElidedTemporaryObjectKind, TEMPORARY_BEGIN = SimpleTemporaryObjectKind, TEMPORARY_END = ElidedTemporaryObjectKind, SimpleReturnedValueKind, CXX17ElidedCopyReturnedValueKind, RETURNED_VALUE_BEGIN = SimpleReturnedValueKind, RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind, ArgumentKind, LambdaCaptureKind };
protected: Kind K;
// Do not make public! These need to only be constructed // via createFromLayers(). explicit ConstructionContext(Kind K) : K(K) {}
private: // A helper function for constructing an instance into a bump vector context. template <typename T, typename... ArgTypes> static T *create(BumpVectorContext &C, ArgTypes... Args) { auto *CC = C.getAllocator().Allocate<T>(); return new (CC) T(Args...); }
// A sub-routine of createFromLayers() that deals with temporary objects // that need to be materialized. The BTE argument is for the situation when // the object also needs to be bound for destruction. static const ConstructionContext *createMaterializedTemporaryFromLayers( BumpVectorContext &C, const MaterializeTemporaryExpr *MTE, const CXXBindTemporaryExpr *BTE, const ConstructionContextLayer *ParentLayer);
// A sub-routine of createFromLayers() that deals with temporary objects // that need to be bound for destruction. Automatically finds out if the // object also needs to be materialized and delegates to // createMaterializedTemporaryFromLayers() if necessary. static const ConstructionContext * createBoundTemporaryFromLayers( BumpVectorContext &C, const CXXBindTemporaryExpr *BTE, const ConstructionContextLayer *ParentLayer);
public: /// Consume the construction context layer, together with its parent layers, /// and wrap it up into a complete construction context. May return null /// if layers do not form any supported construction context. static const ConstructionContext * createFromLayers(BumpVectorContext &C, const ConstructionContextLayer *TopLayer);
Kind getKind() const { return K; }
virtual const ArrayInitLoopExpr *getArrayInitLoop() const { return nullptr; }
// Only declared to silence -Wnon-virtual-dtor warnings. virtual ~ConstructionContext() = default; };
/// An abstract base class for local variable constructors. class VariableConstructionContext : public ConstructionContext { const DeclStmt *DS;
protected: VariableConstructionContext(ConstructionContext::Kind K, const DeclStmt *DS) : ConstructionContext(K), DS(DS) { assert(classof(this)); assert(DS); }
public: const DeclStmt *getDeclStmt() const { return DS; }
const ArrayInitLoopExpr *getArrayInitLoop() const override { const auto *Var = cast<VarDecl>(DS->getSingleDecl());
return dyn_cast<ArrayInitLoopExpr>(Var->getInit()); }
static bool classof(const ConstructionContext *CC) { return CC->getKind() >= VARIABLE_BEGIN && CC->getKind() <= VARIABLE_END; } };
/// Represents construction into a simple local variable, eg. T var(123);. /// If a variable has an initializer, eg. T var = makeT();, then the final /// elidable copy-constructor from makeT() into var would also be a simple /// variable constructor handled by this class. class SimpleVariableConstructionContext : public VariableConstructionContext { friend class ConstructionContext; // Allows to create<>() itself.
explicit SimpleVariableConstructionContext(const DeclStmt *DS) : VariableConstructionContext(ConstructionContext::SimpleVariableKind, DS) {}
public: static bool classof(const ConstructionContext *CC) { return CC->getKind() == SimpleVariableKind; } };
/// Represents construction into a simple variable with an initializer syntax, /// with a single constructor, eg. T var = makeT();. Such construction context /// may only appear in C++17 because previously it was split into a temporary /// object constructor and an elidable simple variable copy-constructor and /// we were producing separate construction contexts for these constructors. /// In C++17 we have a single construction context that combines both. /// Note that if the object has trivial destructor, then this code is /// indistinguishable from a simple variable constructor on the AST level; /// in this case we provide a simple variable construction context. class CXX17ElidedCopyVariableConstructionContext : public VariableConstructionContext { const CXXBindTemporaryExpr *BTE;
friend class ConstructionContext; // Allows to create<>() itself.
explicit CXX17ElidedCopyVariableConstructionContext( const DeclStmt *DS, const CXXBindTemporaryExpr *BTE) : VariableConstructionContext(CXX17ElidedCopyVariableKind, DS), BTE(BTE) { assert(BTE); }
public: const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
static bool classof(const ConstructionContext *CC) { return CC->getKind() == CXX17ElidedCopyVariableKind; } };
// An abstract base class for constructor-initializer-based constructors. class ConstructorInitializerConstructionContext : public ConstructionContext { const CXXCtorInitializer *I;
protected: explicit ConstructorInitializerConstructionContext( ConstructionContext::Kind K, const CXXCtorInitializer *I) : ConstructionContext(K), I(I) { assert(classof(this)); assert(I); }
public: const CXXCtorInitializer *getCXXCtorInitializer() const { return I; }
const ArrayInitLoopExpr *getArrayInitLoop() const override { return dyn_cast<ArrayInitLoopExpr>(I->getInit()); }
static bool classof(const ConstructionContext *CC) { return CC->getKind() >= INITIALIZER_BEGIN && CC->getKind() <= INITIALIZER_END; } };
/// Represents construction into a field or a base class within a bigger object /// via a constructor initializer, eg. T(): field(123) { ... }. class SimpleConstructorInitializerConstructionContext : public ConstructorInitializerConstructionContext { friend class ConstructionContext; // Allows to create<>() itself.
explicit SimpleConstructorInitializerConstructionContext( const CXXCtorInitializer *I) : ConstructorInitializerConstructionContext( ConstructionContext::SimpleConstructorInitializerKind, I) {}
public: static bool classof(const ConstructionContext *CC) { return CC->getKind() == SimpleConstructorInitializerKind; } };
/// Represents construction into a field or a base class within a bigger object /// via a constructor initializer, with a single constructor, eg. /// T(): field(Field(123)) { ... }. Such construction context may only appear /// in C++17 because previously it was split into a temporary object constructor /// and an elidable simple constructor-initializer copy-constructor and we were /// producing separate construction contexts for these constructors. In C++17 /// we have a single construction context that combines both. Note that if the /// object has trivial destructor, then this code is indistinguishable from /// a simple constructor-initializer constructor on the AST level; in this case /// we provide a simple constructor-initializer construction context. class CXX17ElidedCopyConstructorInitializerConstructionContext : public ConstructorInitializerConstructionContext { const CXXBindTemporaryExpr *BTE;
friend class ConstructionContext; // Allows to create<>() itself.
explicit CXX17ElidedCopyConstructorInitializerConstructionContext( const CXXCtorInitializer *I, const CXXBindTemporaryExpr *BTE) : ConstructorInitializerConstructionContext( CXX17ElidedCopyConstructorInitializerKind, I), BTE(BTE) { assert(BTE); }
public: const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
static bool classof(const ConstructionContext *CC) { return CC->getKind() == CXX17ElidedCopyConstructorInitializerKind; } };
/// Represents immediate initialization of memory allocated by operator new, /// eg. new T(123);. class NewAllocatedObjectConstructionContext : public ConstructionContext { const CXXNewExpr *NE;
friend class ConstructionContext; // Allows to create<>() itself.
explicit NewAllocatedObjectConstructionContext(const CXXNewExpr *NE) : ConstructionContext(ConstructionContext::NewAllocatedObjectKind), NE(NE) { assert(NE); }
public: const CXXNewExpr *getCXXNewExpr() const { return NE; }
static bool classof(const ConstructionContext *CC) { return CC->getKind() == NewAllocatedObjectKind; } };
/// Represents a temporary object, eg. T(123), that does not immediately cross /// function boundaries "by value"; constructors that construct function /// value-type arguments or values that are immediately returned from the /// function that returns a value receive separate construction context kinds. class TemporaryObjectConstructionContext : public ConstructionContext { const CXXBindTemporaryExpr *BTE; const MaterializeTemporaryExpr *MTE;
protected: explicit TemporaryObjectConstructionContext( ConstructionContext::Kind K, const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr *MTE) : ConstructionContext(K), BTE(BTE), MTE(MTE) { // Both BTE and MTE can be null here, all combinations possible. // Even though for now at least one should be non-null, we simply haven't // implemented the other case yet (this would be a temporary in the middle // of nowhere that doesn't have a non-trivial destructor). }
public: /// CXXBindTemporaryExpr here is non-null as long as the temporary has /// a non-trivial destructor. const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
/// MaterializeTemporaryExpr is non-null as long as the temporary is actually /// used after construction, eg. by binding to a reference (lifetime /// extension), accessing a field, calling a method, or passing it into /// a function (an elidable copy or move constructor would be a common /// example) by reference. const MaterializeTemporaryExpr *getMaterializedTemporaryExpr() const { return MTE; }
static bool classof(const ConstructionContext *CC) { return CC->getKind() >= TEMPORARY_BEGIN && CC->getKind() <= TEMPORARY_END; } };
/// Represents a temporary object that is not constructed for the purpose of /// being immediately copied/moved by an elidable copy/move-constructor. /// This includes temporary objects "in the middle of nowhere" like T(123) and /// lifetime-extended temporaries. class SimpleTemporaryObjectConstructionContext : public TemporaryObjectConstructionContext { friend class ConstructionContext; // Allows to create<>() itself.
explicit SimpleTemporaryObjectConstructionContext( const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr *MTE) : TemporaryObjectConstructionContext( ConstructionContext::SimpleTemporaryObjectKind, BTE, MTE) {}
public: static bool classof(const ConstructionContext *CC) { return CC->getKind() == SimpleTemporaryObjectKind; } };
/// Represents a temporary object that is constructed for the sole purpose /// of being immediately copied by an elidable copy/move constructor. /// For example, T t = T(123); includes a temporary T(123) that is immediately /// copied to variable t. In such cases the elidable copy can (but not /// necessarily should) be omitted ("elided") according to the rules of the /// language; the constructor would then construct variable t directly. /// This construction context contains information of the elidable constructor /// and its respective construction context. class ElidedTemporaryObjectConstructionContext : public TemporaryObjectConstructionContext { const CXXConstructExpr *ElidedCE; const ConstructionContext *ElidedCC;
friend class ConstructionContext; // Allows to create<>() itself.
explicit ElidedTemporaryObjectConstructionContext( const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr *MTE, const CXXConstructExpr *ElidedCE, const ConstructionContext *ElidedCC) : TemporaryObjectConstructionContext( ConstructionContext::ElidedTemporaryObjectKind, BTE, MTE), ElidedCE(ElidedCE), ElidedCC(ElidedCC) { // Elided constructor and its context should be either both specified // or both unspecified. In the former case, the constructor must be // elidable. assert(ElidedCE && ElidedCE->isElidable() && ElidedCC); }
public: const CXXConstructExpr *getConstructorAfterElision() const { return ElidedCE; }
const ConstructionContext *getConstructionContextAfterElision() const { return ElidedCC; }
static bool classof(const ConstructionContext *CC) { return CC->getKind() == ElidedTemporaryObjectKind; } };
class ReturnedValueConstructionContext : public ConstructionContext { const ReturnStmt *RS;
protected: explicit ReturnedValueConstructionContext(ConstructionContext::Kind K, const ReturnStmt *RS) : ConstructionContext(K), RS(RS) { assert(classof(this)); assert(RS); }
public: const ReturnStmt *getReturnStmt() const { return RS; }
static bool classof(const ConstructionContext *CC) { return CC->getKind() >= RETURNED_VALUE_BEGIN && CC->getKind() <= RETURNED_VALUE_END; } };
/// Represents a temporary object that is being immediately returned from a /// function by value, eg. return t; or return T(123);. In this case there is /// always going to be a constructor at the return site. However, the usual /// temporary-related bureaucracy (CXXBindTemporaryExpr, /// MaterializeTemporaryExpr) is normally located in the caller function's AST. class SimpleReturnedValueConstructionContext : public ReturnedValueConstructionContext { friend class ConstructionContext; // Allows to create<>() itself.
explicit SimpleReturnedValueConstructionContext(const ReturnStmt *RS) : ReturnedValueConstructionContext( ConstructionContext::SimpleReturnedValueKind, RS) {}
public: static bool classof(const ConstructionContext *CC) { return CC->getKind() == SimpleReturnedValueKind; } };
/// Represents a temporary object that is being immediately returned from a /// function by value, eg. return t; or return T(123); in C++17. /// In C++17 there is not going to be an elidable copy constructor at the /// return site. However, the usual temporary-related bureaucracy (CXXBindTemporaryExpr, /// MaterializeTemporaryExpr) is normally located in the caller function's AST. /// Note that if the object has trivial destructor, then this code is /// indistinguishable from a simple returned value constructor on the AST level; /// in this case we provide a simple returned value construction context. class CXX17ElidedCopyReturnedValueConstructionContext : public ReturnedValueConstructionContext { const CXXBindTemporaryExpr *BTE;
friend class ConstructionContext; // Allows to create<>() itself.
explicit CXX17ElidedCopyReturnedValueConstructionContext( const ReturnStmt *RS, const CXXBindTemporaryExpr *BTE) : ReturnedValueConstructionContext( ConstructionContext::CXX17ElidedCopyReturnedValueKind, RS), BTE(BTE) { assert(BTE); }
public: const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
static bool classof(const ConstructionContext *CC) { return CC->getKind() == CXX17ElidedCopyReturnedValueKind; } };
class ArgumentConstructionContext : public ConstructionContext { // The call of which the context is an argument. const Expr *CE;
// Which argument we're constructing. Note that when numbering between // arguments and parameters is inconsistent (eg., operator calls), // this is the index of the argument, not of the parameter. unsigned Index;
// Whether the object needs to be destroyed. const CXXBindTemporaryExpr *BTE;
friend class ConstructionContext; // Allows to create<>() itself.
explicit ArgumentConstructionContext(const Expr *CE, unsigned Index, const CXXBindTemporaryExpr *BTE) : ConstructionContext(ArgumentKind), CE(CE), Index(Index), BTE(BTE) { assert(isa<CallExpr>(CE) || isa<CXXConstructExpr>(CE) || isa<ObjCMessageExpr>(CE)); // BTE is optional. }
public: const Expr *getCallLikeExpr() const { return CE; } unsigned getIndex() const { return Index; } const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
static bool classof(const ConstructionContext *CC) { return CC->getKind() == ArgumentKind; } };
class LambdaCaptureConstructionContext : public ConstructionContext { // The lambda of which the initializer we capture. const LambdaExpr *LE;
// Index of the captured element in the captured list. unsigned Index;
friend class ConstructionContext; // Allows to create<>() itself.
explicit LambdaCaptureConstructionContext(const LambdaExpr *LE, unsigned Index) : ConstructionContext(LambdaCaptureKind), LE(LE), Index(Index) {}
public: const LambdaExpr *getLambdaExpr() const { return LE; } unsigned getIndex() const { return Index; }
const Expr *getInitializer() const { return *(LE->capture_init_begin() + Index); }
const FieldDecl *getFieldDecl() const { auto It = LE->getLambdaClass()->field_begin(); std::advance(It, Index); return *It; }
const ArrayInitLoopExpr *getArrayInitLoop() const override { return dyn_cast_or_null<ArrayInitLoopExpr>(getInitializer()); }
static bool classof(const ConstructionContext *CC) { return CC->getKind() == LambdaCaptureKind; } };
} // end namespace clang
#endif // LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H
|