From 16b96f05360bf7220ac1c1e309b92ebcb516d3f3 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 11 Mar 2016 17:01:43 -0500
Subject: [PATCH 06/10] FIXME: WIP at rich_location to support arbitrary number
 of locations

---
 gcc/diagnostic-show-locus.c                        | 25 +++++--
 gcc/diagnostic.c                                   |  2 +-
 gcc/diagnostic.h                                   |  2 +-
 .../gcc.dg/plugin/diagnostic-test-show-locus-bw.c  | 36 +++++++++
 .../plugin/diagnostic_plugin_test_show_locus.c     | 44 +++++++++++
 libcpp/include/line-map.h                          | 13 ++--
 libcpp/line-map.c                                  | 85 +++++++++++++++++++---
 7 files changed, 180 insertions(+), 27 deletions(-)

diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index f10ade5..55ee6b6 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -297,8 +297,12 @@ colorizer::begin_state (int state)
       break;
 
     default:
-      /* We don't expect more than 3 ranges per diagnostic.  */
-      gcc_unreachable ();
+      /* For ranges beyond 2, alternate between color 1 and color 2.  */
+      {
+	gcc_assert (state > 2);
+	pp_string (m_context->printer,
+		   state % 2 ? m_range1_cs : m_range2_cs);
+      }
       break;
     }
 }
