aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2013-04-24 02:49:16 +0000
committerAnna Zaks <ganna@apple.com>2013-04-24 02:49:16 +0000
commitcaadc413a88e864e058a3bea832f42debd8ddef2 (patch)
tree8c1fc8a35731386270ba28201fcfe6d760fe1e31
parente3a813abc1874bbd842bcfbdd0fd676fb5cfdde8 (diff)
[analyzer] IvarInvalidation: correctly handle cases where only partial invalidators exist
- If only partial invalidators exist and there are no full invalidators in @implementation, report every ivar that has not been invalidated. (Previously, we reported the first Ivar in the list, which could actually have been invalidated by a partial invalidator. The code assumed you cannot have only partial invalidators.) - Do not report missing invalidation method declaration if a partial invalidation method declaration exists. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180170 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp47
-rw-r--r--test/Analysis/objc_invalidation.m41
2 files changed, 75 insertions, 13 deletions
diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
index 5ed28e955d..cc940be7b1 100644
--- a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -437,6 +437,7 @@ visit(const ObjCImplementationDecl *ImplD) const {
// Remove ivars invalidated by the partial invalidation methods. They do not
// need to be invalidated in the regular invalidation methods.
+ bool AtImplementationContainsAtLeastOnePartialInvalidationMethod = false;
for (MethodSet::iterator
I = PartialInfo.InvalidationMethods.begin(),
E = PartialInfo.InvalidationMethods.end(); I != E; ++I) {
@@ -446,6 +447,8 @@ visit(const ObjCImplementationDecl *ImplD) const {
const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(),
InterfD->isInstanceMethod());
if (D && D->hasBody()) {
+ AtImplementationContainsAtLeastOnePartialInvalidationMethod = true;
+
bool CalledAnotherInvalidationMethod = false;
// The MethodCrowler is going to remove the invalidated ivars.
MethodCrawler(Ivars,
@@ -471,7 +474,7 @@ visit(const ObjCImplementationDecl *ImplD) const {
containsInvalidationMethod(InterfaceD, Info, /*LookForPartial*/ false);
// Report an error in case none of the invalidation methods are declared.
- if (!Info.needsInvalidation()) {
+ if (!Info.needsInvalidation() && !PartialInfo.needsInvalidation()) {
if (Filter.check_MissingInvalidationMethod)
reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
/*MissingDeclaration*/ true);
@@ -520,9 +523,19 @@ visit(const ObjCImplementationDecl *ImplD) const {
}
// Report an error in case none of the invalidation methods are implemented.
- if (!AtImplementationContainsAtLeastOneInvalidationMethod)
- reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
- /*MissingDeclaration*/ false);
+ if (!AtImplementationContainsAtLeastOneInvalidationMethod) {
+ if (AtImplementationContainsAtLeastOnePartialInvalidationMethod) {
+ // Warn on the ivars that were not invalidated by the prrtial
+ // invalidation methods.
+ for (IvarSet::const_iterator
+ I = Ivars.begin(), E = Ivars.end(); I != E; ++I)
+ reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, 0);
+ } else {
+ // Otherwise, no invalidation methods were implemented.
+ reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
+ /*MissingDeclaration*/ false);
+ }
+ }
}
void IvarInvalidationCheckerImpl::
@@ -551,19 +564,27 @@ reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
void IvarInvalidationCheckerImpl::
reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
- const IvarToPropMapTy &IvarToPopertyMap,
- const ObjCMethodDecl *MethodD) const {
+ const IvarToPropMapTy &IvarToPopertyMap,
+ const ObjCMethodDecl *MethodD) const {
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
printIvar(os, IvarD, IvarToPopertyMap);
os << "needs to be invalidated or set to nil";
- PathDiagnosticLocation MethodDecLocation =
- PathDiagnosticLocation::createEnd(MethodD->getBody(),
- BR.getSourceManager(),
- Mgr.getAnalysisDeclContext(MethodD));
- BR.EmitBasicReport(MethodD, "Incomplete invalidation",
- categories::CoreFoundationObjectiveC, os.str(),
- MethodDecLocation);
+ if (MethodD) {
+ PathDiagnosticLocation MethodDecLocation =
+ PathDiagnosticLocation::createEnd(MethodD->getBody(),
+ BR.getSourceManager(),
+ Mgr.getAnalysisDeclContext(MethodD));
+ BR.EmitBasicReport(MethodD, "Incomplete invalidation",
+ categories::CoreFoundationObjectiveC, os.str(),
+ MethodDecLocation);
+ } else {
+ BR.EmitBasicReport(IvarD, "Incomplete invalidation",
+ categories::CoreFoundationObjectiveC, os.str(),
+ PathDiagnosticLocation::createBegin(IvarD,
+ BR.getSourceManager()));
+
+ }
}
void IvarInvalidationCheckerImpl::MethodCrawler::markInvalidated(
diff --git a/test/Analysis/objc_invalidation.m b/test/Analysis/objc_invalidation.m
index a6f5ec3f84..6919feaccf 100644
--- a/test/Analysis/objc_invalidation.m
+++ b/test/Analysis/objc_invalidation.m
@@ -322,6 +322,47 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1,
#endif
@end
+@interface SomeNotInvalidatedInPartial : SomeInvalidationImplementingObject {
+ SomeInvalidationImplementingObject *Ivar1;
+ SomeInvalidationImplementingObject *Ivar2;
+#if RUN_IVAR_INVALIDATION
+ // expected-warning@-2 {{Instance variable Ivar2 needs to be invalidated or set to nil}}
+#endif
+}
+-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial")));
+-(void)partialInvalidatorCallsPartial __attribute__((annotate("objc_instance_variable_invalidator_partial")));
+@end
+@implementation SomeNotInvalidatedInPartial {
+ SomeInvalidationImplementingObject *Ivar3;
+#if RUN_IVAR_INVALIDATION
+ // expected-warning@-2 {{Instance variable Ivar3 needs to be invalidated or set to nil}}
+#endif
+}
+-(void)partialInvalidator {
+ Ivar1 = 0;
+}
+-(void)partialInvalidatorCallsPartial {
+ [self partialInvalidator];
+}
+@end
+
+@interface OnlyPartialDeclsBase : NSObject
+-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial")));
+@end
+@implementation OnlyPartialDeclsBase
+-(void)partialInvalidator {}
+@end
+
+@interface OnlyPartialDecls : OnlyPartialDeclsBase {
+ SomeInvalidationImplementingObject *Ivar1;
+#if RUN_IVAR_INVALIDATION
+ // expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for OnlyPartialDecls}}
+#endif
+}
+@end
+@implementation OnlyPartialDecls
+@end
+
// False negative.
@interface PartialCallsFull : SomeInvalidationImplementingObject {
SomeInvalidationImplementingObject *Ivar1;