saqut-compiler/llvm/include/clang/Analysis/Analyses/LifetimeSafety/Facts.h

253 lines
8.4 KiB
C++

//===- Facts.h - Lifetime Analysis Facts and Fact Manager ------*- 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 Facts, which are atomic lifetime-relevant events (such as
// loan issuance, loan expiration, origin flow, and use), and the FactManager,
// which manages the storage and retrieval of facts for each CFG block.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_FACTS_H
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_FACTS_H
#include "clang/Analysis/Analyses/LifetimeSafety/Loans.h"
#include "clang/Analysis/Analyses/LifetimeSafety/Origins.h"
#include "clang/Analysis/Analyses/LifetimeSafety/Utils.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Debug.h"
#include <cstdint>
namespace clang::lifetimes::internal {
using FactID = utils::ID<struct FactTag>;
/// An abstract base class for a single, atomic lifetime-relevant event.
class Fact {
public:
enum class Kind : uint8_t {
/// A new loan is issued from a borrow expression (e.g., &x).
Issue,
/// A loan expires as its underlying storage is freed (e.g., variable goes
/// out of scope).
Expire,
/// An origin is propagated from a source to a destination (e.g., p = q).
/// This can also optionally kill the destination origin before flowing into
/// it. Otherwise, the source's loan set is merged into the destination's
/// loan set.
OriginFlow,
/// An origin is used (eg. appears as l-value expression like DeclRefExpr).
Use,
/// A marker for a specific point in the code, for testing.
TestPoint,
/// An origin that escapes the function scope (e.g., via return).
OriginEscapes,
};
private:
Kind K;
FactID ID;
protected:
Fact(Kind K) : K(K) {}
public:
virtual ~Fact() = default;
Kind getKind() const { return K; }
void setID(FactID ID) { this->ID = ID; }
FactID getID() const { return ID; }
template <typename T> const T *getAs() const {
if (T::classof(this))
return static_cast<const T *>(this);
return nullptr;
}
virtual void dump(llvm::raw_ostream &OS, const LoanManager &,
const OriginManager &) const;
};
/// A `ProgramPoint` identifies a location in the CFG by pointing to a specific
/// `Fact`. identified by a lifetime-related event (`Fact`).
///
/// A `ProgramPoint` has "after" semantics: it represents the location
/// immediately after its corresponding `Fact`.
using ProgramPoint = const Fact *;
class IssueFact : public Fact {
LoanID LID;
OriginID OID;
public:
static bool classof(const Fact *F) { return F->getKind() == Kind::Issue; }
IssueFact(LoanID LID, OriginID OID) : Fact(Kind::Issue), LID(LID), OID(OID) {}
LoanID getLoanID() const { return LID; }
OriginID getOriginID() const { return OID; }
void dump(llvm::raw_ostream &OS, const LoanManager &LM,
const OriginManager &OM) const override;
};
class ExpireFact : public Fact {
LoanID LID;
SourceLocation ExpiryLoc;
public:
static bool classof(const Fact *F) { return F->getKind() == Kind::Expire; }
ExpireFact(LoanID LID, SourceLocation ExpiryLoc)
: Fact(Kind::Expire), LID(LID), ExpiryLoc(ExpiryLoc) {}
LoanID getLoanID() const { return LID; }
SourceLocation getExpiryLoc() const { return ExpiryLoc; }
void dump(llvm::raw_ostream &OS, const LoanManager &LM,
const OriginManager &) const override;
};
class OriginFlowFact : public Fact {
OriginID OIDDest;
OriginID OIDSrc;
// True if the destination origin should be killed (i.e., its current loans
// cleared) before the source origin's loans are flowed into it.
bool KillDest;
public:
static bool classof(const Fact *F) {
return F->getKind() == Kind::OriginFlow;
}
OriginFlowFact(OriginID OIDDest, OriginID OIDSrc, bool KillDest)
: Fact(Kind::OriginFlow), OIDDest(OIDDest), OIDSrc(OIDSrc),
KillDest(KillDest) {}
OriginID getDestOriginID() const { return OIDDest; }
OriginID getSrcOriginID() const { return OIDSrc; }
bool getKillDest() const { return KillDest; }
void dump(llvm::raw_ostream &OS, const LoanManager &,
const OriginManager &OM) const override;
};
class OriginEscapesFact : public Fact {
OriginID OID;
const Expr *EscapeExpr;
public:
static bool classof(const Fact *F) {
return F->getKind() == Kind::OriginEscapes;
}
OriginEscapesFact(OriginID OID, const Expr *EscapeExpr)
: Fact(Kind::OriginEscapes), OID(OID), EscapeExpr(EscapeExpr) {}
OriginID getEscapedOriginID() const { return OID; }
const Expr *getEscapeExpr() const { return EscapeExpr; };
void dump(llvm::raw_ostream &OS, const LoanManager &,
const OriginManager &OM) const override;
};
class UseFact : public Fact {
const Expr *UseExpr;
const OriginList *OList;
// True if this use is a write operation (e.g., left-hand side of assignment).
// Write operations are exempted from use-after-free checks.
bool IsWritten = false;
public:
static bool classof(const Fact *F) { return F->getKind() == Kind::Use; }
UseFact(const Expr *UseExpr, const OriginList *OList)
: Fact(Kind::Use), UseExpr(UseExpr), OList(OList) {}
const OriginList *getUsedOrigins() const { return OList; }
const Expr *getUseExpr() const { return UseExpr; }
void markAsWritten() { IsWritten = true; }
bool isWritten() const { return IsWritten; }
void dump(llvm::raw_ostream &OS, const LoanManager &,
const OriginManager &OM) const override;
};
/// A dummy-fact used to mark a specific point in the code for testing.
/// It is generated by recognizing a `void("__lifetime_test_point_...")` cast.
class TestPointFact : public Fact {
StringRef Annotation;
public:
static bool classof(const Fact *F) { return F->getKind() == Kind::TestPoint; }
explicit TestPointFact(StringRef Annotation)
: Fact(Kind::TestPoint), Annotation(Annotation) {}
StringRef getAnnotation() const { return Annotation; }
void dump(llvm::raw_ostream &OS, const LoanManager &,
const OriginManager &) const override;
};
class FactManager {
public:
FactManager(const AnalysisDeclContext &AC, const CFG &Cfg)
: OriginMgr(AC.getASTContext()) {
BlockToFacts.resize(Cfg.getNumBlockIDs());
}
llvm::ArrayRef<const Fact *> getFacts(const CFGBlock *B) const {
return BlockToFacts[B->getBlockID()];
}
void addBlockFacts(const CFGBlock *B, llvm::ArrayRef<Fact *> NewFacts) {
if (!NewFacts.empty())
BlockToFacts[B->getBlockID()].assign(NewFacts.begin(), NewFacts.end());
}
template <typename FactType, typename... Args>
FactType *createFact(Args &&...args) {
void *Mem = FactAllocator.Allocate<FactType>();
FactType *Res = new (Mem) FactType(std::forward<Args>(args)...);
Res->setID(NextFactID++);
return Res;
}
void dump(const CFG &Cfg, AnalysisDeclContext &AC) const;
/// Retrieves program points that were specially marked in the source code
/// for testing.
///
/// The analysis recognizes special function calls of the form
/// `void("__lifetime_test_point_<name>")` as test points. This method returns
/// a map from the annotation string (<name>) to the corresponding
/// `ProgramPoint`. This allows test harnesses to query the analysis state at
/// user-defined locations in the code.
/// \note This is intended for testing only.
llvm::StringMap<ProgramPoint> getTestPoints() const;
/// Retrieves all the facts in the block containing Program Point P.
/// \note This is intended for testing only.
llvm::ArrayRef<const Fact *> getBlockContaining(ProgramPoint P) const;
unsigned getNumFacts() const { return NextFactID.Value; }
LoanManager &getLoanMgr() { return LoanMgr; }
const LoanManager &getLoanMgr() const { return LoanMgr; }
OriginManager &getOriginMgr() { return OriginMgr; }
const OriginManager &getOriginMgr() const { return OriginMgr; }
private:
FactID NextFactID{0};
LoanManager LoanMgr;
OriginManager OriginMgr;
/// Facts for each CFG block, indexed by block ID.
llvm::SmallVector<llvm::SmallVector<const Fact *>> BlockToFacts;
llvm::BumpPtrAllocator FactAllocator;
};
} // namespace clang::lifetimes::internal
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_FACTS_H