diff options
Diffstat (limited to 'lib/Analysis/CheckObjCUnusedIVars.cpp')
-rw-r--r-- | lib/Analysis/CheckObjCUnusedIVars.cpp | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Analysis/CheckObjCUnusedIVars.cpp new file mode 100644 index 0000000..7979f9c --- /dev/null +++ b/lib/Analysis/CheckObjCUnusedIVars.cpp @@ -0,0 +1,111 @@ +//==- CheckObjCUnusedIVars.cpp - Check for unused ivars ----------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a CheckObjCUnusedIvars, a checker that +// analyzes an Objective-C class's interface/implementation to determine if it +// has any ivars that are never accessed. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/LocalCheckers.h" +#include "clang/Analysis/PathDiagnostic.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/LangOptions.h" +#include <sstream> + +using namespace clang; + +enum IVarState { Unused, Used }; +typedef llvm::DenseMap<ObjCIvarDecl*,IVarState> IvarUsageMap; + +static void Scan(IvarUsageMap& M, Stmt* S) { + if (!S) + return; + + if (ObjCIvarRefExpr* Ex = dyn_cast<ObjCIvarRefExpr>(S)) { + ObjCIvarDecl* D = Ex->getDecl(); + IvarUsageMap::iterator I = M.find(D); + if (I != M.end()) I->second = Used; + return; + } + + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E;++I) + Scan(M, *I); +} + +static void Scan(IvarUsageMap& M, ObjCPropertyImplDecl* D) { + if (!D) + return; + + ObjCIvarDecl* ID = D->getPropertyIvarDecl(); + + if (!ID) + return; + + IvarUsageMap::iterator I = M.find(ID); + if (I != M.end()) I->second = Used; +} + +void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) { + + ObjCInterfaceDecl* ID = D->getClassInterface(); + IvarUsageMap M; + + + ASTContext &Ctx = BR.getContext(); + + // Iterate over the ivars. + for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end(); + I!=E; ++I) { + + ObjCIvarDecl* ID = *I; + + // Ignore ivars that aren't private. + if (ID->getAccessControl() != ObjCIvarDecl::Private) + continue; + + // Skip IB Outlets. + if (ID->getAttr<IBOutletAttr>()) + continue; + + M[ID] = Unused; + } + + if (M.empty()) + return; + + // Now scan the methods for accesses. + for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(Ctx), + E = D->instmeth_end(Ctx); I!=E; ++I) + Scan(M, (*I)->getBody(Ctx)); + + // Scan for @synthesized property methods that act as setters/getters + // to an ivar. + for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(Ctx), + E = D->propimpl_end(Ctx); I!=E; ++I) + Scan(M, *I); + + // Find ivars that are unused. + for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) + if (I->second == Unused) { + + std::ostringstream os; + os << "Instance variable '" << I->first->getNameAsString() + << "' in class '" << ID->getNameAsString() + << "' is never used by the methods in its @implementation " + "(although it may be used by category methods)."; + + BR.EmitBasicReport("Unused instance variable", "Optimization", + os.str().c_str(), I->first->getLocation()); + } +} + |