]> granicus.if.org Git - clang/commitdiff
[analyzer] Fix non-determinizm introduced in r172104.
authorAnna Zaks <ganna@apple.com>
Thu, 10 Jan 2013 22:44:16 +0000 (22:44 +0000)
committerAnna Zaks <ganna@apple.com>
Thu, 10 Jan 2013 22:44:16 +0000 (22:44 +0000)
In some cases, we just pick any ivar that needs invalidation and attach
the warning to it. Picking the first from DenseMap of pointer keys was
triggering non-deterministic output.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172134 91177308-0d34-0410-b5e6-96231b3b80d8

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

index b0454433c143ba51b03c5f1076642e3a3de95158..fd763d46f981aaaa8932a65026f585c34008a368 100644 (file)
@@ -175,7 +175,8 @@ class IvarInvalidationChecker :
 
   /// Check if ivar should be tracked and add to TrackedIvars if positive.
   /// Returns true if ivar should be tracked.
-  static bool trackIvar(const ObjCIvarDecl *Iv, IvarSet &TrackedIvars);
+  static bool trackIvar(const ObjCIvarDecl *Iv, IvarSet &TrackedIvars,
+                        const ObjCIvarDecl **FirstIvarDecl);
 
   /// Given the property declaration, and the list of tracked ivars, finds
   /// the ivar backing the property when possible. Returns '0' when no such
@@ -183,7 +184,8 @@ class IvarInvalidationChecker :
   static const ObjCIvarDecl *findPropertyBackingIvar(
       const ObjCPropertyDecl *Prop,
       const ObjCInterfaceDecl *InterfaceD,
-      IvarSet &TrackedIvars);
+      IvarSet &TrackedIvars,
+      const ObjCIvarDecl **FirstIvarDecl);
 
   /// Print ivar name or the property if the given ivar backs a property.
   static void printIvar(llvm::raw_svector_ostream &os,
@@ -251,7 +253,8 @@ void IvarInvalidationChecker::containsInvalidationMethod(
 }
 
 bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv,
-                                        IvarSet &TrackedIvars) {
+                                        IvarSet &TrackedIvars,
+                                        const ObjCIvarDecl **FirstIvarDecl) {
   QualType IvQTy = Iv->getType();
   const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>();
   if (!IvTy)
@@ -261,7 +264,10 @@ bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv,
   InvalidationInfo Info;
   containsInvalidationMethod(IvInterf, Info);
   if (Info.needsInvalidation()) {
-    TrackedIvars[cast<ObjCIvarDecl>(Iv->getCanonicalDecl())] = Info;
+    const ObjCIvarDecl *I = cast<ObjCIvarDecl>(Iv->getCanonicalDecl());
+    TrackedIvars[I] = Info;
+    if (!*FirstIvarDecl)
+      *FirstIvarDecl = I;
     return true;
   }
   return false;
@@ -270,7 +276,8 @@ bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv,
 const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar(
                         const ObjCPropertyDecl *Prop,
                         const ObjCInterfaceDecl *InterfaceD,
-                        IvarSet &TrackedIvars) {
+                        IvarSet &TrackedIvars,
+                        const ObjCIvarDecl **FirstIvarDecl) {
   const ObjCIvarDecl *IvarD = 0;
 
   // Lookup for the synthesized case.
@@ -282,7 +289,7 @@ const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar(
       return IvarD;
     }
     // If the ivar is synthesized we still want to track it.
-    if (trackIvar(IvarD, TrackedIvars))
+    if (trackIvar(IvarD, TrackedIvars, FirstIvarDecl))
       return IvarD;
   }
 
@@ -330,13 +337,17 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCImplementationDecl *ImplD,
                                           BugReporter &BR) const {
   // Collect all ivars that need cleanup.
   IvarSet Ivars;
+  // Record the first Ivar needing invalidation; used in reporting when only
+  // one ivar is sufficient. Cannot grab the first on the Ivars set to ensure
+  // deterministic output.
+  const ObjCIvarDecl *FirstIvarDecl = 0;
   const ObjCInterfaceDecl *InterfaceD = ImplD->getClassInterface();
 
   // Collect ivars declared in this class, its extensions and its implementation
   ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(InterfaceD);
   for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv;
        Iv= Iv->getNextIvar())
