diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/Driver/Analyses.def | 3 | ||||
| -rw-r--r-- | clang/Driver/AnalysisConsumer.cpp | 5 | ||||
| -rw-r--r-- | clang/include/clang/Analysis/LocalCheckers.h | 1 | ||||
| -rw-r--r-- | clang/lib/Analysis/CheckObjCUnusedIVars.cpp | 87 |
4 files changed, 96 insertions, 0 deletions
diff --git a/clang/Driver/Analyses.def b/clang/Driver/Analyses.def index 623a2475d6b..841f0c1da1e 100644 --- a/clang/Driver/Analyses.def +++ b/clang/Driver/Analyses.def @@ -33,6 +33,9 @@ ANALYSIS(WarnObjCMethSigs, "warn-objc-methodsigs", ANALYSIS(WarnObjCDealloc, "warn-objc-missing-dealloc", "Warn about Objective-C classes that lack a correct implementation of -dealloc", ObjCImplementation) + +ANALYSIS(WarnObjCUnusedIvars, "warn-objc-unused-ivars", + "Warn about private ivars that are never used", ObjCImplementation) ANALYSIS(CheckerSimple, "checker-simple", "Perform simple path-sensitive checks.", Code) diff --git a/clang/Driver/AnalysisConsumer.cpp b/clang/Driver/AnalysisConsumer.cpp index deb7a85006c..134f6d65334 100644 --- a/clang/Driver/AnalysisConsumer.cpp +++ b/clang/Driver/AnalysisConsumer.cpp @@ -393,6 +393,11 @@ static void ActionWarnObjCDealloc(AnalysisManager& mgr) { mgr.getLangOptions(), BR); } +static void ActionWarnObjCUnusedIvars(AnalysisManager& mgr) { + BugReporter BR(mgr); + CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(mgr.getCodeDecl()), BR); +} + static void ActionWarnObjCMethSigs(AnalysisManager& mgr) { BugReporter BR(mgr); diff --git a/clang/include/clang/Analysis/LocalCheckers.h b/clang/include/clang/Analysis/LocalCheckers.h index 8da144ebce1..23610f9a2d9 100644 --- a/clang/include/clang/Analysis/LocalCheckers.h +++ b/clang/include/clang/Analysis/LocalCheckers.h @@ -45,6 +45,7 @@ void CheckObjCDealloc(ObjCImplementationDecl* D, const LangOptions& L, BugReporter& BR); void CheckObjCInstMethSignature(ObjCImplementationDecl* ID, BugReporter& BR); +void CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR); void RegisterAppleChecks(GRExprEngine& Eng); diff --git a/clang/lib/Analysis/CheckObjCUnusedIVars.cpp b/clang/lib/Analysis/CheckObjCUnusedIVars.cpp new file mode 100644 index 00000000000..4eb273314d5 --- /dev/null +++ b/clang/lib/Analysis/CheckObjCUnusedIVars.cpp @@ -0,0 +1,87 @@ +//==- 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; + } + else + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E;++I) + Scan(M, *I); +} + +void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) { + + ObjCInterfaceDecl* ID = D->getClassInterface(); + IvarUsageMap M; + + + + // 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. + ObjCIvarDecl::AccessControl ac = ID->getAccessControl(); + if (!(ac == ObjCIvarDecl::None || ac == ObjCIvarDecl::Private)) + continue; + + if (ID->getAttr<IBOutletAttr>() == 0) + continue; + + M[ID] = Unused; + } + + if (M.empty()) + return; + + // Now scan the methods for accesses. + for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(), + E = D->instmeth_end(); I!=E; ++I) + Scan(M, (*I)->getBody()); + + // 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 << "Private ivar '" << I->first->getName() << "' is never used."; + + BR.EmitBasicReport("unused ivar", + os.str().c_str(), I->first->getLocation()); + } +} + |

