vsavchenko created this revision.
Herald added subscribers: steakhal, ASDenysPetrov, martong, Charusso, dkrupp, 
donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, 
xazax.hun.
vsavchenko requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

When reporting leaks, we try to attach the leaking object to some
variable, so it's easier to understand.  Before the patch, we always
tried to use the first variable to store the object in question.
This can get very confusing for the user, if that variable doesn't
contain that object at the moment of the actual leak.  In many cases,
the warning is dismissed as false positive and it is effectively a
false positive when we fail to properly explain the warning to the
user.

This patch addresses the bigest issue in cases like this.  Now we
check if the variable still contains the leaking symbolic object.
If not, we look for the last variable to actually hold it and use
that variable instead.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D100839

Files:
  
clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
  clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
  clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
  clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
  clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist
  clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist
  clang/test/Analysis/osobject-retain-release.cpp
  clang/test/Analysis/retain-release-path-notes.m
  clang/test/Analysis/retain-release.m

Index: clang/test/Analysis/retain-release.m
===================================================================
--- clang/test/Analysis/retain-release.m
+++ clang/test/Analysis/retain-release.m
@@ -2282,7 +2282,7 @@
 
 void testAutoreleaseReturnsInput() {
   extern CFTypeRef CFCreateSomething();
-  CFTypeRef obj = CFCreateSomething(); // expected-warning{{Potential leak of an object stored into 'obj'}}
+  CFTypeRef obj = CFCreateSomething(); // expected-warning{{Potential leak of an object stored into 'second'}}
   CFTypeRef second = CFAutorelease(obj);
   CFRetain(second);
 }
@@ -2302,7 +2302,7 @@
 }
 
 void autoreleaseReturningTypedObject() {
-  CFArrayRef arr = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{Potential leak of an object stored into 'arr'}}
+  CFArrayRef arr = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks); // expected-warning{{Potential leak of an object stored into 'alias'}}
   CFArrayRef alias = (CFArrayRef)CFAutorelease((CFTypeRef)arr);
   CFRetain(alias);
 }
Index: clang/test/Analysis/retain-release-path-notes.m
===================================================================
--- clang/test/Analysis/retain-release-path-notes.m
+++ clang/test/Analysis/retain-release-path-notes.m
@@ -212,7 +212,7 @@
 }
 
 -(id)initY {
-  self = [super init]; //expected-note {{Method returns an instance of MyObj with a +1 retain count}}
+  self = [super init]; // expected-note 4 {{Method returns an instance of MyObj with a +1 retain count}}
   return self;
 }
 
@@ -327,5 +327,54 @@
 
 @end
 
+int seed();
 
+@interface LeakReassignmentTests : MyObj
+@end
+
+@implementation LeakReassignmentTests
++(void)testLeakAliasSimple {
+  id Original = [[MyObj alloc] initY]; // expected-note {{Calling 'initY'}}
+                                       // expected-note@-1 {{Returning from 'initY'}}
+  id New = Original;
+  Original = [[MyObj alloc] initZ];
+  (void)New;
+  [Original release]; // expected-warning {{Potential leak of an object stored into 'New'}}
+                      // expected-note@-1 {{Object leaked: object allocated and stored into 'New' is not referenced later in this execution path and has a retain count of +1}}
+}
+
++(void)testLeakAliasChain {
+  id Original = [[MyObj alloc] initY]; // expected-note {{Calling 'initY'}}
+                                       // expected-note@-1 {{Returning from 'initY'}}
+  id Intermediate = Original;
+  id New = Intermediate;
+  Original = [[MyObj alloc] initZ];
+  (void)New;
+  [Original release]; // expected-warning {{Potential leak of an object stored into 'New'}}
+                      // expected-note@-1 {{Object leaked: object allocated and stored into 'New' is not referenced later in this execution path and has a retain count of +1}}
+}
+
++(void)log:(id)Obj with:(int)Num {
+  Num *= 42;
+  if (Obj )
+    Num /= 2;
+}
+
++(int)calculate {
+  int x = 10;
+  int y = 25;
+  x += y * x + seed();
+  return y - x * y;
+}
 
