156b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek//==- DeadStoresChecker.cpp - Check for stores to dead variables -*- C++ -*-==//
21ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//
31ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//                     The LLVM Compiler Infrastructure
41ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//
50bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// This file is distributed under the University of Illinois Open Source
60bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// License. See LICENSE.TXT for details.
71ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//
81ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//===----------------------------------------------------------------------===//
91ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//
10843e934ba8c6ebc00d2f6969a50af7074597e8e3Gabor Greif//  This file defines a DeadStores, a flow-sensitive checker that looks for
111ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//  stores to variables that are no longer live.
121ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//
131ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek//===----------------------------------------------------------------------===//
141ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek
157dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis#include "ClangSACheckers.h"
16ce1cab9fc0b4aec9cdef1b30a14e4ccdca3ac5f1Ted Kremenek#include "clang/AST/ASTContext.h"
172fa67efeaf66a9332c30a026dc1c21bef6c33a6cBenjamin Kramer#include "clang/AST/Attr.h"
181a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek#include "clang/AST/ParentMap.h"
192827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek#include "clang/AST/RecursiveASTVisitor.h"
2019948ac84f145b9ea576db2faefda1927c249e44Ted Kremenek#include "clang/Analysis/Analyses/LiveVariables.h"
2119948ac84f145b9ea576db2faefda1927c249e44Ted Kremenek#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
2219948ac84f145b9ea576db2faefda1927c249e44Ted Kremenek#include "clang/StaticAnalyzer/Core/Checker.h"
2319948ac84f145b9ea576db2faefda1927c249e44Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
2419948ac84f145b9ea576db2faefda1927c249e44Ted Kremenek#include "llvm/ADT/BitVector.h"
258fe83e1df954d72c0f4ffc15d20a5222ec151c21Benjamin Kramer#include "llvm/ADT/SmallString.h"
262827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek#include "llvm/Support/SaveAndRestore.h"
271ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek
281ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenekusing namespace clang;
299ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento;
301ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek
312827f5af018c515986ffb1779ec2e7246988f150Ted Kremeneknamespace {
322827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek
332827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek/// A simple visitor to record what VarDecls occur in EH-handling code.
342827f5af018c515986ffb1779ec2e7246988f150Ted Kremenekclass EHCodeVisitor : public RecursiveASTVisitor<EHCodeVisitor> {
352827f5af018c515986ffb1779ec2e7246988f150Ted Kremenekpublic:
362827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  bool inEH;
372827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  llvm::DenseSet<const VarDecl *> &S;
382827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek
392827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
402827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    SaveAndRestore<bool> inFinally(inEH, true);
412827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S);
422827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  }
432827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek
442827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) {
452827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    SaveAndRestore<bool> inCatch(inEH, true);
462827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S);
472827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  }
482827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek
492827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  bool TraverseCXXCatchStmt(CXXCatchStmt *S) {
502827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    SaveAndRestore<bool> inCatch(inEH, true);
512827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    return TraverseStmt(S->getHandlerBlock());
522827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  }
532827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek
542827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  bool VisitDeclRefExpr(DeclRefExpr *DR) {
552827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    if (inEH)
562827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek      if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl()))
572827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek        S.insert(D);
582827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    return true;
592827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  }
602827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek
612827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  EHCodeVisitor(llvm::DenseSet<const VarDecl *> &S) :
622827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  inEH(false), S(S) {}
632827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek};
641a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek
65848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek// FIXME: Eventually migrate into its own file, and have it managed by
66848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek// AnalysisManager.
67848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenekclass ReachableCode {
68848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  const CFG &cfg;
69848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  llvm::BitVector reachable;
70848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenekpublic:
71848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  ReachableCode(const CFG &cfg)
72848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    : cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {}
73848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
74848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  void computeReachableBlocks();
75848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
76848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  bool isReachable(const CFGBlock *block) const {
77848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    return reachable[block->getBlockID()];
78848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  }
79848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek};
80848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek}
81848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
82848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenekvoid ReachableCode::computeReachableBlocks() {
83848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  if (!cfg.getNumBlockIDs())
84848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    return;
85848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
865f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  SmallVector<const CFGBlock*, 10> worklist;
87848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  worklist.push_back(&cfg.getEntry());
88344472ebeded2fca2ed5013b9e87f81d09bfa908Robert Wilhelm
89848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  while (!worklist.empty()) {
90344472ebeded2fca2ed5013b9e87f81d09bfa908Robert Wilhelm    const CFGBlock *block = worklist.pop_back_val();
91848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    llvm::BitVector::reference isReachable = reachable[block->getBlockID()];
92848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    if (isReachable)
93848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek      continue;
94848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    isReachable = true;
95848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    for (CFGBlock::const_succ_iterator i = block->succ_begin(),
96848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek                                       e = block->succ_end(); i != e; ++i)
97848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek      if (const CFGBlock *succ = *i)
98848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek        worklist.push_back(succ);
99848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  }
100848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek}
101848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
1029ed6d8068f767819951bc4eebf6f4912087c442aAnna Zaksstatic const Expr *
1039ed6d8068f767819951bc4eebf6f4912087c442aAnna ZaksLookThroughTransitiveAssignmentsAndCommaOperators(const Expr *Ex) {
104bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek  while (Ex) {
105bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek    const BinaryOperator *BO =
106bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek      dyn_cast<BinaryOperator>(Ex->IgnoreParenCasts());
107bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek    if (!BO)
108bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek      break;
109bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek    if (BO->getOpcode() == BO_Assign) {
110bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek      Ex = BO->getRHS();
111bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek      continue;
112bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek    }
1139ed6d8068f767819951bc4eebf6f4912087c442aAnna Zaks    if (BO->getOpcode() == BO_Comma) {
1149ed6d8068f767819951bc4eebf6f4912087c442aAnna Zaks      Ex = BO->getRHS();
1159ed6d8068f767819951bc4eebf6f4912087c442aAnna Zaks      continue;
1169ed6d8068f767819951bc4eebf6f4912087c442aAnna Zaks    }
117bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek    break;
118bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek  }
119bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek  return Ex;
120bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek}
121bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek
122848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremeneknamespace {
123882998923889a2fcce9b49696506c499e22cf38fTed Kremenekclass DeadStoreObs : public LiveVariables::Observer {
124848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  const CFG &cfg;
125c0508f9fe37a3afb1ccad39879348272545e55dbChris Lattner  ASTContext &Ctx;
1268f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek  BugReporter& BR;
127651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  const CheckerBase *Checker;
1281d26f48dc2eea1c07431ca1519d7034a21b9bcffTed Kremenek  AnalysisDeclContext* AC;
1291a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek  ParentMap& Parents;
130882998923889a2fcce9b49696506c499e22cf38fTed Kremenek  llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
131651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::unique_ptr<ReachableCode> reachableCode;
132848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  const CFGBlock *currentBlock;
133651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::unique_ptr<llvm::DenseSet<const VarDecl *>> InEH;
1341eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1352cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek  enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
1361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1371ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenekpublic:
138651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  DeadStoreObs(const CFG &cfg, ASTContext &ctx, BugReporter &br,
139651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines               const CheckerBase *checker, AnalysisDeclContext *ac,
140651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines               ParentMap &parents,
141651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines               llvm::SmallPtrSet<const VarDecl *, 20> &escaped)
142651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      : cfg(cfg), Ctx(ctx), BR(br), Checker(checker), AC(ac), Parents(parents),
1436bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        Escaped(escaped), currentBlock(nullptr) {}
1441eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
145fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek  virtual ~DeadStoreObs() {}
146b930d7adb7cb7642c9c49b39df04ebd5cbfa713aTed Kremenek
1472827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  bool isLive(const LiveVariables::LivenessValues &Live, const VarDecl *D) {
1482827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    if (Live.isLive(D))
1492827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek      return true;
1502827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    // Lazily construct the set that records which VarDecls are in
1512827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    // EH code.
1522827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    if (!InEH.get()) {
1532827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek      InEH.reset(new llvm::DenseSet<const VarDecl *>());
1542827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek      EHCodeVisitor V(*InEH.get());
1552827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek      V.TraverseStmt(AC->getBody());
1562827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    }
1572827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    // Treat all VarDecls that occur in EH code as being "always live"
1582827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    // when considering to suppress dead stores.  Frequently stores
1592827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    // are followed by reads in EH code, but we don't have the ability
1602827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    // to analyze that yet.
1612827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    return InEH->count(D);
1622827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek  }
1632827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek
1649c378f705405d37f49795d5e915989de774fe11fTed Kremenek  void Report(const VarDecl *V, DeadStoreKind dsk,
165590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks              PathDiagnosticLocation L, SourceRange R) {
166f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek    if (Escaped.count(V))
167f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek      return;
168848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
169848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    // Compute reachable blocks within the CFG for trivial cases
170848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    // where a bogus dead store can be reported because itself is unreachable.
171848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    if (!reachableCode.get()) {
172848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek      reachableCode.reset(new ReachableCode(cfg));
173848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek      reachableCode->computeReachableBlocks();
174848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    }
175848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
176848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    if (!reachableCode->isReachable(currentBlock))
177848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek      return;
1788f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek
179f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith    SmallString<64> buf;
1807df1234c2e62b2a23dc4417e527f941c20ebe858Jordy Rose    llvm::raw_svector_ostream os(buf);
1816bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    const char *BugType = nullptr;
1821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1832cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    switch (dsk) {
1842cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      case DeadInit:
185efc620c4eb14d2ff59e3ec0714602997ffeddfd7Ted Kremenek        BugType = "Dead initialization";
186b8989f27f116ff2400e92a52c067a69846119eb5Benjamin Kramer        os << "Value stored to '" << *V
1877df1234c2e62b2a23dc4417e527f941c20ebe858Jordy Rose           << "' during its initialization is never read";
1882cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        break;
1891eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1902cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      case DeadIncrement:
191efc620c4eb14d2ff59e3ec0714602997ffeddfd7Ted Kremenek        BugType = "Dead increment";
1922cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      case Standard:
193efc620c4eb14d2ff59e3ec0714602997ffeddfd7Ted Kremenek        if (!BugType) BugType = "Dead assignment";
194b8989f27f116ff2400e92a52c067a69846119eb5Benjamin Kramer        os << "Value stored to '" << *V << "' is never read";
1952cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        break;
1961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1972cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      case Enclosing:
19856b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek        // Don't report issues in this case, e.g.: "if (x = foo())",
19956b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek        // where 'x' is unused later.  We have yet to see a case where
20056b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek        // this is a real bug.
20156b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek        return;
202f9c2a5d1b49b60962b613a1dfffa23831ca298a2Ted Kremenek    }
2031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
204651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    BR.EmitBasicReport(AC->getDecl(), Checker, BugType, "Dead store", os.str(),
205651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                       L, R);
2061a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek  }
2071eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2089c378f705405d37f49795d5e915989de774fe11fTed Kremenek  void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val,
2092cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek                    DeadStoreKind dsk,
210882998923889a2fcce9b49696506c499e22cf38fTed Kremenek                    const LiveVariables::LivenessValues &Live) {
2111a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek
212852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek    if (!VD->hasLocalStorage())
213852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek      return;
214852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek    // Reference types confuse the dead stores checker.  Skip them
215852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek    // for now.
216852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek    if (VD->getType()->getAs<ReferenceType>())
217852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek      return;
218852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek
2192827f5af018c515986ffb1779ec2e7246988f150Ted Kremenek    if (!isLive(Live, VD) &&
220651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        !(VD->hasAttr<UnusedAttr>() || VD->hasAttr<BlocksAttr>() ||
221651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines          VD->hasAttr<ObjCPreciseLifetimeAttr>())) {
222590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks
223590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks      PathDiagnosticLocation ExLoc =
224590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks        PathDiagnosticLocation::createBegin(Ex, BR.getSourceManager(), AC);
225590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks      Report(VD, dsk, ExLoc, Val->getSourceRange());
226590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks    }
2273eb817e5095d25e7bf4a8df9ed3f9b13bed6f298Ted Kremenek  }
2281eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2299c378f705405d37f49795d5e915989de774fe11fTed Kremenek  void CheckDeclRef(const DeclRefExpr *DR, const Expr *Val, DeadStoreKind dsk,
230882998923889a2fcce9b49696506c499e22cf38fTed Kremenek                    const LiveVariables::LivenessValues& Live) {
2319c378f705405d37f49795d5e915989de774fe11fTed Kremenek    if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
232882998923889a2fcce9b49696506c499e22cf38fTed Kremenek      CheckVarDecl(VD, DR, Val, dsk, Live);
2332cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek  }
2341eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2359c378f705405d37f49795d5e915989de774fe11fTed Kremenek  bool isIncrement(VarDecl *VD, const BinaryOperator* B) {
2362cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    if (B->isCompoundAssignmentOp())
2372cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      return true;
2381eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2399c378f705405d37f49795d5e915989de774fe11fTed Kremenek    const Expr *RHS = B->getRHS()->IgnoreParenCasts();
240882998923889a2fcce9b49696506c499e22cf38fTed Kremenek    const BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
2411eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2422cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    if (!BRHS)
2432cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      return false;
2441eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
245882998923889a2fcce9b49696506c499e22cf38fTed Kremenek    const DeclRefExpr *DR;
2461eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2472cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
2482cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      if (DR->getDecl() == VD)
2492cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        return true;
2501eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2512cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts())))
2522cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      if (DR->getDecl() == VD)
2532cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        return true;
2541eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2552cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    return false;
256a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek  }
2571eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
258651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  void observeStmt(const Stmt *S, const CFGBlock *block,
259651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                   const LiveVariables::LivenessValues &Live) override {
2601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
261848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    currentBlock = block;
262848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
2631c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek    // Skip statements in macros.
2641c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek    if (S->getLocStart().isMacroID())
2651c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek      return;
2661eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
267f4e532b5a1683a9f6c842f361c7415bf3474315fTed Kremenek    // Only cover dead stores from regular assignments.  ++/-- dead stores
268f4e532b5a1683a9f6c842f361c7415bf3474315fTed Kremenek    // have never flagged a real bug.
269882998923889a2fcce9b49696506c499e22cf38fTed Kremenek    if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
270fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek      if (!B->isAssignmentOp()) return; // Skip non-assignments.
2711eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2729c378f705405d37f49795d5e915989de774fe11fTed Kremenek      if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS()))
2731a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek        if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
274e12691c2a2109016df12b2cbf54d51a921e6b618Ted Kremenek          // Special case: check for assigning null to a pointer.
2751eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump          //  This is a common form of defensive programming.
2769ed6d8068f767819951bc4eebf6f4912087c442aAnna Zaks          const Expr *RHS =
2779ed6d8068f767819951bc4eebf6f4912087c442aAnna Zaks            LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS());
2789ed6d8068f767819951bc4eebf6f4912087c442aAnna Zaks          RHS = RHS->IgnoreParenCasts();
279bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek
280891322002b5f5886d812f6e8df12174fb2d8e73bTed Kremenek          QualType T = VD->getType();
281891322002b5f5886d812f6e8df12174fb2d8e73bTed Kremenek          if (T->isPointerType() || T->isObjCObjectPointerType()) {
282bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek            if (RHS->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull))
28393fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek              return;
284e12691c2a2109016df12b2cbf54d51a921e6b618Ted Kremenek          }
28593fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek
2863b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek          // Special case: self-assignments.  These are often used to shut up
2873b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek          //  "unused variable" compiler warnings.
288bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek          if (const DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS))
2893b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek            if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
2903b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek              return;
2911eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2923b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek          // Otherwise, issue a warning.
293b930d7adb7cb7642c9c49b39df04ebd5cbfa713aTed Kremenek          DeadStoreKind dsk = Parents.isConsumedExpr(B)
2941eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                              ? Enclosing
2957f5fce7200fdbf03f7d70134a57271e584fcb766Ted Kremenek                              : (isIncrement(VD,B) ? DeadIncrement : Standard);
2961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
297882998923889a2fcce9b49696506c499e22cf38fTed Kremenek          CheckVarDecl(VD, DR, B->getRHS(), dsk, Live);
2981eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        }
2991ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek    }
300882998923889a2fcce9b49696506c499e22cf38fTed Kremenek    else if (const UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
301f4e532b5a1683a9f6c842f361c7415bf3474315fTed Kremenek      if (!U->isIncrementOp() || U->isPrefix())
302a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek        return;
3031eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
304882998923889a2fcce9b49696506c499e22cf38fTed Kremenek      const Stmt *parent = Parents.getParentIgnoreParenCasts(U);
305f4e532b5a1683a9f6c842f361c7415bf3474315fTed Kremenek      if (!parent || !isa<ReturnStmt>(parent))
306380277e46ec1d2d9abedcddf357ceea935cbe576Ted Kremenek        return;
307b0f36323d9d8392075274b95816e2241f99ddb0dTed Kremenek
308882998923889a2fcce9b49696506c499e22cf38fTed Kremenek      const Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
3091eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3109c378f705405d37f49795d5e915989de774fe11fTed Kremenek      if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex))
311882998923889a2fcce9b49696506c499e22cf38fTed Kremenek        CheckDeclRef(DR, U, DeadIncrement, Live);
3121eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    }
3139c378f705405d37f49795d5e915989de774fe11fTed Kremenek    else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S))
314fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek      // Iterate through the decls.  Warn if any initializers are complex
315fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek      // expressions that are not live (never used).
316651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      for (const auto *DI : DS->decls()) {
317651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        const auto *V = dyn_cast<VarDecl>(DI);
318fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek
319fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek        if (!V)
320fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek          continue;
321852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek
322852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek        if (V->hasLocalStorage()) {
323852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek          // Reference types confuse the dead stores checker.  Skip them
324852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek          // for now.
325852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek          if (V->getType()->getAs<ReferenceType>())
326852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek            return;
327852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek
328bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek          if (const Expr *E = V->getInit()) {
329bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek            while (const ExprWithCleanups *exprClean =
330bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek                    dyn_cast<ExprWithCleanups>(E))
331f85e193739c953358c865005855253af4f68a497John McCall              E = exprClean->getSubExpr();
332f85e193739c953358c865005855253af4f68a497John McCall
333bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek            // Look through transitive assignments, e.g.:
334bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek            // int x = y = 0;
3359ed6d8068f767819951bc4eebf6f4912087c442aAnna Zaks            E = LookThroughTransitiveAssignmentsAndCommaOperators(E);
336bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek
33743f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek            // Don't warn on C++ objects (yet) until we can show that their
33843f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek            // constructors/destructors don't have side effects.
33943f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek            if (isa<CXXConstructExpr>(E))
34043f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek              return;
341604d939ac15d1398761df313679673d30bb10f27Ted Kremenek
342fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek            // A dead initialization is a variable that is dead after it
343fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek            // is initialized.  We don't flag warnings for those variables
344651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            // marked 'unused' or 'objc_precise_lifetime'.
345651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines            if (!isLive(Live, V) &&
346651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                !V->hasAttr<UnusedAttr>() &&
347651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                !V->hasAttr<ObjCPreciseLifetimeAttr>()) {
348c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              // Special case: check for initializations with constants.
349c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              //
350c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              //  e.g. : int x = 0;
351c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              //
352c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              // If x is EVER assigned a new value later, don't issue
353c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              // a warning.  This is because such initialization can be
354c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              // due to defensive programming.
3550e35b4ecee380c2b4c33d75da6bc2fb6f6bc7df3Richard Smith              if (E->isEvaluatable(Ctx))
356d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek                return;
3571eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
358bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek              if (const DeclRefExpr *DRE =
359bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek                  dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
360bb811cab1bfa91074f1992b154fcb0c288e6eda3Ted Kremenek                if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
361ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  // Special case: check for initialization from constant
362ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //  variables.
363ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //
364ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //  e.g. extern const int MyConstant;
365ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //       int x = MyConstant;
366ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //
367d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek                  if (VD->hasGlobalStorage() &&
368ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                      VD->getType().isConstQualified())
369ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                    return;
370ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  // Special case: check for initialization from scalar
371ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //  parameters.  This is often a form of defensive
372ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //  programming.  Non-scalars are still an error since
373ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //  because it more likely represents an actual algorithmic
374ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //  bug.
375ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType())
376ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                    return;
377ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                }
3781eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
379590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks              PathDiagnosticLocation Loc =
380590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks                PathDiagnosticLocation::create(V, BR.getSourceManager());
381590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks              Report(V, DeadInit, Loc, E->getSourceRange());
382ce1cab9fc0b4aec9cdef1b30a14e4ccdca3ac5f1Ted Kremenek            }
383fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek          }
384852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek        }
385fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek      }
3861ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek  }
3871ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek};
3881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3891ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek} // end anonymous namespace
3901ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek
391d2f642b56e87493edfc3b0dab359b5e32d5f8a5eTed Kremenek//===----------------------------------------------------------------------===//
392e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek// Driver function to invoke the Dead-Stores checker on a CFG.
393e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek//===----------------------------------------------------------------------===//
394e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek
395f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremeneknamespace {
396d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Roseclass FindEscaped {
397f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenekpublic:
398882998923889a2fcce9b49696506c499e22cf38fTed Kremenek  llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
399f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek
400d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose  void operator()(const Stmt *S) {
401d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose    // Check for '&'. Any VarDecl whose address has been taken we treat as
402d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose    // escaped.
403d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose    // FIXME: What about references?
404d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose    const UnaryOperator *U = dyn_cast<UnaryOperator>(S);
405d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose    if (!U)
406d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose      return;
407d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose    if (U->getOpcode() != UO_AddrOf)
408d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose      return;
409d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose
410d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose    const Expr *E = U->getSubExpr()->IgnoreParenCasts();
411d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose    if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
412d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
413d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose        Escaped.insert(VD);
414f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek  }
415f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek};
416f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek} // end anonymous namespace
4171eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
418f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek
4197dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis//===----------------------------------------------------------------------===//
4207dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis// DeadStoresChecker
4217dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis//===----------------------------------------------------------------------===//
4227dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis
4237dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidisnamespace {
424ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidisclass DeadStoresChecker : public Checker<check::ASTCodeBody> {
4257dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidispublic:
4267dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis  void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
4277dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis                        BugReporter &BR) const {
428724cfee8b506ffef6f55e556a3329a7403ef7198Ted Kremenek
429724cfee8b506ffef6f55e556a3329a7403ef7198Ted Kremenek    // Don't do anything for template instantiations.
430724cfee8b506ffef6f55e556a3329a7403ef7198Ted Kremenek    // Proving that code in a template instantiation is "dead"
431724cfee8b506ffef6f55e556a3329a7403ef7198Ted Kremenek    // means proving that it is dead in all instantiations.
432724cfee8b506ffef6f55e556a3329a7403ef7198Ted Kremenek    // This same problem exists with -Wunreachable-code.
433724cfee8b506ffef6f55e556a3329a7403ef7198Ted Kremenek    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
434724cfee8b506ffef6f55e556a3329a7403ef7198Ted Kremenek      if (FD->isTemplateInstantiation())
435724cfee8b506ffef6f55e556a3329a7403ef7198Ted Kremenek        return;
436724cfee8b506ffef6f55e556a3329a7403ef7198Ted Kremenek
437a5937bbfd19e61d651a58b0f0ffeef68457902a5Ted Kremenek    if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) {
4387dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis      CFG &cfg = *mgr.getCFG(D);
4391d26f48dc2eea1c07431ca1519d7034a21b9bcffTed Kremenek      AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D);
4407dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis      ParentMap &pmap = mgr.getParentMap(D);
441d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose      FindEscaped FS;
442d049b40ef411eee12a735233dbe04fdc42c67e1aJordan Rose      cfg.VisitBlockStmts(FS);
443651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped);
444882998923889a2fcce9b49696506c499e22cf38fTed Kremenek      L->runOnAllBlocks(A);
4457dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis    }
4467dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis  }
4477dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis};
4487dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis}
4497dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis
4507dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidisvoid ento::registerDeadStoresChecker(CheckerManager &mgr) {
4517dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis  mgr.registerChecker<DeadStoresChecker>();
452d2f642b56e87493edfc3b0dab359b5e32d5f8a5eTed Kremenek}
453