]> granicus.if.org Git - clang/commitdiff
[analyzer] IvarInvalidation: correctly handle cases where only partial invalidators...
authorAnna Zaks <ganna@apple.com>
Wed, 24 Apr 2013 02:49:16 +0000 (02:49 +0000)
committerAnna Zaks <ganna@apple.com>
Wed, 24 Apr 2013 02:49:16 +0000 (02:49 +0000)
 - 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

lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
test/Analysis/objc_invalidation.m

index 5ed28e955d4e0330f0b58c88ca65125a6ca73444..cc940be7b187f0375b0b06e0897885cc10730d71 100644 (file)
@@ -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(
index a6f5ec3f84c70b4e296cef42b9c72c33e263f324..6919feaccfc75bf6aae7a27f9472b491b63d5c4d 100644 (file)
@@ -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;