++(void)testLeakAliasDeathInExpr {
+  id Original = [[MyObj alloc] initY]; // expected-note {{Calling 'initY'}}
+                                       // expected-note@-1 {{Returning from 'initY'}}
+  id New = Original;
+  Original = [[MyObj alloc] initZ];
+  [self log:New with:[self calculate]];
+  [Original release]; // expected-warning {{Potential leak of an object stored into 'New'}}
+                      // expected-note@-1 {{Object leaked: object allocated and stored into 'New' is not referenced later in this execution path and has a retain count of +1}}
+}
+
+@end
Index: clang/test/Analysis/osobject-retain-release.cpp
===================================================================
--- clang/test/Analysis/osobject-retain-release.cpp
+++ clang/test/Analysis/osobject-retain-release.cpp
@@ -641,7 +641,7 @@
   OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
   {
     OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}
-   // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}
+                        // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}
     // expected-note@os_smart_ptr.h:13{{Field 'pointer' is non-null}}
     // expected-note@os_smart_ptr.h:13{{Taking true branch}}
     // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
@@ -653,9 +653,9 @@
   // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
   // expected-note@os_smart_ptr.h:76{{Reference count decremented. The object now has a +1 retain count}}
   // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
- // expected-note@-6{{Returning from '~smart_ptr'}}
-} // expected-warning{{Potential leak of an object stored into 'obj'}}
-// expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}
+  // expected-note@-6{{Returning from '~smart_ptr'}}
+} // expected-warning{{Potential leak of an object stored into 'p'}}
+// expected-note@-1{{Object leaked: object allocated and stored into 'p' is not referenced later in this execution path and has a retain count of +1}}
 
 void test_smart_ptr_no_leak() {
   OSObject *obj = new OSObject;
Index: clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist
===================================================================
--- clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist
+++ clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist
@@ -25476,12 +25476,12 @@
      </dict>
      <key>depth</key><integer>0</integer>
      <key>extended_message</key>
-     <string>Object leaked: object allocated and stored into &apos;obj&apos; is not referenced later in this execution path and has a retain count of +1</string>
+     <string>Object leaked: object allocated and stored into &apos;second&apos; is not referenced later in this execution path and has a retain count of +1</string>
      <key>message</key>
-     <string>Object leaked: object allocated and stored into &apos;obj&apos; is not referenced later in this execution path and has a retain count of +1</string>
+     <string>Object leaked: object allocated and stored into &apos;second&apos; is not referenced later in this execution path and has a retain count of +1</string>
     </dict>
    </array>
-   <key>description</key><string>Potential leak of an object stored into &apos;obj&apos;</string>
+   <key>description</key><string>Potential leak of an object stored into &apos;second&apos;</string>
    <key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
    <key>type</key><string>Leak</string>
    <key>check_name</key><string>osx.cocoa.RetainCount</string>
@@ -25734,12 +25734,12 @@
      </dict>
      <key>depth</key><integer>0</integer>
      <key>extended_message</key>
-     <string>Object leaked: object allocated and stored into &apos;arr&apos; is not referenced later in this execution path and has a retain count of +1</string>
+     <string>Object leaked: object allocated and stored into &apos;alias&apos; is not referenced later in this execution path and has a retain count of +1</string>
      <key>message</key>
-     <string>Object leaked: object allocated and stored into &apos;arr&apos; is not referenced later in this execution path and has a retain count of +1</string>
+     <string>Object leaked: object allocated and stored into &apos;alias&apos; is not referenced later in this execution path and has a retain count of +1</string>
     </dict>
    </array>
-   <key>description</key><string>Potential leak of an object stored into &apos;arr&apos;</string>
+   <key>description</key><string>Potential leak of an object stored into &apos;alias&apos;</string>
    <key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
    <key>type</key><string>Leak</string>
    <key>check_name</key><string>osx.cocoa.RetainCount</string>
Index: clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist
===================================================================
--- clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist
+++ clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist
@@ -25407,12 +25407,12 @@
      </dict>
      <key>depth</key><integer>0</integer>
      <key>extended_message</key>
-     <string>Object leaked: object allocated and stored into &apos;obj&apos; is not referenced later in this execution path and has a retain count of +1</string>
+     <string>Object leaked: object allocated and stored into &apos;second&apos; is not referenced later in this execution path and has a retain count of +1</string>
      <key>message</key>
-     <string>Object leaked: object allocated and stored into &apos;obj&apos; is not referenced later in this execution path and has a retain count of +1</string>
+     <string>Object leaked: object allocated and stored into &apos;second&apos; is not referenced later in this execution path and has a retain count of +1</string>
     </dict>
    </array>
-   <key>description</key><string>Potential leak of an object stored into &apos;obj&apos;</string>
+   <key>description</key><string>Potential leak of an object stored into &apos;second&apos;</string>
    <key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
    <key>type</key><string>Leak</string>
    <key>check_name</key><string>osx.cocoa.RetainCount</string>
@@ -25665,12 +25665,12 @@
      </dict>
      <key>depth</key><integer>0</integer>
      <key>extended_message</key>
-     <string>Object leaked: object allocated and stored into &apos;arr&apos; is not referenced later in this execution path and has a retain count of +1</string>
+     <string>Object leaked: object allocated and stored into &apos;alias&apos; is not referenced later in this execution path and has a retain count of +1</string>
      <key>message</key>
-     <string>Object leaked: object allocated and stored into &apos;arr&apos; is not referenced later in this execution path and has a retain count of +1</string>
+     <string>Object leaked: object allocated and stored into &apos;alias&apos; is not referenced later in this execution path and has a retain count of +1</string>
     </dict>
    </array>
-   <key>description</key><string>Potential leak of an object stored into &apos;arr&apos;</string>
+   <key>description</key><string>Potential leak of an object stored into &apos;alias&apos;</string>
    <key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
    <key>type</key><string>Leak</string>
    <key>check_name</key><string>osx.cocoa.RetainCount</string>
Index: clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
===================================================================
--- clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
+++ clang/test/Analysis/Inputs/expected-plists/retain-release-path-notes.m.plist
@@ -5012,6 +5012,1030 @@
    </array>
   </dict>
   </dict>
+  <dict>
+   <key>path</key>
+   <array>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>337</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>337</integer>
+           <key>col</key><integer>4</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>337</integer>
+           <key>col</key><integer>17</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>337</integer>
+           <key>col</key><integer>17</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>337</integer>
+      <key>col</key><integer>17</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>337</integer>
+         <key>col</key><integer>17</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>337</integer>
+         <key>col</key><integer>37</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Calling &apos;initY&apos;</string>
+     <key>message</key>
+     <string>Calling &apos;initY&apos;</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>214</integer>
+      <key>col</key><integer>1</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>depth</key><integer>1</integer>
+     <key>extended_message</key>
+     <string>Entered call from &apos;testLeakAliasSimple&apos;</string>
+     <key>message</key>
+     <string>Entered call from &apos;testLeakAliasSimple&apos;</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>214</integer>
+           <key>col</key><integer>1</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>214</integer>
+           <key>col</key><integer>1</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>215</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>215</integer>
+           <key>col</key><integer>6</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>215</integer>
+      <key>col</key><integer>10</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>215</integer>
+         <key>col</key><integer>10</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>215</integer>
+         <key>col</key><integer>21</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>1</integer>
+     <key>extended_message</key>
+     <string>Method returns an instance of MyObj with a +1 retain count</string>
+     <key>message</key>
+     <string>Method returns an instance of MyObj with a +1 retain count</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>215</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>215</integer>
+           <key>col</key><integer>6</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>216</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>216</integer>
+           <key>col</key><integer>8</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>337</integer>
+      <key>col</key><integer>17</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>337</integer>
+         <key>col</key><integer>17</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>337</integer>
+         <key>col</key><integer>37</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Returning from &apos;initY&apos;</string>
+     <key>message</key>
+     <string>Returning from &apos;initY&apos;</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>337</integer>
+           <key>col</key><integer>17</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>337</integer>
+           <key>col</key><integer>17</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>337</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>337</integer>
+           <key>col</key><integer>4</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>337</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>337</integer>
+           <key>col</key><integer>4</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>342</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>342</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>342</integer>
+      <key>col</key><integer>3</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>342</integer>
+         <key>col</key><integer>3</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>342</integer>
+         <key>col</key><integer>20</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Object leaked: object allocated and stored into &apos;New&apos; is not referenced later in this execution path and has a retain count of +1</string>
+     <key>message</key>
+     <string>Object leaked: object allocated and stored into &apos;New&apos; is not referenced later in this execution path and has a retain count of +1</string>
+    </dict>
+   </array>
+   <key>description</key><string>Potential leak of an object stored into &apos;New&apos;</string>
+   <key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
+   <key>type</key><string>Leak</string>
+   <key>check_name</key><string>osx.cocoa.RetainCount</string>
+   <!-- This hash is experimental and going to change! -->
+   <key>issue_hash_content_of_line_in_context</key><string>c6578d694dd90a2f586f52c9b53042c3</string>
+  <key>issue_context_kind</key><string>Objective-C method</string>
+  <key>issue_context</key><string>testLeakAliasSimple</string>
+  <key>issue_hash_function_offset</key><string>1</string>
+  <key>location</key>
+  <dict>
+   <key>line</key><integer>342</integer>
+   <key>col</key><integer>3</integer>
+   <key>file</key><integer>0</integer>
+  </dict>
+  <key>ExecutedLines</key>
+  <dict>
+   <key>0</key>
+   <array>
+    <integer>214</integer>
+    <integer>215</integer>
+    <integer>216</integer>
+    <integer>219</integer>
+    <integer>220</integer>
+    <integer>221</integer>
+    <integer>336</integer>
+    <integer>337</integer>
+    <integer>339</integer>
+    <integer>340</integer>
+    <integer>341</integer>
+    <integer>342</integer>
+   </array>
+  </dict>
+  </dict>
+  <dict>
+   <key>path</key>
+   <array>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>347</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>347</integer>
+           <key>col</key><integer>4</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>347</integer>
+           <key>col</key><integer>17</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>347</integer>
+           <key>col</key><integer>17</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>347</integer>
+      <key>col</key><integer>17</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>347</integer>
+         <key>col</key><integer>17</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>347</integer>
+         <key>col</key><integer>37</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Calling &apos;initY&apos;</string>
+     <key>message</key>
+     <string>Calling &apos;initY&apos;</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>214</integer>
+      <key>col</key><integer>1</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>depth</key><integer>1</integer>
+     <key>extended_message</key>
+     <string>Entered call from &apos;testLeakAliasChain&apos;</string>
+     <key>message</key>
+     <string>Entered call from &apos;testLeakAliasChain&apos;</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>214</integer>
+           <key>col</key><integer>1</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>214</integer>
+           <key>col</key><integer>1</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>215</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>215</integer>
+           <key>col</key><integer>6</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>215</integer>
+      <key>col</key><integer>10</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>215</integer>
+         <key>col</key><integer>10</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>215</integer>
+         <key>col</key><integer>21</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>1</integer>
+     <key>extended_message</key>
+     <string>Method returns an instance of MyObj with a +1 retain count</string>
+     <key>message</key>
+     <string>Method returns an instance of MyObj with a +1 retain count</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>215</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>215</integer>
+           <key>col</key><integer>6</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>216</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>216</integer>
+           <key>col</key><integer>8</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>347</integer>
+      <key>col</key><integer>17</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>347</integer>
+         <key>col</key><integer>17</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>347</integer>
+         <key>col</key><integer>37</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Returning from &apos;initY&apos;</string>
+     <key>message</key>
+     <string>Returning from &apos;initY&apos;</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>347</integer>
+           <key>col</key><integer>17</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>347</integer>
+           <key>col</key><integer>17</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>347</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>347</integer>
+           <key>col</key><integer>4</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>347</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>347</integer>
+           <key>col</key><integer>4</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>353</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>353</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>353</integer>
+      <key>col</key><integer>3</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>353</integer>
+         <key>col</key><integer>3</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>353</integer>
+         <key>col</key><integer>20</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Object leaked: object allocated and stored into &apos;New&apos; is not referenced later in this execution path and has a retain count of +1</string>
+     <key>message</key>
+     <string>Object leaked: object allocated and stored into &apos;New&apos; is not referenced later in this execution path and has a retain count of +1</string>
+    </dict>
+   </array>
+   <key>description</key><string>Potential leak of an object stored into &apos;New&apos;</string>
+   <key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
+   <key>type</key><string>Leak</string>
+   <key>check_name</key><string>osx.cocoa.RetainCount</string>
+   <!-- This hash is experimental and going to change! -->
+   <key>issue_hash_content_of_line_in_context</key><string>076457f7cf482449386f129554f48f68</string>
+  <key>issue_context_kind</key><string>Objective-C method</string>
+  <key>issue_context</key><string>testLeakAliasChain</string>
+  <key>issue_hash_function_offset</key><string>1</string>
+  <key>location</key>
+  <dict>
+   <key>line</key><integer>353</integer>
+   <key>col</key><integer>3</integer>
+   <key>file</key><integer>0</integer>
+  </dict>
+  <key>ExecutedLines</key>
+  <dict>
+   <key>0</key>
+   <array>
+    <integer>214</integer>
+    <integer>215</integer>
+    <integer>216</integer>
+    <integer>219</integer>
+    <integer>220</integer>
+    <integer>221</integer>
+    <integer>346</integer>
+    <integer>347</integer>
+    <integer>349</integer>
+    <integer>350</integer>
+    <integer>351</integer>
+    <integer>352</integer>
+    <integer>353</integer>
+   </array>
+  </dict>
+  </dict>
+  <dict>
+   <key>path</key>
+   <array>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>371</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>371</integer>
+           <key>col</key><integer>4</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>371</integer>
+           <key>col</key><integer>17</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>371</integer>
+           <key>col</key><integer>17</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>371</integer>
+      <key>col</key><integer>17</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>371</integer>
+         <key>col</key><integer>17</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>371</integer>
+         <key>col</key><integer>37</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Calling &apos;initY&apos;</string>
+     <key>message</key>
+     <string>Calling &apos;initY&apos;</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>214</integer>
+      <key>col</key><integer>1</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>depth</key><integer>1</integer>
+     <key>extended_message</key>
+     <string>Entered call from &apos;testLeakAliasDeathInExpr&apos;</string>
+     <key>message</key>
+     <string>Entered call from &apos;testLeakAliasDeathInExpr&apos;</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>214</integer>
+           <key>col</key><integer>1</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>214</integer>
+           <key>col</key><integer>1</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>215</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>215</integer>
+           <key>col</key><integer>6</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>215</integer>
+      <key>col</key><integer>10</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>215</integer>
+         <key>col</key><integer>10</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>215</integer>
+         <key>col</key><integer>21</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>1</integer>
+     <key>extended_message</key>
+     <string>Method returns an instance of MyObj with a +1 retain count</string>
+     <key>message</key>
+     <string>Method returns an instance of MyObj with a +1 retain count</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>215</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>215</integer>
+           <key>col</key><integer>6</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>216</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>216</integer>
+           <key>col</key><integer>8</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>371</integer>
+      <key>col</key><integer>17</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>371</integer>
+         <key>col</key><integer>17</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>371</integer>
+         <key>col</key><integer>37</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Returning from &apos;initY&apos;</string>
+     <key>message</key>
+     <string>Returning from &apos;initY&apos;</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>371</integer>
+           <key>col</key><integer>17</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>371</integer>
+           <key>col</key><integer>17</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>371</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>371</integer>
+           <key>col</key><integer>4</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>371</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>371</integer>
+           <key>col</key><integer>4</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>376</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>376</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>376</integer>
+      <key>col</key><integer>3</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>376</integer>
+         <key>col</key><integer>3</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>376</integer>
+         <key>col</key><integer>20</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Object leaked: object allocated and stored into &apos;New&apos; is not referenced later in this execution path and has a retain count of +1</string>
+     <key>message</key>
+     <string>Object leaked: object allocated and stored into &apos;New&apos; is not referenced later in this execution path and has a retain count of +1</string>
+    </dict>
+   </array>
+   <key>description</key><string>Potential leak of an object stored into &apos;New&apos;</string>
+   <key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
+   <key>type</key><string>Leak</string>
+   <key>check_name</key><string>osx.cocoa.RetainCount</string>
+   <!-- This hash is experimental and going to change! -->
+   <key>issue_hash_content_of_line_in_context</key><string>1ead75ff85eb09fa93374d0083f531e5</string>
+  <key>issue_context_kind</key><string>Objective-C method</string>
+  <key>issue_context</key><string>testLeakAliasDeathInExpr</string>
+  <key>issue_hash_function_offset</key><string>1</string>
+  <key>location</key>
+  <dict>
+   <key>line</key><integer>376</integer>
+   <key>col</key><integer>3</integer>
+   <key>file</key><integer>0</integer>
+  </dict>
+  <key>ExecutedLines</key>
+  <dict>
+   <key>0</key>
+   <array>
+    <integer>214</integer>
+    <integer>215</integer>
+    <integer>216</integer>
+    <integer>219</integer>
+    <integer>220</integer>
+    <integer>221</integer>
+    <integer>357</integer>
+    <integer>358</integer>
+    <integer>359</integer>
+    <integer>360</integer>
+    <integer>363</integer>
+    <integer>364</integer>
+    <integer>365</integer>
+    <integer>366</integer>
+    <integer>367</integer>
+    <integer>370</integer>
+    <integer>371</integer>
+    <integer>373</integer>
+    <integer>374</integer>
+    <integer>375</integer>
+    <integer>376</integer>
+   </array>
+  </dict>
+  </dict>
  </array>
  <key>files</key>
  <array>
Index: clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
===================================================================
--- clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
+++ clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
@@ -21946,12 +21946,12 @@
      </dict>
      <key>depth</key><integer>0</integer>
      <key>extended_message</key>
-     <string>Object leaked: object allocated and stored into &apos;foo&apos; is not referenced later in this execution path and has a retain count of +1</string>
+     <string>Object leaked: object allocated and stored into &apos;garply&apos; is not referenced later in this execution path and has a retain count of +1</string>
      <key>message</key>
-     <string>Object leaked: object allocated and stored into &apos;foo&apos; is not referenced later in this execution path and has a retain count of +1</string>
+     <string>Object leaked: object allocated and stored into &apos;garply&apos; is not referenced later in this execution path and has a retain count of +1</string>
     </dict>
    </array>
-   <key>description</key><string>Potential leak of an object stored into &apos;foo&apos;</string>
+   <key>description</key><string>Potential leak of an object stored into &apos;garply&apos;</string>
    <key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
    <key>type</key><string>Leak</string>
    <key>check_name</key><string>osx.cocoa.RetainCount</string>
Index: clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
+++ clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
@@ -68,17 +68,20 @@
 };
 
 class RefLeakReport : public RefCountReport {
-  const MemRegion* AllocBinding;
-  const Stmt *AllocStmt;
+  const MemRegion *AllocFirstBinding = nullptr;
+  const MemRegion *AllocBindingToReport = nullptr;
+  const Stmt *AllocStmt = nullptr;
   PathDiagnosticLocation Location;
 
   // Finds the function declaration where a leak warning for the parameter
   // 'sym' should be raised.
-  void deriveParamLocation(CheckerContext &Ctx, SymbolRef sym);
-  // Finds the location where a leak warning for 'sym' should be raised.
-  void deriveAllocLocation(CheckerContext &Ctx, SymbolRef sym);
+  void deriveParamLocation(CheckerContext &Ctx);
+  // Finds the location where the leaking object is allocated.
+  void deriveAllocLocation(CheckerContext &Ctx);
   // Produces description of a leak warning which is printed on the console.
   void createDescription(CheckerContext &Ctx);
+  // Finds the binding that we should use in a leak warning.
+  void findBindingToReport(CheckerContext &Ctx, ExplodedNode *Node);
 
 public:
   RefLeakReport(const RefCountBug &D, const LangOptions &LOpts, ExplodedNode *n,
Index: clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -13,6 +13,8 @@
 
 #include "RetainCountDiagnostics.h"
 #include "RetainCountChecker.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
 
 using namespace clang;
 using namespace ento;
@@ -337,15 +339,15 @@
 
 class RefLeakReportVisitor : public RefCountReportVisitor {
 public:
-  RefLeakReportVisitor(SymbolRef Sym, const MemRegion *FirstBinding)
-      : RefCountReportVisitor(Sym), FirstBinding(FirstBinding) {}
+  RefLeakReportVisitor(SymbolRef Sym, const MemRegion *LastBinding)
+      : RefCountReportVisitor(Sym), LastBinding(LastBinding) {}
 
   PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
                                     const ExplodedNode *N,
                                     PathSensitiveBugReport &BR) override;
 
 private:
-  const MemRegion *FirstBinding;
+  const MemRegion *LastBinding;
 };
 
 } // end namespace retaincountchecker