-    trackIvar(Iv, Ivars);
+    trackIvar(Iv, Ivars, &FirstIvarDecl);
 
   // Construct Property/Property Accessor to Ivar maps to assist checking if an
   // ivar which is backing a property has been reset.
@@ -352,7 +363,8 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCImplementationDecl *ImplD,
       I = PropMap.begin(), E = PropMap.end(); I != E; ++I) {
     const ObjCPropertyDecl *PD = I->second;
 
-    const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars);
+    const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars,
+                                                     &FirstIvarDecl);
     if (!ID) {
       continue;
     }
@@ -390,14 +402,14 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCImplementationDecl *ImplD,
     llvm::raw_svector_ostream os(sbuf);
     os << "No invalidation method declared in the @interface for "
        << InterfaceD->getName() << "; ";
-    const ObjCIvarDecl *IvarDecl = Ivars.begin()->first;
-    printIvar(os, IvarDecl, IvarToPopertyMap);
+    assert(FirstIvarDecl);
+    printIvar(os, FirstIvarDecl, IvarToPopertyMap);
     os << "needs to be invalidated";
 
     PathDiagnosticLocation IvarDecLocation =
-        PathDiagnosticLocation::createBegin(IvarDecl, BR.getSourceManager());
+      PathDiagnosticLocation::createBegin(FirstIvarDecl, BR.getSourceManager());
 
-    BR.EmitBasicReport(IvarDecl, "Incomplete invalidation",
+    BR.EmitBasicReport(FirstIvarDecl, "Incomplete invalidation",
                        categories::CoreFoundationObjectiveC, os.str(),
                        IvarDecLocation);
     return;
@@ -455,14 +467,14 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCImplementationDecl *ImplD,
     llvm::raw_svector_ostream os(sbuf);
     os << "No invalidation method defined in the @implementation for "
        << InterfaceD->getName() << "; ";
-    const ObjCIvarDecl *IvarDecl = Ivars.begin()->first;
-    printIvar(os, IvarDecl, IvarToPopertyMap);
+    assert(FirstIvarDecl);
+    printIvar(os, FirstIvarDecl, IvarToPopertyMap);
     os << "needs to be invalidated";
 
     PathDiagnosticLocation IvarDecLocation =
-        PathDiagnosticLocation::createBegin(IvarDecl,
+        PathDiagnosticLocation::createBegin(FirstIvarDecl,
                                             BR.getSourceManager());
-    BR.EmitBasicReport(IvarDecl, "Incomplete invalidation",
+    BR.EmitBasicReport(FirstIvarDecl, "Incomplete invalidation",
                        categories::CoreFoundationObjectiveC, os.str(),
                        IvarDecLocation);
   }
@@ -576,7 +588,7 @@ void IvarInvalidationChecker::MethodCrawler::VisitBinaryOperator(
 }
 
 void IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr(
-    const ObjCMessageExpr *ME) {
+  const ObjCMessageExpr *ME) {
   const ObjCMethodDecl *MD = ME->getMethodDecl();
   const Expr *Receiver = ME->getInstanceReceiver();
 
index 6bb8f8257b65d2a867c18124a1f28f6a63d448b2..8e9cd488a8c430b9bb483d81027bb813433ac87f 100644 (file)
@@ -214,9 +214,9 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1,
 
 @interface MissingInvalidationMethodDecl2 : NSObject {
 @private
-    Foo *_foo1;
+    Foo *_foo1; // expected-warning {{No invalidation method declared in the @interface for MissingInvalidationMethodDecl2; Instance variable _foo1 needs to be invalidated}} 
 }
-@property (strong) Foo *bar1; // expected-warning {{No invalidation method declared in the @interface for MissingInvalidationMethodDecl2; Property bar1 needs to be invalidated}} 
+@property (strong) Foo *bar1; 
 @end
 @implementation MissingInvalidationMethodDecl2
 @end