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 "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
;
28 enum IVarState
{ Unused
, Used
};
29 typedef llvm::DenseMap
<const ObjCIvarDecl
*,IVarState
> IvarUsageMap
;
31 static void Scan(IvarUsageMap
& M
, const Stmt
* S
) {
35 if (const ObjCIvarRefExpr
*Ex
= dyn_cast
<ObjCIvarRefExpr
>(S
)) {
36 const ObjCIvarDecl
*D
= Ex
->getDecl();
37 IvarUsageMap::iterator I
= M
.find(D
);
43 // Blocks can reference an instance variable of a class.
44 if (const BlockExpr
*BE
= dyn_cast
<BlockExpr
>(S
)) {
45 Scan(M
, BE
->getBody());
49 for (Stmt::const_child_iterator I
=S
->child_begin(),E
=S
->child_end(); I
!=E
;++I
)
53 static void Scan(IvarUsageMap
& M
, const ObjCPropertyImplDecl
* D
) {
57 const ObjCIvarDecl
* ID
= D
->getPropertyIvarDecl();
62 IvarUsageMap::iterator I
= M
.find(ID
);
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
76 for (ObjCImplementationDecl::propimpl_iterator I
= ID
->propimpl_begin(),
77 E
= ID
->propimpl_end(); I
!=E
; ++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())
90 static void Scan(IvarUsageMap
&M
, const DeclContext
*C
, const FileID FID
,
92 for (DeclContext::decl_iterator I
=C
->decls_begin(), E
=C
->decls_end();
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
,
104 const ObjCInterfaceDecl
* ID
= D
->getClassInterface();
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
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())
130 // Now scan the implementation declaration.
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
) {
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"
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
) {
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());