@@ -552,8 +556,8 @@ layout::layout (diagnostic_context * context,
   m_exploc (diagnostic->richloc->get_expanded_location (0)),
   m_colorizer (context, diagnostic),
   m_colorize_source_p (context->colorize_source_p),
-  m_layout_ranges (rich_location::MAX_RANGES),
-  m_line_spans (1 + rich_location::MAX_RANGES),
+  m_layout_ranges (diagnostic->richloc->get_num_locations ()),
+  m_line_spans (1 + diagnostic->richloc->get_num_locations ()),
   m_x_offset (0)
 {
   rich_location *richloc = diagnostic->richloc;
@@ -734,7 +738,7 @@ layout::calculate_line_spans ()
 
   /* Populate tmp_spans with individual spans, for each of
      m_exploc, and for m_layout_ranges.  */
-  auto_vec<line_span> tmp_spans (1 + rich_location::MAX_RANGES);
+  auto_vec<line_span> tmp_spans (1 + m_layout_ranges.length ());
   tmp_spans.safe_push (line_span (m_exploc.line, m_exploc.line));
   for (unsigned int i = 0; i < m_layout_ranges.length (); i++)
     {
@@ -880,8 +884,15 @@ layout::print_annotation_line (int row, const line_bounds lbounds)
 	  /* Within a range.  Draw either the caret or an underline.  */
 	  m_colorizer.set_range (state.range_idx);
 	  if (state.draw_caret_p)
-	    /* Draw the caret.  */
-	    pp_character (m_pp, m_context->caret_chars[state.range_idx]);
+	    {
+	      /* Draw the caret.  */
+	      char caret_char;
+	      if (state.range_idx < rich_location::STATICALLY_ALLOCATED_RANGES)
+		caret_char = m_context->caret_chars[state.range_idx];
+	      else
+		caret_char = '^';
+	      pp_character (m_pp, caret_char);
+	    }
 	  else
 	    pp_character (m_pp, '~');
 	}
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 6a679cb..ae52642 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -144,7 +144,7 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
     context->classify_diagnostic[i] = DK_UNSPECIFIED;
   context->show_caret = false;
   diagnostic_set_caret_max_width (context, pp_line_cutoff (context->printer));
-  for (i = 0; i < rich_location::MAX_RANGES; i++)
+  for (i = 0; i < rich_location::STATICALLY_ALLOCATED_RANGES; i++)
     context->caret_chars[i] = '^';
   context->show_option_requested = false;
   context->abort_on_error = false;
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index ff57357..5cac8ba 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -109,7 +109,7 @@ struct diagnostic_context
   int caret_max_width;
 
   /* Character used for caret diagnostics.  */
-  char caret_chars[rich_location::MAX_RANGES];
+  char caret_chars[rich_location::STATICALLY_ALLOCATED_RANGES];
 
   /* True if we should print the command line option which controls
      each diagnostic, if known.  */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
index 8d44078..1cbd4e5 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
@@ -202,3 +202,39 @@ int test_percent_q_plus_d (void)
    { dg-end-multiline-output "" } */
   return local;
 }
+
+/* Test of many nested locations.  */
+
+void test_many_nested_locations (void)
+{
+  /* { dg-warning "test of 70 locations" }
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+    sed do eiusmod tempor incididunt ut labore et dolore magna
+    aliqua. Ut enim ad minim veniam, quis nostrud exercitation
+    ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
+    aute irure dolor in reprehenderit in voluptate velit esse cillum
+    dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+    cupidatat non proident, sunt in culpa qui officia deserunt
+    mollit anim id est laborum.
+  */
+}
+/* { dg-begin-multiline-output "" }
+   /*
+   ^
+     Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+     ^~~~~ ^~~~~ ^~~~~ ^~~ ^~~~  ^~~~~~~~~~~ ^~~~~~~~~~ ^~~~
+     sed do eiusmod tempor incididunt ut labore et dolore magna
+     ^~~ ^~ ^~~~~~~ ^~~~~~ ^~~~~~~~~~ ^~ ^~~~~~ ^~ ^~~~~~ ^~~~~
+     aliqua. Ut enim ad minim veniam, quis nostrud exercitation
+     ^~~~~~  ^~ ^~~~ ^~ ^~~~~ ^~~~~~  ^~~~ ^~~~~~~ ^~~~~~~~~~~~
+     ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
+     ^~~~~~~ ^~~~~~~ ^~~~ ^~ ^~~~~~~ ^~ ^~ ^~~~~~~ ^~~~~~~~~  ^~~~
+     aute irure dolor in reprehenderit in voluptate velit esse cillum
+     ^~~~ ^~~~~ ^~~~~ ^~ ^~~~~~~~~~~~~ ^~ ^~~~~~~~~ ^~~~~ ^~~~ ^~~~~~
+     dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+     ^~~~~~ ^~ ^~~~~~ ^~~~~ ^~~~~~~~  ^~~~~~~~~ ^~~~ ^~~~~~~~
+     cupidatat non proident, sunt in culpa qui officia deserunt
+     ^~~~~~~~~ ^~~ ^~~~~~~~  ^~~~ ^~ ^~~~~ ^~~ ^~~~~~~ ^~~~~~~~
+     mollit anim id est laborum.
+     ^~~~~~ ^~~~ ^~ ^~~ ^~~~~~~
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
index 95078ce..23302ce 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
@@ -323,6 +323,50 @@ test_show_locus (function *fun)
       warning_at (input_location, 0,
 		  "example of plus in format code for %q+D", local);
     }
+
+  /* Example of many locations.  Underline (separately) every word
+     in a comment.  */
+  if (0 == strcmp (fnname, "test_many_nested_locations"))
+    {
+      const char *file = LOCATION_FILE (fnstart);
+      const int start_line = fnstart_line + 2;
+      const int finish_line = start_line + 7;
+      location_t loc = get_loc (start_line - 1, 2);
+      rich_location richloc (line_table, loc);
+      for (int line = start_line; line <= finish_line; line++)
+	{
+	  int line_size;
+	  const char *content = location_get_source_line (file, line,
+							  &line_size);
+	  gcc_assert (content);
+	  /* Split line up into words.  */
+	  for (int idx = 0; idx < line_size; idx++)
+	    {
+	      if (ISALPHA (content[idx]))
+		{
+		  int start_idx = idx;
+		  while (idx < line_size && ISALPHA (content[idx]))
+		    idx++;
+		  if (idx == line_size || !ISALPHA (content[idx]))
+		    {
+		      location_t start_of_word = get_loc (line, start_idx);
+		      location_t end_of_word = get_loc (line, idx - 1);
+		      location_t word
+			= make_location (start_of_word, start_of_word,
+					 end_of_word);
+		      richloc.add_range (word, true);
+		    }
+		}
+	    }
+	}
+      /* Verify that we added enough locations to fully exercise
+	 rich_location.  We want to exceed both the
+	 statically-allocated buffer in class rich_location,
+	 and then trigger a reallocation of the dynamic buffer.  */
+      gcc_assert (richloc.get_num_locations () > 3 + (2 * 16));
+      warning_at_rich_loc (&richloc, 0, "test of %i locations",
+			   richloc.get_num_locations ());
+    }
 }
 
 unsigned int
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index 292abce..6ead57c 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -1366,11 +1366,8 @@ class rich_location
 
   unsigned int get_num_locations () const { return m_num_ranges; }
 
-  location_range *get_range (unsigned int idx)
-  {
-    linemap_assert (idx < m_num_ranges);
-    return &m_ranges[idx];
-  }
+  const location_range *get_range (unsigned int idx) const;
+  location_range *get_range (unsigned int idx);
 
   expanded_location get_expanded_location (unsigned int idx);
 
@@ -1393,12 +1390,14 @@ class rich_location
   fixit_hint *get_fixit_hint (int idx) const { return m_fixit_hints[idx]; }
 
 public:
-  static const int MAX_RANGES = 3;
+  static const int STATICALLY_ALLOCATED_RANGES = 3;
   static const int MAX_FIXIT_HINTS = 2;
 
 protected:
   unsigned int m_num_ranges;
