22#include "llvm/ADT/StringMap.h"
28class MissingOriginCollector
29 :
public RecursiveASTVisitor<MissingOriginCollector> {
31 MissingOriginCollector(
32 const llvm::DenseMap<const clang::Expr *, OriginList *> &ExprToOriginList,
33 const OriginManager &OM, LifetimeSafetyStats &LSStats)
34 : ExprToOriginList(ExprToOriginList), OM(OM), LSStats(LSStats) {}
35 bool VisitExpr(Expr *E) {
36 if (!OM.hasOrigins(E))
39 if (!ExprToOriginList.contains(E)) {
41 LSStats.ExprTypeToMissingOriginCount[E->getType().getTypePtr()]++;
42 LSStats.ExprStmtClassToMissingOriginCount[std::string(
43 E->getStmtClassName())]++;
49 const llvm::DenseMap<const clang::Expr *, OriginList *> &ExprToOriginList;
50 const OriginManager &OM;
51 LifetimeSafetyStats &LSStats;
54class LifetimeAnnotatedOriginTypeCollector
55 :
public RecursiveASTVisitor<LifetimeAnnotatedOriginTypeCollector> {
57 bool VisitCallExpr(
const CallExpr *CE) {
60 if (
const auto *FD = CE->getDirectCallee()) {
61 collect(FD, FD->getReturnType());
67 bool VisitCXXConstructExpr(
const CXXConstructExpr *CCE) {
68 collect(CCE->getConstructor(), CCE->getType());
69 collectCaptureBy(CCE->getConstructor());
73 bool shouldVisitLambdaBody()
const {
return false; }
74 bool shouldVisitTemplateInstantiations()
const {
return true; }
76 const llvm::SmallVector<QualType> &getCollectedTypes()
const {
77 return CollectedTypes;
81 llvm::SmallVector<QualType> CollectedTypes;
83 void collect(
const FunctionDecl *FD, QualType RetType) {
88 if (
const auto *MD = dyn_cast<CXXMethodDecl>(FD);
91 CollectedTypes.push_back(RetType);
95 for (
const auto *Param : FD->parameters()) {
96 if (Param->hasAttr<LifetimeBoundAttr>()) {
97 CollectedTypes.push_back(RetType);
103 void collectCaptureBy(
const FunctionDecl *FD) {
107 const auto *MD = dyn_cast<CXXMethodDecl>(FD);
108 bool IsInstance = MD && MD->isInstance();
109 int Offset = (MD && MD->isImplicitObjectMemberFunction()) ? 1 : 0;
110 auto ProcessAttr = [&](
const LifetimeCaptureByAttr *Attr) {
111 for (
int Idx : Attr->params()) {
112 if (Idx == LifetimeCaptureByAttr::Global ||
113 Idx == LifetimeCaptureByAttr::Unknown ||
114 Idx == LifetimeCaptureByAttr::Invalid)
116 if (Idx == LifetimeCaptureByAttr::This) {
118 CollectedTypes.push_back(MD->getFunctionObjectParameterType());
119 }
else if (
int LogicalIdx = Idx - Offset;
121 (unsigned)LogicalIdx < FD->getNumParams()) {
122 CollectedTypes.push_back(
123 FD->getParamDecl(LogicalIdx)->getType().getNonReferenceType());
127 if (
const auto *MethodAttr =
129 ProcessAttr(MethodAttr);
130 for (
const auto *Param : FD->parameters()) {
131 if (
auto *Attr = Param->getAttr<LifetimeCaptureByAttr>())
142 if (!IntrinsicOnly &&
148 return hasOrigins(AT->getValueType(), IntrinsicOnly);
160 for (
const auto *FD : RD->fields())
202 : AST(AC.getASTContext()) {
203 collectLifetimeAnnotatedOriginTypes(AC);
204 initializeThisOrigins(AC.
getDecl());
207void OriginManager::initializeThisOrigins(
const Decl *D) {
208 const auto *MD = llvm::dyn_cast_or_null<CXXMethodDecl>(D);
209 if (!MD || !MD->isInstance())
215 ThisOrigins = buildListForType(MD->getThisType(), MD);
219 bool NamesDeclStorage) {
222 return new (ListAllocator.Allocate<OriginList>()) OriginList(NewID);
225OriginList *OriginManager::createNode(
const Expr *E,
QualType QT,
226 bool NamesDeclStorage) {
229 return new (ListAllocator.Allocate<OriginList>()) OriginList(NewID);
238 bool NamesDeclStorage) {
239 assert(
hasOrigins(QT) &&
"buildListForType called for non-pointer type");
242 return buildListForType(AT->getValueType(), Node, NamesDeclStorage);
243 OriginList *Head = createNode(Node, QT, NamesDeclStorage);
258 auto It = DeclToList.find(D);
259 if (It != DeclToList.end())
261 return DeclToList[D] = buildListForType(D->
getType(), D);
280 if (
const auto *BaseAsME = dyn_cast<MemberExpr>(
Base)) {
281 const auto *BaseField = dyn_cast<FieldDecl>(BaseAsME->getMemberDecl());
282 if (BaseField && BaseField->isAnonymousStructOrUnion())
289 if (
auto *ParenIgnored = E->
IgnoreParens(); ParenIgnored != E)
298 if (
const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
299 if (
const Expr *Src = OVE->getSourceExpr())
305 auto It = ExprToList.find(E);
306 if (It != ExprToList.end())
317 const ValueDecl *ReferencedDecl =
nullptr;
318 if (
auto *DRE = dyn_cast<DeclRefExpr>(E))
319 ReferencedDecl = DRE->getDecl();
320 else if (
auto *ME = dyn_cast<MemberExpr>(E)) {
321 if (
auto *Field = dyn_cast<FieldDecl>(ME->getMemberDecl());
323 ReferencedDecl = Field;
325 else if (
auto *VD = dyn_cast<VarDecl>(ME->getMemberDecl()))
328 if (ReferencedDecl) {
350 return ExprToList[E] = Head;
357 Type = AST.getLValueReferenceType(
Type);
360 bool NamesDeclStorage =
false;
361 if (
const auto *CE = dyn_cast<CastExpr>(E);
362 CE && CE->getCastKind() == CK_NoOp && E->
isGLValue())
365 return ExprToList[E] = buildListForType(
Type, E, NamesDeclStorage);
372 OS <<
"Decl: " << VD->getNameAsString();
375 if (
auto *DRE = dyn_cast<DeclRefExpr>(E)) {
376 if (
const ValueDecl *VD = DRE->getDecl())
377 OS <<
", Decl: " << VD->getNameAsString();
388 assert(ID.Value < AllOrigins.size());
389 return AllOrigins[ID.Value];
394 MissingOriginCollector Collector(this->ExprToList, *
this, LSStats);
395 Collector.TraverseStmt(
const_cast<Stmt *
>(&FunctionBody));
398void OriginManager::collectLifetimeAnnotatedOriginTypes(
400 LifetimeAnnotatedOriginTypeCollector Collector;
402 Collector.TraverseStmt(Body);
403 if (
const auto *CD = dyn_cast<CXXConstructorDecl>(AC.
getDecl()))
404 for (
const auto *
Init : CD->inits())
405 Collector.TraverseStmt(
Init->getInit());
406 for (
QualType QT : Collector.getCollectedTypes())
407 registerLifetimeAnnotatedOriginType(QT);
410void OriginManager::registerLifetimeAnnotatedOriginType(
QualType QT) {
Defines the clang::ASTContext interface.
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
C Language Family Type Representation.
AnalysisDeclContext contains the context data for the function, method or block under analysis.
const Decl * getDecl() const
Represents a C++ struct/union/class.
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Decl - This represents one declaration (or definition), e.g.
Represents an expression – generally a full-expression – that introduces cleanups to be run at the en...
This represents one expression.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
A (possibly-)qualified type.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
QualType getCanonicalType() const
const Type * getTypePtrOrNull() const
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
Stmt - This represents one statement.
const char * getStmtClassName() const
The base class of the type hierarchy.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isReferenceType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isPointerOrReferenceType() const
const T * getAs() const
Member-template getAs<specific type>'.
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
A list of origins representing levels of indirection for pointer-like types.
void setInnerOriginList(OriginList *Inner)
OriginList * getOrCreateList(const ValueDecl *D)
Gets or creates the OriginList for a given ValueDecl.
OriginList * createSingleOriginList(OriginID OID)
Wraps an existing OriginID in a new single-element OriginList, so a fact can refer to a single level ...
const Origin & getOrigin(OriginID ID) const
void collectMissingOrigins(Stmt &FunctionBody, LifetimeSafetyStats &LSStats)
Collects statistics about expressions that lack associated origins.
OriginManager(const AnalysisDeclContext &AC)
void dump(OriginID OID, llvm::raw_ostream &OS) const
bool hasOrigins(QualType QT, bool IntrinsicOnly=false) const
Determines whether a type can carry lifetime origins.
utils::ID< struct OriginTag > OriginID
bool doesDeclHaveStorage(const ValueDecl *D)
Returns true if the declaration has its own storage that can be borrowed.
static bool isSubobjectOfThis(const MemberExpr *ME)
Returns true if the field named by ME denotes a subobject of *this, reached as this->f or through ano...
bool isGslPointerType(QualType QT)
bool isStdCallableWrapperType(const CXXRecordDecl *RD)
bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD)
const FunctionDecl * getDeclWithMergedLifetimeBoundAttrs(const FunctionDecl *FD)
const LifetimeCaptureByAttr * getCaptureByAttrFromFunctionType(const FunctionDecl *FD)
bool isa(CodeGen::Address addr)
const FunctionProtoType * T
A structure to hold the statistics related to LifetimeAnalysis.
An Origin is a symbolic identifier that represents the set of possible loans a pointer-like object co...
bool NamesDeclStorage
True if this origin only holds a loan to a declaration named in scope, so it can never hold an expire...
const clang::Expr * getExpr() const
const clang::ValueDecl * getDecl() const
const Type * Ty
The type at this indirection level.