Files
clang-p2996/clang/lib/Analysis/CheckObjCUnusedIVars.cpp
Douglas Gregor 29bd76fd04 Eliminate the three SmallVectors in ObjCImplDecl (for instance
methods, class methods, and property implementations) and instead
place all of these entities into the DeclContext.

This eliminates more linear walks when looking for class or instance
methods and should make PCH (de-)serialization of ObjCDecls trivial
(and lazy).

llvm-svn: 69849
2009-04-23 01:02:12 +00:00

112 lines
3.2 KiB
C++

//==- 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());
}
}