Add option to include multiple lines in snippets.

When a diagnostic includes a highlighted range spanning multiple lines, clang
now supports printing out multiple lines of context if necessary to show the
highlighted ranges. This is not yet exposed in the driver, but can be enabled
by "-Xclang -fcaret-diagnostics-max-lines -Xclang N".

This is experimental until we can find out whether it works well in practice,
and if so, what a good default for the maximum number of lines is.

llvm-svn: 303589
diff --git a/clang/test/Misc/caret-diags-multiline.cpp b/clang/test/Misc/caret-diags-multiline.cpp
new file mode 100644
index 0000000..4826d9b
--- /dev/null
+++ b/clang/test/Misc/caret-diags-multiline.cpp
@@ -0,0 +1,234 @@
+// RUN: not %clang_cc1 -std=c++11 -fcaret-diagnostics-max-lines 5 -Wsometimes-uninitialized %s 2>&1 | FileCheck %s --strict-whitespace
+
+void line(int);
+
+// Check we expand the range as much as possible within the limit.
+
+// CHECK:      warning: variable 'a' is used uninitialized whenever 'if' condition is true
+// CHECK-NEXT: {{^}}  if (cond) {
+// CHECK-NEXT: {{^}}      ^~~~{{$}}
+// CHECK-NEXT: note: uninitialized use occurs here
+// CHECK-NEXT: {{^}}  return a;
+// CHECK-NEXT: {{^}}         ^
+// CHECK-NEXT: note: remove the 'if' if its condition is always false
+// CHECK-NEXT: {{^}}  if (cond) {
+// CHECK-NEXT: {{^}}  ^~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(1);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}  } else {
+// CHECK-NEXT: {{^}}~~~~~~~~~{{$}}
+// CHECK-NEXT: note: initialize the variable
+int f1(int cond) {
+  int a;
+  if (cond) {
+    line(1);
+  } else {
+    a = 3;
+  }
+  return a;
+}
+
+// CHECK:      warning: variable 'a' is used uninitialized whenever 'if' condition is true
+// CHECK-NEXT: {{^}}  if (cond) {
+// CHECK-NEXT: {{^}}      ^~~~{{$}}
+// CHECK-NEXT: note: uninitialized use occurs here
+// CHECK-NEXT: {{^}}  return a;
+// CHECK-NEXT: {{^}}         ^
+// CHECK-NEXT: note: remove the 'if' if its condition is always false
+// CHECK-NEXT: {{^}}  if (cond) {
+// CHECK-NEXT: {{^}}  ^~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(1);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(2);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}  } else {
+// CHECK-NEXT: {{^}}~~~~~~~~~{{$}}
+// CHECK-NEXT: note: initialize the variable
+int f2(int cond) {
+  int a;
+  if (cond) {
+    line(1);
+    line(2);
+  } else {
+    a = 3;
+  }
+  return a;
+}
+
+// CHECK:      warning: variable 'a' is used uninitialized whenever 'if' condition is true
+// CHECK-NEXT: {{^}}  if (cond) {
+// CHECK-NEXT: {{^}}      ^~~~{{$}}
+// CHECK-NEXT: note: uninitialized use occurs here
+// CHECK-NEXT: {{^}}  return a;
+// CHECK-NEXT: {{^}}         ^
+// CHECK-NEXT: note: remove the 'if' if its condition is always false
+// CHECK-NEXT: {{^}}  if (cond) {
+// CHECK-NEXT: {{^}}  ^~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(1);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(2);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(3);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}  } else {
+// CHECK-NEXT: {{^}}~~~~~~~~~{{$}}
+// CHECK-NEXT: note: initialize the variable
+int f3(int cond) {
+  int a;
+  if (cond) {
+    line(1);
+    line(2);
+    line(3);
+  } else {
+    a = 3;
+  }
+  return a;
+}
+
+// CHECK:      warning: variable 'a' is used uninitialized whenever 'if' condition is true
+// CHECK-NEXT: {{^}}  if (cond) {
+// CHECK-NEXT: {{^}}      ^~~~{{$}}
+// CHECK-NEXT: note: uninitialized use occurs here
+// CHECK-NEXT: {{^}}  return a;
+// CHECK-NEXT: {{^}}         ^
+// CHECK-NEXT: note: remove the 'if' if its condition is always false
+// CHECK-NEXT: {{^}}  if (cond) {
+// CHECK-NEXT: {{^}}  ^~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(1);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(2);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(3);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(4);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: note: initialize the variable
+int f4(int cond) {
+  int a;
+  if (cond) {
+    line(1);
+    line(2);
+    line(3);
+    line(4);
+  } else {
+    a = 3;
+  }
+  return a;
+}
+
+// CHECK:      warning: variable 'a' is used uninitialized whenever 'if' condition is true
+// CHECK-NEXT: {{^}}  if (cond) {
+// CHECK-NEXT: {{^}}      ^~~~{{$}}
+// CHECK-NEXT: note: uninitialized use occurs here
+// CHECK-NEXT: {{^}}  return a;
+// CHECK-NEXT: {{^}}         ^
+// CHECK-NEXT: note: remove the 'if' if its condition is always false
+// CHECK-NEXT: {{^}}  if (cond) {
+// CHECK-NEXT: {{^}}  ^~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(1);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(2);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(3);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: {{^}}    line(4);
+// CHECK-NEXT: {{^}}~~~~~~~~~~~~{{$}}
+// CHECK-NEXT: note: initialize the variable
+int f5(int cond) {
+  int a;
+  if (cond) {
+    line(1);
+    line(2);
+    line(3);
+    line(4);
+    line(5);
+  } else {
+    a = 3;
+  }
+  return a;
+}
+
+
+// Check that we don't include lines with no interesting code if we can't reach
+// the interesting part within the line limit.
+
+// CHECK:      error: no matching function for call to 'g
+
+// CHECK:      note: candidate template ignored: substitution failure
+// CHECK-NEXT: {{^}}decltype(T()
+// CHECK-NEXT: {{^}}         ~{{$}}
+// CHECK-NEXT: {{^}}    + 1
+// CHECK-NEXT: {{^}}    + 2
+// CHECK-NEXT: {{^}}    + 3
+// CHECK-NEXT: {{^}}void g();
+// CHECK-NEXT: {{^}}     ^{{$}}
+template<typename T>
+decltype(T()
+    + 1
+    + 2
+    + 3)
+void g();
+
+// CHECK:      note: candidate template ignored: substitution failure
+// CHECK-NEXT: {{^}}void g();
+// CHECK-NEXT: {{^}}     ^{{$}}
+template<typename T>
+decltype(T()
+    + 1
+    + 2
+    + 3
+    + 4)
+void g();
+
+void h() { g<int()>(); }
+
+
+void multiple_ranges(int a, int b) {
+  // CHECK:      error: invalid operands
+  // CHECK-NEXT: &(a)
+  // CHECK-NEXT: ~~~~
+  // CHECK-NEXT: +
+  // CHECK-NEXT: ^
+  // CHECK-NEXT: &(b)
+  // CHECK-NEXT: ~~~~
+  &(a)
+  +
+  &(b);
+
+  // CHECK-NEXT: error: invalid operands
+  // CHECK-NEXT: &(
+  // CHECK-NEXT: ~~
+  // CHECK-NEXT: a
+  // CHECK-NEXT: ~
+  // CHECK-NEXT: )
+  // CHECK-NEXT: ~
+  // CHECK-NEXT: +
+  // CHECK-NEXT: ^
+  // CHECK-NEXT: &(
+  // CHECK-NEXT: ~~
+  &(
+  a
+  )
+  +
+  &(
+  b
+  );
+
+  // CHECK-NEXT: error: invalid operands
+  // CHECK-NEXT: &(a
+  // CHECK-NEXT: ~~
+  // CHECK-NEXT: )
+  // CHECK-NEXT: ~
+  // CHECK-NEXT: +
+  // CHECK-NEXT: ^
+  // CHECK-NEXT: &(
+  // CHECK-NEXT: ~~
+  // CHECK-NEXT: b
+  // CHECK-NEXT: ~
+  &(a
+  )
+  +
+  &(
+  b
+  );
+}