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) {
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)) {
281 if (CE->getCastKind() == CK_LValueBitCast) {
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());
356 if (DRE && DRE->
getDecl() == VD)
362 void ClassifyRefs::classify(
const Expr *E, Class C) {
366 classify(CO->getTrueExpr(),
C);
367 classify(CO->getFalseExpr(),
C);
372 dyn_cast<BinaryConditionalOperator>(E)) {
373 classify(BCO->getFalseExpr(),
C);
378 classify(OVE->getSourceExpr(),
C);
382 if (
const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
383 if (
VarDecl *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
384 if (!VD->isStaticDataMember())
385 classify(ME->getBase(),
C);
391 switch (BO->getOpcode()) {
394 classify(BO->getLHS(),
C);
397 classify(BO->getRHS(),
C);
404 FindVarResult Var = findVar(E, DC);
406 Classification[DRE] =
std::max(Classification[DRE], C);
409 void ClassifyRefs::VisitDeclStmt(
DeclStmt *DS) {
410 for (
auto *DI : DS->
decls()) {
414 Classification[DRE] = SelfInit;
425 classify(BO->
getLHS(), Use);
427 classify(BO->
getLHS(), Ignore);
441 void ClassifyRefs::VisitCallExpr(
CallExpr *CE) {
445 if (FD->isInStdNamespace() && FD->getIdentifier() &&
446 FD->getIdentifier()->isStr(
"move")) {
449 classify(CE->
getArg(0), Use);
460 if ((*I)->isGLValue()) {
461 if ((*I)->getType().isConstQualified())
462 classify((*I), Ignore);
466 if (UO && UO->getOpcode() == UO_AddrOf)
467 Ex = UO->getSubExpr();
468 classify(Ex, Ignore);
473 void ClassifyRefs::VisitCastExpr(
CastExpr *CE) {
477 if (CSE->getType()->isVoidType()) {
481 classify(CSE->getSubExpr(), Ignore);
491 class TransferFunctions :
public StmtVisitor<TransferFunctions> {
492 CFGBlockValues &vals;
496 const ClassifyRefs &classification;
501 TransferFunctions(CFGBlockValues &vals,
const CFG &cfg,
503 const ClassifyRefs &classification,
505 : vals(vals), cfg(cfg), block(block), ac(ac),
506 classification(classification), objCNoRet(ac.getASTContext()),
523 FindVarResult findVar(
const Expr *ex) {
524 return ::findVar(ex, cast<DeclContext>(ac.getDecl()));
582 Queue.push_back(block);
587 while (!Queue.empty()) {
588 const CFGBlock *B = Queue.pop_back_val();
592 Use.setUninitAfterCall();
600 Value AtPredExit = vals.getValue(Pred, B, vd);
611 Use.setUninitAfterDecl();
615 unsigned &SV = SuccsVisited[Pred->
getBlockID()];
629 Queue.push_back(Pred);
639 if (SuccsVisited[BlockID] && SuccsVisited[BlockID] < Block->
succ_size() &&
653 if (isa<SwitchStmt>(Term)) {
655 if (!Label || !isa<SwitchCase>(Label))
661 Use.addUninitBranch(Branch);
666 Use.addUninitBranch(Branch);
678 void TransferFunctions::reportUse(
const Expr *ex,
const VarDecl *vd) {
681 handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
693 void TransferFunctions::VisitBlockExpr(
BlockExpr *be) {
695 for (
const auto &I : bd->
captures()) {
696 const VarDecl *vd = I.getVariable();
707 void TransferFunctions::VisitCallExpr(
CallExpr *ce) {
709 if (Callee->hasAttr<ReturnsTwiceAttr>()) {
717 else if (Callee->hasAttr<AnalyzerNoReturnAttr>()) {
725 vals.setAllScratchValues(
Unknown);
730 void TransferFunctions::VisitDeclRefExpr(
DeclRefExpr *dr) {
731 switch (classification.get(dr)) {
732 case ClassifyRefs::Ignore:
734 case ClassifyRefs::Use:
735 reportUse(dr, cast<VarDecl>(dr->
getDecl()));
737 case ClassifyRefs::Init:
740 case ClassifyRefs::SelfInit:
741 handler.handleSelfInit(cast<VarDecl>(dr->
getDecl()));
748 FindVarResult Var = findVar(BO->
getLHS());
749 if (
const VarDecl *VD = Var.getDecl())
754 void TransferFunctions::VisitDeclStmt(
DeclStmt *DS) {
755 for (
auto *DI : DS->
decls()) {
793 if (objCNoRet.isImplicitNoReturn(ME)) {
794 vals.setAllScratchValues(
Unknown);
804 const ClassifyRefs &classification,
805 llvm::BitVector &wasAnalyzed,
817 vals.mergeIntoScratch(vals.getValueVector(pred), isFirst);
822 TransferFunctions tf(vals, cfg, block, ac, classification, handler);
826 tf.Visit(const_cast<Stmt*>(cs->getStmt()));
828 return vals.updateValueVectorWithScratch(block);
837 PruneBlocksHandler(
unsigned numBlocks)
841 ~PruneBlocksHandler()
override {}
844 llvm::BitVector hadUse;
850 unsigned currentBlock;
854 hadUse[currentBlock] =
true;
862 hadUse[currentBlock] =
true;
874 CFGBlockValues vals(cfg);
875 vals.computeSetOfDeclarations(dc);
876 if (vals.hasNoDeclarations())
882 ClassifyRefs classification(ac);
887 ValueVector &vec = vals.getValueVector(&entry);
888 const unsigned n = vals.getNumEntries();
889 for (
unsigned j = 0; j < n ; ++j) {
896 worklist.enqueueSuccessors(&cfg.
getEntry());
901 while (
const CFGBlock *block = worklist.dequeue()) {
905 bool changed =
runOnBlock(block, cfg, ac, vals,
906 classification, wasAnalyzed, PBH);
908 if (changed || !previouslyVisited[block->
getBlockID()])
909 worklist.enqueueSuccessors(block);
910 previouslyVisited[block->
getBlockID()] =
true;
920 runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, handler);
926 UninitVariablesHandler::~UninitVariablesHandler() {}
Defines the clang::ASTContext interface.
CastKind getCastKind() const
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
A (possibly-)qualified type.
ArrayRef< Capture > captures() const
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
succ_iterator succ_begin()
Stmt - This represents one statement.
static bool isPointerToConst(const QualType &QT)
bool isRecordType() const
Decl - This represents one declaration (or definition), e.g.
const Expr * getInit() const
static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc)
VarDecl - An instance of this class is created to represent a variable declaration or definition...
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 ...
AnalysisDeclContext contains the context data for the function or method under analysis.
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)
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
T * getAnalysis()
Return the specified analysis object, lazily running the analysis if necessary.
ElementList::const_iterator const_iterator
A builtin binary operation expression such as "x + y" or "x <= y".
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
decl_iterator decls_begin() const
detail::InMemoryDirectory::const_iterator I
Iterator for iterating over Stmt * arrays that contain only Expr *.
ConditionalOperator - The ?: ternary operator.
Expr * IgnoreParenNoopCasts(ASTContext &Ctx) LLVM_READONLY
IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the value (including ptr->int ...
CFGBlock - Represents a single basic block in a source-level CFG.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
BlockDecl - This represents a block literal declaration, which is like an unnamed FunctionDecl...
Expr - This represents one expression.
void VisitBlockStmts(CALLBACK &O) const
CFG - Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt...
ASTContext & getParentASTContext() const
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
virtual void handleSelfInit(const VarDecl *vd)
Called when the uninitialized variable analysis detects the idiom 'int x = x'.
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.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof), the postinc/postdec operators from postfix-expression, and various extensions.
A use of a variable, which might be uninitialized.
CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style cast in C++ (C++ [expr.cast]), which uses the syntax (Type)expr.
CFGTerminator getTerminator()
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class...
ASTContext & getASTContext() const LLVM_READONLY
bool isLocalVarDecl() const
isLocalVarDecl - Returns true for local variable declarations other than parameters.
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
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()
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return 0.
U cast(CodeGen::Address addr)
detail::InMemoryDirectory::const_iterator E
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
specific_decl_iterator - Iterates over a subrange of declarations stored in a DeclContext, providing only those that are of type SpecificDecl (or a class derived from it).
std::vector< const CFGBlock * >::reverse_iterator iterator
The use is always uninitialized.
Represents Objective-C's collection statement.
char __ovld __cnfn max(char x, char y)
Returns y if x < y, otherwise it returns x.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
static bool isCompoundAssignmentOp(Opcode Opc)
BinaryConditionalOperator - The GNU extension to the conditional operator which allows the middle ope...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
A reference to a declared variable, function, enum, etc.
unsigned NumVariablesAnalyzed
bool isConstQualified() const
Determine whether this type is const-qualified.
unsigned getNumBlockIDs() const
getNumBlockIDs - Returns the total number of BlockIDs allocated (which start at 0).
Expr * IgnoreParens() LLVM_READONLY
IgnoreParens - Ignore parentheses.
static bool isUninitialized(const Value v)