opnsense-src/lib/Checker/CheckObjCUnusedIVars.cpp

163 lines
4.9 KiB
C++
Raw Normal View History

2009-06-02 13:58:47 -04:00
//==- 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.
//
//===----------------------------------------------------------------------===//
2010-02-16 04:31:36 -05:00
#include "clang/Checker/Checkers/LocalCheckers.h"
#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/Checker/BugReporter/BugReporter.h"
2009-06-02 13:58:47 -04:00
#include "clang/AST/ExprObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/LangOptions.h"
2009-12-01 06:08:04 -05:00
#include "clang/Basic/SourceManager.h"
2009-06-02 13:58:47 -04:00
using namespace clang;
enum IVarState { Unused, Used };
2009-10-14 14:03:49 -04:00
typedef llvm::DenseMap<const ObjCIvarDecl*,IVarState> IvarUsageMap;
2009-06-02 13:58:47 -04:00
2009-10-14 14:03:49 -04:00
static void Scan(IvarUsageMap& M, const Stmt* S) {
2009-06-02 13:58:47 -04:00
if (!S)
return;
2009-10-14 14:03:49 -04:00
if (const ObjCIvarRefExpr *Ex = dyn_cast<ObjCIvarRefExpr>(S)) {
const ObjCIvarDecl *D = Ex->getDecl();
2009-06-02 13:58:47 -04:00
IvarUsageMap::iterator I = M.find(D);
2009-10-14 14:03:49 -04:00
if (I != M.end())
I->second = Used;
return;
}
// Blocks can reference an instance variable of a class.
if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
Scan(M, BE->getBody());
2009-06-02 13:58:47 -04:00
return;
}
2009-10-14 14:03:49 -04:00
for (Stmt::const_child_iterator I=S->child_begin(),E=S->child_end(); I!=E;++I)
2009-06-02 13:58:47 -04:00
Scan(M, *I);
}
2009-10-14 14:03:49 -04:00
static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) {
2009-06-02 13:58:47 -04:00
if (!D)
return;
2009-10-14 14:03:49 -04:00
const ObjCIvarDecl* ID = D->getPropertyIvarDecl();
2009-06-02 13:58:47 -04:00
if (!ID)
return;
2009-10-14 14:03:49 -04:00
2009-06-02 13:58:47 -04:00
IvarUsageMap::iterator I = M.find(ID);
2009-10-14 14:03:49 -04:00
if (I != M.end())
I->second = Used;
2009-06-02 13:58:47 -04:00
}
2009-11-04 10:04:32 -05:00
static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) {
// Scan the methods for accesses.
for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(),
E = D->instmeth_end(); I!=E; ++I)
Scan(M, (*I)->getBody());
if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) {
// Scan for @synthesized property methods that act as setters/getters
// to an ivar.
for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(),
E = ID->propimpl_end(); I!=E; ++I)
Scan(M, *I);
// Scan the associated categories as well.
for (const ObjCCategoryDecl *CD =
ID->getClassInterface()->getCategoryList(); CD ;
CD = CD->getNextClassCategory()) {
if (const ObjCCategoryImplDecl *CID = CD->getImplementation())
Scan(M, CID);
}
}
}
2009-12-01 06:08:04 -05:00
static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID,
SourceManager &SM) {
for (DeclContext::decl_iterator I=C->decls_begin(), E=C->decls_end();
I!=E; ++I)
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
SourceLocation L = FD->getLocStart();
if (SM.getFileID(L) == FID)
Scan(M, FD->getBody());
}
}
2009-10-14 14:03:49 -04:00
void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
BugReporter &BR) {
2009-06-02 13:58:47 -04:00
2009-10-14 14:03:49 -04:00
const ObjCInterfaceDecl* ID = D->getClassInterface();
2009-06-02 13:58:47 -04:00
IvarUsageMap M;
// Iterate over the ivars.
2009-10-14 14:03:49 -04:00
for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(),
E=ID->ivar_end(); I!=E; ++I) {
const ObjCIvarDecl* ID = *I;
2009-06-02 13:58:47 -04:00
// Ignore ivars that aren't private.
if (ID->getAccessControl() != ObjCIvarDecl::Private)
continue;
// Skip IB Outlets.
2009-07-04 09:58:54 -04:00
if (ID->getAttr<IBOutletAttr>())
2009-06-02 13:58:47 -04:00
continue;
2009-10-14 14:03:49 -04:00
2009-06-02 13:58:47 -04:00
M[ID] = Unused;
}
if (M.empty())
return;
2009-12-01 06:08:04 -05:00
2009-11-04 10:04:32 -05:00
// Now scan the implementation declaration.
Scan(M, D);
2009-10-14 14:03:49 -04:00
2009-12-01 06:08:04 -05:00
// Any potentially unused ivars?
bool hasUnused = false;
for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
if (I->second == Unused) {
hasUnused = true;
break;
}
if (!hasUnused)
return;
// We found some potentially unused ivars. Scan the entire translation unit
// for functions inside the @implementation that reference these ivars.
// FIXME: In the future hopefully we can just use the lexical DeclContext
// to go from the ObjCImplementationDecl to the lexically "nested"
// C functions.
SourceManager &SM = BR.getSourceManager();
Scan(M, D->getDeclContext(), SM.getFileID(D->getLocation()), SM);
2009-06-02 13:58:47 -04:00
// Find ivars that are unused.
for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
if (I->second == Unused) {
2009-06-27 06:45:02 -04:00
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
2009-06-02 13:58:47 -04:00
os << "Instance variable '" << I->first->getNameAsString()
2009-10-14 14:03:49 -04:00
<< "' in class '" << ID->getNameAsString()
2009-06-02 13:58:47 -04:00
<< "' is never used by the methods in its @implementation "
"(although it may be used by category methods).";
BR.EmitBasicReport("Unused instance variable", "Optimization",
2009-12-01 06:08:04 -05:00
os.str(), I->first->getLocation());
2009-06-02 13:58:47 -04:00
}
}