@@ -614,6 +616,41 @@
   return None;
 }
 
+using Bindings = llvm::SmallVector<const MemRegion *, 4>;
+
+class VarBindingsCollector : public StoreManager::BindingsHandler {
+  SymbolRef Sym;
+  Bindings &Result;
+
+public:
+  VarBindingsCollector(SymbolRef Sym, Bindings &ToFill)
+      : Sym(Sym), Result(ToFill) {}
+
+  bool HandleBinding(StoreManager &SMgr, Store Store, const MemRegion *R,
+                     SVal Val) override {
+    SymbolRef SymV = Val.getAsLocSymbol();
+    if (!SymV || SymV != Sym)
+      return true;
+
+    if (isa<NonParamVarRegion>(R))
+      Result.push_back(R);
+
+    return true;
+  }
+};
+
+Bindings getAllVarBindingsForSymbol(ProgramStateManager &Manager,
+                                    const ExplodedNode *Node, SymbolRef Sym) {
+  Bindings Result;
+  VarBindingsCollector Collector{Sym, Result};
+  while (Result.empty() && Node) {
+    Manager.iterBindings(Node->getState(), Collector);
+    Node = Node->getFirstPred();
+  }
+
+  return Result;
+}
+
 namespace {
 // Find the first node in the current function context that referred to the
 // tracked symbol and the memory location that value was stored to. Note, the
@@ -740,7 +777,7 @@
 
   os << "Object leaked: ";
 
-  Optional<std::string> RegionDescription = describeRegion(FirstBinding);
+  Optional<std::string> RegionDescription = describeRegion(LastBinding);
   if (RegionDescription) {
     os << "object allocated and stored into '" << *RegionDescription << '\'';
   } else {
@@ -749,7 +786,7 @@
   }
 
   // Get the retain count.
-  const RefVal* RV = getRefBinding(EndN->getState(), Sym);
+  const RefVal *RV = getRefBinding(EndN->getState(), Sym);
   assert(RV);
 
   if (RV->getKind() == RefVal::ErrorLeakReturned) {
@@ -790,14 +827,15 @@
                 " Foundation";
         } else if (RV->getObjKind() == ObjKind::OS) {
           std::string FuncName = FD->getNameAsString();
-          os << "whose name ('" << FuncName
-            << "') starts with '" << StringRef(FuncName).substr(0, 3) << "'";
+          os << "whose name ('" << FuncName << "') starts with '"
+             << StringRef(FuncName).substr(0, 3) << "'";
         }
       }
     }
   } else {
     os << " is not referenced later in this execution path and has a retain "
-          "count of +" << RV->getCount();
+          "count of +"
+       << RV->getCount();
   }
 
   return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
