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
39 !vd->isImplicit() && vd->getDeclContext() == dc) {
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());
354 = dyn_cast<
DeclRefExpr>(stripCasts(VD->getASTContext(), Init));
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);
465 if (UO && UO->getOpcode() == UO_AddrOf)
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() &&
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,
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
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()
static bool isPointerToConst(const QualType &QT)
bool isRecordType() const
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)
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
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'.
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...
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.
ExprIterator arg_iterator
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)