 |
|
 |
|
| 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 |
| |
 |
|
 |
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