-  location_range m_ranges[MAX_RANGES];
+  location_range m_static_ranges[STATICALLY_ALLOCATED_RANGES];
+  unsigned int m_num_allocated_ranges;
+  location_range *m_dynamic_ranges;
 
   int m_column_override;
 
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index 1fb634a..a3a512b 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -1993,6 +1993,8 @@ source_range::intersects_line_p (const char *file, int line) const
 
 rich_location::rich_location (line_maps */*set*/, source_location loc) :
   m_num_ranges (0),
+  m_num_allocated_ranges (0),
+  m_dynamic_ranges (NULL),
   m_column_override (0),
   m_have_expanded_location (false),
   m_num_fixit_hints (0)
@@ -2004,6 +2006,7 @@ rich_location::rich_location (line_maps */*set*/, source_location loc) :
 
 rich_location::~rich_location ()
 {
+  XDELETEVEC (m_dynamic_ranges);
   for (unsigned int i = 0; i < m_num_fixit_hints; i++)
     delete m_fixit_hints[i];
 }
@@ -2014,7 +2017,41 @@ source_location
 rich_location::get_loc (unsigned int idx) const
 {
   linemap_assert (idx < m_num_ranges);
-  return m_ranges[idx].m_loc;
+  const location_range *locrange = get_range (idx);
+  return locrange->m_loc;
+}
+
+/* FIXME.  */
+
+const location_range *
+rich_location::get_range (unsigned int idx) const
+{
+  linemap_assert (idx < m_num_ranges);
+  if (idx < STATICALLY_ALLOCATED_RANGES)
+    {
+      return &m_static_ranges[idx];
+    }
+  else
+    {
+      linemap_assert (m_dynamic_ranges);
+      return &m_dynamic_ranges[idx - STATICALLY_ALLOCATED_RANGES];
+    }
+}
+
+/* FIXME.  */
+location_range *
+rich_location::get_range (unsigned int idx)
+{
+  linemap_assert (idx < m_num_ranges);
+  if (idx < STATICALLY_ALLOCATED_RANGES)
+    {
+      return &m_static_ranges[idx];
+    }
+  else
+    {
+      linemap_assert (m_dynamic_ranges);
+      return &m_dynamic_ranges[idx - STATICALLY_ALLOCATED_RANGES];
+    }
 }
 
 /* Expand location IDX within this rich_location.  */
@@ -2057,9 +2094,36 @@ rich_location::override_column (int column)
 void
 rich_location::add_range (source_location loc, bool show_caret_p)
 {
-  linemap_assert (m_num_ranges < MAX_RANGES);
+  unsigned int idx;
+  location_range *range;
 
-  location_range *range = &m_ranges[m_num_ranges++];
+  /* Ranges [0..STATICALLY_ALLOCATED_RANGES) are allocated
+     within m_static_ranges, after that they are within
+     m_dynamic_ranges.  */
+  idx = m_num_ranges++;
+  if (idx < STATICALLY_ALLOCATED_RANGES)
+    range = &m_static_ranges[idx];
+  else
+    {
+      /* Offset "idx" to within m_dynamic_ranges.  */
+      idx -= STATICALLY_ALLOCATED_RANGES;
+      if (NULL == m_dynamic_ranges)
+	{
+	  linemap_assert (m_num_allocated_ranges == 0);
+	  m_num_allocated_ranges = 16;
+	  m_dynamic_ranges = XNEWVEC (location_range, m_num_allocated_ranges);
+	}
+      else if (idx >= m_num_allocated_ranges)
+	{
+	  linemap_assert (m_num_allocated_ranges > 0);
+	  m_num_allocated_ranges *= 2;
+	  m_dynamic_ranges = XRESIZEVEC (location_range, m_dynamic_ranges,
+					 m_num_allocated_ranges);
+	}
+      linemap_assert (m_dynamic_ranges);
+      linemap_assert (idx < m_num_allocated_ranges);
+      range = &m_dynamic_ranges[idx];
+    }
   range->m_loc = loc;
   range->m_show_caret_p = show_caret_p;
 }
@@ -2081,19 +2145,18 @@ void
 rich_location::set_range (line_maps * /*set*/, unsigned int idx,
 			  source_location loc, bool show_caret_p)
 {
-  linemap_assert (idx < MAX_RANGES);
-
   /* We can either overwrite an existing range, or add one exactly
      on the end of the array.  */
   linemap_assert (idx <= m_num_ranges);
 
-  location_range *locrange = &m_ranges[idx];
-  locrange->m_loc = loc;
-  locrange->m_show_caret_p = show_caret_p;
-
-  /* Are we adding a range onto the end?  */
   if (idx == m_num_ranges)
-    m_num_ranges = idx + 1;
+    add_range (loc,  show_caret_p);
+  else
+    {
+      location_range *locrange = get_range (idx);
+      locrange->m_loc = loc;
+      locrange->m_show_caret_p = show_caret_p;
+    }
 
   if (idx == 0)
     /* Mark any cached value here as dirty.  */
-- 
1.8.5.3

