DeadStoresChecker.cpp revision 07189521a15d9c088216b943649cb9fe231cbb57
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"
16ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h"
17cf6e41baf2b23b6b56f0f79fff5554b7745737acTed Kremenek#include "clang/Analysis/Analyses/LiveVariables.h"
18fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
199b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
209b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
21f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
221ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek#include "clang/Basic/Diagnostic.h"
23ce1cab9fc0b4aec9cdef1b30a14e4ccdca3ac5f1Ted Kremenek#include "clang/AST/ASTContext.h"
241a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek#include "clang/AST/ParentMap.h"
25f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek#include "llvm/ADT/SmallPtrSet.h"
268fe83e1df954d72c0f4ffc15d20a5222ec151c21Benjamin Kramer#include "llvm/ADT/SmallString.h"
271ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek
281ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenekusing namespace clang;
299ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento;
301ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek
311ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremeneknamespace {
321a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek
33848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek// FIXME: Eventually migrate into its own file, and have it managed by
34848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek// AnalysisManager.
35848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenekclass ReachableCode {
36848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  const CFG &cfg;
37848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  llvm::BitVector reachable;
38848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenekpublic:
39848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  ReachableCode(const CFG &cfg)
40848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    : cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {}
41848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
42848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  void computeReachableBlocks();
43848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
44848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  bool isReachable(const CFGBlock *block) const {
45848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    return reachable[block->getBlockID()];
46848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  }
47848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek};
48848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek}
49848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
50848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenekvoid ReachableCode::computeReachableBlocks() {
51848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  if (!cfg.getNumBlockIDs())
52848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    return;
53848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
545f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner  SmallVector<const CFGBlock*, 10> worklist;
55848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  worklist.push_back(&cfg.getEntry());
56848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
57848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  while (!worklist.empty()) {
58848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    const CFGBlock *block = worklist.back();
59848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    worklist.pop_back();
60848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    llvm::BitVector::reference isReachable = reachable[block->getBlockID()];
61848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    if (isReachable)
62848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek      continue;
63848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    isReachable = true;
64848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    for (CFGBlock::const_succ_iterator i = block->succ_begin(),
65848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek                                       e = block->succ_end(); i != e; ++i)
66848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek      if (const CFGBlock *succ = *i)
67848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek        worklist.push_back(succ);
68848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  }
69848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek}
70848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
71848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremeneknamespace {
72882998923889a2fcce9b49696506c499e22cf38fTed Kremenekclass DeadStoreObs : public LiveVariables::Observer {
73848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  const CFG &cfg;
74c0508f9fe37a3afb1ccad39879348272545e55dbChris Lattner  ASTContext &Ctx;
758f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek  BugReporter& BR;
761d26f48dc2eea1c07431ca1519d7034a21b9bcffTed Kremenek  AnalysisDeclContext* AC;
771a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek  ParentMap& Parents;
78882998923889a2fcce9b49696506c499e22cf38fTed Kremenek  llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
796f42b62b6194f53bcbc349f5d17388e1936535d7Dylan Noblesmith  OwningPtr<ReachableCode> reachableCode;
80848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  const CFGBlock *currentBlock;
811eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
822cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek  enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
831eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
841ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenekpublic:
85848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek  DeadStoreObs(const CFG &cfg, ASTContext &ctx,
861d26f48dc2eea1c07431ca1519d7034a21b9bcffTed Kremenek               BugReporter& br, AnalysisDeclContext* ac, ParentMap& parents,
87882998923889a2fcce9b49696506c499e22cf38fTed Kremenek               llvm::SmallPtrSet<const VarDecl*, 20> &escaped)
88590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks    : cfg(cfg), Ctx(ctx), BR(br), AC(ac), Parents(parents),
89848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek      Escaped(escaped), currentBlock(0) {}
901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
91fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek  virtual ~DeadStoreObs() {}
92b930d7adb7cb7642c9c49b39df04ebd5cbfa713aTed Kremenek
939c378f705405d37f49795d5e915989de774fe11fTed Kremenek  void Report(const VarDecl *V, DeadStoreKind dsk,
94590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks              PathDiagnosticLocation L, SourceRange R) {
95f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek    if (Escaped.count(V))
96f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek      return;
97848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
98848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    // Compute reachable blocks within the CFG for trivial cases
99848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    // where a bogus dead store can be reported because itself is unreachable.
100848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    if (!reachableCode.get()) {
101848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek      reachableCode.reset(new ReachableCode(cfg));
102848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek      reachableCode->computeReachableBlocks();
103848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    }
104848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
105848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    if (!reachableCode->isReachable(currentBlock))
106848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek      return;
1078f2698621f5090db1dea691059bd0ebd79fb7f14Ted Kremenek
108f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith    SmallString<64> buf;
1097df1234c2e62b2a23dc4417e527f941c20ebe858Jordy Rose    llvm::raw_svector_ostream os(buf);
1107df1234c2e62b2a23dc4417e527f941c20ebe858Jordy Rose    const char *BugType = 0;
1111eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1122cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    switch (dsk) {
1132cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      case DeadInit:
114efc620c4eb14d2ff59e3ec0714602997ffeddfd7Ted Kremenek        BugType = "Dead initialization";
115b8989f27f116ff2400e92a52c067a69846119eb5Benjamin Kramer        os << "Value stored to '" << *V
1167df1234c2e62b2a23dc4417e527f941c20ebe858Jordy Rose           << "' during its initialization is never read";
1172cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        break;
1181eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1192cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      case DeadIncrement:
120efc620c4eb14d2ff59e3ec0714602997ffeddfd7Ted Kremenek        BugType = "Dead increment";
1212cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      case Standard:
122efc620c4eb14d2ff59e3ec0714602997ffeddfd7Ted Kremenek        if (!BugType) BugType = "Dead assignment";
123b8989f27f116ff2400e92a52c067a69846119eb5Benjamin Kramer        os << "Value stored to '" << *V << "' is never read";
1242cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        break;
1251eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1262cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      case Enclosing:
12756b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek        // Don't report issues in this case, e.g.: "if (x = foo())",
12856b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek        // where 'x' is unused later.  We have yet to see a case where
12956b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek        // this is a real bug.
13056b1f71156db11b9c8234ca621c29213a73218e0Ted Kremenek        return;
131f9c2a5d1b49b60962b613a1dfffa23831ca298a2Ted Kremenek    }
1321eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
13307189521a15d9c088216b943649cb9fe231cbb57Ted Kremenek    BR.EmitBasicReport(AC->getDecl(), BugType, "Dead store", os.str(), L, R);
1341a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek  }
1351eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1369c378f705405d37f49795d5e915989de774fe11fTed Kremenek  void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val,
1372cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek                    DeadStoreKind dsk,
138882998923889a2fcce9b49696506c499e22cf38fTed Kremenek                    const LiveVariables::LivenessValues &Live) {
1391a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek
140852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek    if (!VD->hasLocalStorage())
141852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek      return;
142852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek    // Reference types confuse the dead stores checker.  Skip them
143852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek    // for now.
144852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek    if (VD->getType()->getAs<ReferenceType>())
145852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek      return;
146852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek
147882998923889a2fcce9b49696506c499e22cf38fTed Kremenek    if (!Live.isLive(VD) &&
148590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks        !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) {
149590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks
150590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks      PathDiagnosticLocation ExLoc =
151590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks        PathDiagnosticLocation::createBegin(Ex, BR.getSourceManager(), AC);
152590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks      Report(VD, dsk, ExLoc, Val->getSourceRange());
153590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks    }
1543eb817e5095d25e7bf4a8df9ed3f9b13bed6f298Ted Kremenek  }
1551eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1569c378f705405d37f49795d5e915989de774fe11fTed Kremenek  void CheckDeclRef(const DeclRefExpr *DR, const Expr *Val, DeadStoreKind dsk,
157882998923889a2fcce9b49696506c499e22cf38fTed Kremenek                    const LiveVariables::LivenessValues& Live) {
1589c378f705405d37f49795d5e915989de774fe11fTed Kremenek    if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
159882998923889a2fcce9b49696506c499e22cf38fTed Kremenek      CheckVarDecl(VD, DR, Val, dsk, Live);
1602cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek  }
1611eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1629c378f705405d37f49795d5e915989de774fe11fTed Kremenek  bool isIncrement(VarDecl *VD, const BinaryOperator* B) {
1632cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    if (B->isCompoundAssignmentOp())
1642cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      return true;
1651eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1669c378f705405d37f49795d5e915989de774fe11fTed Kremenek    const Expr *RHS = B->getRHS()->IgnoreParenCasts();
167882998923889a2fcce9b49696506c499e22cf38fTed Kremenek    const BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
1681eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1692cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    if (!BRHS)
1702cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      return false;
1711eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
172882998923889a2fcce9b49696506c499e22cf38fTed Kremenek    const DeclRefExpr *DR;
1731eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1742cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
1752cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      if (DR->getDecl() == VD)
1762cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        return true;
1771eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1782cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts())))
1792cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek      if (DR->getDecl() == VD)
1802cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek        return true;
1811eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1822cfac226b028e5a2165af077268f70cd2ab4b1a8Ted Kremenek    return false;
183a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek  }
1841eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1859c378f705405d37f49795d5e915989de774fe11fTed Kremenek  virtual void observeStmt(const Stmt *S, const CFGBlock *block,
186882998923889a2fcce9b49696506c499e22cf38fTed Kremenek                           const LiveVariables::LivenessValues &Live) {
1871eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
188848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek    currentBlock = block;
189848ec83483ca4ba52ed72c7e29ebc330f8c87252Ted Kremenek
1901c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek    // Skip statements in macros.
1911c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek    if (S->getLocStart().isMacroID())
1921c86b156ff5b6e42319add892c0b18eb12f6b32bTed Kremenek      return;
1931eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
194f4e532b5a1683a9f6c842f361c7415bf3474315fTed Kremenek    // Only cover dead stores from regular assignments.  ++/-- dead stores
195f4e532b5a1683a9f6c842f361c7415bf3474315fTed Kremenek    // have never flagged a real bug.
196882998923889a2fcce9b49696506c499e22cf38fTed Kremenek    if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
197fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek      if (!B->isAssignmentOp()) return; // Skip non-assignments.
1981eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1999c378f705405d37f49795d5e915989de774fe11fTed Kremenek      if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS()))
2001a654b60ef40e84f3943cdb581795c4d4dae1e45Ted Kremenek        if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
201e12691c2a2109016df12b2cbf54d51a921e6b618Ted Kremenek          // Special case: check for assigning null to a pointer.
2021eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump          //  This is a common form of defensive programming.
203891322002b5f5886d812f6e8df12174fb2d8e73bTed Kremenek          QualType T = VD->getType();
204891322002b5f5886d812f6e8df12174fb2d8e73bTed Kremenek          if (T->isPointerType() || T->isObjCObjectPointerType()) {
20593fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek            if (B->getRHS()->isNullPointerConstant(Ctx,
20693fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek                                              Expr::NPC_ValueDependentIsNull))
20793fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek              return;
208e12691c2a2109016df12b2cbf54d51a921e6b618Ted Kremenek          }
20993fab7c94008d9e2b1e4ce15784544c6710945feTed Kremenek
2109c378f705405d37f49795d5e915989de774fe11fTed Kremenek          Expr *RHS = B->getRHS()->IgnoreParenCasts();
2113b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek          // Special case: self-assignments.  These are often used to shut up
2123b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek          //  "unused variable" compiler warnings.
2139c378f705405d37f49795d5e915989de774fe11fTed Kremenek          if (DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS))
2143b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek            if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
2153b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek              return;
2161eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2173b58786f85aaa173e122f6eaff0b6efa233d59a2Ted Kremenek          // Otherwise, issue a warning.
218b930d7adb7cb7642c9c49b39df04ebd5cbfa713aTed Kremenek          DeadStoreKind dsk = Parents.isConsumedExpr(B)
2191eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump                              ? Enclosing
2207f5fce7200fdbf03f7d70134a57271e584fcb766Ted Kremenek                              : (isIncrement(VD,B) ? DeadIncrement : Standard);
2211eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
222882998923889a2fcce9b49696506c499e22cf38fTed Kremenek          CheckVarDecl(VD, DR, B->getRHS(), dsk, Live);
2231eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        }
2241ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek    }
225882998923889a2fcce9b49696506c499e22cf38fTed Kremenek    else if (const UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
226f4e532b5a1683a9f6c842f361c7415bf3474315fTed Kremenek      if (!U->isIncrementOp() || U->isPrefix())
227a23157e6b9e2388edebd3d383dd7acfab6a4c0c0Ted Kremenek        return;
2281eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
229882998923889a2fcce9b49696506c499e22cf38fTed Kremenek      const Stmt *parent = Parents.getParentIgnoreParenCasts(U);
230f4e532b5a1683a9f6c842f361c7415bf3474315fTed Kremenek      if (!parent || !isa<ReturnStmt>(parent))
231380277e46ec1d2d9abedcddf357ceea935cbe576Ted Kremenek        return;
232b0f36323d9d8392075274b95816e2241f99ddb0dTed Kremenek
233882998923889a2fcce9b49696506c499e22cf38fTed Kremenek      const Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
2341eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2359c378f705405d37f49795d5e915989de774fe11fTed Kremenek      if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex))
236882998923889a2fcce9b49696506c499e22cf38fTed Kremenek        CheckDeclRef(DR, U, DeadIncrement, Live);
2371eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    }
2389c378f705405d37f49795d5e915989de774fe11fTed Kremenek    else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S))
239fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek      // Iterate through the decls.  Warn if any initializers are complex
240fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek      // expressions that are not live (never used).
241882998923889a2fcce9b49696506c499e22cf38fTed Kremenek      for (DeclStmt::const_decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
24214f8b4ff660bcaa763974b8d0fae81857c594495Ted Kremenek           DI != DE; ++DI) {
2431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2449c378f705405d37f49795d5e915989de774fe11fTed Kremenek        VarDecl *V = dyn_cast<VarDecl>(*DI);
245fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek
246fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek        if (!V)
247fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek          continue;
248852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek
249852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek        if (V->hasLocalStorage()) {
250852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek          // Reference types confuse the dead stores checker.  Skip them
251852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek          // for now.
252852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek          if (V->getType()->getAs<ReferenceType>())
253852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek            return;
254852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek
2559c378f705405d37f49795d5e915989de774fe11fTed Kremenek          if (Expr *E = V->getInit()) {
256f85e193739c953358c865005855253af4f68a497John McCall            while (ExprWithCleanups *exprClean = dyn_cast<ExprWithCleanups>(E))
257f85e193739c953358c865005855253af4f68a497John McCall              E = exprClean->getSubExpr();
258f85e193739c953358c865005855253af4f68a497John McCall
25943f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek            // Don't warn on C++ objects (yet) until we can show that their
26043f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek            // constructors/destructors don't have side effects.
26143f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek            if (isa<CXXConstructExpr>(E))
26243f19e3136a9610eeba3cdef9f9af70d93df2f7eTed Kremenek              return;
263604d939ac15d1398761df313679673d30bb10f27Ted Kremenek
264fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek            // A dead initialization is a variable that is dead after it
265fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek            // is initialized.  We don't flag warnings for those variables
266fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek            // marked 'unused'.
267882998923889a2fcce9b49696506c499e22cf38fTed Kremenek            if (!Live.isLive(V) && V->getAttr<UnusedAttr>() == 0) {
268c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              // Special case: check for initializations with constants.
269c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              //
270c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              //  e.g. : int x = 0;
271c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              //
272c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              // If x is EVER assigned a new value later, don't issue
273c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              // a warning.  This is because such initialization can be
274c6a1fafe4289da10487799fc745eedc73dd8e5bcTed Kremenek              // due to defensive programming.
2750e35b4ecee380c2b4c33d75da6bc2fb6f6bc7df3Richard Smith              if (E->isEvaluatable(Ctx))
276d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek                return;
2771eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
278d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek              if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
279ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
280ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  // Special case: check for initialization from constant
281ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //  variables.
282ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //
283ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //  e.g. extern const int MyConstant;
284ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //       int x = MyConstant;
285ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //
286d3098ee64c069a3eff4d2d0a5d655d968c7b5dd2Ted Kremenek                  if (VD->hasGlobalStorage() &&
287ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                      VD->getType().isConstQualified())
288ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                    return;
289ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  // Special case: check for initialization from scalar
290ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //  parameters.  This is often a form of defensive
291ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //  programming.  Non-scalars are still an error since
292ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //  because it more likely represents an actual algorithmic
293ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  //  bug.
294ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                  if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType())
295ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                    return;
296ebd42f40803396d63bc59b77285d088cca61f53fTed Kremenek                }
2971eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
298590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks              PathDiagnosticLocation Loc =
299590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks                PathDiagnosticLocation::create(V, BR.getSourceManager());
300590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks              Report(V, DeadInit, Loc, E->getSourceRange());
301ce1cab9fc0b4aec9cdef1b30a14e4ccdca3ac5f1Ted Kremenek            }
302fc7ff5540412f8003024e1b4940fb8408dff2ca6Ted Kremenek          }
303852274d4257134906995cb252fb3dfd2d71deae8Ted Kremenek        }
304fdd225ed6f362a8550e597eb875d9c402b8a309cTed Kremenek      }
3051ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek  }
3061ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek};
3071eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3081ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek} // end anonymous namespace
3091ed6d2e4fda310af2de2ec09cdfedfa280cce948Ted Kremenek
310d2f642b56e87493edfc3b0dab359b5e32d5f8a5eTed Kremenek//===----------------------------------------------------------------------===//
311e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek// Driver function to invoke the Dead-Stores checker on a CFG.
312e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek//===----------------------------------------------------------------------===//
313e207558e9dbed963eebf5cf31fdb02616f1545a3Ted Kremenek
314f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremeneknamespace {
315ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
316f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek  CFG *cfg;
317f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenekpublic:
318f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek  FindEscaped(CFG *c) : cfg(c) {}
3191eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
320f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek  CFG& getCFG() { return *cfg; }
3211eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
322882998923889a2fcce9b49696506c499e22cf38fTed Kremenek  llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
323f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek
324f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek  void VisitUnaryOperator(UnaryOperator* U) {
325f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek    // Check for '&'.  Any VarDecl whose value has its address-taken we
326f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek    // treat as escaped.
3279c378f705405d37f49795d5e915989de774fe11fTed Kremenek    Expr *E = U->getSubExpr()->IgnoreParenCasts();
3282de56d1d0c3a504ad1529de2677628bdfbb95cd4John McCall    if (U->getOpcode() == UO_AddrOf)
3299c378f705405d37f49795d5e915989de774fe11fTed Kremenek      if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
3309c378f705405d37f49795d5e915989de774fe11fTed Kremenek        if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
331f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek          Escaped.insert(VD);
332f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek          return;
333f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek        }
334f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek    Visit(E);
335f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek  }
336f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek};
337f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek} // end anonymous namespace
3381eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
339f96f16d9f529ec95c20b9a91405653554e9646d1Ted Kremenek
3407dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis//===----------------------------------------------------------------------===//
3417dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis// DeadStoresChecker
3427dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis//===----------------------------------------------------------------------===//
3437dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis
3447dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidisnamespace {
345ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidisclass DeadStoresChecker : public Checker<check::ASTCodeBody> {
3467dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidispublic:
3477dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis  void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
3487dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis                        BugReporter &BR) const {
349a5937bbfd19e61d651a58b0f0ffeef68457902a5Ted Kremenek    if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) {
3507dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis      CFG &cfg = *mgr.getCFG(D);
3511d26f48dc2eea1c07431ca1519d7034a21b9bcffTed Kremenek      AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D);
3527dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis      ParentMap &pmap = mgr.getParentMap(D);
3537dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis      FindEscaped FS(&cfg);
3547dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis      FS.getCFG().VisitBlockStmts(FS);
355590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks      DeadStoreObs A(cfg, BR.getContext(), BR, AC, pmap, FS.Escaped);
356882998923889a2fcce9b49696506c499e22cf38fTed Kremenek      L->runOnAllBlocks(A);
3577dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis    }
3587dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis  }
3597dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis};
3607dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis}
3617dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis
3627dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidisvoid ento::registerDeadStoresChecker(CheckerManager &mgr) {
3637dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis  mgr.registerChecker<DeadStoresChecker>();
364d2f642b56e87493edfc3b0dab359b5e32d5f8a5eTed Kremenek}
365