zcov: / lib/Checker/CheckObjCUnusedIVars.cpp


Files: 1 Branches Taken: 75.0% 39 / 52
Generated: 2010-02-10 01:31 Branches Executed: 88.5% 46 / 52
Line Coverage: 81.9% 59 / 72


Programs: 1 Runs 2897


       1                 : //==- CheckObjCUnusedIVars.cpp - Check for unused ivars ----------*- 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 CheckObjCUnusedIvars, a checker that
      11                 : //  analyzes an Objective-C class's interface/implementation to determine if it
      12                 : //  has any ivars that are never accessed.
      13                 : //
      14                 : //===----------------------------------------------------------------------===//
      15                 : 
      16                 : #include "clang/Checker/Checkers/LocalCheckers.h"
      17                 : #include "clang/Checker/BugReporter/PathDiagnostic.h"
      18                 : #include "clang/Checker/BugReporter/BugReporter.h"
      19                 : #include "clang/AST/ExprObjC.h"
      20                 : #include "clang/AST/Expr.h"
      21                 : #include "clang/AST/DeclObjC.h"
      22                 : #include "clang/Basic/LangOptions.h"
      23                 : #include "clang/Basic/SourceManager.h"
      24                 : 
      25                 : using namespace clang;
      26                 : 
      27                 : enum IVarState { Unused, Used };
      28                 : typedef llvm::DenseMap<const ObjCIvarDecl*,IVarState> IvarUsageMap;
      29                 : 
      30               40: static void Scan(IvarUsageMap& M, const Stmt* S) {
                        0: branch 0 not taken
                       40: branch 1 taken
      31               40:   if (!S)
      32                0:     return;
      33                 : 
                        6: branch 1 taken
                       34: branch 2 taken
      34               40:   if (const ObjCIvarRefExpr *Ex = dyn_cast<ObjCIvarRefExpr>(S)) {
      35                6:     const ObjCIvarDecl *D = Ex->getDecl();
      36                6:     IvarUsageMap::iterator I = M.find(D);
                        5: branch 3 taken
                        1: branch 4 taken
      37                6:     if (I != M.end())
      38                5:       I->second = Used;
      39                6:     return;
      40                 :   }
      41                 : 
      42                 :   // Blocks can reference an instance variable of a class.
                        2: branch 1 taken
                       32: branch 2 taken
      43               34:   if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
      44                2:     Scan(M, BE->getBody());
      45                2:     return;
      46                 :   }
      47                 : 
                       33: branch 4 taken
                       32: branch 5 taken
      48               65:   for (Stmt::const_child_iterator I=S->child_begin(),E=S->child_end(); I!=E;++I)
      49               33:     Scan(M, *I);
      50                 : }
      51                 : 
      52                0: static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) {
                        0: branch 0 not taken
                        0: branch 1 not taken
      53                0:   if (!D)
      54                0:     return;
      55                 : 
      56                0:   const ObjCIvarDecl* ID = D->getPropertyIvarDecl();
      57                 : 
                        0: branch 0 not taken
                        0: branch 1 not taken
      58                0:   if (!ID)
      59                0:     return;
      60                 : 
      61                0:   IvarUsageMap::iterator I = M.find(ID);
                        0: branch 3 not taken
                        0: branch 4 not taken
      62                0:   if (I != M.end())
      63                0:     I->second = Used;
      64                 : }
      65                 : 
      66                5: static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) {
      67                 :   // Scan the methods for accesses.
                        3: branch 3 taken
                        5: branch 4 taken
      68               13:   for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(),
      69                5:        E = D->instmeth_end(); I!=E; ++I)
      70                3:     Scan(M, (*I)->getBody());
      71                 :   
                        4: branch 1 taken
                        1: branch 2 taken
      72                5:   if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) {    
      73                 :     // Scan for @synthesized property methods that act as setters/getters
      74                 :     // to an ivar.
                        0: branch 3 not taken
                        4: branch 4 taken
      75                8:     for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(),
      76                4:          E = ID->propimpl_end(); I!=E; ++I)
      77                0:       Scan(M, *I);
      78                 :     
      79                 :     // Scan the associated categories as well.
                        1: branch 1 taken
                        4: branch 2 taken
      80                5:     for (const ObjCCategoryDecl *CD =
      81                4:           ID->getClassInterface()->getCategoryList(); CD ;
      82                 :           CD = CD->getNextClassCategory()) {
                        1: branch 1 taken
                        0: branch 2 not taken
      83                1:       if (const ObjCCategoryImplDecl *CID = CD->getImplementation())
      84                1:         Scan(M, CID);
      85                 :     }
      86                 :   }
      87                5: }
      88                 : 
      89                 : static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID,
      90                2:                  SourceManager &SM) {
                       34: branch 4 taken
                        2: branch 5 taken
      91               36:   for (DeclContext::decl_iterator I=C->decls_begin(), E=C->decls_end();
      92                 :        I!=E; ++I)
                        2: branch 2 taken
                       32: branch 3 taken
      93               34:     if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
      94                2:       SourceLocation L = FD->getLocStart();
                        2: branch 2 taken
                        0: branch 3 not taken
      95                2:       if (SM.getFileID(L) == FID)      
      96                2:         Scan(M, FD->getBody());
      97                 :     }
      98                2: }
      99                 : 
     100                 : void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
     101                4:                                 BugReporter &BR) {
     102                 : 
     103                4:   const ObjCInterfaceDecl* ID = D->getClassInterface();
     104                4:   IvarUsageMap M;
     105                 : 
     106                 :   // Iterate over the ivars.
                        4: branch 1 taken
                        4: branch 2 taken
     107               12:   for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(),
     108                4:         E=ID->ivar_end(); I!=E; ++I) {
     109                 : 
     110                4:     const ObjCIvarDecl* ID = *I;
     111                 : 
     112                 :     // Ignore ivars that aren't private.
                        0: branch 1 not taken
                        4: branch 2 taken
     113                4:     if (ID->getAccessControl() != ObjCIvarDecl::Private)
     114                0:       continue;
     115                 : 
     116                 :     // Skip IB Outlets.
                        0: branch 1 not taken
                        4: branch 2 taken
     117                4:     if (ID->getAttr<IBOutletAttr>())
     118                0:       continue;
     119                 : 
     120                4:     M[ID] = Unused;
     121                 :   }
     122                 : 
                        0: branch 1 not taken
                        4: branch 2 taken
     123                4:   if (M.empty())
     124                2:     return;
     125                 :   
     126                 :   // Now scan the implementation declaration.
     127                4:   Scan(M, D);
     128                 : 
     129                 :   
     130                 :   // Any potentially unused ivars?
     131                4:   bool hasUnused = false;
                        4: branch 5 taken
                        2: branch 6 taken
     132                6:   for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
                        2: branch 1 taken
                        2: branch 2 taken
     133                4:     if (I->second == Unused) {
     134                2:       hasUnused = true;
     135                2:       break;
     136                 :     }
     137                 :   
                        2: branch 0 taken
                        2: branch 1 taken
     138                4:   if (!hasUnused)
     139                 :     return;
     140                 :   
     141                 :   // We found some potentially unused ivars.  Scan the entire translation unit
     142                 :   // for functions inside the @implementation that reference these ivars.
     143                 :   // FIXME: In the future hopefully we can just use the lexical DeclContext
     144                 :   // to go from the ObjCImplementationDecl to the lexically "nested"
     145                 :   // C functions.
     146                2:   SourceManager &SM = BR.getSourceManager();
     147                2:   Scan(M, D->getDeclContext(), SM.getFileID(D->getLocation()), SM);
     148                 : 
     149                 :   // Find ivars that are unused.
                        2: branch 5 taken
                        2: branch 6 taken
     150                4:   for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
                        1: branch 1 taken
                        1: branch 2 taken
     151                2:     if (I->second == Unused) {
     152                1:       std::string sbuf;
     153                1:       llvm::raw_string_ostream os(sbuf);
     154                 :       os << "Instance variable '" << I->first->getNameAsString()
     155                 :          << "' in class '" << ID->getNameAsString()
     156                 :          << "' is never used by the methods in its @implementation "
     157                1:             "(although it may be used by category methods).";
     158                 : 
     159                 :       BR.EmitBasicReport("Unused instance variable", "Optimization",
     160                1:                          os.str(), I->first->getLocation());
                        2: branch 1 taken
                        2: branch 2 taken
     161                4:     }
     162                 : }

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