17#include "llvm/ADT/FoldingSet.h"
18#include "llvm/ADT/ImmutableMap.h"
19#include "llvm/ADT/ImmutableSet.h"
20#include "llvm/ADT/PointerUnion.h"
21#include "llvm/ADT/SmallBitVector.h"
22#include "llvm/ADT/SmallVector.h"
23#include "llvm/Support/Debug.h"
24#include "llvm/Support/TimeProfiler.h"
68 llvm::PointerUnion<const clang::ValueDecl *, const clang::Expr *>
Ptr;
87 AllLoans.emplace_back(getNextLoanID(),
Path, IssueExpr);
88 return AllLoans.back();
92 assert(
ID.
Value < AllLoans.size());
98 LoanID getNextLoanID() {
return NextLoanID++; }
113 AllOrigins.emplace_back(
ID, &
D);
114 return AllOrigins.back();
117 AllOrigins.emplace_back(
ID, &
E);
118 return AllOrigins.back();
123 if (
const auto *DRE = dyn_cast<DeclRefExpr>(&
E))
124 return get(*DRE->getDecl());
125 auto It = ExprToOriginID.find(&
E);
129 if (It == ExprToOriginID.end())
136 auto It = DeclToOriginID.find(&
D);
140 if (It == DeclToOriginID.end())
147 auto It = ExprToOriginID.find(&
E);
148 if (It != ExprToOriginID.end())
151 if (
const auto *DRE = dyn_cast<DeclRefExpr>(&
E)) {
157 ExprToOriginID[&
E] = NewID;
162 assert(
ID.
Value < AllOrigins.size());
169 auto It = DeclToOriginID.find(&
D);
170 if (It != DeclToOriginID.end())
174 DeclToOriginID[&
D] = NewID;
182 OS <<
"Decl: " << VD->getNameAsString();
184 OS <<
"Expr: " <<
E->getStmtClassName();
191 OriginID getNextOriginID() {
return NextOriginID++; }
197 llvm::DenseMap<const clang::ValueDecl *, OriginID> DeclToOriginID;
198 llvm::DenseMap<const clang::Expr *, OriginID> ExprToOriginID;
231 template <
typename T>
const T *
getAs()
const {
232 if (T::classof(
this))
233 return static_cast<const T *
>(
this);
238 OS <<
"Fact (Kind: " <<
static_cast<int>(K) <<
")\n";
253 OS <<
"Issue (LoanID: " <<
getLoanID() <<
", ToOrigin: ";
273 OS <<
"Expire (LoanID: " <<
getLoanID() <<
")\n";
291 OS <<
"AssignOrigin (Dest: ";
310 OS <<
"ReturnOfOrigin (";
324 :
Fact(
Kind::
Use), UsedOrigin(UsedOrigin), UseExpr(UseExpr) {}
339 StringRef Annotation;
350 OS <<
"TestPoint (Annotation: \"" <<
getAnnotation() <<
"\")\n";
357 auto It = BlockToFactsMap.find(B);
358 if (It != BlockToFactsMap.end())
364 if (!NewFacts.empty())
365 BlockToFactsMap[B].assign(NewFacts.begin(), NewFacts.end());
368 template <
typename FactType,
typename... Args>
370 void *Mem = FactAllocator.Allocate<FactType>();
371 return new (Mem) FactType(std::forward<Args>(args)...);
375 llvm::dbgs() <<
"==========================================\n";
376 llvm::dbgs() <<
" Lifetime Analysis Facts:\n";
377 llvm::dbgs() <<
"==========================================\n";
378 if (
const Decl *
D = AC.getDecl())
379 if (
const auto *ND = dyn_cast<NamedDecl>(
D))
380 llvm::dbgs() <<
"Function: " << ND->getQualifiedNameAsString() <<
"\n";
383 llvm::dbgs() <<
" Block B" << B->getBlockID() <<
":\n";
384 auto It = BlockToFactsMap.find(B);
385 if (It != BlockToFactsMap.end()) {
386 for (
const Fact *F : It->second) {
388 F->
dump(llvm::dbgs(), OriginMgr);
391 llvm::dbgs() <<
" End of Block\n";
401 llvm::DenseMap<const clang::CFGBlock *, llvm::SmallVector<const Fact *>>
403 llvm::BumpPtrAllocator FactAllocator;
411 : FactMgr(FactMgr), AC(AC) {}
414 llvm::TimeTraceScope TimeProfile(
"FactGenerator");
418 CurrentBlockFacts.clear();
419 for (
unsigned I = 0; I <
Block->size(); ++I) {
421 if (std::optional<CFGStmt> CS = Element.getAs<
CFGStmt>())
422 Visit(CS->getStmt());
423 else if (std::optional<CFGAutomaticObjDtor> DtorOpt =
425 handleDestructor(*DtorOpt);
433 if (
const auto *VD = dyn_cast<VarDecl>(
D))
434 if (hasOrigin(VD->getType()))
435 if (
const Expr *InitExpr = VD->getInit())
436 addAssignOriginFact(*VD, *InitExpr);
446 if (!hasOrigin(ICE->
getType()))
454 addAssignOriginFact(*ICE, *ICE->
getSubExpr());
460 if (
const auto *DRE = dyn_cast<DeclRefExpr>(SubExpr)) {
461 if (
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
463 if (VD->hasLocalStorage()) {
468 CurrentBlockFacts.push_back(
473 }
else if (UO->
getOpcode() == UO_Deref) {
482 if (hasOrigin(RetExpr->getType())) {
484 CurrentBlockFacts.push_back(
499 if (
const auto *DRE_LHS = dyn_cast<DeclRefExpr>(LHSExpr))
500 if (
const auto *VD_LHS =
501 dyn_cast<ValueDecl>(DRE_LHS->getDecl()->getCanonicalDecl());
502 VD_LHS && hasOrigin(VD_LHS->getType()))
503 addAssignOriginFact(*VD_LHS, *RHSExpr);
510 if (VisitTestPoint(FCE))
513 Base::VisitCXXFunctionalCastExpr(FCE);
520 template <
typename Destination,
typename Source>
521 void addAssignOriginFact(
const Destination &
D,
const Source &S) {
524 CurrentBlockFacts.push_back(
525 FactMgr.
createFact<AssignOriginFact>(DestOID, SrcOID));
541 const AccessPath &LoanPath = L.Path;
544 if (LoanPath.D == DestructedVD)
545 CurrentBlockFacts.push_back(FactMgr.
createFact<ExpireFact>(
552 bool VisitTestPoint(
const CXXFunctionalCastExpr *FCE) {
553 if (!FCE->getType()->isVoidType())
556 const auto *SubExpr = FCE->getSubExpr()->IgnoreParenImpCasts();
557 if (
const auto *SL = dyn_cast<StringLiteral>(SubExpr)) {
558 llvm::StringRef LiteralValue = SL->getString();
559 const std::string Prefix =
"__lifetime_test_point_";
561 if (LiteralValue.starts_with(Prefix)) {
562 StringRef Annotation = LiteralValue.drop_front(Prefix.length());
563 CurrentBlockFacts.push_back(
564 FactMgr.
createFact<TestPointFact>(Annotation));
571 FactManager &FactMgr;
572 AnalysisDeclContext &AC;
607template <
typename Derived,
typename LatticeType, Direction Dir>
618 llvm::DenseMap<const CFGBlock *, Lattice> InStates;
620 llvm::DenseMap<const CFGBlock *, Lattice> OutStates;
624 llvm::DenseMap<ProgramPoint, Lattice> PerPointStates;
637 Derived &
D =
static_cast<Derived &
>(*this);
638 llvm::TimeTraceScope Time(
D.getAnalysisName());
646 InStates[Start] =
D.getInitialState();
647 W.enqueueBlock(Start);
651 while (
const CFGBlock *B = W.dequeue()) {
653 Lattice StateOut = transferBlock(B, StateIn);
654 OutStates[B] = StateOut;
656 for (
const CFGBlock *AdjacentB : isForward() ? B->succs() : B->preds()) {
660 Lattice NewInState =
D.join(OldInState, StateOut);
663 if (!
Visited.test(AdjacentB->getBlockID()) ||
664 NewInState != OldInState) {
665 InStates[AdjacentB] = NewInState;
666 W.enqueueBlock(AdjacentB);
680 const Derived *
D =
static_cast<const Derived *
>(
this);
681 llvm::dbgs() <<
"==========================================\n";
682 llvm::dbgs() <<
D->getAnalysisName() <<
" results:\n";
683 llvm::dbgs() <<
"==========================================\n";
693 if constexpr (isForward()) {
694 for (
const Fact *F : Facts) {
695 State = transferFact(State, F);
696 PerPointStates[F] = State;
699 for (
const Fact *F : llvm::reverse(Facts)) {
701 PerPointStates[F] = State;
702 State = transferFact(State, F);
710 Derived *
D =
static_cast<Derived *
>(
this);
711 switch (F->getKind()) {
713 return D->transfer(In, *F->getAs<IssueFact>());
715 return D->transfer(In, *F->getAs<ExpireFact>());
717 return D->transfer(In, *F->getAs<AssignOriginFact>());
719 return D->transfer(In, *F->getAs<ReturnOfOriginFact>());
721 return D->transfer(In, *F->getAs<UseFact>());
723 return D->transfer(In, *F->getAs<TestPointFact>());
725 llvm_unreachable(
"Unknown fact kind");
741static llvm::ImmutableSet<T>
join(llvm::ImmutableSet<T> A,
742 llvm::ImmutableSet<T> B,
743 typename llvm::ImmutableSet<T>::Factory &F) {
744 if (A.getHeight() < B.getHeight())
754 const llvm::ImmutableSet<T> &B) {
759 for (
const T &Elem : A)
760 if (!B.contains(Elem))
769template <
typename K,
typename V,
typename Joiner>
770static llvm::ImmutableMap<K, V>
771join(llvm::ImmutableMap<K, V> A, llvm::ImmutableMap<K, V> B,
772 typename llvm::ImmutableMap<K, V>::Factory &F, Joiner JoinValues) {
773 if (A.getHeight() < B.getHeight())
778 for (
const auto &Entry : B) {
779 const K &Key = Entry.first;
780 const V &ValB = Entry.second;
781 if (
const V *ValA = A.lookup(Key))
782 A = F.add(A, Key, JoinValues(*ValA, ValB));
784 A = F.add(A, Key, ValB);
823 return !(*
this ==
Other);
826 void dump(llvm::raw_ostream &OS)
const {
827 OS <<
"LoanPropagationLattice State:\n";
830 for (
const auto &Entry :
Origins) {
831 if (Entry.second.isEmpty())
832 OS <<
" Origin " << Entry.first <<
" contains no loans\n";
833 for (
const LoanID &LID : Entry.second)
834 OS <<
" Origin " << Entry.first <<
" contains Loan " << LID <<
"\n";
842 Direction::Forward> {
843 OriginLoanMap::Factory &OriginLoanMapFactory;
844 LoanSet::Factory &LoanSetFactory;
850 OriginLoanMapFactory(LFactory.OriginMapFactory),
851 LoanSetFactory(LFactory.LoanSetFactory) {}
865 return utils::join(S1, S2, LoanSetFactory);
876 LoanSetFactory.add(LoanSetFactory.getEmptySet(), LID)));
886 OriginLoanMapFactory.add(In.Origins, DestOID, SrcLoans));
895 if (
auto *Loans = L.Origins.lookup(OID))
897 return LoanSetFactory.getEmptySet();
917 return !(*
this ==
Other);
920 void dump(llvm::raw_ostream &OS)
const {
921 OS <<
"ExpiredLattice State:\n";
925 OS <<
" Loan " <<
ID <<
" is expired\n";
932 Direction::Forward> {
934 ExpiredLoanMap::Factory &Factory;
953 return F1->getExpiryLoc() > F2->getExpiryLoc() ? F1 : F2;
1007 llvm::DenseMap<LoanID, PendingWarning> FinalWarningsMap;
1018 : LoanPropagation(LPA), ExpiredLoans(ELA), FactMgr(FM), ADC(ADC),
1019 Reporter(Reporter) {}
1022 llvm::TimeTraceScope TimeProfile(
"LifetimeChecker");
1025 if (
const auto *UF = F->getAs<
UseFact>())
1047 if (HeldLoans.isEmpty() || AllExpiredLoans.isEmpty())
1055 bool IsDefiniteError =
true;
1056 for (
LoanID L : HeldLoans) {
1057 if (AllExpiredLoans.contains(L))
1058 DefaultedLoans.push_back(L);
1061 IsDefiniteError =
false;
1064 if (DefaultedLoans.empty())
1072 for (
LoanID DefaultedLoan : DefaultedLoans) {
1075 if (FinalWarningsMap.count(DefaultedLoan) &&
1076 CurrentConfidence <= FinalWarningsMap[DefaultedLoan].ConfidenceLevel)
1079 auto *EF = AllExpiredLoans.lookup(DefaultedLoan);
1080 assert(EF &&
"Could not find ExpireFact for an expired loan.");
1082 FinalWarningsMap[DefaultedLoan] = {(*EF)->getExpiryLoc(),
1091 for (
const auto &[LID,
Warning] : FinalWarningsMap) {
1113 llvm::TimeTraceScope TimeProfile(
"LifetimeSafetyAnalysis");
1115 const CFG &Cfg = *AC.getCFG();
1116 DEBUG_WITH_TYPE(
"PrintCFG", Cfg.
dump(AC.getASTContext().getLangOpts(),
1121 DEBUG_WITH_TYPE(
"LifetimeFacts", FactMgr->dump(Cfg, AC));
1135 std::make_unique<LoanPropagationAnalysis>(Cfg, AC, *FactMgr, *Factory);
1136 LoanPropagation->run();
1139 std::make_unique<ExpiredLoansAnalysis>(Cfg, AC, *FactMgr, *Factory);
1140 ExpiredLoans->run();
1142 LifetimeChecker Checker(*LoanPropagation, *ExpiredLoans, *FactMgr, AC,
1149 assert(LoanPropagation &&
"Analysis has not been run.");
1150 return LoanPropagation->getLoans(OID, PP);
1155 assert(ExpiredLoans &&
"ExpiredLoansAnalysis has not been run.");
1156 std::vector<LoanID>
Result;
1157 for (
const auto &pair : ExpiredLoans->getExpiredLoans(PP))
1158 Result.push_back(pair.first);
1162std::optional<OriginID>
1164 assert(FactMgr &&
"FactManager not initialized");
1168 return FactMgr->getOriginMgr().get(*
D);
1173 assert(FactMgr &&
"FactManager not initialized");
1174 std::vector<LoanID>
Result;
1175 for (
const Loan &L : FactMgr->getLoanMgr().getLoans())
1182 assert(FactMgr &&
"FactManager not initialized");
1183 llvm::StringMap<ProgramPoint> AnnotationToPointMap;
1185 for (
const Fact *F : FactMgr->getFacts(
Block)) {
1187 StringRef PointName = TPF->getAnnotation();
1188 assert(AnnotationToPointMap.find(PointName) ==
1189 AnnotationToPointMap.end() &&
1190 "more than one test points with the same name");
1191 AnnotationToPointMap[PointName] = F;
1195 return AnnotationToPointMap;
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
llvm::DenseSet< const void * > Visited
TypeErasedDataflowAnalysis & Analysis
The analysis to be run.
C Language Family Type Representation.
AnalysisDeclContext contains the context data for the function, method or block under analysis.
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isAssignmentOp(Opcode Opc)
Represents C++ object destructor implicitly generated for automatic object or temporary bound to cons...
const VarDecl * getVarDecl() const
const Stmt * getTriggerStmt() const
Represents a single basic block in a source-level CFG.
Represents a top-level expression in a basic block.
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
void dump(const LangOptions &LO, bool ShowColors) const
dump - A simple pretty printer of a CFG that outputs to stderr.
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Represents an explicit C++ type conversion that uses "functional" notation (C++ [expr....
The null pointer literal (C++11 [lex.nullptr])
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Decl - This represents one declaration (or definition), e.g.
This represents one expression.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
A (possibly-)qualified type.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Encodes a location in the source.
RetTy Visit(PTR(Stmt) S, ParamTys... P)
SourceLocation getEndLoc() const LLVM_READONLY
bool isPointerOrReferenceType() const
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
virtual void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr, SourceLocation FreeLoc, Confidence Confidence)
AssignOriginFact(OriginID OIDDest, OriginID OIDSrc)
OriginID getSrcOriginID() const
static bool classof(const Fact *F)
OriginID getDestOriginID() const
void dump(llvm::raw_ostream &OS, const OriginManager &OM) const override
A generic, policy-based driver for dataflow analyses.
Lattice getInState(const CFGBlock *B) const
Lattice transfer(Lattice In, const TestPointFact &)
Lattice getOutState(const CFGBlock *B) const
DataflowAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F)
Lattice transfer(Lattice In, const ReturnOfOriginFact &)
Lattice transfer(Lattice In, const UseFact &)
Lattice transfer(Lattice In, const IssueFact &)
Lattice transfer(Lattice In, const AssignOriginFact &)
Lattice transfer(Lattice In, const ExpireFact &)
Lattice getState(ProgramPoint P) const
SourceLocation getExpiryLoc() const
static bool classof(const Fact *F)
void dump(llvm::raw_ostream &OS, const OriginManager &OM) const override
ExpireFact(LoanID LID, SourceLocation ExpiryLoc)
The analysis that tracks which loans have expired.
Lattice transfer(Lattice In, const ExpireFact &F)
StringRef getAnalysisName() const
ExpiredLoanMap getExpiredLoans(ProgramPoint P)
Lattice transfer(Lattice In, const IssueFact &F)
ExpiredLoansAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, LifetimeFactory &Factory)
Lattice join(Lattice L1, Lattice L2)
Merges two lattices by taking the union of the two expired loans.
Lattice getInitialState()
void VisitUnaryOperator(const UnaryOperator *UO)
void VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *N)
void VisitDeclStmt(const DeclStmt *DS)
void VisitImplicitCastExpr(const ImplicitCastExpr *ICE)
void VisitBinaryOperator(const BinaryOperator *BO)
FactGenerator(FactManager &FactMgr, AnalysisDeclContext &AC)
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *FCE)
void VisitReturnStmt(const ReturnStmt *RS)
llvm::ArrayRef< const Fact * > getFacts(const CFGBlock *B) const
FactType * createFact(Args &&...args)
OriginManager & getOriginMgr()
void dump(const CFG &Cfg, AnalysisDeclContext &AC) const
LoanManager & getLoanMgr()
void addBlockFacts(const CFGBlock *B, llvm::ArrayRef< Fact * > NewFacts)
An abstract base class for a single, atomic lifetime-relevant event.
@ TestPoint
A marker for a specific point in the code, for testing.
@ Expire
A loan expires as its underlying storage is freed (e.g., variable goes out of scope).
@ ReturnOfOrigin
An origin escapes the function by flowing into the return value.
@ Issue
A new loan is issued from a borrow expression (e.g., &x).
@ Use
An origin is used (eg. dereferencing a pointer).
@ AssignOrigin
An origin is propagated from a source to a destination (e.g., p = q).
virtual void dump(llvm::raw_ostream &OS, const OriginManager &) const
void dump(llvm::raw_ostream &OS, const OriginManager &OM) const override
OriginID getOriginID() const
IssueFact(LoanID LID, OriginID OID)
static bool classof(const Fact *F)
void issuePendingWarnings()
LifetimeChecker(LoanPropagationAnalysis &LPA, ExpiredLoansAnalysis &ELA, FactManager &FM, AnalysisDeclContext &ADC, LifetimeSafetyReporter *Reporter)
void checkUse(const UseFact *UF)
Checks for use-after-free errors for a given use of an Origin.
Running the lifetime safety analysis and querying its results.
LoanSet getLoansAtPoint(OriginID OID, ProgramPoint PP) const
Returns the set of loans an origin holds at a specific program point.
std::optional< OriginID > getOriginIDForDecl(const ValueDecl *D) const
Finds the OriginID for a given declaration.
std::vector< LoanID > getExpiredLoansAtPoint(ProgramPoint PP) const
Returns the set of loans that have expired at a specific program point.
std::vector< LoanID > getLoanIDForVar(const VarDecl *VD) const
Finds the LoanID's for the loan created with the specific variable as their Path.
llvm::StringMap< ProgramPoint > getTestPoints() const
Retrieves program points that were specially marked in the source code for testing.
LifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter)
~LifetimeSafetyAnalysis()
Manages the creation, storage and retrieval of loans.
const Loan & getLoan(LoanID ID) const
Loan & addLoan(AccessPath Path, const Expr *IssueExpr)
llvm::ArrayRef< Loan > getLoans() const
The analysis that tracks which loans belong to which origins.
LoanPropagationAnalysis(const CFG &C, AnalysisDeclContext &AC, FactManager &F, LifetimeFactory &LFactory)
Lattice getInitialState()
Lattice transfer(Lattice In, const IssueFact &F)
A new loan is issued to the origin. Old loans are erased.
Lattice transfer(Lattice In, const AssignOriginFact &F)
The destination origin's loan set is replaced by the source's.
Lattice join(Lattice A, Lattice B)
Merges two lattices by taking the union of loans for each origin.
StringRef getAnalysisName() const
LoanSet getLoans(OriginID OID, ProgramPoint P)
Manages the creation, storage, and retrieval of origins for pointer-like variables and expressions.
OriginID getOrCreate(const ValueDecl &D)
OriginID get(const ValueDecl &D)
const Origin & getOrigin(OriginID ID) const
Origin & addOrigin(OriginID ID, const clang::Expr &E)
OriginID getOrCreate(const Expr &E)
llvm::ArrayRef< Origin > getOrigins() const
void dump(OriginID OID, llvm::raw_ostream &OS) const
Origin & addOrigin(OriginID ID, const clang::ValueDecl &D)
OriginID get(const Expr &E)
ReturnOfOriginFact(OriginID OID)
OriginID getReturnedOriginID() const
void dump(llvm::raw_ostream &OS, const OriginManager &OM) const override
static bool classof(const Fact *F)
A dummy-fact used to mark a specific point in the code for testing.
void dump(llvm::raw_ostream &OS, const OriginManager &) const override
static bool classof(const Fact *F)
StringRef getAnnotation() const
TestPointFact(StringRef Annotation)
const Expr * getUseExpr() const
static bool classof(const Fact *F)
UseFact(OriginID UsedOrigin, const Expr *UseExpr)
void dump(llvm::raw_ostream &OS, const OriginManager &OM) const override
OriginID getUsedOrigin() const
static bool isSubsetOf(const llvm::ImmutableSet< T > &A, const llvm::ImmutableSet< T > &B)
Checks if set A is a subset of set B.
static llvm::ImmutableSet< T > join(llvm::ImmutableSet< T > A, llvm::ImmutableSet< T > B, typename llvm::ImmutableSet< T >::Factory &F)
Computes the union of two ImmutableSets.
llvm::ImmutableSet< LoanID > LoanSet
ID< struct OriginTag > OriginID
ID< struct LoanTag > LoanID
llvm::ImmutableMap< LoanID, const ExpireFact * > ExpiredLoanMap
llvm::ImmutableMap< OriginID, LoanSet > OriginLoanMap
void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetyReporter *Reporter)
The main entry point for the analysis.
Confidence
Enum to track the confidence level of a potential error.
@ Result
The result type of a method or function.
const FunctionProtoType * T
@ Other
Other implicit parameter.
A worklist implementation for backward dataflow analysis.
A worklist implementation for forward dataflow analysis.
Represents the storage location being borrowed, e.g., a specific stack variable.
AccessPath(const clang::ValueDecl *D)
const clang::ValueDecl * D
The dataflow lattice for tracking the set of expired loans.
ExpiredLoanMap Expired
Map from an expired LoanID to the ExpireFact that made it expire.
bool operator==(const ExpiredLattice &Other) const
void dump(llvm::raw_ostream &OS) const
ExpiredLattice(ExpiredLoanMap M)
bool operator!=(const ExpiredLattice &Other) const
An object to hold the factories for immutable collections, ensuring that all created states share the...
ExpiredLoanMap::Factory ExpiredLoanMapFactory
OriginLoanMap::Factory OriginMapFactory
LoanSet::Factory LoanSetFactory
Represents the dataflow lattice for loan propagation.
bool operator!=(const LoanPropagationLattice &Other) const
OriginLoanMap Origins
The map from an origin to the set of loans it contains.
LoanPropagationLattice()=default
LoanPropagationLattice(const OriginLoanMap &S)
void dump(llvm::raw_ostream &OS) const
bool operator==(const LoanPropagationLattice &Other) const
Information about a single borrow, or "Loan".
Loan(LoanID id, AccessPath path, const Expr *IssueExpr)
const Expr * IssueExpr
The expression that creates the loan, e.g., &x.
LoanID ID
TODO: Represent opaque loans.
An Origin is a symbolic identifier that represents the set of possible loans a pointer-like object co...
Origin(OriginID ID, const clang::Expr *E)
const clang::Expr * getExpr() const
const clang::ValueDecl * getDecl() const
llvm::PointerUnion< const clang::ValueDecl *, const clang::Expr * > Ptr
A pointer to the AST node that this origin represents.
Origin(OriginID ID, const clang::ValueDecl *D)
Struct to store the complete context for a potential lifetime violation.
Confidence ConfidenceLevel