@@ -819,16 +857,16 @@
   addVisitor(std::make_unique<RefCountReportVisitor>(sym));
 }
 
-void RefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) {
-  const SourceManager& SMgr = Ctx.getSourceManager();
+void RefLeakReport::deriveParamLocation(CheckerContext &Ctx) {
+  const SourceManager &SMgr = Ctx.getSourceManager();
 
-  if (!sym->getOriginRegion())
+  if (!Sym->getOriginRegion())
     return;
 
-  auto *Region = dyn_cast<DeclRegion>(sym->getOriginRegion());
+  auto *Region = dyn_cast<DeclRegion>(Sym->getOriginRegion());
   if (Region) {
     const Decl *PDecl = Region->getDecl();
-    if (PDecl && isa<ParmVarDecl>(PDecl)) {
+    if (isa_and_nonnull<ParmVarDecl>(PDecl)) {
       PathDiagnosticLocation ParamLocation =
           PathDiagnosticLocation::create(PDecl, SMgr);
       Location = ParamLocation;
@@ -838,8 +876,7 @@
   }
 }
 
-void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx,
-                                          SymbolRef sym) {
+void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx) {
   // Most bug reports are cached at the location where they occurred.
   // With leaks, we want to unique them by the location where they were
   // allocated, and only report a single path.  To do this, we need to find
@@ -850,13 +887,13 @@
   // same SourceLocation.
   const ExplodedNode *AllocNode = nullptr;
 
-  const SourceManager& SMgr = Ctx.getSourceManager();
+  const SourceManager &SMgr = Ctx.getSourceManager();
 
   AllocationInfo AllocI =
-      GetAllocationSite(Ctx.getStateManager(), getErrorNode(), sym);
+      GetAllocationSite(Ctx.getStateManager(), getErrorNode(), Sym);
 
   AllocNode = AllocI.N;
-  AllocBinding = AllocI.R;
+  AllocFirstBinding = AllocI.R;
   markInteresting(AllocI.InterestingMethodContext);
 
   // Get the SourceLocation for the allocation site.
@@ -866,13 +903,12 @@
   AllocStmt = AllocNode->getStmtForDiagnostics();
 
   if (!AllocStmt) {
-    AllocBinding = nullptr;
+    AllocFirstBinding = nullptr;
     return;
   }
 
-  PathDiagnosticLocation AllocLocation =
-    PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
-                                        AllocNode->getLocationContext());
+  PathDiagnosticLocation AllocLocation = PathDiagnosticLocation::createBegin(
+      AllocStmt, SMgr, AllocNode->getLocationContext());
   Location = AllocLocation;
 
   // Set uniqieing info, which will be used for unique the bug reports. The
@@ -887,7 +923,8 @@
   llvm::raw_string_ostream os(Description);
   os << "Potential leak of an object";
 
-  Optional<std::string> RegionDescription = describeRegion(AllocBinding);
+  Optional<std::string> RegionDescription =
+      describeRegion(AllocBindingToReport);
   if (RegionDescription) {
     os << " stored into '" << *RegionDescription << '\'';
   } else {
@@ -897,16 +934,56 @@
   }
 }
 
+void RefLeakReport::findBindingToReport(CheckerContext &Ctx,
+                                        ExplodedNode *Node) {
+  if (!AllocFirstBinding)
+    // If we don't have any bindings, we won't be able to find any
+    // better binding to report.
+    return;
+
+  // If the original region still contains the leaking symbol...
+  if (Node->getState()->getSVal(AllocFirstBinding).getAsSymbol() == Sym) {
+    // ...it is the best binding to report.
+    AllocBindingToReport = AllocFirstBinding;
+    return;
+  }
+
+  // At this point, we know that the original region doesn't contain the leaking
+  // when the actual leak happens.  It means that it can be confusing for the
+  // user to see such description in the message.
+  //
+  // Let's consider the following example:
+  //   Object *Original = allocate(...);
+  //   Object *New = Original;
+  //   Original = allocate(...);
+  //   Original->release();
+  //
+  // Complaining about a leaking object "stored into Original" might cause a
+  // rightful confusion because 'Original' is actually released.
+  // We should complain about 'New' instead.
+  Bindings AllVarBindings =
+      getAllVarBindingsForSymbol(Ctx.getStateManager(), Node, Sym);
+
+  if (!AllVarBindings.empty() &&
+      llvm::count(AllVarBindings, AllocFirstBinding) == 0)
+    // Let's pick one of them at random (if there is something to pick from).
+    AllocBindingToReport = AllVarBindings[0];
+  else
+    AllocBindingToReport = AllocFirstBinding;
+}
+
 RefLeakReport::RefLeakReport(const RefCountBug &D, const LangOptions &LOpts,
                              ExplodedNode *N, SymbolRef Sym,
                              CheckerContext &Ctx)
     : RefCountReport(D, LOpts, N, Sym, /*isLeak=*/true) {
 
-  deriveAllocLocation(Ctx, Sym);
-  if (!AllocBinding)
-    deriveParamLocation(Ctx, Sym);
+  deriveAllocLocation(Ctx);
+  findBindingToReport(Ctx, N);
+
+  if (!AllocFirstBinding)
+    deriveParamLocation(Ctx);
 
   createDescription(Ctx);
 
-  addVisitor(std::make_unique<RefLeakReportVisitor>(Sym, AllocBinding));
+  addVisitor(std::make_unique<RefLeakReportVisitor>(Sym, AllocBindingToReport));
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to