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
112 lines
3.2 KiB
C++
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());
|
|
}
|
|
}
|
|
|