mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 17:06:05 +00:00
Remove unused, awkward CFGStmtVisitor and subclasses.
This class is a StmtVisitor that distinguishes between block-level and non-block-level statements in a CFG. However, it does so using a hard-coded idea of which statements might be block-level, which probably isn't accurate anymore. The only implementer of the CFGStmtVisitor hierarchy was the analyzer's DeadStoresChecker, and the analyzer creates a linearized CFG anyway (every non-trivial statement is a block-level statement). This also allows us to remove the block-expr map ("BlkExprMap"), which mapped statements to positions in the CFG. Apart from having a helper type that really should have just been Optional<unsigned>, it was only being used to ask /if/ a particular expression was block-level, for traversal purposes in CFGStmtVisitor. llvm-svn: 181945
This commit is contained in:
parent
36f00d9f02
commit
a7f94ce8a3
@ -763,21 +763,6 @@ public:
|
||||
// CFG Introspection.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
struct BlkExprNumTy {
|
||||
const signed Idx;
|
||||
explicit BlkExprNumTy(signed idx) : Idx(idx) {}
|
||||
explicit BlkExprNumTy() : Idx(-1) {}
|
||||
operator bool() const { return Idx >= 0; }
|
||||
operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; }
|
||||
};
|
||||
|
||||
bool isBlkExpr(const Stmt *S) { return getBlkExprNum(S); }
|
||||
bool isBlkExpr(const Stmt *S) const {
|
||||
return const_cast<CFG*>(this)->isBlkExpr(S);
|
||||
}
|
||||
BlkExprNumTy getBlkExprNum(const Stmt *S);
|
||||
unsigned getNumBlkExprs();
|
||||
|
||||
/// getNumBlockIDs - Returns the total number of BlockIDs allocated (which
|
||||
/// start at 0).
|
||||
unsigned getNumBlockIDs() const { return NumBlockIDs; }
|
||||
@ -800,9 +785,7 @@ public:
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0),
|
||||
BlkExprMap(NULL), Blocks(BlkBVC, 10) {}
|
||||
|
||||
~CFG();
|
||||
Blocks(BlkBVC, 10) {}
|
||||
|
||||
llvm::BumpPtrAllocator& getAllocator() {
|
||||
return BlkBVC.getAllocator();
|
||||
@ -819,11 +802,6 @@ private:
|
||||
// for indirect gotos
|
||||
unsigned NumBlockIDs;
|
||||
|
||||
// BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h.
|
||||
// It represents a map from Expr* to integers to record the set of
|
||||
// block-level expressions and their "statement number" in the CFG.
|
||||
void * BlkExprMap;
|
||||
|
||||
BumpVectorContext BlkBVC;
|
||||
|
||||
CFGBlockListTy Blocks;
|
||||
|
@ -1,307 +0,0 @@
|
||||
// BlkExprDeclBitVector.h - Dataflow types for Bitvector Analysis --*- C++ --*--
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides definition of dataflow types used by analyses such
|
||||
// as LiveVariables and UninitializedValues. The underlying dataflow values
|
||||
// are implemented as bitvectors, but the definitions in this file include
|
||||
// the necessary boilerplate to use with our dataflow framework.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_STMTDECLBVDVAL_H
|
||||
#define LLVM_CLANG_STMTDECLBVDVAL_H
|
||||
|
||||
#include "clang/AST/Decl.h" // for Decl* -> NamedDecl* conversion
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Stmt;
|
||||
class ASTContext;
|
||||
|
||||
struct DeclBitVector_Types {
|
||||
|
||||
class Idx {
|
||||
unsigned I;
|
||||
public:
|
||||
explicit Idx(unsigned i) : I(i) {}
|
||||
Idx() : I(~0U) {}
|
||||
|
||||
bool isValid() const {
|
||||
return I != ~0U;
|
||||
}
|
||||
operator unsigned() const {
|
||||
assert (isValid());
|
||||
return I;
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// AnalysisDataTy - Whole-function meta data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class AnalysisDataTy {
|
||||
public:
|
||||
typedef llvm::DenseMap<const NamedDecl*, unsigned > DMapTy;
|
||||
typedef DMapTy::const_iterator decl_iterator;
|
||||
|
||||
protected:
|
||||
DMapTy DMap;
|
||||
unsigned NDecls;
|
||||
|
||||
public:
|
||||
|
||||
AnalysisDataTy() : NDecls(0) {}
|
||||
virtual ~AnalysisDataTy() {}
|
||||
|
||||
bool isTracked(const NamedDecl *SD) { return DMap.find(SD) != DMap.end(); }
|
||||
|
||||
Idx getIdx(const NamedDecl *SD) const {
|
||||
DMapTy::const_iterator I = DMap.find(SD);
|
||||
return I == DMap.end() ? Idx() : Idx(I->second);
|
||||
}
|
||||
|
||||
unsigned getNumDecls() const { return NDecls; }
|
||||
|
||||
void Register(const NamedDecl *SD) {
|
||||
if (!isTracked(SD)) DMap[SD] = NDecls++;
|
||||
}
|
||||
|
||||
decl_iterator begin_decl() const { return DMap.begin(); }
|
||||
decl_iterator end_decl() const { return DMap.end(); }
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// ValTy - Dataflow value.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class ValTy {
|
||||
llvm::BitVector DeclBV;
|
||||
public:
|
||||
|
||||
void resetDeclValues(AnalysisDataTy& AD) {
|
||||
DeclBV.resize(AD.getNumDecls());
|
||||
DeclBV.reset();
|
||||
}
|
||||
|
||||
void setDeclValues(AnalysisDataTy& AD) {
|
||||
DeclBV.resize(AD.getNumDecls());
|
||||
DeclBV.set();
|
||||
}
|
||||
|
||||
void resetValues(AnalysisDataTy& AD) {
|
||||
resetDeclValues(AD);
|
||||
}
|
||||
|
||||
bool operator==(const ValTy& RHS) const {
|
||||
assert (sizesEqual(RHS));
|
||||
return DeclBV == RHS.DeclBV;
|
||||
}
|
||||
|
||||
void copyValues(const ValTy& RHS) { DeclBV = RHS.DeclBV; }
|
||||
|
||||
llvm::BitVector::reference getBit(unsigned i) {
|
||||
return DeclBV[i];
|
||||
}
|
||||
|
||||
bool getBit(unsigned i) const {
|
||||
return DeclBV[i];
|
||||
}
|
||||
|
||||
llvm::BitVector::reference
|
||||
operator()(const NamedDecl *ND, const AnalysisDataTy& AD) {
|
||||
return getBit(AD.getIdx(ND));
|
||||
}
|
||||
|
||||
bool operator()(const NamedDecl *ND, const AnalysisDataTy& AD) const {
|
||||
return getBit(AD.getIdx(ND));
|
||||
}
|
||||
|
||||
llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; }
|
||||
const llvm::BitVector::reference getDeclBit(unsigned i) const {
|
||||
return const_cast<llvm::BitVector&>(DeclBV)[i];
|
||||
}
|
||||
|
||||
ValTy& operator|=(const ValTy& RHS) {
|
||||
assert (sizesEqual(RHS));
|
||||
DeclBV |= RHS.DeclBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValTy& operator&=(const ValTy& RHS) {
|
||||
assert (sizesEqual(RHS));
|
||||
DeclBV &= RHS.DeclBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValTy& OrDeclBits(const ValTy& RHS) {
|
||||
return operator|=(RHS);
|
||||
}
|
||||
|
||||
ValTy& AndDeclBits(const ValTy& RHS) {
|
||||
return operator&=(RHS);
|
||||
}
|
||||
|
||||
bool sizesEqual(const ValTy& RHS) const {
|
||||
return DeclBV.size() == RHS.DeclBV.size();
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Some useful merge operations.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } };
|
||||
struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } };
|
||||
};
|
||||
|
||||
|
||||
struct StmtDeclBitVector_Types {
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// AnalysisDataTy - Whole-function meta data.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class AnalysisDataTy : public DeclBitVector_Types::AnalysisDataTy {
|
||||
ASTContext *ctx;
|
||||
CFG* cfg;
|
||||
public:
|
||||
AnalysisDataTy() : ctx(0), cfg(0) {}
|
||||
virtual ~AnalysisDataTy() {}
|
||||
|
||||
void setContext(ASTContext &c) { ctx = &c; }
|
||||
ASTContext &getContext() {
|
||||
assert(ctx && "ASTContext should not be NULL.");
|
||||
return *ctx;
|
||||
}
|
||||
|
||||
void setCFG(CFG& c) { cfg = &c; }
|
||||
CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; }
|
||||
|
||||
bool isTracked(const Stmt *S) { return cfg->isBlkExpr(S); }
|
||||
using DeclBitVector_Types::AnalysisDataTy::isTracked;
|
||||
|
||||
unsigned getIdx(const Stmt *S) const {
|
||||
CFG::BlkExprNumTy I = cfg->getBlkExprNum(S);
|
||||
assert(I && "Stmtession not tracked for bitvector.");
|
||||
return I;
|
||||
}
|
||||
using DeclBitVector_Types::AnalysisDataTy::getIdx;
|
||||
|
||||
unsigned getNumBlkExprs() const { return cfg->getNumBlkExprs(); }
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// ValTy - Dataflow value.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
class ValTy : public DeclBitVector_Types::ValTy {
|
||||
llvm::BitVector BlkExprBV;
|
||||
typedef DeclBitVector_Types::ValTy ParentTy;
|
||||
|
||||
static inline ParentTy& ParentRef(ValTy& X) {
|
||||
return static_cast<ParentTy&>(X);
|
||||
}
|
||||
|
||||
static inline const ParentTy& ParentRef(const ValTy& X) {
|
||||
return static_cast<const ParentTy&>(X);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
void resetBlkExprValues(AnalysisDataTy& AD) {
|
||||
BlkExprBV.resize(AD.getNumBlkExprs());
|
||||
BlkExprBV.reset();
|
||||
}
|
||||
|
||||
void setBlkExprValues(AnalysisDataTy& AD) {
|
||||
BlkExprBV.resize(AD.getNumBlkExprs());
|
||||
BlkExprBV.set();
|
||||
}
|
||||
|
||||
void resetValues(AnalysisDataTy& AD) {
|
||||
resetDeclValues(AD);
|
||||
resetBlkExprValues(AD);
|
||||
}
|
||||
|
||||
void setValues(AnalysisDataTy& AD) {
|
||||
setDeclValues(AD);
|
||||
setBlkExprValues(AD);
|
||||
}
|
||||
|
||||
bool operator==(const ValTy& RHS) const {
|
||||
return ParentRef(*this) == ParentRef(RHS)
|
||||
&& BlkExprBV == RHS.BlkExprBV;
|
||||
}
|
||||
|
||||
void copyValues(const ValTy& RHS) {
|
||||
ParentRef(*this).copyValues(ParentRef(RHS));
|
||||
BlkExprBV = RHS.BlkExprBV;
|
||||
}
|
||||
|
||||
llvm::BitVector::reference
|
||||
operator()(const Stmt *S, const AnalysisDataTy& AD) {
|
||||
return BlkExprBV[AD.getIdx(S)];
|
||||
}
|
||||
const llvm::BitVector::reference
|
||||
operator()(const Stmt *S, const AnalysisDataTy& AD) const {
|
||||
return const_cast<ValTy&>(*this)(S,AD);
|
||||
}
|
||||
|
||||
using DeclBitVector_Types::ValTy::operator();
|
||||
|
||||
|
||||
llvm::BitVector::reference getStmtBit(unsigned i) { return BlkExprBV[i]; }
|
||||
const llvm::BitVector::reference getStmtBit(unsigned i) const {
|
||||
return const_cast<llvm::BitVector&>(BlkExprBV)[i];
|
||||
}
|
||||
|
||||
ValTy& OrBlkExprBits(const ValTy& RHS) {
|
||||
BlkExprBV |= RHS.BlkExprBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValTy& AndBlkExprBits(const ValTy& RHS) {
|
||||
BlkExprBV &= RHS.BlkExprBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValTy& operator|=(const ValTy& RHS) {
|
||||
assert (sizesEqual(RHS));
|
||||
ParentRef(*this) |= ParentRef(RHS);
|
||||
BlkExprBV |= RHS.BlkExprBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValTy& operator&=(const ValTy& RHS) {
|
||||
assert (sizesEqual(RHS));
|
||||
ParentRef(*this) &= ParentRef(RHS);
|
||||
BlkExprBV &= RHS.BlkExprBV;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool sizesEqual(const ValTy& RHS) const {
|
||||
return ParentRef(*this).sizesEqual(ParentRef(RHS))
|
||||
&& BlkExprBV.size() == RHS.BlkExprBV.size();
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Some useful merge operations.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } };
|
||||
struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } };
|
||||
|
||||
};
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
@ -1,107 +0,0 @@
|
||||
//= CFGRecStmtDeclVisitor - Recursive visitor of CFG stmts/decls -*- C++ --*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the template class CFGRecStmtDeclVisitor, which extends
|
||||
// CFGRecStmtVisitor by implementing (typed) visitation of decls.
|
||||
//
|
||||
// FIXME: This may not be fully complete. We currently explore only subtypes
|
||||
// of ScopedDecl.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H
|
||||
#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
|
||||
|
||||
#define DISPATCH_CASE(CLASS) \
|
||||
case Decl::CLASS: \
|
||||
static_cast<ImplClass*>(this)->Visit##CLASS##Decl( \
|
||||
static_cast<CLASS##Decl*>(D)); \
|
||||
break;
|
||||
|
||||
#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D) {}
|
||||
#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D)\
|
||||
{ static_cast<ImplClass*>(this)->VisitVarDecl(D); }
|
||||
|
||||
|
||||
namespace clang {
|
||||
template <typename ImplClass>
|
||||
class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> {
|
||||
public:
|
||||
|
||||
void VisitDeclRefExpr(DeclRefExpr *DR) {
|
||||
static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl());
|
||||
}
|
||||
|
||||
void VisitDeclStmt(DeclStmt *DS) {
|
||||
for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
|
||||
DI != DE; ++DI) {
|
||||
Decl *D = *DI;
|
||||
static_cast<ImplClass*>(this)->VisitDecl(D);
|
||||
// Visit the initializer.
|
||||
if (VarDecl *VD = dyn_cast<VarDecl>(D))
|
||||
if (Expr *I = VD->getInit())
|
||||
static_cast<ImplClass*>(this)->Visit(I);
|
||||
}
|
||||
}
|
||||
|
||||
void VisitDecl(Decl *D) {
|
||||
switch (D->getKind()) {
|
||||
DISPATCH_CASE(Function)
|
||||
DISPATCH_CASE(CXXMethod)
|
||||
DISPATCH_CASE(Var)
|
||||
DISPATCH_CASE(ParmVar) // FIXME: (same)
|
||||
DISPATCH_CASE(ImplicitParam)
|
||||
DISPATCH_CASE(EnumConstant)
|
||||
DISPATCH_CASE(Typedef)
|
||||
DISPATCH_CASE(TypeAlias)
|
||||
DISPATCH_CASE(Record) // FIXME: Refine. VisitStructDecl?
|
||||
DISPATCH_CASE(CXXRecord)
|
||||
DISPATCH_CASE(Enum)
|
||||
DISPATCH_CASE(Field)
|
||||
DISPATCH_CASE(UsingDirective)
|
||||
DISPATCH_CASE(Using)
|
||||
DISPATCH_CASE(NamespaceAlias)
|
||||
default:
|
||||
llvm_unreachable("Subtype of ScopedDecl not handled.");
|
||||
}
|
||||
}
|
||||
|
||||
DEFAULT_DISPATCH(Var)
|
||||
DEFAULT_DISPATCH(Function)
|
||||
DEFAULT_DISPATCH(CXXMethod)
|
||||
DEFAULT_DISPATCH_VARDECL(ParmVar)
|
||||
DEFAULT_DISPATCH(ImplicitParam)
|
||||
DEFAULT_DISPATCH(EnumConstant)
|
||||
DEFAULT_DISPATCH(Typedef)
|
||||
DEFAULT_DISPATCH(TypeAlias)
|
||||
DEFAULT_DISPATCH(Record)
|
||||
DEFAULT_DISPATCH(Enum)
|
||||
DEFAULT_DISPATCH(Field)
|
||||
DEFAULT_DISPATCH(ObjCInterface)
|
||||
DEFAULT_DISPATCH(ObjCMethod)
|
||||
DEFAULT_DISPATCH(ObjCProtocol)
|
||||
DEFAULT_DISPATCH(ObjCCategory)
|
||||
DEFAULT_DISPATCH(UsingDirective)
|
||||
DEFAULT_DISPATCH(Using)
|
||||
DEFAULT_DISPATCH(NamespaceAlias)
|
||||
|
||||
void VisitCXXRecordDecl(CXXRecordDecl *D) {
|
||||
static_cast<ImplClass*>(this)->VisitRecordDecl(D);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#undef DISPATCH_CASE
|
||||
#undef DEFAULT_DISPATCH
|
||||
#endif
|
@ -1,59 +0,0 @@
|
||||
//==- CFGRecStmtVisitor - Recursive visitor of CFG statements ---*- C++ --*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the template class CFGRecStmtVisitor, which extends
|
||||
// CFGStmtVisitor by implementing a default recursive visit of all statements.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H
|
||||
#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H
|
||||
|
||||
#include "clang/Analysis/Visitors/CFGStmtVisitor.h"
|
||||
|
||||
namespace clang {
|
||||
template <typename ImplClass>
|
||||
class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> {
|
||||
public:
|
||||
|
||||
void VisitStmt(Stmt *S) {
|
||||
static_cast< ImplClass* >(this)->VisitChildren(S);
|
||||
}
|
||||
|
||||
void VisitCompoundStmt(CompoundStmt *S) {
|
||||
// Do nothing. Everything in a CompoundStmt is inlined
|
||||
// into the CFG.
|
||||
}
|
||||
|
||||
void VisitConditionVariableInit(Stmt *S) {
|
||||
assert(S == this->getCurrentBlkStmt());
|
||||
VarDecl *CondVar = 0;
|
||||
switch (S->getStmtClass()) {
|
||||
#define CONDVAR_CASE(CLASS) \
|
||||
case Stmt::CLASS ## Class:\
|
||||
CondVar = cast<CLASS>(S)->getConditionVariable();\
|
||||
break;
|
||||
CONDVAR_CASE(IfStmt)
|
||||
CONDVAR_CASE(ForStmt)
|
||||
CONDVAR_CASE(SwitchStmt)
|
||||
CONDVAR_CASE(WhileStmt)
|
||||
#undef CONDVAR_CASE
|
||||
default:
|
||||
llvm_unreachable("Infeasible");
|
||||
}
|
||||
static_cast<ImplClass*>(this)->Visit(CondVar->getInit());
|
||||
}
|
||||
|
||||
// Defining operator() allows the visitor to be used as a C++ style functor.
|
||||
void operator()(Stmt *S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
@ -1,175 +0,0 @@
|
||||
//===--- CFGStmtVisitor.h - Visitor for Stmts in a CFG ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the CFGStmtVisitor interface, which extends
|
||||
// StmtVisitor. This interface is useful for visiting statements in a CFG
|
||||
// where some statements have implicit control-flow and thus should
|
||||
// be treated specially.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H
|
||||
#define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H
|
||||
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
#define DISPATCH_CASE(CLASS) \
|
||||
case Stmt::CLASS ## Class: return \
|
||||
static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S));
|
||||
|
||||
#define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\
|
||||
{ return\
|
||||
static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(\
|
||||
cast<Expr>(S)); }
|
||||
|
||||
template <typename ImplClass, typename RetTy=void>
|
||||
class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
|
||||
Stmt *CurrentBlkStmt;
|
||||
|
||||
struct NullifyStmt {
|
||||
Stmt*& S;
|
||||
|
||||
NullifyStmt(Stmt*& s) : S(s) {}
|
||||
~NullifyStmt() { S = NULL; }
|
||||
};
|
||||
|
||||
public:
|
||||
CFGStmtVisitor() : CurrentBlkStmt(NULL) {}
|
||||
|
||||
Stmt *getCurrentBlkStmt() const { return CurrentBlkStmt; }
|
||||
|
||||
RetTy Visit(Stmt *S) {
|
||||
if (S == CurrentBlkStmt ||
|
||||
!static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S))
|
||||
return StmtVisitor<ImplClass,RetTy>::Visit(S);
|
||||
else
|
||||
return RetTy();
|
||||
}
|
||||
|
||||
/// VisitConditionVariableInit - Handle the initialization of condition
|
||||
/// variables at branches. Valid statements include IfStmt, ForStmt,
|
||||
/// WhileStmt, and SwitchStmt.
|
||||
RetTy VisitConditionVariableInit(Stmt *S) {
|
||||
return RetTy();
|
||||
}
|
||||
|
||||
/// BlockVisit_XXX - Visitor methods for visiting the "root" statements in
|
||||
/// CFGBlocks. Root statements are the statements that appear explicitly in
|
||||
/// the list of statements in a CFGBlock. For substatements, or when there
|
||||
/// is no implementation provided for a BlockStmt_XXX method, we default
|
||||
/// to using StmtVisitor's Visit method.
|
||||
RetTy BlockStmt_Visit(Stmt *S) {
|
||||
CurrentBlkStmt = S;
|
||||
NullifyStmt cleanup(CurrentBlkStmt);
|
||||
|
||||
switch (S->getStmtClass()) {
|
||||
case Stmt::IfStmtClass:
|
||||
case Stmt::ForStmtClass:
|
||||
case Stmt::WhileStmtClass:
|
||||
case Stmt::SwitchStmtClass:
|
||||
return static_cast<ImplClass*>(this)->VisitConditionVariableInit(S);
|
||||
|
||||
DISPATCH_CASE(StmtExpr)
|
||||
DISPATCH_CASE(ConditionalOperator)
|
||||
DISPATCH_CASE(BinaryConditionalOperator)
|
||||
DISPATCH_CASE(ObjCForCollectionStmt)
|
||||
DISPATCH_CASE(CXXForRangeStmt)
|
||||
|
||||
case Stmt::BinaryOperatorClass: {
|
||||
BinaryOperator* B = cast<BinaryOperator>(S);
|
||||
if (B->isLogicalOp())
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitLogicalOp(B);
|
||||
else if (B->getOpcode() == BO_Comma)
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitComma(B);
|
||||
// Fall through.
|
||||
}
|
||||
|
||||
default:
|
||||
if (isa<Expr>(S))
|
||||
return
|
||||
static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(cast<Expr>(S));
|
||||
else
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
|
||||
}
|
||||
}
|
||||
|
||||
DEFAULT_BLOCKSTMT_VISIT(StmtExpr)
|
||||
DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator)
|
||||
DEFAULT_BLOCKSTMT_VISIT(BinaryConditionalOperator)
|
||||
|
||||
RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitCXXForRangeStmt(CXXForRangeStmt *S) {
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr *E) {
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitExpr(Expr *E) {
|
||||
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitStmt(Stmt *S) {
|
||||
return static_cast<ImplClass*>(this)->Visit(S);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) {
|
||||
return
|
||||
static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
|
||||
}
|
||||
|
||||
RetTy BlockStmt_VisitComma(BinaryOperator* B) {
|
||||
return
|
||||
static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Utility methods. Not called by default (but subclasses may use them).
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// VisitChildren: Call "Visit" on each child of S.
|
||||
void VisitChildren(Stmt *S) {
|
||||
|
||||
switch (S->getStmtClass()) {
|
||||
default:
|
||||
break;
|
||||
|
||||
case Stmt::StmtExprClass: {
|
||||
CompoundStmt *CS = cast<StmtExpr>(S)->getSubStmt();
|
||||
if (CS->body_empty()) return;
|
||||
static_cast<ImplClass*>(this)->Visit(CS->body_back());
|
||||
return;
|
||||
}
|
||||
|
||||
case Stmt::BinaryOperatorClass: {
|
||||
BinaryOperator* B = cast<BinaryOperator>(S);
|
||||
if (B->getOpcode() != BO_Comma) break;
|
||||
static_cast<ImplClass*>(this)->Visit(B->getRHS());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (Stmt::child_range I = S->children(); I; ++I)
|
||||
if (*I) static_cast<ImplClass*>(this)->Visit(*I);
|
||||
}
|
||||
};
|
||||
|
||||
#undef DEFAULT_BLOCKSTMT_VISIT
|
||||
#undef DISPATCH_CASE
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
@ -3399,113 +3399,6 @@ bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CFG: Queries for BlkExprs.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy;
|
||||
}
|
||||
|
||||
static void FindSubExprAssignments(const Stmt *S,
|
||||
llvm::SmallPtrSet<const Expr*,50>& Set) {
|
||||
if (!S)
|
||||
return;
|
||||
|
||||
for (Stmt::const_child_range I = S->children(); I; ++I) {
|
||||
const Stmt *child = *I;
|
||||
if (!child)
|
||||
continue;
|
||||
|
||||
if (const BinaryOperator* B = dyn_cast<BinaryOperator>(child))
|
||||
if (B->isAssignmentOp()) Set.insert(B);
|
||||
|
||||
FindSubExprAssignments(child, Set);
|
||||
}
|
||||
}
|
||||
|
||||
static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
|
||||
BlkExprMapTy* M = new BlkExprMapTy();
|
||||
|
||||
// Look for assignments that are used as subexpressions. These are the only
|
||||
// assignments that we want to *possibly* register as a block-level
|
||||
// expression. Basically, if an assignment occurs both in a subexpression and
|
||||
// at the block-level, it is a block-level expression.
|
||||
llvm::SmallPtrSet<const Expr*,50> SubExprAssignments;
|
||||
|
||||
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I)
|
||||
for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI)
|
||||
if (Optional<CFGStmt> S = BI->getAs<CFGStmt>())
|
||||
FindSubExprAssignments(S->getStmt(), SubExprAssignments);
|
||||
|
||||
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) {
|
||||
|
||||
// Iterate over the statements again on identify the Expr* and Stmt* at the
|
||||
// block-level that are block-level expressions.
|
||||
|
||||
for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) {
|
||||
Optional<CFGStmt> CS = BI->getAs<CFGStmt>();
|
||||
if (!CS)
|
||||
continue;
|
||||
if (const Expr *Exp = dyn_cast<Expr>(CS->getStmt())) {
|
||||
assert((Exp->IgnoreParens() == Exp) && "No parens on block-level exps");
|
||||
|
||||
if (const BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) {
|
||||
// Assignment expressions that are not nested within another
|
||||
// expression are really "statements" whose value is never used by
|
||||
// another expression.
|
||||
if (B->isAssignmentOp() && !SubExprAssignments.count(Exp))
|
||||
continue;
|
||||
} else if (const StmtExpr *SE = dyn_cast<StmtExpr>(Exp)) {
|
||||
// Special handling for statement expressions. The last statement in
|
||||
// the statement expression is also a block-level expr.
|
||||
const CompoundStmt *C = SE->getSubStmt();
|
||||
if (!C->body_empty()) {
|
||||
const Stmt *Last = C->body_back();
|
||||
if (const Expr *LastEx = dyn_cast<Expr>(Last))
|
||||
Last = LastEx->IgnoreParens();
|
||||
unsigned x = M->size();
|
||||
(*M)[Last] = x;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned x = M->size();
|
||||
(*M)[Exp] = x;
|
||||
}
|
||||
}
|
||||
|
||||
// Look at terminators. The condition is a block-level expression.
|
||||
|
||||
Stmt *S = (*I)->getTerminatorCondition();
|
||||
|
||||
if (S && M->find(S) == M->end()) {
|
||||
unsigned x = M->size();
|
||||
(*M)[S] = x;
|
||||
}
|
||||
}
|
||||
|
||||
return M;
|
||||
}
|
||||
|
||||
CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt *S) {
|
||||
assert(S != NULL);
|
||||
if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); }
|
||||
|
||||
BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap);
|
||||
BlkExprMapTy::iterator I = M->find(S);
|
||||
return (I == M->end()) ? CFG::BlkExprNumTy() : CFG::BlkExprNumTy(I->second);
|
||||
}
|
||||
|
||||
unsigned CFG::getNumBlkExprs() {
|
||||
if (const BlkExprMapTy* M = reinterpret_cast<const BlkExprMapTy*>(BlkExprMap))
|
||||
return M->size();
|
||||
|
||||
// We assume callers interested in the number of BlkExprs will want
|
||||
// the map constructed if it doesn't already exist.
|
||||
BlkExprMap = (void*) PopulateBlkExprMap(*this);
|
||||
return reinterpret_cast<BlkExprMapTy*>(BlkExprMap)->size();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Filtered walking of the CFG.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -3529,14 +3422,6 @@ bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F,
|
||||
return false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Cleanup: CFG dstor.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
CFG::~CFG() {
|
||||
delete reinterpret_cast<const BlkExprMapTy*>(BlkExprMap);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CFG pretty printing
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -14,12 +14,12 @@
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
|
||||
#include "clang/Analysis/Analyses/UninitializedValues.h"
|
||||
#include "clang/Analysis/AnalysisContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
|
||||
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/PackedVector.h"
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "clang/AST/ParentMap.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/Analysis/Analyses/LiveVariables.h"
|
||||
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
|
||||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
|
||||
@ -391,26 +390,24 @@ public:
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
|
||||
CFG *cfg;
|
||||
class FindEscaped {
|
||||
public:
|
||||
FindEscaped(CFG *c) : cfg(c) {}
|
||||
|
||||
CFG& getCFG() { return *cfg; }
|
||||
|
||||
llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
|
||||
|
||||
void VisitUnaryOperator(UnaryOperator* U) {
|
||||
// Check for '&'. Any VarDecl whose value has its address-taken we
|
||||
// treat as escaped.
|
||||
Expr *E = U->getSubExpr()->IgnoreParenCasts();
|
||||
if (U->getOpcode() == UO_AddrOf)
|
||||
if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
|
||||
if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
|
||||
Escaped.insert(VD);
|
||||
return;
|
||||
}
|
||||
Visit(E);
|
||||
void operator()(const Stmt *S) {
|
||||
// Check for '&'. Any VarDecl whose address has been taken we treat as
|
||||
// escaped.
|
||||
// FIXME: What about references?
|
||||
const UnaryOperator *U = dyn_cast<UnaryOperator>(S);
|
||||
if (!U)
|
||||
return;
|
||||
if (U->getOpcode() != UO_AddrOf)
|
||||
return;
|
||||
|
||||
const Expr *E = U->getSubExpr()->IgnoreParenCasts();
|
||||
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
|
||||
Escaped.insert(VD);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
@ -438,8 +435,8 @@ public:
|
||||
CFG &cfg = *mgr.getCFG(D);
|
||||
AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D);
|
||||
ParentMap &pmap = mgr.getParentMap(D);
|
||||
FindEscaped FS(&cfg);
|
||||
FS.getCFG().VisitBlockStmts(FS);
|
||||
FindEscaped FS;
|
||||
cfg.VisitBlockStmts(FS);
|
||||
DeadStoreObs A(cfg, BR.getContext(), BR, AC, pmap, FS.Escaped);
|
||||
L->runOnAllBlocks(A);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user