24 #include "llvm/ADT/DenseMap.h"
25 #include "llvm/ADT/Optional.h"
26 #include "llvm/ADT/PackedVector.h"
27 #include "llvm/ADT/SmallBitVector.h"
28 #include "llvm/ADT/SmallVector.h"
29 #include "llvm/Support/SaveAndRestore.h"
32 using namespace clang;
34 #define DEBUG_LOGGING 0
52 llvm::DenseMap<const VarDecl *, unsigned> map;
60 unsigned size()
const {
return map.size(); }
67 void DeclToIndex::computeMap(
const DeclContext &dc) {
71 for ( ; I != E; ++I) {
79 llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
105 typedef llvm::PackedVector<Value, 2, llvm::SmallBitVector> ValueVector;
107 class CFGBlockValues {
111 DeclToIndex declToIndex;
113 CFGBlockValues(
const CFG &cfg);
115 unsigned getNumEntries()
const {
return declToIndex.size(); }
117 void computeSetOfDeclarations(
const DeclContext &dc);
118 ValueVector &getValueVector(
const CFGBlock *block) {
122 void setAllScratchValues(
Value V);
123 void mergeIntoScratch(ValueVector
const &source,
bool isFirst);
124 bool updateValueVectorWithScratch(
const CFGBlock *block);
126 bool hasNoDeclarations()
const {
127 return declToIndex.size() == 0;
132 ValueVector::reference operator[](
const VarDecl *vd);
137 assert(idx.hasValue());
138 return getValueVector(block)[idx.getValue()];
143 CFGBlockValues::CFGBlockValues(
const CFG &c) : cfg(c), vals(0) {}
145 void CFGBlockValues::computeSetOfDeclarations(
const DeclContext &dc) {
146 declToIndex.computeMap(dc);
147 unsigned decls = declToIndex.size();
148 scratch.resize(decls);
149 unsigned n = cfg.getNumBlockIDs();
153 for (
unsigned i = 0; i < n; ++i)
154 vals[i].resize(decls);
158 static void printVector(
const CFGBlock *block, ValueVector &bv,
161 for (
unsigned i = 0; i < bv.size(); ++i) {
162 llvm::errs() <<
' ' << bv[i];
164 llvm::errs() <<
" : " << num <<
'\n';
168 void CFGBlockValues::setAllScratchValues(
Value V) {
169 for (
unsigned I = 0, E = scratch.size(); I != E; ++I)
173 void CFGBlockValues::mergeIntoScratch(ValueVector
const &source,
181 bool CFGBlockValues::updateValueVectorWithScratch(
const CFGBlock *block) {
182 ValueVector &dst = getValueVector(block);
183 bool changed = (dst != scratch);
187 printVector(block, scratch, 0);
192 void CFGBlockValues::resetScratch() {
196 ValueVector::reference CFGBlockValues::operator[](
const VarDecl *vd) {
198 assert(idx.hasValue());
199 return scratch[idx.getValue()];
207 class DataflowWorklist {
210 llvm::BitVector enqueuedBlocks;
213 : PO_I(view.begin()), PO_E(view.end()),
214 enqueuedBlocks(cfg.getNumBlockIDs(),
true) {
218 enqueuedBlocks[(*PO_I)->getBlockID()] =
false;
223 void enqueueSuccessors(
const CFGBlock *block);
228 void DataflowWorklist::enqueueSuccessors(
const clang::CFGBlock *block) {
230 E = block->
succ_end(); I != E; ++I) {
232 if (!Successor || enqueuedBlocks[Successor->
getBlockID()])
234 worklist.push_back(Successor);
235 enqueuedBlocks[Successor->
getBlockID()] =
true;
239 const CFGBlock *DataflowWorklist::dequeue() {
244 if (!worklist.empty())
245 B = worklist.pop_back_val();
249 else if (PO_I != PO_E) {
257 assert(enqueuedBlocks[B->
getBlockID()] ==
true);
267 class FindVarResult {
273 const DeclRefExpr *getDeclRefExpr()
const {
return dr; }
274 const VarDecl *getDecl()
const {
return vd; }
280 if (
const CastExpr *CE = dyn_cast<CastExpr>(Ex)) {
282 Ex = CE->getSubExpr();
296 if (
const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
298 return FindVarResult(VD, DRE);
299 return FindVarResult(
nullptr,
nullptr);
305 class ClassifyRefs :
public StmtVisitor<ClassifyRefs> {
316 llvm::DenseMap<const DeclRefExpr*, Class> Classification;
322 void classify(
const Expr *E, Class C);
336 llvm::DenseMap<const DeclRefExpr*, Class>::const_iterator I
337 = Classification.find(DRE);
338 if (I != Classification.end())
341 const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl());
355 if (DRE && DRE->
getDecl() == VD)
361 void ClassifyRefs::classify(
const Expr *E, Class C) {
365 classify(CO->getTrueExpr(),
C);
366 classify(CO->getFalseExpr(),
C);
371 dyn_cast<BinaryConditionalOperator>(E)) {
372 classify(BCO->getFalseExpr(),
C);
377 classify(OVE->getSourceExpr(),
C);
381 if (
const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
382 if (
VarDecl *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
383 if (!VD->isStaticDataMember())
384 classify(ME->getBase(),
C);
390 switch (BO->getOpcode()) {
393 classify(BO->getLHS(),
C);
396 classify(BO->getRHS(),
C);
403 FindVarResult Var = findVar(E, DC);
405 Classification[DRE] = std::max(Classification[DRE], C);
408 void ClassifyRefs::VisitDeclStmt(
DeclStmt *DS) {
409 for (
auto *DI : DS->
decls()) {
413 Classification[DRE] = SelfInit;
424 classify(BO->
getLHS(), Use);
426 classify(BO->
getLHS(), Ignore);
440 void ClassifyRefs::VisitCallExpr(
CallExpr *CE) {
444 if (FD->isInStdNamespace() && FD->getIdentifier() &&
445 FD->getIdentifier()->isStr(
"move")) {
448 classify(CE->
getArg(0), Use);
459 if ((*I)->isGLValue()) {
460 if ((*I)->getType().isConstQualified())
461 classify((*I), Ignore);
466 Ex = UO->getSubExpr();
467 classify(Ex, Ignore);
472 void ClassifyRefs::VisitCastExpr(
CastExpr *CE) {
476 if (CSE->getType()->isVoidType()) {
480 classify(CSE->getSubExpr(), Ignore);
490 class TransferFunctions :
public StmtVisitor<TransferFunctions> {
491 CFGBlockValues &vals;
495 const ClassifyRefs &classification;
500 TransferFunctions(CFGBlockValues &vals,
const CFG &cfg,
502 const ClassifyRefs &classification,
504 : vals(vals), cfg(cfg), block(block), ac(ac),
505 classification(classification), objCNoRet(ac.getASTContext()),
522 FindVarResult findVar(
const Expr *ex) {
523 return ::findVar(ex, cast<DeclContext>(ac.getDecl()));
581 Queue.push_back(block);
586 while (!Queue.empty()) {
587 const CFGBlock *B = Queue.pop_back_val();
591 Use.setUninitAfterCall();
599 Value AtPredExit = vals.getValue(Pred, B, vd);
610 Use.setUninitAfterDecl();
614 unsigned &SV = SuccsVisited[Pred->
getBlockID()];
628 Queue.push_back(Pred);
638 if (SuccsVisited[BlockID] && SuccsVisited[BlockID] < Block->
succ_size() &&
644 E = Block->
succ_end(); I != E; ++I) {
652 if (isa<SwitchStmt>(Term)) {
654 if (!Label || !isa<SwitchCase>(Label))
660 Use.addUninitBranch(Branch);
665 Use.addUninitBranch(Branch);
677 void TransferFunctions::reportUse(
const Expr *ex,
const VarDecl *vd) {
680 handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
692 void TransferFunctions::VisitBlockExpr(
BlockExpr *be) {
694 for (
const auto &I : bd->
captures()) {
695 const VarDecl *vd = I.getVariable();
706 void TransferFunctions::VisitCallExpr(
CallExpr *ce) {
708 if (Callee->hasAttr<ReturnsTwiceAttr>()) {
716 else if (Callee->hasAttr<AnalyzerNoReturnAttr>()) {
724 vals.setAllScratchValues(
Unknown);
729 void TransferFunctions::VisitDeclRefExpr(
DeclRefExpr *dr) {
730 switch (classification.get(dr)) {
731 case ClassifyRefs::Ignore:
733 case ClassifyRefs::Use:
734 reportUse(dr, cast<VarDecl>(dr->
getDecl()));
736 case ClassifyRefs::Init:
739 case ClassifyRefs::SelfInit:
740 handler.handleSelfInit(cast<VarDecl>(dr->
getDecl()));
747 FindVarResult Var = findVar(BO->
getLHS());
748 if (
const VarDecl *VD = Var.getDecl())
753 void TransferFunctions::VisitDeclStmt(
DeclStmt *DS) {
754 for (
auto *DI : DS->
decls()) {
792 if (objCNoRet.isImplicitNoReturn(ME)) {
793 vals.setAllScratchValues(
Unknown);
803 const ClassifyRefs &classification,
804 llvm::BitVector &wasAnalyzed,
811 E = block->
pred_end(); I != E; ++I) {
816 vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
821 TransferFunctions tf(vals, cfg, block, ac, classification, handler);
825 tf.Visit(const_cast<Stmt*>(cs->getStmt()));
827 return vals.updateValueVectorWithScratch(block);
836 PruneBlocksHandler(
unsigned numBlocks)
840 ~PruneBlocksHandler()
override {}
843 llvm::BitVector hadUse;
849 unsigned currentBlock;
853 hadUse[currentBlock] =
true;
861 hadUse[currentBlock] =
true;
873 CFGBlockValues vals(cfg);
874 vals.computeSetOfDeclarations(dc);
875 if (vals.hasNoDeclarations())
881 ClassifyRefs classification(ac);
886 ValueVector &vec = vals.getValueVector(&entry);
887 const unsigned n = vals.getNumEntries();
888 for (
unsigned j = 0; j < n ; ++j) {
895 worklist.enqueueSuccessors(&cfg.
getEntry());
900 while (
const CFGBlock *block = worklist.dequeue()) {
904 bool changed =
runOnBlock(block, cfg, ac, vals,
905 classification, wasAnalyzed, PBH);
907 if (changed || !previouslyVisited[block->
getBlockID()])
908 worklist.enqueueSuccessors(block);
909 previouslyVisited[block->
getBlockID()] =
true;
919 runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, handler);
925 UninitVariablesHandler::~UninitVariablesHandler() {}
Defines the clang::ASTContext interface.
CastKind getCastKind() const
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
succ_iterator succ_begin()
static bool isPointerToConst(const QualType &QT)
bool isRecordType() const
const Expr * getInit() const
static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc)
unsigned succ_size() const
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
decl_iterator decls_end() const
bool isScalarType() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
bool isAnyPointerType() const
static bool isIncrementDecrementOp(Opcode Op)
static bool isAlwaysUninit(const Value v)
static bool runOnBlock(const CFGBlock *block, const CFG &cfg, AnalysisDeclContext &ac, CFGBlockValues &vals, const ClassifyRefs &classification, llvm::BitVector &wasAnalyzed, UninitVariablesHandler &handler)
ElementList::const_iterator const_iterator
A builtin binary operation expression such as "x + y" or "x <= y".
decl_iterator decls_begin() const
Expr * IgnoreParenNoopCasts(ASTContext &Ctx) LLVM_READONLY
QualType getPointeeType() const
void VisitBlockStmts(CALLBACK &O) const
ASTContext & getParentASTContext() const
virtual void handleSelfInit(const VarDecl *vd)
DeclContext * getDeclContext()
static SVal getValue(SVal val, SValBuilder &svalBuilder)
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, AnalysisDeclContext &ac, UninitVariablesHandler &handler, UninitVariablesAnalysisStats &stats)
AdjacentBlocks::const_iterator const_pred_iterator
Expr * getSubExpr() const
bool isExceptionVariable() const
Determine whether this variable is the exception variable in a C++ catch statememt or an Objective-C ...
unsigned getBlockID() const
An expression that sends a message to the given Objective-C object or class.
A use of a variable, which might be uninitialized.
CFGTerminator getTerminator()
ASTContext & getASTContext() const LLVM_READONLY
bool isLocalVarDecl() const
virtual void handleUseOfUninitVariable(const VarDecl *vd, const UninitUse &use)
Called when the uninitialized variable is used at the given expression.
bool isVectorType() const
const BlockDecl * getBlockDecl() const
AdjacentBlocks::const_iterator const_succ_iterator
const Decl * getSingleDecl() const
bool isInitCapture() const
Whether this variable is the implicit variable for a lambda init-capture.
static const DeclRefExpr * getSelfInitExpr(VarDecl *VD)
pred_iterator pred_begin()
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return 0.
unsigned getNumArgs() const
std::vector< const CFGBlock * >::reverse_iterator iterator
The use is always uninitialized.
Represents Objective-C's collection statement.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
static bool isCompoundAssignmentOp(Opcode Opc)
A reference to a declared variable, function, enum, etc. [C99 6.5.1p2].
unsigned NumVariablesAnalyzed
bool isConstQualified() const
Determine whether this type is const-qualified.
unsigned getNumBlockIDs() const
Expr * IgnoreParens() LLVM_READONLY
static bool isUninitialized(const Value v)