[analyzer] Refactoring: Move stuff into namespace 'GR'.
[clang.git] / lib / GR / Checkers / ObjCUnusedIVarsChecker.cpp
blob611914fbc0090f5557802c0efa5bc0670d056274
1 //==- ObjCUnusedIVarsChecker.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.
14 //===----------------------------------------------------------------------===//
16 #include "clang/GR/Checkers/LocalCheckers.h"
17 #include "clang/GR/BugReporter/PathDiagnostic.h"
18 #include "clang/GR/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"
25 using namespace clang;
26 using namespace GR;
28 enum IVarState { Unused, Used };
29 typedef llvm::DenseMap<const ObjCIvarDecl*,IVarState> IvarUsageMap;
31 static void Scan(IvarUsageMap& M, const Stmt* S) {
32 if (!S)
33 return;
35 if (const ObjCIvarRefExpr *Ex = dyn_cast<ObjCIvarRefExpr>(S)) {
36 const ObjCIvarDecl *D = Ex->getDecl();
37 IvarUsageMap::iterator I = M.find(D);
38 if (I != M.end())
39 I->second = Used;
40 return;
43 // Blocks can reference an instance variable of a class.
44 if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
45 Scan(M, BE->getBody());
46 return;
49 for (Stmt::const_child_iterator I=S->child_begin(),E=S->child_end(); I!=E;++I)
50 Scan(M, *I);
53 static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) {
54 if (!D)
55 return;
57 const ObjCIvarDecl* ID = D->getPropertyIvarDecl();
59 if (!ID)
60 return;
62 IvarUsageMap::iterator I = M.find(ID);
63 if (I != M.end())
64 I->second = Used;
67 static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) {
68 // Scan the methods for accesses.
69 for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(),
70 E = D->instmeth_end(); I!=E; ++I)
71 Scan(M, (*I)->getBody());
73 if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) {
74 // Scan for @synthesized property methods that act as setters/getters
75 // to an ivar.
76 for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(),
77 E = ID->propimpl_end(); I!=E; ++I)
78 Scan(M, *I);
80 // Scan the associated categories as well.
81 for (const ObjCCategoryDecl *CD =
82 ID->getClassInterface()->getCategoryList(); CD ;
83 CD = CD->getNextClassCategory()) {
84 if (const ObjCCategoryImplDecl *CID = CD->getImplementation())
85 Scan(M, CID);
90 static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID,
91 SourceManager &SM) {
92 for (DeclContext::decl_iterator I=C->decls_begin(), E=C->decls_end();
93 I!=E; ++I)
94 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
95 SourceLocation L = FD->getLocStart();
96 if (SM.getFileID(L) == FID)
97 Scan(M, FD->getBody());
101 void GR::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
102 BugReporter &BR) {
104 const ObjCInterfaceDecl* ID = D->getClassInterface();
105 IvarUsageMap M;
107 // Iterate over the ivars.
108 for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(),
109 E=ID->ivar_end(); I!=E; ++I) {
111 const ObjCIvarDecl* ID = *I;
113 // Ignore ivars that...
114 // (a) aren't private
115 // (b) explicitly marked unused
116 // (c) are iboutlets
117 // (d) are unnamed bitfields
118 if (ID->getAccessControl() != ObjCIvarDecl::Private ||
119 ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>() ||
120 ID->getAttr<IBOutletCollectionAttr>() ||
121 ID->isUnnamedBitfield())
122 continue;
124 M[ID] = Unused;
127 if (M.empty())
128 return;
130 // Now scan the implementation declaration.
131 Scan(M, D);
133 // Any potentially unused ivars?
134 bool hasUnused = false;
135 for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
136 if (I->second == Unused) {
137 hasUnused = true;
138 break;
141 if (!hasUnused)
142 return;
144 // We found some potentially unused ivars. Scan the entire translation unit
145 // for functions inside the @implementation that reference these ivars.
146 // FIXME: In the future hopefully we can just use the lexical DeclContext
147 // to go from the ObjCImplementationDecl to the lexically "nested"
148 // C functions.
149 SourceManager &SM = BR.getSourceManager();
150 Scan(M, D->getDeclContext(), SM.getFileID(D->getLocation()), SM);
152 // Find ivars that are unused.
153 for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
154 if (I->second == Unused) {
155 std::string sbuf;
156 llvm::raw_string_ostream os(sbuf);
157 os << "Instance variable '" << I->first << "' in class '" << ID
158 << "' is never used by the methods in its @implementation "
159 "(although it may be used by category methods).";
161 BR.EmitBasicReport("Unused instance variable", "Optimization",
162 os.str(), I->first->getLocation());