[analyzer] Fix non-determinizm introduced in r172104.

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
diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
index b045443..fd763d4 100644
--- a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -175,7 +175,8 @@
 
   /// 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 @@
   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 @@
 }
 
 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 @@
   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 @@
 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 @@
       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 @@
                                           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 @@
       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 @@
     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 @@
     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::VisitObjCMessageExpr(
-    const ObjCMessageExpr *ME) {
+  const ObjCMessageExpr *ME) {
   const ObjCMethodDecl *MD = ME->getMethodDecl();
   const Expr *Receiver = ME->getInstanceReceiver();
 
diff --git a/test/Analysis/objc_invalidation.m b/test/Analysis/objc_invalidation.m
index 6bb8f82..8e9cd48 100644
--- a/test/Analysis/objc_invalidation.m
+++ b/test/Analysis/objc_invalidation.m
@@ -214,9 +214,9 @@
 
 @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