[analyzer; new edges] Omit subexpression back-edges that span multiple lines.

A.1 -> A -> B
becomes
A.1 -> B

This only applies if there's an edge from a subexpression to its parent
expression, and that is immediately followed by another edge from the
parent expression to a subsequent expression. Normally this is useful for
bringing the edges back to the left side of the code, but when the
subexpression is on a different line the backedge ends up looking strange,
and may even obscure code. In these cases, it's better to just continue
to the next top-level statement.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183164 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index c19e12c..305450a 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -2092,7 +2092,7 @@
   }
 }
 
-/// Returns the number of bytes in the given SourceRange.
+/// Returns the number of bytes in the given (character-based) SourceRange.
 ///
 /// If the locations in the range are not on the same line, returns None.
 ///
@@ -2413,6 +2413,21 @@
                  !lexicalContains(PM, s1End, s1Start)) {
           removeEdge = true;
         }
+        // Trim edges from a subexpression back to the top level if the
+        // subexpression is on a different line.
+        //
+        // A.1 -> A -> B
+        // becomes
+        // A.1 -> B
+        //
+        // These edges just look ugly and don't usually add anything.
+        else if (s1Start && s2End &&
+                 lexicalContains(PM, s1Start, s1End)) {
+          SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
+                                PieceI->getStartLocation().asLocation());
+          if (!getLengthOnSingleLine(SM, EdgeRange).hasValue())
+            removeEdge = true;
+        }
       }
 
       if (removeEdge) {
diff --git a/test/Analysis/edges-new.mm b/test/Analysis/edges-new.mm
index 3b42d3c..7dcf0a4 100644
--- a/test/Analysis/edges-new.mm
+++ b/test/Analysis/edges-new.mm
@@ -12885,40 +12885,6 @@
 // CHECK-NEXT:         <key>end</key>
 // CHECK-NEXT:          <array>
 // CHECK-NEXT:           <dict>
-// CHECK-NEXT:            <key>line</key><integer>535</integer>
-// CHECK-NEXT:            <key>col</key><integer>3</integer>
-// CHECK-NEXT:            <key>file</key><integer>0</integer>
-// CHECK-NEXT:           </dict>
-// CHECK-NEXT:           <dict>
-// CHECK-NEXT:            <key>line</key><integer>535</integer>
-// CHECK-NEXT:            <key>col</key><integer>4</integer>
-// CHECK-NEXT:            <key>file</key><integer>0</integer>
-// CHECK-NEXT:           </dict>
-// CHECK-NEXT:          </array>
-// CHECK-NEXT:        </dict>
-// CHECK-NEXT:       </array>
-// CHECK-NEXT:     </dict>
-// CHECK-NEXT:     <dict>
-// CHECK-NEXT:      <key>kind</key><string>control</string>
-// CHECK-NEXT:      <key>edges</key>
-// CHECK-NEXT:       <array>
-// CHECK-NEXT:        <dict>
-// CHECK-NEXT:         <key>start</key>
-// CHECK-NEXT:          <array>
-// CHECK-NEXT:           <dict>
-// CHECK-NEXT:            <key>line</key><integer>535</integer>
-// CHECK-NEXT:            <key>col</key><integer>3</integer>
-// CHECK-NEXT:            <key>file</key><integer>0</integer>
-// CHECK-NEXT:           </dict>
-// CHECK-NEXT:           <dict>
-// CHECK-NEXT:            <key>line</key><integer>535</integer>
-// CHECK-NEXT:            <key>col</key><integer>4</integer>
-// CHECK-NEXT:            <key>file</key><integer>0</integer>
-// CHECK-NEXT:           </dict>
-// CHECK-NEXT:          </array>
-// CHECK-NEXT:         <key>end</key>
-// CHECK-NEXT:          <array>
-// CHECK-NEXT:           <dict>
 // CHECK-NEXT:            <key>line</key><integer>537</integer>
 // CHECK-NEXT:            <key>col</key><integer>3</integer>
 // CHECK-NEXT:            <key>file</key><integer>0</integer>