xref: /aosp_15_r20/external/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li //==- DeadStoresChecker.cpp - Check for stores to dead variables -*- C++ -*-==//
2*67e74705SXin Li //
3*67e74705SXin Li //                     The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li //  This file defines a DeadStores, a flow-sensitive checker that looks for
11*67e74705SXin Li //  stores to variables that are no longer live.
12*67e74705SXin Li //
13*67e74705SXin Li //===----------------------------------------------------------------------===//
14*67e74705SXin Li 
15*67e74705SXin Li #include "ClangSACheckers.h"
16*67e74705SXin Li #include "clang/AST/ASTContext.h"
17*67e74705SXin Li #include "clang/AST/Attr.h"
18*67e74705SXin Li #include "clang/AST/ParentMap.h"
19*67e74705SXin Li #include "clang/AST/RecursiveASTVisitor.h"
20*67e74705SXin Li #include "clang/Analysis/Analyses/LiveVariables.h"
21*67e74705SXin Li #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
22*67e74705SXin Li #include "clang/StaticAnalyzer/Core/Checker.h"
23*67e74705SXin Li #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
24*67e74705SXin Li #include "llvm/ADT/BitVector.h"
25*67e74705SXin Li #include "llvm/ADT/SmallString.h"
26*67e74705SXin Li #include "llvm/Support/SaveAndRestore.h"
27*67e74705SXin Li 
28*67e74705SXin Li using namespace clang;
29*67e74705SXin Li using namespace ento;
30*67e74705SXin Li 
31*67e74705SXin Li namespace {
32*67e74705SXin Li 
33*67e74705SXin Li /// A simple visitor to record what VarDecls occur in EH-handling code.
34*67e74705SXin Li class EHCodeVisitor : public RecursiveASTVisitor<EHCodeVisitor> {
35*67e74705SXin Li public:
36*67e74705SXin Li   bool inEH;
37*67e74705SXin Li   llvm::DenseSet<const VarDecl *> &S;
38*67e74705SXin Li 
TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt * S)39*67e74705SXin Li   bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
40*67e74705SXin Li     SaveAndRestore<bool> inFinally(inEH, true);
41*67e74705SXin Li     return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S);
42*67e74705SXin Li   }
43*67e74705SXin Li 
TraverseObjCAtCatchStmt(ObjCAtCatchStmt * S)44*67e74705SXin Li   bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) {
45*67e74705SXin Li     SaveAndRestore<bool> inCatch(inEH, true);
46*67e74705SXin Li     return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S);
47*67e74705SXin Li   }
48*67e74705SXin Li 
TraverseCXXCatchStmt(CXXCatchStmt * S)49*67e74705SXin Li   bool TraverseCXXCatchStmt(CXXCatchStmt *S) {
50*67e74705SXin Li     SaveAndRestore<bool> inCatch(inEH, true);
51*67e74705SXin Li     return TraverseStmt(S->getHandlerBlock());
52*67e74705SXin Li   }
53*67e74705SXin Li 
VisitDeclRefExpr(DeclRefExpr * DR)54*67e74705SXin Li   bool VisitDeclRefExpr(DeclRefExpr *DR) {
55*67e74705SXin Li     if (inEH)
56*67e74705SXin Li       if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl()))
57*67e74705SXin Li         S.insert(D);
58*67e74705SXin Li     return true;
59*67e74705SXin Li   }
60*67e74705SXin Li 
EHCodeVisitor(llvm::DenseSet<const VarDecl * > & S)61*67e74705SXin Li   EHCodeVisitor(llvm::DenseSet<const VarDecl *> &S) :
62*67e74705SXin Li   inEH(false), S(S) {}
63*67e74705SXin Li };
64*67e74705SXin Li 
65*67e74705SXin Li // FIXME: Eventually migrate into its own file, and have it managed by
66*67e74705SXin Li // AnalysisManager.
67*67e74705SXin Li class ReachableCode {
68*67e74705SXin Li   const CFG &cfg;
69*67e74705SXin Li   llvm::BitVector reachable;
70*67e74705SXin Li public:
ReachableCode(const CFG & cfg)71*67e74705SXin Li   ReachableCode(const CFG &cfg)
72*67e74705SXin Li     : cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {}
73*67e74705SXin Li 
74*67e74705SXin Li   void computeReachableBlocks();
75*67e74705SXin Li 
isReachable(const CFGBlock * block) const76*67e74705SXin Li   bool isReachable(const CFGBlock *block) const {
77*67e74705SXin Li     return reachable[block->getBlockID()];
78*67e74705SXin Li   }
79*67e74705SXin Li };
80*67e74705SXin Li }
81*67e74705SXin Li 
computeReachableBlocks()82*67e74705SXin Li void ReachableCode::computeReachableBlocks() {
83*67e74705SXin Li   if (!cfg.getNumBlockIDs())
84*67e74705SXin Li     return;
85*67e74705SXin Li 
86*67e74705SXin Li   SmallVector<const CFGBlock*, 10> worklist;
87*67e74705SXin Li   worklist.push_back(&cfg.getEntry());
88*67e74705SXin Li 
89*67e74705SXin Li   while (!worklist.empty()) {
90*67e74705SXin Li     const CFGBlock *block = worklist.pop_back_val();
91*67e74705SXin Li     llvm::BitVector::reference isReachable = reachable[block->getBlockID()];
92*67e74705SXin Li     if (isReachable)
93*67e74705SXin Li       continue;
94*67e74705SXin Li     isReachable = true;
95*67e74705SXin Li     for (CFGBlock::const_succ_iterator i = block->succ_begin(),
96*67e74705SXin Li                                        e = block->succ_end(); i != e; ++i)
97*67e74705SXin Li       if (const CFGBlock *succ = *i)
98*67e74705SXin Li         worklist.push_back(succ);
99*67e74705SXin Li   }
100*67e74705SXin Li }
101*67e74705SXin Li 
102*67e74705SXin Li static const Expr *
LookThroughTransitiveAssignmentsAndCommaOperators(const Expr * Ex)103*67e74705SXin Li LookThroughTransitiveAssignmentsAndCommaOperators(const Expr *Ex) {
104*67e74705SXin Li   while (Ex) {
105*67e74705SXin Li     const BinaryOperator *BO =
106*67e74705SXin Li       dyn_cast<BinaryOperator>(Ex->IgnoreParenCasts());
107*67e74705SXin Li     if (!BO)
108*67e74705SXin Li       break;
109*67e74705SXin Li     if (BO->getOpcode() == BO_Assign) {
110*67e74705SXin Li       Ex = BO->getRHS();
111*67e74705SXin Li       continue;
112*67e74705SXin Li     }
113*67e74705SXin Li     if (BO->getOpcode() == BO_Comma) {
114*67e74705SXin Li       Ex = BO->getRHS();
115*67e74705SXin Li       continue;
116*67e74705SXin Li     }
117*67e74705SXin Li     break;
118*67e74705SXin Li   }
119*67e74705SXin Li   return Ex;
120*67e74705SXin Li }
121*67e74705SXin Li 
122*67e74705SXin Li namespace {
123*67e74705SXin Li class DeadStoreObs : public LiveVariables::Observer {
124*67e74705SXin Li   const CFG &cfg;
125*67e74705SXin Li   ASTContext &Ctx;
126*67e74705SXin Li   BugReporter& BR;
127*67e74705SXin Li   const CheckerBase *Checker;
128*67e74705SXin Li   AnalysisDeclContext* AC;
129*67e74705SXin Li   ParentMap& Parents;
130*67e74705SXin Li   llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
131*67e74705SXin Li   std::unique_ptr<ReachableCode> reachableCode;
132*67e74705SXin Li   const CFGBlock *currentBlock;
133*67e74705SXin Li   std::unique_ptr<llvm::DenseSet<const VarDecl *>> InEH;
134*67e74705SXin Li 
135*67e74705SXin Li   enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
136*67e74705SXin Li 
137*67e74705SXin Li public:
DeadStoreObs(const CFG & cfg,ASTContext & ctx,BugReporter & br,const CheckerBase * checker,AnalysisDeclContext * ac,ParentMap & parents,llvm::SmallPtrSet<const VarDecl *,20> & escaped)138*67e74705SXin Li   DeadStoreObs(const CFG &cfg, ASTContext &ctx, BugReporter &br,
139*67e74705SXin Li                const CheckerBase *checker, AnalysisDeclContext *ac,
140*67e74705SXin Li                ParentMap &parents,
141*67e74705SXin Li                llvm::SmallPtrSet<const VarDecl *, 20> &escaped)
142*67e74705SXin Li       : cfg(cfg), Ctx(ctx), BR(br), Checker(checker), AC(ac), Parents(parents),
143*67e74705SXin Li         Escaped(escaped), currentBlock(nullptr) {}
144*67e74705SXin Li 
~DeadStoreObs()145*67e74705SXin Li   ~DeadStoreObs() override {}
146*67e74705SXin Li 
isLive(const LiveVariables::LivenessValues & Live,const VarDecl * D)147*67e74705SXin Li   bool isLive(const LiveVariables::LivenessValues &Live, const VarDecl *D) {
148*67e74705SXin Li     if (Live.isLive(D))
149*67e74705SXin Li       return true;
150*67e74705SXin Li     // Lazily construct the set that records which VarDecls are in
151*67e74705SXin Li     // EH code.
152*67e74705SXin Li     if (!InEH.get()) {
153*67e74705SXin Li       InEH.reset(new llvm::DenseSet<const VarDecl *>());
154*67e74705SXin Li       EHCodeVisitor V(*InEH.get());
155*67e74705SXin Li       V.TraverseStmt(AC->getBody());
156*67e74705SXin Li     }
157*67e74705SXin Li     // Treat all VarDecls that occur in EH code as being "always live"
158*67e74705SXin Li     // when considering to suppress dead stores.  Frequently stores
159*67e74705SXin Li     // are followed by reads in EH code, but we don't have the ability
160*67e74705SXin Li     // to analyze that yet.
161*67e74705SXin Li     return InEH->count(D);
162*67e74705SXin Li   }
163*67e74705SXin Li 
Report(const VarDecl * V,DeadStoreKind dsk,PathDiagnosticLocation L,SourceRange R)164*67e74705SXin Li   void Report(const VarDecl *V, DeadStoreKind dsk,
165*67e74705SXin Li               PathDiagnosticLocation L, SourceRange R) {
166*67e74705SXin Li     if (Escaped.count(V))
167*67e74705SXin Li       return;
168*67e74705SXin Li 
169*67e74705SXin Li     // Compute reachable blocks within the CFG for trivial cases
170*67e74705SXin Li     // where a bogus dead store can be reported because itself is unreachable.
171*67e74705SXin Li     if (!reachableCode.get()) {
172*67e74705SXin Li       reachableCode.reset(new ReachableCode(cfg));
173*67e74705SXin Li       reachableCode->computeReachableBlocks();
174*67e74705SXin Li     }
175*67e74705SXin Li 
176*67e74705SXin Li     if (!reachableCode->isReachable(currentBlock))
177*67e74705SXin Li       return;
178*67e74705SXin Li 
179*67e74705SXin Li     SmallString<64> buf;
180*67e74705SXin Li     llvm::raw_svector_ostream os(buf);
181*67e74705SXin Li     const char *BugType = nullptr;
182*67e74705SXin Li 
183*67e74705SXin Li     switch (dsk) {
184*67e74705SXin Li       case DeadInit:
185*67e74705SXin Li         BugType = "Dead initialization";
186*67e74705SXin Li         os << "Value stored to '" << *V
187*67e74705SXin Li            << "' during its initialization is never read";
188*67e74705SXin Li         break;
189*67e74705SXin Li 
190*67e74705SXin Li       case DeadIncrement:
191*67e74705SXin Li         BugType = "Dead increment";
192*67e74705SXin Li       case Standard:
193*67e74705SXin Li         if (!BugType) BugType = "Dead assignment";
194*67e74705SXin Li         os << "Value stored to '" << *V << "' is never read";
195*67e74705SXin Li         break;
196*67e74705SXin Li 
197*67e74705SXin Li       case Enclosing:
198*67e74705SXin Li         // Don't report issues in this case, e.g.: "if (x = foo())",
199*67e74705SXin Li         // where 'x' is unused later.  We have yet to see a case where
200*67e74705SXin Li         // this is a real bug.
201*67e74705SXin Li         return;
202*67e74705SXin Li     }
203*67e74705SXin Li 
204*67e74705SXin Li     BR.EmitBasicReport(AC->getDecl(), Checker, BugType, "Dead store", os.str(),
205*67e74705SXin Li                        L, R);
206*67e74705SXin Li   }
207*67e74705SXin Li 
CheckVarDecl(const VarDecl * VD,const Expr * Ex,const Expr * Val,DeadStoreKind dsk,const LiveVariables::LivenessValues & Live)208*67e74705SXin Li   void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val,
209*67e74705SXin Li                     DeadStoreKind dsk,
210*67e74705SXin Li                     const LiveVariables::LivenessValues &Live) {
211*67e74705SXin Li 
212*67e74705SXin Li     if (!VD->hasLocalStorage())
213*67e74705SXin Li       return;
214*67e74705SXin Li     // Reference types confuse the dead stores checker.  Skip them
215*67e74705SXin Li     // for now.
216*67e74705SXin Li     if (VD->getType()->getAs<ReferenceType>())
217*67e74705SXin Li       return;
218*67e74705SXin Li 
219*67e74705SXin Li     if (!isLive(Live, VD) &&
220*67e74705SXin Li         !(VD->hasAttr<UnusedAttr>() || VD->hasAttr<BlocksAttr>() ||
221*67e74705SXin Li           VD->hasAttr<ObjCPreciseLifetimeAttr>())) {
222*67e74705SXin Li 
223*67e74705SXin Li       PathDiagnosticLocation ExLoc =
224*67e74705SXin Li         PathDiagnosticLocation::createBegin(Ex, BR.getSourceManager(), AC);
225*67e74705SXin Li       Report(VD, dsk, ExLoc, Val->getSourceRange());
226*67e74705SXin Li     }
227*67e74705SXin Li   }
228*67e74705SXin Li 
CheckDeclRef(const DeclRefExpr * DR,const Expr * Val,DeadStoreKind dsk,const LiveVariables::LivenessValues & Live)229*67e74705SXin Li   void CheckDeclRef(const DeclRefExpr *DR, const Expr *Val, DeadStoreKind dsk,
230*67e74705SXin Li                     const LiveVariables::LivenessValues& Live) {
231*67e74705SXin Li     if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
232*67e74705SXin Li       CheckVarDecl(VD, DR, Val, dsk, Live);
233*67e74705SXin Li   }
234*67e74705SXin Li 
isIncrement(VarDecl * VD,const BinaryOperator * B)235*67e74705SXin Li   bool isIncrement(VarDecl *VD, const BinaryOperator* B) {
236*67e74705SXin Li     if (B->isCompoundAssignmentOp())
237*67e74705SXin Li       return true;
238*67e74705SXin Li 
239*67e74705SXin Li     const Expr *RHS = B->getRHS()->IgnoreParenCasts();
240*67e74705SXin Li     const BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
241*67e74705SXin Li 
242*67e74705SXin Li     if (!BRHS)
243*67e74705SXin Li       return false;
244*67e74705SXin Li 
245*67e74705SXin Li     const DeclRefExpr *DR;
246*67e74705SXin Li 
247*67e74705SXin Li     if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
248*67e74705SXin Li       if (DR->getDecl() == VD)
249*67e74705SXin Li         return true;
250*67e74705SXin Li 
251*67e74705SXin Li     if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts())))
252*67e74705SXin Li       if (DR->getDecl() == VD)
253*67e74705SXin Li         return true;
254*67e74705SXin Li 
255*67e74705SXin Li     return false;
256*67e74705SXin Li   }
257*67e74705SXin Li 
observeStmt(const Stmt * S,const CFGBlock * block,const LiveVariables::LivenessValues & Live)258*67e74705SXin Li   void observeStmt(const Stmt *S, const CFGBlock *block,
259*67e74705SXin Li                    const LiveVariables::LivenessValues &Live) override {
260*67e74705SXin Li 
261*67e74705SXin Li     currentBlock = block;
262*67e74705SXin Li 
263*67e74705SXin Li     // Skip statements in macros.
264*67e74705SXin Li     if (S->getLocStart().isMacroID())
265*67e74705SXin Li       return;
266*67e74705SXin Li 
267*67e74705SXin Li     // Only cover dead stores from regular assignments.  ++/-- dead stores
268*67e74705SXin Li     // have never flagged a real bug.
269*67e74705SXin Li     if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
270*67e74705SXin Li       if (!B->isAssignmentOp()) return; // Skip non-assignments.
271*67e74705SXin Li 
272*67e74705SXin Li       if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS()))
273*67e74705SXin Li         if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
274*67e74705SXin Li           // Special case: check for assigning null to a pointer.
275*67e74705SXin Li           //  This is a common form of defensive programming.
276*67e74705SXin Li           const Expr *RHS =
277*67e74705SXin Li             LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS());
278*67e74705SXin Li           RHS = RHS->IgnoreParenCasts();
279*67e74705SXin Li 
280*67e74705SXin Li           QualType T = VD->getType();
281*67e74705SXin Li           if (T.isVolatileQualified())
282*67e74705SXin Li             return;
283*67e74705SXin Li           if (T->isPointerType() || T->isObjCObjectPointerType()) {
284*67e74705SXin Li             if (RHS->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull))
285*67e74705SXin Li               return;
286*67e74705SXin Li           }
287*67e74705SXin Li 
288*67e74705SXin Li           // Special case: self-assignments.  These are often used to shut up
289*67e74705SXin Li           //  "unused variable" compiler warnings.
290*67e74705SXin Li           if (const DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS))
291*67e74705SXin Li             if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
292*67e74705SXin Li               return;
293*67e74705SXin Li 
294*67e74705SXin Li           // Otherwise, issue a warning.
295*67e74705SXin Li           DeadStoreKind dsk = Parents.isConsumedExpr(B)
296*67e74705SXin Li                               ? Enclosing
297*67e74705SXin Li                               : (isIncrement(VD,B) ? DeadIncrement : Standard);
298*67e74705SXin Li 
299*67e74705SXin Li           CheckVarDecl(VD, DR, B->getRHS(), dsk, Live);
300*67e74705SXin Li         }
301*67e74705SXin Li     }
302*67e74705SXin Li     else if (const UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
303*67e74705SXin Li       if (!U->isIncrementOp() || U->isPrefix())
304*67e74705SXin Li         return;
305*67e74705SXin Li 
306*67e74705SXin Li       const Stmt *parent = Parents.getParentIgnoreParenCasts(U);
307*67e74705SXin Li       if (!parent || !isa<ReturnStmt>(parent))
308*67e74705SXin Li         return;
309*67e74705SXin Li 
310*67e74705SXin Li       const Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
311*67e74705SXin Li 
312*67e74705SXin Li       if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex))
313*67e74705SXin Li         CheckDeclRef(DR, U, DeadIncrement, Live);
314*67e74705SXin Li     }
315*67e74705SXin Li     else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S))
316*67e74705SXin Li       // Iterate through the decls.  Warn if any initializers are complex
317*67e74705SXin Li       // expressions that are not live (never used).
318*67e74705SXin Li       for (const auto *DI : DS->decls()) {
319*67e74705SXin Li         const auto *V = dyn_cast<VarDecl>(DI);
320*67e74705SXin Li 
321*67e74705SXin Li         if (!V)
322*67e74705SXin Li           continue;
323*67e74705SXin Li 
324*67e74705SXin Li         if (V->hasLocalStorage()) {
325*67e74705SXin Li           // Reference types confuse the dead stores checker.  Skip them
326*67e74705SXin Li           // for now.
327*67e74705SXin Li           if (V->getType()->getAs<ReferenceType>())
328*67e74705SXin Li             return;
329*67e74705SXin Li 
330*67e74705SXin Li           if (const Expr *E = V->getInit()) {
331*67e74705SXin Li             while (const ExprWithCleanups *exprClean =
332*67e74705SXin Li                     dyn_cast<ExprWithCleanups>(E))
333*67e74705SXin Li               E = exprClean->getSubExpr();
334*67e74705SXin Li 
335*67e74705SXin Li             // Look through transitive assignments, e.g.:
336*67e74705SXin Li             // int x = y = 0;
337*67e74705SXin Li             E = LookThroughTransitiveAssignmentsAndCommaOperators(E);
338*67e74705SXin Li 
339*67e74705SXin Li             // Don't warn on C++ objects (yet) until we can show that their
340*67e74705SXin Li             // constructors/destructors don't have side effects.
341*67e74705SXin Li             if (isa<CXXConstructExpr>(E))
342*67e74705SXin Li               return;
343*67e74705SXin Li 
344*67e74705SXin Li             // A dead initialization is a variable that is dead after it
345*67e74705SXin Li             // is initialized.  We don't flag warnings for those variables
346*67e74705SXin Li             // marked 'unused' or 'objc_precise_lifetime'.
347*67e74705SXin Li             if (!isLive(Live, V) &&
348*67e74705SXin Li                 !V->hasAttr<UnusedAttr>() &&
349*67e74705SXin Li                 !V->hasAttr<ObjCPreciseLifetimeAttr>()) {
350*67e74705SXin Li               // Special case: check for initializations with constants.
351*67e74705SXin Li               //
352*67e74705SXin Li               //  e.g. : int x = 0;
353*67e74705SXin Li               //
354*67e74705SXin Li               // If x is EVER assigned a new value later, don't issue
355*67e74705SXin Li               // a warning.  This is because such initialization can be
356*67e74705SXin Li               // due to defensive programming.
357*67e74705SXin Li               if (E->isEvaluatable(Ctx))
358*67e74705SXin Li                 return;
359*67e74705SXin Li 
360*67e74705SXin Li               if (const DeclRefExpr *DRE =
361*67e74705SXin Li                   dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
362*67e74705SXin Li                 if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
363*67e74705SXin Li                   // Special case: check for initialization from constant
364*67e74705SXin Li                   //  variables.
365*67e74705SXin Li                   //
366*67e74705SXin Li                   //  e.g. extern const int MyConstant;
367*67e74705SXin Li                   //       int x = MyConstant;
368*67e74705SXin Li                   //
369*67e74705SXin Li                   if (VD->hasGlobalStorage() &&
370*67e74705SXin Li                       VD->getType().isConstQualified())
371*67e74705SXin Li                     return;
372*67e74705SXin Li                   // Special case: check for initialization from scalar
373*67e74705SXin Li                   //  parameters.  This is often a form of defensive
374*67e74705SXin Li                   //  programming.  Non-scalars are still an error since
375*67e74705SXin Li                   //  because it more likely represents an actual algorithmic
376*67e74705SXin Li                   //  bug.
377*67e74705SXin Li                   if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType())
378*67e74705SXin Li                     return;
379*67e74705SXin Li                 }
380*67e74705SXin Li 
381*67e74705SXin Li               PathDiagnosticLocation Loc =
382*67e74705SXin Li                 PathDiagnosticLocation::create(V, BR.getSourceManager());
383*67e74705SXin Li               Report(V, DeadInit, Loc, E->getSourceRange());
384*67e74705SXin Li             }
385*67e74705SXin Li           }
386*67e74705SXin Li         }
387*67e74705SXin Li       }
388*67e74705SXin Li   }
389*67e74705SXin Li };
390*67e74705SXin Li 
391*67e74705SXin Li } // end anonymous namespace
392*67e74705SXin Li 
393*67e74705SXin Li //===----------------------------------------------------------------------===//
394*67e74705SXin Li // Driver function to invoke the Dead-Stores checker on a CFG.
395*67e74705SXin Li //===----------------------------------------------------------------------===//
396*67e74705SXin Li 
397*67e74705SXin Li namespace {
398*67e74705SXin Li class FindEscaped {
399*67e74705SXin Li public:
400*67e74705SXin Li   llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
401*67e74705SXin Li 
operator ()(const Stmt * S)402*67e74705SXin Li   void operator()(const Stmt *S) {
403*67e74705SXin Li     // Check for '&'. Any VarDecl whose address has been taken we treat as
404*67e74705SXin Li     // escaped.
405*67e74705SXin Li     // FIXME: What about references?
406*67e74705SXin Li     if (auto *LE = dyn_cast<LambdaExpr>(S)) {
407*67e74705SXin Li       findLambdaReferenceCaptures(LE);
408*67e74705SXin Li       return;
409*67e74705SXin Li     }
410*67e74705SXin Li 
411*67e74705SXin Li     const UnaryOperator *U = dyn_cast<UnaryOperator>(S);
412*67e74705SXin Li     if (!U)
413*67e74705SXin Li       return;
414*67e74705SXin Li     if (U->getOpcode() != UO_AddrOf)
415*67e74705SXin Li       return;
416*67e74705SXin Li 
417*67e74705SXin Li     const Expr *E = U->getSubExpr()->IgnoreParenCasts();
418*67e74705SXin Li     if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
419*67e74705SXin Li       if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
420*67e74705SXin Li         Escaped.insert(VD);
421*67e74705SXin Li   }
422*67e74705SXin Li 
423*67e74705SXin Li   // Treat local variables captured by reference in C++ lambdas as escaped.
findLambdaReferenceCaptures(const LambdaExpr * LE)424*67e74705SXin Li   void findLambdaReferenceCaptures(const LambdaExpr *LE)  {
425*67e74705SXin Li     const CXXRecordDecl *LambdaClass = LE->getLambdaClass();
426*67e74705SXin Li     llvm::DenseMap<const VarDecl *, FieldDecl *> CaptureFields;
427*67e74705SXin Li     FieldDecl *ThisCaptureField;
428*67e74705SXin Li     LambdaClass->getCaptureFields(CaptureFields, ThisCaptureField);
429*67e74705SXin Li 
430*67e74705SXin Li     for (const LambdaCapture &C : LE->captures()) {
431*67e74705SXin Li       if (!C.capturesVariable())
432*67e74705SXin Li         continue;
433*67e74705SXin Li 
434*67e74705SXin Li       VarDecl *VD = C.getCapturedVar();
435*67e74705SXin Li       const FieldDecl *FD = CaptureFields[VD];
436*67e74705SXin Li       if (!FD)
437*67e74705SXin Li         continue;
438*67e74705SXin Li 
439*67e74705SXin Li       // If the capture field is a reference type, it is capture-by-reference.
440*67e74705SXin Li       if (FD->getType()->isReferenceType())
441*67e74705SXin Li         Escaped.insert(VD);
442*67e74705SXin Li     }
443*67e74705SXin Li   }
444*67e74705SXin Li };
445*67e74705SXin Li } // end anonymous namespace
446*67e74705SXin Li 
447*67e74705SXin Li 
448*67e74705SXin Li //===----------------------------------------------------------------------===//
449*67e74705SXin Li // DeadStoresChecker
450*67e74705SXin Li //===----------------------------------------------------------------------===//
451*67e74705SXin Li 
452*67e74705SXin Li namespace {
453*67e74705SXin Li class DeadStoresChecker : public Checker<check::ASTCodeBody> {
454*67e74705SXin Li public:
checkASTCodeBody(const Decl * D,AnalysisManager & mgr,BugReporter & BR) const455*67e74705SXin Li   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
456*67e74705SXin Li                         BugReporter &BR) const {
457*67e74705SXin Li 
458*67e74705SXin Li     // Don't do anything for template instantiations.
459*67e74705SXin Li     // Proving that code in a template instantiation is "dead"
460*67e74705SXin Li     // means proving that it is dead in all instantiations.
461*67e74705SXin Li     // This same problem exists with -Wunreachable-code.
462*67e74705SXin Li     if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
463*67e74705SXin Li       if (FD->isTemplateInstantiation())
464*67e74705SXin Li         return;
465*67e74705SXin Li 
466*67e74705SXin Li     if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) {
467*67e74705SXin Li       CFG &cfg = *mgr.getCFG(D);
468*67e74705SXin Li       AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D);
469*67e74705SXin Li       ParentMap &pmap = mgr.getParentMap(D);
470*67e74705SXin Li       FindEscaped FS;
471*67e74705SXin Li       cfg.VisitBlockStmts(FS);
472*67e74705SXin Li       DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped);
473*67e74705SXin Li       L->runOnAllBlocks(A);
474*67e74705SXin Li     }
475*67e74705SXin Li   }
476*67e74705SXin Li };
477*67e74705SXin Li }
478*67e74705SXin Li 
registerDeadStoresChecker(CheckerManager & mgr)479*67e74705SXin Li void ento::registerDeadStoresChecker(CheckerManager &mgr) {
480*67e74705SXin Li   mgr.registerChecker<DeadStoresChecker>();
481*67e74705SXin Li }
482