zcov: / lib/Checker/CheckDeadStores.cpp


Files: 1 Branches Taken: 82.3% 93 / 113
Generated: 2010-02-10 01:31 Branches Executed: 98.2% 111 / 113
Line Coverage: 95.4% 103 / 108


Programs: 1 Runs 2897


       1                 : //==- DeadStores.cpp - Check for stores to dead variables --------*- C++ -*-==//
       2                 : //
       3                 : //                     The LLVM Compiler Infrastructure
       4                 : //
       5                 : // This file is distributed under the University of Illinois Open Source
       6                 : // License. See LICENSE.TXT for details.
       7                 : //
       8                 : //===----------------------------------------------------------------------===//
       9                 : //
      10                 : //  This file defines a DeadStores, a flow-sensitive checker that looks for
      11                 : //  stores to variables that are no longer live.
      12                 : //
      13                 : //===----------------------------------------------------------------------===//
      14                 : 
      15                 : #include "clang/Checker/Checkers/LocalCheckers.h"
      16                 : #include "clang/Analysis/Analyses/LiveVariables.h"
      17                 : #include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
      18                 : #include "clang/Checker/BugReporter/BugReporter.h"
      19                 : #include "clang/Checker/PathSensitive/GRExprEngine.h"
      20                 : #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
      21                 : #include "clang/Basic/Diagnostic.h"
      22                 : #include "clang/AST/ASTContext.h"
      23                 : #include "clang/AST/ParentMap.h"
      24                 : #include "llvm/ADT/SmallPtrSet.h"
      25                 : 
      26                 : using namespace clang;
      27                 : 
      28                 : namespace {
      29                 : 
      30                 : class DeadStoreObs : public LiveVariables::ObserverTy {
      31                 :   ASTContext &Ctx;
      32                 :   BugReporter& BR;
      33                 :   ParentMap& Parents;
      34                 :   llvm::SmallPtrSet<VarDecl*, 20> Escaped;
      35                 : 
      36                 :   enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
      37                 : 
      38                 : public:
      39                 :   DeadStoreObs(ASTContext &ctx, BugReporter& br, ParentMap& parents,
      40              252:                llvm::SmallPtrSet<VarDecl*, 20> &escaped)
      41              252:     : Ctx(ctx), BR(br), Parents(parents), Escaped(escaped) {}
      42                 : 
                        0: branch 2 not taken
                        0: branch 3 not taken
                        0: branch 7 not taken
                      252: branch 8 taken
      43              252:   virtual ~DeadStoreObs() {}
      44                 : 
      45              105:   void Report(VarDecl* V, DeadStoreKind dsk, SourceLocation L, SourceRange R) {
                        0: branch 1 not taken
                      105: branch 2 taken
      46              105:     if (Escaped.count(V))
      47                0:       return;
      48                 : 
      49              105:     std::string name = V->getNameAsString();
      50                 : 
      51              105:     const char* BugType = 0;
      52              105:     std::string msg;
      53                 : 
                        0: branch 0 not taken
                       30: branch 1 taken
                       40: branch 2 taken
                       20: branch 3 taken
                       15: branch 4 taken
      54              105:     switch (dsk) {
      55                 :       default:
      56                0:         assert(false && "Impossible dead store type.");
      57                 : 
      58                 :       case DeadInit:
      59               30:         BugType = "Dead initialization";
      60                 :         msg = "Value stored to '" + name +
      61               30:           "' during its initialization is never read";
      62               30:         break;
      63                 : 
      64                 :       case DeadIncrement:
      65               40:         BugType = "Dead increment";
      66                 :       case Standard:
                       20: branch 0 taken
                       40: branch 1 taken
      67               60:         if (!BugType) BugType = "Dead assignment";
      68               60:         msg = "Value stored to '" + name + "' is never read";
      69               60:         break;
      70                 : 
      71                 :       case Enclosing:
      72               15:         BugType = "Dead nested assignment";
      73                 :         msg = "Although the value stored to '" + name +
      74                 :           "' is used in the enclosing expression, the value is never actually"
      75               15:           " read from '" + name + "'";
      76                 :         break;
      77                 :     }
      78                 : 
      79              105:     BR.EmitBasicReport(BugType, "Dead store", msg, L, R);
      80                 :   }
      81                 : 
      82                 :   void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val,
      83                 :                     DeadStoreKind dsk,
      84                 :                     const LiveVariables::AnalysisDataTy& AD,
      85              251:                     const LiveVariables::ValTy& Live) {
      86                 : 
                        0: branch 1 not taken
                      251: branch 2 taken
      87              251:     if (!VD->hasLocalStorage())
      88                0:       return;
      89                 :     // Reference types confuse the dead stores checker.  Skip them
      90                 :     // for now.
                       15: branch 3 taken
                      236: branch 4 taken
      91              251:     if (VD->getType()->getAs<ReferenceType>())
      92               15:       return;
      93                 : 
                       85: branch 1 taken
                      151: branch 2 taken
                       85: branch 4 taken
                        0: branch 5 not taken
                       75: branch 7 taken
                       10: branch 8 taken
                       75: branch 9 taken
                      161: branch 10 taken
      94              236:     if (!Live(VD, AD) && 
      95                 :         !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>()))
      96                 :       Report(VD, dsk, Ex->getSourceRange().getBegin(),
      97               75:              Val->getSourceRange());
      98                 :   }
      99                 : 
     100                 :   void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk,
     101                 :                     const LiveVariables::AnalysisDataTy& AD,
     102              145:                     const LiveVariables::ValTy& Live) {
                      145: branch 2 taken
                        0: branch 3 not taken
     103              145:     if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
     104              145:       CheckVarDecl(VD, DR, Val, dsk, AD, Live);
     105              145:   }
     106                 : 
     107               80:   bool isIncrement(VarDecl* VD, BinaryOperator* B) {
                        0: branch 1 not taken
                       80: branch 2 taken
     108               80:     if (B->isCompoundAssignmentOp())
     109                0:       return true;
     110                 : 
     111               80:     Expr* RHS = B->getRHS()->IgnoreParenCasts();
     112               80:     BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
     113                 : 
                       55: branch 0 taken
                       25: branch 1 taken
     114               80:     if (!BRHS)
     115               55:       return false;
     116                 : 
     117                 :     DeclRefExpr *DR;
     118                 : 
                       20: branch 3 taken
                        5: branch 4 taken
     119               25:     if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
                       10: branch 1 taken
                       10: branch 2 taken
     120               20:       if (DR->getDecl() == VD)
     121               10:         return true;
     122                 : 
                        5: branch 3 taken
                       10: branch 4 taken
     123               15:     if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts())))
                        5: branch 1 taken
                        0: branch 2 not taken
     124                5:       if (DR->getDecl() == VD)
     125                5:         return true;
     126                 : 
     127               10:     return false;
     128                 :   }
     129                 : 
     130                 :   virtual void ObserveStmt(Stmt* S,
     131                 :                            const LiveVariables::AnalysisDataTy& AD,
     132             3239:                            const LiveVariables::ValTy& Live) {
     133                 : 
     134                 :     // Skip statements in macros.
                       35: branch 2 taken
                     3204: branch 3 taken
     135             3239:     if (S->getLocStart().isMacroID())
     136               35:       return;
     137                 : 
                      340: branch 1 taken
                     2864: branch 2 taken
     138             3204:     if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
                      131: branch 1 taken
                      209: branch 2 taken
     139              340:       if (!B->isAssignmentOp()) return; // Skip non-assignments.
     140                 : 
                      131: branch 2 taken
                        0: branch 3 not taken
     141              131:       if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
                      131: branch 2 taken
                        0: branch 3 not taken
     142              131:         if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
     143                 :           // Special case: check for assigning null to a pointer.
     144                 :           //  This is a common form of defensive programming.
                       25: branch 3 taken
                      106: branch 4 taken
     145              131:           if (VD->getType()->isPointerType()) {
                       20: branch 2 taken
                        5: branch 3 taken
     146               25:             if (B->getRHS()->isNullPointerConstant(Ctx,
     147                 :                                               Expr::NPC_ValueDependentIsNull))
     148               20:               return;
     149                 :           }
     150                 : 
     151              111:           Expr* RHS = B->getRHS()->IgnoreParenCasts();
     152                 :           // Special case: self-assignments.  These are often used to shut up
     153                 :           //  "unused variable" compiler warnings.
                        5: branch 1 taken
                      106: branch 2 taken
     154              111:           if (DeclRefExpr* RhsDR = dyn_cast<DeclRefExpr>(RHS))
                        5: branch 2 taken
                        0: branch 3 not taken
     155                5:             if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
     156                5:               return;
     157                 : 
     158                 :           // Otherwise, issue a warning.
     159                 :           DeadStoreKind dsk = Parents.isConsumedExpr(B)
     160                 :                               ? Enclosing
                       26: branch 1 taken
                       80: branch 2 taken
                       15: branch 4 taken
                       65: branch 5 taken
     161              106:                               : (isIncrement(VD,B) ? DeadIncrement : Standard);
     162                 : 
     163              106:           CheckVarDecl(VD, DR, B->getRHS(), dsk, AD, Live);
     164                 :         }
     165                 :     }
                      156: branch 1 taken
                     2708: branch 2 taken
     166             2864:     else if (UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
                        6: branch 1 taken
                      150: branch 2 taken
     167              156:       if (!U->isIncrementOp())
     168                6:         return;
     169                 : 
     170                 :       // Handle: ++x within a subexpression.  The solution is not warn
     171                 :       //  about preincrements to dead variables when the preincrement occurs
     172                 :       //  as a subexpression.  This can lead to false negatives, e.g. "(++x);"
     173                 :       //  A generalized dead code checker should find such issues.
                      145: branch 1 taken
                        5: branch 2 taken
                        5: branch 4 taken
                      140: branch 5 taken
                        5: branch 6 taken
                      145: branch 7 taken
     174              150:       if (U->isPrefix() && Parents.isConsumedExpr(U))
     175                5:         return;
     176                 : 
     177              145:       Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
     178                 : 
                      145: branch 1 taken
                        0: branch 2 not taken
     179              145:       if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(Ex))
     180              145:         CheckDeclRef(DR, U, DeadIncrement, AD, Live);
     181                 :     }
                      342: branch 1 taken
                     2366: branch 2 taken
     182             2708:     else if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
     183                 :       // Iterate through the decls.  Warn if any initializers are complex
     184                 :       // expressions that are not live (never used).
                      342: branch 2 taken
                      302: branch 3 taken
     185              644:       for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
     186                 :            DI != DE; ++DI) {
     187                 : 
     188              342:         VarDecl* V = dyn_cast<VarDecl>(*DI);
     189                 : 
                        5: branch 0 taken
                      337: branch 1 taken
     190              342:         if (!V)
     191                5:           continue;
     192                 :           
                      337: branch 1 taken
                        0: branch 2 not taken
     193              337:         if (V->hasLocalStorage()) {          
     194                 :           // Reference types confuse the dead stores checker.  Skip them
     195                 :           // for now.
                       15: branch 3 taken
                      322: branch 4 taken
     196              337:           if (V->getType()->getAs<ReferenceType>())
     197               15:             return;
     198                 :             
                      281: branch 1 taken
                       41: branch 2 taken
     199              322:           if (Expr* E = V->getInit()) {
     200                 :             // Don't warn on C++ objects (yet) until we can show that their
     201                 :             // constructors/destructors don't have side effects.
                       10: branch 1 taken
                      271: branch 2 taken
     202              281:             if (isa<CXXConstructExpr>(E))
     203               10:               return;
     204                 : 
                        0: branch 1 not taken
                      271: branch 2 taken
     205              271:             if (isa<CXXExprWithTemporaries>(E))
     206                0:               return;
     207                 :             
     208                 :             // A dead initialization is a variable that is dead after it
     209                 :             // is initialized.  We don't flag warnings for those variables
     210                 :             // marked 'unused'.
                       55: branch 1 taken
                      216: branch 2 taken
                       45: branch 4 taken
                       10: branch 5 taken
                       45: branch 6 taken
                      226: branch 7 taken
     211              271:             if (!Live(V, AD) && V->getAttr<UnusedAttr>() == 0) {
     212                 :               // Special case: check for initializations with constants.
     213                 :               //
     214                 :               //  e.g. : int x = 0;
     215                 :               //
     216                 :               // If x is EVER assigned a new value later, don't issue
     217                 :               // a warning.  This is because such initialization can be
     218                 :               // due to defensive programming.
                       10: branch 1 taken
                       35: branch 2 taken
     219               45:               if (E->isConstantInitializer(Ctx))
     220               10:                 return;
     221                 : 
     222                 :               // Special case: check for initializations from constant
     223                 :               //  variables.
     224                 :               //
     225                 :               //  e.g. extern const int MyConstant;
     226                 :               //       int x = MyConstant;
     227                 :               //
                       10: branch 2 taken
                       25: branch 3 taken
     228               35:               if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
                       10: branch 2 taken
                        0: branch 3 not taken
     229               10:                 if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
                        5: branch 1 taken
                        5: branch 2 taken
                        5: branch 5 taken
                        0: branch 6 not taken
                        5: branch 7 taken
                        5: branch 8 taken
     230               10:                   if (VD->hasGlobalStorage() &&
     231                5:                       VD->getType().isConstQualified()) return;
     232                 : 
     233               30:               Report(V, DeadInit, V->getLocation(), E->getSourceRange());
     234                 :             }
     235                 :           }
     236                 :         }
     237                 :       }
     238                 :   }
     239                 : };
     240                 : 
     241                 : } // end anonymous namespace
     242                 : 
     243                 : //===----------------------------------------------------------------------===//
     244                 : // Driver function to invoke the Dead-Stores checker on a CFG.
     245                 : //===----------------------------------------------------------------------===//
     246                 : 
     247                 : namespace {
     248              252: class FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
     249                 :   CFG *cfg;
     250                 : public:
     251              252:   FindEscaped(CFG *c) : cfg(c) {}
     252                 : 
     253             2557:   CFG& getCFG() { return *cfg; }
     254                 : 
     255                 :   llvm::SmallPtrSet<VarDecl*, 20> Escaped;
     256                 : 
     257              156:   void VisitUnaryOperator(UnaryOperator* U) {
     258                 :     // Check for '&'.  Any VarDecl whose value has its address-taken we
     259                 :     // treat as escaped.
     260              156:     Expr* E = U->getSubExpr()->IgnoreParenCasts();
                        6: branch 1 taken
                      150: branch 2 taken
     261              156:     if (U->getOpcode() == UnaryOperator::AddrOf)
                        6: branch 1 taken
                        0: branch 2 not taken
     262                6:       if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
                        6: branch 2 taken
                        0: branch 3 not taken
     263                6:         if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
     264                6:           Escaped.insert(VD);
     265                6:           return;
     266                 :         }
     267              150:     Visit(E);
     268                 :   }
     269                 : };
     270                 : } // end anonymous namespace
     271                 : 
     272                 : 
     273                 : void clang::CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &pmap, 
     274              252:                             BugReporter& BR) {
     275              252:   FindEscaped FS(&cfg);
     276              252:   FS.getCFG().VisitBlockStmts(FS);
     277              252:   DeadStoreObs A(BR.getContext(), BR, pmap, FS.Escaped);
     278              252:   L.runOnAllBlocks(cfg, &A);
     279              252: }

Generated: 2010-02-10 01:31 by zcov