1 //==- ObjCUnusedIVarsChecker.cpp - Check for unused ivars --------*- C++ -*-==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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 "ClangSACheckers.h"
17 #include "clang/StaticAnalyzer/Core/CheckerV2.h"
18 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
19 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
20 #include "clang/AST/ExprObjC.h"
21 #include "clang/AST/Expr.h"
22 #include "clang/AST/DeclObjC.h"
23 #include "clang/Basic/LangOptions.h"
24 #include "clang/Basic/SourceManager.h"
26 using namespace clang
;
29 enum IVarState
{ Unused
, Used
};
30 typedef llvm::DenseMap
<const ObjCIvarDecl
*,IVarState
> IvarUsageMap
;
32 static void Scan(IvarUsageMap
& M
, const Stmt
* S
) {
36 if (const ObjCIvarRefExpr
*Ex
= dyn_cast
<ObjCIvarRefExpr
>(S
)) {
37 const ObjCIvarDecl
*D
= Ex
->getDecl();
38 IvarUsageMap::iterator I
= M
.find(D
);
44 // Blocks can reference an instance variable of a class.
45 if (const BlockExpr
*BE
= dyn_cast
<BlockExpr
>(S
)) {
46 Scan(M
, BE
->getBody());
50 for (Stmt::const_child_iterator I
=S
->child_begin(),E
=S
->child_end(); I
!=E
;++I
)
54 static void Scan(IvarUsageMap
& M
, const ObjCPropertyImplDecl
* D
) {
58 const ObjCIvarDecl
* ID
= D
->getPropertyIvarDecl();
63 IvarUsageMap::iterator I
= M
.find(ID
);
68 static void Scan(IvarUsageMap
& M
, const ObjCContainerDecl
* D
) {
69 // Scan the methods for accesses.
70 for (ObjCContainerDecl::instmeth_iterator I
= D
->instmeth_begin(),
71 E
= D
->instmeth_end(); I
!=E
; ++I
)
72 Scan(M
, (*I
)->getBody());
74 if (const ObjCImplementationDecl
*ID
= dyn_cast
<ObjCImplementationDecl
>(D
)) {
75 // Scan for @synthesized property methods that act as setters/getters
77 for (ObjCImplementationDecl::propimpl_iterator I
= ID
->propimpl_begin(),
78 E
= ID
->propimpl_end(); I
!=E
; ++I
)
81 // Scan the associated categories as well.
82 for (const ObjCCategoryDecl
*CD
=
83 ID
->getClassInterface()->getCategoryList(); CD
;
84 CD
= CD
->getNextClassCategory()) {
85 if (const ObjCCategoryImplDecl
*CID
= CD
->getImplementation())
91 static void Scan(IvarUsageMap
&M
, const DeclContext
*C
, const FileID FID
,
93 for (DeclContext::decl_iterator I
=C
->decls_begin(), E
=C
->decls_end();
95 if (const FunctionDecl
*FD
= dyn_cast
<FunctionDecl
>(*I
)) {
96 SourceLocation L
= FD
->getLocStart();
97 if (SM
.getFileID(L
) == FID
)
98 Scan(M
, FD
->getBody());
102 static void checkObjCUnusedIvar(const ObjCImplementationDecl
*D
,
105 const ObjCInterfaceDecl
* ID
= D
->getClassInterface();
108 // Iterate over the ivars.
109 for (ObjCInterfaceDecl::ivar_iterator I
=ID
->ivar_begin(),
110 E
=ID
->ivar_end(); I
!=E
; ++I
) {
112 const ObjCIvarDecl
* ID
= *I
;
114 // Ignore ivars that...
115 // (a) aren't private
116 // (b) explicitly marked unused
118 // (d) are unnamed bitfields
119 if (ID
->getAccessControl() != ObjCIvarDecl::Private
||
120 ID
->getAttr
<UnusedAttr
>() || ID
->getAttr
<IBOutletAttr
>() ||
121 ID
->getAttr
<IBOutletCollectionAttr
>() ||
122 ID
->isUnnamedBitfield())
131 // Now scan the implementation declaration.
134 // Any potentially unused ivars?
135 bool hasUnused
= false;
136 for (IvarUsageMap::iterator I
= M
.begin(), E
= M
.end(); I
!=E
; ++I
)
137 if (I
->second
== Unused
) {
145 // We found some potentially unused ivars. Scan the entire translation unit
146 // for functions inside the @implementation that reference these ivars.
147 // FIXME: In the future hopefully we can just use the lexical DeclContext
148 // to go from the ObjCImplementationDecl to the lexically "nested"
150 SourceManager
&SM
= BR
.getSourceManager();
151 Scan(M
, D
->getDeclContext(), SM
.getFileID(D
->getLocation()), SM
);
153 // Find ivars that are unused.
154 for (IvarUsageMap::iterator I
= M
.begin(), E
= M
.end(); I
!=E
; ++I
)
155 if (I
->second
== Unused
) {
157 llvm::raw_string_ostream
os(sbuf
);
158 os
<< "Instance variable '" << I
->first
<< "' in class '" << ID
159 << "' is never used by the methods in its @implementation "
160 "(although it may be used by category methods).";
162 BR
.EmitBasicReport("Unused instance variable", "Optimization",
163 os
.str(), I
->first
->getLocation());
167 //===----------------------------------------------------------------------===//
168 // ObjCUnusedIvarsChecker
169 //===----------------------------------------------------------------------===//
172 class ObjCUnusedIvarsChecker
: public CheckerV2
<
173 check::ASTDecl
<ObjCImplementationDecl
> > {
175 void checkASTDecl(const ObjCImplementationDecl
*D
, AnalysisManager
& mgr
,
176 BugReporter
&BR
) const {
177 checkObjCUnusedIvar(D
, BR
);
182 void ento::registerObjCUnusedIvarsChecker(CheckerManager
&mgr
) {
183 mgr
.registerChecker
<ObjCUnusedIvarsChecker
>();