r174781 - [analyzer] Split IvarInvalidation into two checkers
Anna Zaks
ganna at apple.com
Fri Feb 8 15:55:47 PST 2013
Author: zaks
Date: Fri Feb 8 17:55:47 2013
New Revision: 174781
URL: http://llvm.org/viewvc/llvm-project?rev=174781&view=rev
Log:
[analyzer] Split IvarInvalidation into two checkers
Separate the checking for the missing invalidation methods into a
separate checker so that it can be turned on/off independently.
Modified:
cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td
cfe/trunk/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
cfe/trunk/test/Analysis/objc_invalidation.m
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td?rev=174781&r1=174780&r2=174781&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td Fri Feb 8 17:55:47 2013
@@ -412,10 +412,14 @@ def ObjCDeallocChecker : Checker<"Deallo
HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">,
DescFile<"CheckObjCDealloc.cpp">;
-def IvarInvalidationChecker : Checker<"InstanceVariableInvalidation">,
+def InstanceVariableInvalidation : Checker<"InstanceVariableInvalidation">,
HelpText<"Check that the invalidatable instance variables are invalidated in the methods annotated with objc_instance_variable_invalidator">,
DescFile<"IvarInvalidationChecker.cpp">;
+def MissingInvalidationMethod : Checker<"MissingInvalidationMethod">,
+ HelpText<"Check that the invalidation methods are present in classes that contain invalidatable instance variables">,
+ DescFile<"IvarInvalidationChecker.cpp">;
+
def DirectIvarAssignment : Checker<"DirectIvarAssignment">,
HelpText<"Check for direct assignments to instance variables">,
DescFile<"DirectIvarAssignment.cpp">;
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp?rev=174781&r1=174780&r2=174781&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp Fri Feb 8 17:55:47 2013
@@ -43,7 +43,22 @@ using namespace clang;
using namespace ento;
namespace {
-class IvarInvalidationChecker :
+// TODO: move this somewhere?
+struct DefaultBool {
+ bool val;
+ DefaultBool() : val(false) {}
+ operator bool() const { return val; }
+ DefaultBool &operator=(bool b) { val = b; return *this; }
+};
+
+struct ChecksFilter {
+ /// Check for missing invalidation method declarations.
+ DefaultBool check_MissingInvalidationMethod;
+ /// Check that all ivars are invalidated.
+ DefaultBool check_InstanceVariableInvalidation;
+};
+
+class IvarInvalidationCheckerImpl :
public Checker<check::ASTDecl<ObjCImplementationDecl> > {
typedef llvm::SmallSetVector<const ObjCMethodDecl*, 2> MethodSet;
@@ -193,21 +208,26 @@ class IvarInvalidationChecker :
const ObjCIvarDecl *IvarDecl,
const IvarToPropMapTy &IvarToPopertyMap);
- static void reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
- const IvarToPropMapTy &IvarToPopertyMap,
- const ObjCInterfaceDecl *InterfaceD,
- BugReporter &BR,
- bool MissingDeclaration);
- static void reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
- const IvarToPropMapTy &IvarToPopertyMap,
- const ObjCMethodDecl *MethodD,
- AnalysisManager& Mgr,
- BugReporter &BR);
-
+ void reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
+ const IvarToPropMapTy &IvarToPopertyMap,
+ const ObjCInterfaceDecl *InterfaceD,
+ bool MissingDeclaration) const;
+ void reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
+ const IvarToPropMapTy &IvarToPopertyMap,
+ const ObjCMethodDecl *MethodD) const;
+
+ AnalysisManager& Mgr;
+ BugReporter &BR;
+ /// Filter on the checks performed.
+ const ChecksFilter &Filter;
public:
- void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr,
- BugReporter &BR) const;
+ IvarInvalidationCheckerImpl(AnalysisManager& InMgr,
+ BugReporter &InBR,
+ const ChecksFilter &InFilter) :
+ Mgr (InMgr), BR(InBR), Filter(InFilter) {}
+
+ void visit(const ObjCImplementationDecl *D) const;
};
static bool isInvalidationMethod(const ObjCMethodDecl *M, bool LookForPartial) {
@@ -225,7 +245,7 @@ static bool isInvalidationMethod(const O
return false;
}
-void IvarInvalidationChecker::containsInvalidationMethod(
+void IvarInvalidationCheckerImpl::containsInvalidationMethod(
const ObjCContainerDecl *D, InvalidationInfo &OutInfo, bool Partial) {
if (!D)
@@ -280,7 +300,7 @@ void IvarInvalidationChecker::containsIn
return;
}
-bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv,
+bool IvarInvalidationCheckerImpl::trackIvar(const ObjCIvarDecl *Iv,
IvarSet &TrackedIvars,
const ObjCIvarDecl **FirstIvarDecl) {
QualType IvQTy = Iv->getType();
@@ -301,7 +321,7 @@ bool IvarInvalidationChecker::trackIvar(
return false;
}
-const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar(
+const ObjCIvarDecl *IvarInvalidationCheckerImpl::findPropertyBackingIvar(
const ObjCPropertyDecl *Prop,
const ObjCInterfaceDecl *InterfaceD,
IvarSet &TrackedIvars,
@@ -346,7 +366,7 @@ const ObjCIvarDecl *IvarInvalidationChec
return 0;
}
-void IvarInvalidationChecker::printIvar(llvm::raw_svector_ostream &os,
+void IvarInvalidationCheckerImpl::printIvar(llvm::raw_svector_ostream &os,
const ObjCIvarDecl *IvarDecl,
const IvarToPropMapTy &IvarToPopertyMap) {
if (IvarDecl->getSynthesize()) {
@@ -360,9 +380,8 @@ void IvarInvalidationChecker::printIvar(
// Check that the invalidatable interfaces with ivars/properties implement the
// invalidation methods.
-void IvarInvalidationChecker::checkASTDecl(const ObjCImplementationDecl *ImplD,
- AnalysisManager& Mgr,
- BugReporter &BR) const {
+void IvarInvalidationCheckerImpl::
+visit(const ObjCImplementationDecl *ImplD) const {
// Collect all ivars that need cleanup.
IvarSet Ivars;
// Record the first Ivar needing invalidation; used in reporting when only
@@ -459,8 +478,8 @@ void IvarInvalidationChecker::checkASTDe
containsInvalidationMethod(InterfaceD, Info, /*LookForPartial*/ false);
// Report an error in case none of the invalidation methods are declared.
- if (!Info.needsInvalidation()) {
- reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD, BR,
+ if (!Info.needsInvalidation() && Filter.check_MissingInvalidationMethod) {
+ reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
/*MissingDeclaration*/ true);
return;
}
@@ -477,6 +496,11 @@ void IvarInvalidationChecker::checkASTDe
if (D && D->hasBody()) {
AtImplementationContainsAtLeastOneInvalidationMethod = true;
+ // Only check if Ivars are invalidated when InstanceVariableInvalidation
+ // has been requested.
+ if (!Filter.check_InstanceVariableInvalidation)
+ break;
+
// Get a copy of ivars needing invalidation.
IvarSet IvarsI = Ivars;
@@ -495,22 +519,22 @@ void IvarInvalidationChecker::checkASTDe
// Warn on the ivars that were not invalidated by the method.
for (IvarSet::const_iterator
I = IvarsI.begin(), E = IvarsI.end(); I != E; ++I)
- reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, D, Mgr, BR);
+ reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, D);
}
}
// Report an error in case none of the invalidation methods are implemented.
- if (!AtImplementationContainsAtLeastOneInvalidationMethod)
- reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD, BR,
+ if (!AtImplementationContainsAtLeastOneInvalidationMethod &&
+ Filter.check_MissingInvalidationMethod)
+ reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
/*MissingDeclaration*/ false);
}
-void IvarInvalidationChecker::
+void IvarInvalidationCheckerImpl::
reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
const IvarToPropMapTy &IvarToPopertyMap,
const ObjCInterfaceDecl *InterfaceD,
- BugReporter &BR,
- bool MissingDeclaration) {
+ bool MissingDeclaration) const {
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
assert(FirstIvarDecl);
@@ -530,12 +554,10 @@ reportNoInvalidationMethod(const ObjCIva
IvarDecLocation);
}
-void IvarInvalidationChecker::
+void IvarInvalidationCheckerImpl::
reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
const IvarToPropMapTy &IvarToPopertyMap,
- const ObjCMethodDecl *MethodD,
- AnalysisManager& Mgr,
- BugReporter &BR) {
+ const ObjCMethodDecl *MethodD) const {
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
printIvar(os, IvarD, IvarToPopertyMap);
@@ -549,7 +571,7 @@ reportIvarNeedsInvalidation(const ObjCIv
MethodDecLocation);
}
-void IvarInvalidationChecker::MethodCrawler::markInvalidated(
+void IvarInvalidationCheckerImpl::MethodCrawler::markInvalidated(
const ObjCIvarDecl *Iv) {
IvarSet::iterator I = IVars.find(Iv);
if (I != IVars.end()) {
@@ -562,7 +584,7 @@ void IvarInvalidationChecker::MethodCraw
}
}
-const Expr *IvarInvalidationChecker::MethodCrawler::peel(const Expr *E) const {
+const Expr *IvarInvalidationCheckerImpl::MethodCrawler::peel(const Expr *E) const {
E = E->IgnoreParenCasts();
if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
E = POE->getSyntacticForm()->IgnoreParenCasts();
@@ -571,13 +593,13 @@ const Expr *IvarInvalidationChecker::Met
return E;
}
-void IvarInvalidationChecker::MethodCrawler::checkObjCIvarRefExpr(
+void IvarInvalidationCheckerImpl::MethodCrawler::checkObjCIvarRefExpr(
const ObjCIvarRefExpr *IvarRef) {
if (const Decl *D = IvarRef->getDecl())
markInvalidated(cast<ObjCIvarDecl>(D->getCanonicalDecl()));
}
-void IvarInvalidationChecker::MethodCrawler::checkObjCMessageExpr(
+void IvarInvalidationCheckerImpl::MethodCrawler::checkObjCMessageExpr(
const ObjCMessageExpr *ME) {
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (MD) {
@@ -588,7 +610,7 @@ void IvarInvalidationChecker::MethodCraw
}
}
-void IvarInvalidationChecker::MethodCrawler::checkObjCPropertyRefExpr(
+void IvarInvalidationCheckerImpl::MethodCrawler::checkObjCPropertyRefExpr(
const ObjCPropertyRefExpr *PA) {
if (PA->isExplicitProperty()) {
@@ -614,14 +636,14 @@ void IvarInvalidationChecker::MethodCraw
}
}
-bool IvarInvalidationChecker::MethodCrawler::isZero(const Expr *E) const {
+bool IvarInvalidationCheckerImpl::MethodCrawler::isZero(const Expr *E) const {
E = peel(E);
return (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull)
!= Expr::NPCK_NotNull);
}
-void IvarInvalidationChecker::MethodCrawler::check(const Expr *E) {
+void IvarInvalidationCheckerImpl::MethodCrawler::check(const Expr *E) {
E = peel(E);
if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
@@ -640,7 +662,7 @@ void IvarInvalidationChecker::MethodCraw
}
}
-void IvarInvalidationChecker::MethodCrawler::VisitBinaryOperator(
+void IvarInvalidationCheckerImpl::MethodCrawler::VisitBinaryOperator(
const BinaryOperator *BO) {
VisitStmt(BO);
@@ -663,7 +685,7 @@ void IvarInvalidationChecker::MethodCraw
}
}
-void IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr(
+void IvarInvalidationCheckerImpl::MethodCrawler::VisitObjCMessageExpr(
const ObjCMessageExpr *ME) {
const ObjCMethodDecl *MD = ME->getMethodDecl();
const Expr *Receiver = ME->getInstanceReceiver();
@@ -696,7 +718,27 @@ void IvarInvalidationChecker::MethodCraw
}
}
-// Register the checker.
-void ento::registerIvarInvalidationChecker(CheckerManager &mgr) {
- mgr.registerChecker<IvarInvalidationChecker>();
+// Register the checkers.
+namespace {
+
+class IvarInvalidationChecker :
+ public Checker<check::ASTDecl<ObjCImplementationDecl> > {
+public:
+ ChecksFilter Filter;
+public:
+ void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr,
+ BugReporter &BR) const {
+ IvarInvalidationCheckerImpl Walker(Mgr, BR, Filter);
+ Walker.visit(D);
+ }
+};
+}
+
+#define REGISTER_CHECKER(name) \
+void ento::register##name(CheckerManager &mgr) {\
+ mgr.registerChecker<IvarInvalidationChecker>()->Filter.check_##name = true;\
}
+
+REGISTER_CHECKER(InstanceVariableInvalidation)
+REGISTER_CHECKER(MissingInvalidationMethod)
+
Modified: cfe/trunk/test/Analysis/objc_invalidation.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/objc_invalidation.m?rev=174781&r1=174780&r2=174781&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/objc_invalidation.m (original)
+++ cfe/trunk/test/Analysis/objc_invalidation.m Fri Feb 8 17:55:47 2013
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -DRUN_IVAR_INVALIDATION -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.MissingInvalidationMethod -DRUN_MISSING_INVALIDATION_METHOD -fobjc-default-synthesize-properties -verify %s
extern void __assert_fail (__const char *__assertion, __const char *__file,
unsigned int __line, __const char *__function)
__attribute__ ((__noreturn__));
@@ -171,15 +172,16 @@ extern void NSLog(NSString *format, ...)
NSLog(@"%@", _Ivar4);
[super invalidate];
}
-// expected-warning at -1 {{Instance variable Ivar1 needs to be invalidated}}
-// expected-warning at -2 {{Instance variable MultipleProtocols needs to be invalidated}}
-// expected-warning at -3 {{Instance variable MultInheritance needs to be invalidated}}
-// expected-warning at -4 {{Property SynthIvarProp needs to be invalidated or set to nil}}
-// expected-warning at -5 {{Instance variable _Ivar3 needs to be invalidated}}
-// expected-warning at -6 {{Instance variable _Ivar4 needs to be invalidated}}
-// expected-warning at -7 {{Instance variable Ivar5 needs to be invalidated or set to nil}}
-// expected-warning at -8 {{Instance variable Ivar13 needs to be invalidated or set to nil}}
-
+#if RUN_IVAR_INVALIDATION
+// expected-warning at -2 {{Instance variable Ivar1 needs to be invalidated}}
+// expected-warning at -3 {{Instance variable MultipleProtocols needs to be invalidated}}
+// expected-warning at -4 {{Instance variable MultInheritance needs to be invalidated}}
+// expected-warning at -5 {{Property SynthIvarProp needs to be invalidated or set to nil}}
+// expected-warning at -6 {{Instance variable _Ivar3 needs to be invalidated}}
+// expected-warning at -7 {{Instance variable _Ivar4 needs to be invalidated}}
+// expected-warning at -8 {{Instance variable Ivar5 needs to be invalidated or set to nil}}
+// expected-warning at -9 {{Instance variable Ivar13 needs to be invalidated or set to nil}}
+#endif
-(void)partialInvalidator1 {
[Ivar9 invalidate];
@@ -247,20 +249,29 @@ extern void NSLog(NSString *format, ...)
@end
@interface MissingInvalidationMethod : Foo <FooBar_Protocol>
- at property (assign) MissingInvalidationMethod *foobar15_warn; // expected-warning {{Property foobar15_warn needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod}}
+ at property (assign) MissingInvalidationMethod *foobar15_warn;
+#if RUN_MISSING_INVALIDATION_METHOD
+// expected-warning at -2 {{Property foobar15_warn needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod}}
+#endif
@end
@implementation MissingInvalidationMethod
@end
@interface MissingInvalidationMethod2 : Foo <FooBar_Protocol> {
- Foo *Ivar1;// expected-warning {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod2}}
+ Foo *Ivar1;
+#if RUN_MISSING_INVALIDATION_METHOD
+// expected-warning at -2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod2}}
+#endif
}
@end
@implementation MissingInvalidationMethod2
@end
@interface MissingInvalidationMethodDecl : NSObject {
- Foo *Ivar1;// expected-warning {{Instance variable Ivar1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl}}
+ Foo *Ivar1;
+#if RUN_MISSING_INVALIDATION_METHOD
+// expected-warning at -2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl}}
+#endif
}
@end
@implementation MissingInvalidationMethodDecl
@@ -268,7 +279,10 @@ extern void NSLog(NSString *format, ...)
@interface MissingInvalidationMethodDecl2 : NSObject {
@private
- Foo *_foo1; // expected-warning {{Instance variable _foo1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl2}}
+ Foo *_foo1;
+#if RUN_MISSING_INVALIDATION_METHOD
+// expected-warning at -2 {{Instance variable _foo1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl2}}
+#endif
}
@property (strong) Foo *bar1;
@end
@@ -302,8 +316,10 @@ extern void NSLog(NSString *format, ...)
}
-(void)invalidate {
-} // expected-warning {{Instance variable Ivar1 needs to be invalidated or set to nil}}
-
+}
+#if RUN_IVAR_INVALIDATION
+// expected-warning at -2 {{Instance variable Ivar1 needs to be invalidated or set to nil}}
+#endif
@end
// False negative.
More information about the cfe-commits
mailing list