Remove arbitrary limits from rich_location
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 31 Aug 2016 00:35:01 +0000 (00:35 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Wed, 31 Aug 2016 00:35:01 +0000 (00:35 +0000)
This patch eliminates the hard-coded limits within rich_location
(up to 3 ranges, up to 2 fixits).  The common case is still
handled by embedding the values inside rich_location - it only
uses dynamic allocation if these limits are exceeded, so
creation of rich_location instances on the stack should still
be fast.  This is implemented via a new container class,
semi_embedded_vec <T, N>.

gcc/ChangeLog:
* diagnostic-show-locus.c (colorizer::begin_state): Support more
than 3 ranges per diagnostic by alternating between color 1 and
color 2.
(layout::layout): Replace use of rich_location::MAX_RANGES
with richloc->get_num_locations ().
(layout::calculate_line_spans): Replace use of
rich_location::MAX_RANGES with m_layout_ranges.length ().
(layout::print_annotation_line): Handle arbitrary numbers of
ranges in caret-printing by defaulting to '^'.
(selftest::test_one_liner_many_fixits): New function.
(test_diagnostic_show_locus_one_liner): Call it.
* diagnostic.c (diagnostic_initialize): Update for renaming
of rich_location::MAX_RANGES to
rich_location::STATICALLY_ALLOCATED_RANGES.
* diagnostic.h (struct diagnostic_context): Likewise.

gcc/testsuite/ChangeLog:
* gcc.dg/plugin/diagnostic-test-show-locus-bw.c
(test_many_nested_locations): New function.
* gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
(test_show_locus): Handle "test_many_nested_locations".

libcpp/ChangeLog:
* include/line-map.h (class semi_embedded_vec): New class.
(semi_embedded_vec<T, NUM_EMBEDDED>::semi_embedded_vec): New ctor.
(semi_embedded_vec<T, NUM_EMBEDDED>::~semi_embedded_vec): New
dtor.
(semi_embedded_vec<T, NUM_EMBEDDED>::operator[]): New methods.
(semi_embedded_vec<T, NUM_EMBEDDED>::push): New method.
(semi_embedded_vec<T, NUM_EMBEDDED>::truncate): New method.
(rich_location::get_num_locations): Reimplement in terms of
m_ranges.
(rich_location::get_range): Make non-inline.
(rich_location::get_num_fixit_hints): Reimplement in terms of
m_fixit_hints.
(rich_location::add_fixit): New function.
(rich_location::MAX_RANGES): Rename to...
(rich_location::STATICALLY_ALLOCATED_RANGES): ...this.
(rich_location::MAX_FIXIT_HINTS): Rename to...
(rich_location::STATICALLY_ALLOCATED_RANGES): ...this, and make
private.
(rich_location::m_num_ranges): Eliminate in favor of...
(rich_location::m_ranges): ...this, converting from a fixed-size
array to a semi_embedded_vec.
(rich_location::m_num_fixit_hints): Eliminate in favor of...
(rich_location::m_fixit_hints): ...this, converting from a
fixed-size array to a semi_embedded_vec.
* line-map.c (rich_location::rich_location): Update for above
changes.
(rich_location::~rich_location): Likewise.
(rich_location::get_loc): Likewise.
(rich_location::get_range): New methods.
(rich_location::add_range): Update for above changes.
(rich_location::set_range): Likewise.
(rich_location::add_fixit_insert): Likewise.
(rich_location::add_fixit_replace): Likewise.
(rich_location::get_last_fixit_hint): Likewise.
(rich_location::reject_impossible_fixit): Likewise.
(rich_location::add_fixit): New method.

From-SVN: r239879

gcc/ChangeLog
gcc/diagnostic-show-locus.c
gcc/diagnostic.c
gcc/diagnostic.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
libcpp/ChangeLog
libcpp/include/line-map.h
libcpp/line-map.c

index fa764e86425aca217f8045b992695c85e987834b..54f2f7a33ba469be1dfd1c01dc10421a852553fb 100644 (file)
@@ -1,3 +1,21 @@
+2016-08-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * diagnostic-show-locus.c (colorizer::begin_state): Support more
+       than 3 ranges per diagnostic by alternating between color 1 and
+       color 2.
+       (layout::layout): Replace use of rich_location::MAX_RANGES
+       with richloc->get_num_locations ().
+       (layout::calculate_line_spans): Replace use of
+       rich_location::MAX_RANGES with m_layout_ranges.length ().
+       (layout::print_annotation_line): Handle arbitrary numbers of
+       ranges in caret-printing by defaulting to '^'.
+       (selftest::test_one_liner_many_fixits): New function.
+       (test_diagnostic_show_locus_one_liner): Call it.
+       * diagnostic.c (diagnostic_initialize): Update for renaming
+       of rich_location::MAX_RANGES to
+       rich_location::STATICALLY_ALLOCATED_RANGES.
+       * diagnostic.h (struct diagnostic_context): Likewise.
+
 2016-08-30  David Malcolm  <dmalcolm@redhat.com>
 
        * selftest.c (selftest::named_temp_file::named_temp_file): New
index 60f68204df8e194ec61c7a6f0314b58df818a2ec..a22a660543a7bceb8d7408e9fcab88e044cd9005 100644 (file)
@@ -317,8 +317,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 : m_range2);
+      }
       break;
     }
 }
@@ -720,8 +724,8 @@ layout::layout (diagnostic_context * context,
   m_exploc (richloc->get_expanded_location (0)),
   m_colorizer (context, diagnostic_kind),
   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 (richloc->get_num_locations ()),
+  m_line_spans (1 + richloc->get_num_locations ()),
   m_x_offset (0)
 {
   source_location primary_loc = richloc->get_range (0)->m_loc;
@@ -904,7 +908,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++)
     {
@@ -1050,8 +1054,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, '~');
        }
@@ -1654,6 +1665,44 @@ test_one_liner_fixit_validation_adhoc_locations ()
   }
 }
 
+/* Ensure that we can add an arbitrary number of fix-it hints to a
+   rich_location.  */
+
+static void
+test_one_liner_many_fixits ()
+{
+  test_diagnostic_context dc;
+  location_t equals = linemap_position_for_column (line_table, 5);
+  rich_location richloc (line_table, equals);
+  for (int i = 0; i < 19; i++)
+    richloc.add_fixit_insert ("a");
+  ASSERT_EQ (19, richloc.get_num_fixit_hints ());
+  diagnostic_show_locus (&dc, &richloc, DK_ERROR);
+  ASSERT_STREQ ("\n"
+               " foo = bar.field;\n"
+               "     ^\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n"
+               "     a\n",
+               pp_formatted_text (dc.printer));
+}
+
 /* Run the various one-liner tests.  */
 
 static void
@@ -1687,6 +1736,7 @@ test_diagnostic_show_locus_one_liner (const line_table_case &case_)
   test_one_liner_fixit_replace_non_equal_range ();
   test_one_liner_fixit_replace_equal_secondary_range ();
   test_one_liner_fixit_validation_adhoc_locations ();
+  test_one_liner_many_fixits ();
 }
 
 /* Verify that fix-it hints are appropriately consolidated.
index b47da383fc3649dd2b02152841a93d8ffab32838..47b4c79ebcc2a34eb4600f700ab46cb55a65b3c4 100644 (file)
@@ -147,7 +147,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;
index 104e39c868a60d2dab9b41d5b00a39e3e5a98d89..0727644d96b7da5c79a6e698c99ad4dc3e63dc67 100644 (file)
@@ -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.  */
index 6e3b70662d098e123f43b83fe6a8e2d6f94b347f..cf97b393f12587de8c8b88511f05c05765f62dcd 100644 (file)
@@ -1,3 +1,10 @@
+2016-08-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * gcc.dg/plugin/diagnostic-test-show-locus-bw.c
+       (test_many_nested_locations): New function.
+       * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
+       (test_show_locus): Handle "test_many_nested_locations".
+
 2016-08-30  David Malcolm  <dmalcolm@redhat.com>
 
        * g++.dg/template/double-greater-than-fixit.C: New test case.
index 2748fa1f280d46a1e2cb8d35298b379540b475a9..e8112bfa3a5522610ce5707849acd6e3b6009b98 100644 (file)
@@ -205,3 +205,47 @@ int test_percent_q_plus_d (void)
    { dg-end-multiline-output "" } */
   return local;
 }
+
+/* Test of many nested locations and fixits.  */
+
+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,
+     ^~~~~ ^~~~~ ^~~~~ ^~~ ^~~~  ^~~~~~~~~~~ ^~~~~~~~~~ ^~~~
+     LOREM IPSUM DOLOR SIT AMET  CONSECTETUR ADIPISCING ELIT
+     sed do eiusmod tempor incididunt ut labore et dolore magna
+     ^~~ ^~ ^~~~~~~ ^~~~~~ ^~~~~~~~~~ ^~ ^~~~~~ ^~ ^~~~~~ ^~~~~
+     SED DO EIUSMOD TEMPOR INCIDIDUNT UT LABORE ET DOLORE MAGNA
+     aliqua. Ut enim ad minim veniam, quis nostrud exercitation
+     ^~~~~~  ^~ ^~~~ ^~ ^~~~~ ^~~~~~  ^~~~ ^~~~~~~ ^~~~~~~~~~~~
+     ALIQUA  UT ENIM AD MINIM VENIAM  QUIS NOSTRUD EXERCITATION
+     ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
+     ^~~~~~~ ^~~~~~~ ^~~~ ^~ ^~~~~~~ ^~ ^~ ^~~~~~~ ^~~~~~~~~  ^~~~
+     ULLAMCO LABORIS NISI UT ALIQUIP EX EA COMMODO CONSEQUAT  DUIS
+     aute irure dolor in reprehenderit in voluptate velit esse cillum
+     ^~~~ ^~~~~ ^~~~~ ^~ ^~~~~~~~~~~~~ ^~ ^~~~~~~~~ ^~~~~ ^~~~ ^~~~~~
+     AUTE IRURE DOLOR IN REPREHENDERIT IN VOLUPTATE VELIT ESSE CILLUM
+     dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+     ^~~~~~ ^~ ^~~~~~ ^~~~~ ^~~~~~~~  ^~~~~~~~~ ^~~~ ^~~~~~~~
+     DOLORE EU FUGIAT NULLA PARIATUR  EXCEPTEUR SINT OCCAECAT
+     cupidatat non proident, sunt in culpa qui officia deserunt
+     ^~~~~~~~~ ^~~ ^~~~~~~~  ^~~~ ^~ ^~~~~ ^~~ ^~~~~~~ ^~~~~~~~
+     CUPIDATAT NON PROIDENT  SUNT IN CULPA QUI OFFICIA DESERUNT
+     mollit anim id est laborum.
+     ^~~~~~ ^~~~ ^~ ^~~ ^~~~~~~
+     MOLLIT ANIM ID EST LABORUM
+   { dg-end-multiline-output "" } */
+}
index d57400d90fff5f223cad8cffc8837a10c6d38b2c..ea28f046e8d5db88ff51c206a4a902e7f8f3aa34 100644 (file)
@@ -325,6 +325,59 @@ test_show_locus (function *fun)
       warning_at (input_location, 0,
                  "example of plus in format code for %q+D", local);
     }
+
+  /* Example of many locations and many fixits.
+     Underline (separately) every word in a comment, and convert them
+     to upper case.  */
+  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);
+
+                     /* Add a fixit, converting to upper case.  */
+                     char *copy = xstrndup (content + start_idx,
+                                            idx - start_idx);
+                     for (char *ch = copy; *ch; ch++)
+                       *ch = TOUPPER (*ch);
+                     richloc.add_fixit_replace (word, copy);
+                     free (copy);
+                   }
+               }
+           }
+       }
+      /* 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
index a753033b826169be5186dc506d847673e64752b0..595d6ca4cca815153be5d9c1fa5c8fbc3cd071a1 100644 (file)
@@ -1,3 +1,42 @@
+2016-08-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * include/line-map.h (class semi_embedded_vec): New class.
+       (semi_embedded_vec<T, NUM_EMBEDDED>::semi_embedded_vec): New ctor.
+       (semi_embedded_vec<T, NUM_EMBEDDED>::~semi_embedded_vec): New
+       dtor.
+       (semi_embedded_vec<T, NUM_EMBEDDED>::operator[]): New methods.
+       (semi_embedded_vec<T, NUM_EMBEDDED>::push): New method.
+       (semi_embedded_vec<T, NUM_EMBEDDED>::truncate): New method.
+       (rich_location::get_num_locations): Reimplement in terms of
+       m_ranges.
+       (rich_location::get_range): Make non-inline.
+       (rich_location::get_num_fixit_hints): Reimplement in terms of
+       m_fixit_hints.
+       (rich_location::add_fixit): New function.
+       (rich_location::MAX_RANGES): Rename to...
+       (rich_location::STATICALLY_ALLOCATED_RANGES): ...this.
+       (rich_location::MAX_FIXIT_HINTS): Rename to...
+       (rich_location::STATICALLY_ALLOCATED_RANGES): ...this, and make
+       private.
+       (rich_location::m_num_ranges): Eliminate in favor of...
+       (rich_location::m_ranges): ...this, converting from a fixed-size
+       array to a semi_embedded_vec.
+       (rich_location::m_num_fixit_hints): Eliminate in favor of...
+       (rich_location::m_fixit_hints): ...this, converting from a
+       fixed-size array to a semi_embedded_vec.
+       * line-map.c (rich_location::rich_location): Update for above
+       changes.
+       (rich_location::~rich_location): Likewise.
+       (rich_location::get_loc): Likewise.
+       (rich_location::get_range): New methods.
+       (rich_location::add_range): Update for above changes.
+       (rich_location::set_range): Likewise.
+       (rich_location::add_fixit_insert): Likewise.
+       (rich_location::add_fixit_replace): Likewise.
+       (rich_location::get_last_fixit_hint): Likewise.
+       (rich_location::reject_impossible_fixit): Likewise.
+       (rich_location::add_fixit): New method.
+
 2016-08-30  David Malcolm  <dmalcolm@redhat.com>
 
        * include/line-map.h (rich_location::add_fixit_insert): Add
index 122e4742ed3dd84bdc73f020edd0dd862aa83ed8..0c95b292599b60606fbd95359e1446e57aa369ff 100644 (file)
@@ -1288,6 +1288,128 @@ struct location_range
   bool m_show_caret_p;
 };
 
+/* A partially-embedded vec for use within rich_location for storing
+   ranges and fix-it hints.
+
+   Elements [0..NUM_EMBEDDED) are allocated within m_embed, after
+   that they are within the dynamically-allocated m_extra.
+
+   This allows for static allocation in the common case, whilst
+   supporting the rarer case of an arbitrary number of elements.
+
+   Dynamic allocation is not performed unless it's needed.  */
+
+template <typename T, int NUM_EMBEDDED>
+class semi_embedded_vec
+{
+ public:
+  semi_embedded_vec ();
+  ~semi_embedded_vec ();
+
+  unsigned int count () const { return m_num; }
+  T& operator[] (int idx);
+  const T& operator[] (int idx) const;
+
+  void push (const T&);
+  void truncate (int len);
+
+ private:
+  int m_num;
+  T m_embedded[NUM_EMBEDDED];
+  int m_alloc;
+  T *m_extra;
+};
+
+/* Constructor for semi_embedded_vec.  In particular, no dynamic allocation
+   is done.  */
+
+template <typename T, int NUM_EMBEDDED>
+semi_embedded_vec<T, NUM_EMBEDDED>::semi_embedded_vec ()
+: m_num (0), m_alloc (0), m_extra (NULL)
+{
+}
+
+/* semi_embedded_vec's dtor.  Release any dynamically-allocated memory.  */
+
+template <typename T, int NUM_EMBEDDED>
+semi_embedded_vec<T, NUM_EMBEDDED>::~semi_embedded_vec ()
+{
+  XDELETEVEC (m_extra);
+}
+
+/* Look up element IDX, mutably.  */
+
+template <typename T, int NUM_EMBEDDED>
+T&
+semi_embedded_vec<T, NUM_EMBEDDED>::operator[] (int idx)
+{
+  linemap_assert (idx < m_num);
+  if (idx < NUM_EMBEDDED)
+    return m_embedded[idx];
+  else
+    {
+      linemap_assert (m_extra != NULL);
+      return m_extra[idx - NUM_EMBEDDED];
+    }
+}
+
+/* Look up element IDX (const).  */
+
+template <typename T, int NUM_EMBEDDED>
+const T&
+semi_embedded_vec<T, NUM_EMBEDDED>::operator[] (int idx) const
+{
+  linemap_assert (idx < m_num);
+  if (idx < NUM_EMBEDDED)
+    return m_embedded[idx];
+  else
+    {
+      linemap_assert (m_extra != NULL);
+      return m_extra[idx - NUM_EMBEDDED];
+    }
+}
+
+/* Append VALUE to the end of the semi_embedded_vec.  */
+
+template <typename T, int NUM_EMBEDDED>
+void
+semi_embedded_vec<T, NUM_EMBEDDED>::push (const T& value)
+{
+  int idx = m_num++;
+  if (idx < NUM_EMBEDDED)
+    m_embedded[idx] = value;
+  else
+    {
+      /* Offset "idx" to be an index within m_extra.  */
+      idx -= NUM_EMBEDDED;
+      if (NULL == m_extra)
+       {
+         linemap_assert (m_alloc == 0);
+         m_alloc = 16;
+         m_extra = XNEWVEC (T, m_alloc);
+       }
+      else if (idx >= m_alloc)
+       {
+         linemap_assert (m_alloc > 0);
+         m_alloc *= 2;
+         m_extra = XRESIZEVEC (T, m_extra, m_alloc);
+       }
+      linemap_assert (m_extra);
+      linemap_assert (idx < m_alloc);
+      m_extra[idx] = value;
+    }
+}
+
+/* Truncate to length LEN.  No deallocation is performed.  */
+
+template <typename T, int NUM_EMBEDDED>
+void
+semi_embedded_vec<T, NUM_EMBEDDED>::truncate (int len)
+{
+  linemap_assert (len <= m_num);
+  m_num = len;
+}
+
 class fixit_hint;
   class fixit_insert;
   class fixit_remove;
@@ -1387,13 +1509,10 @@ class rich_location
   set_range (line_maps *set, unsigned int idx, source_location loc,
             bool show_caret_p);
 
-  unsigned int get_num_locations () const { return m_num_ranges; }
+  unsigned int get_num_locations () const { return m_ranges.count (); }
 
-  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);
 
@@ -1446,29 +1565,29 @@ class rich_location
   add_fixit_replace (source_range src_range,
                     const char *new_content);
 
-  unsigned int get_num_fixit_hints () const { return m_num_fixit_hints; }
+  unsigned int get_num_fixit_hints () const { return m_fixit_hints.count (); }
   fixit_hint *get_fixit_hint (int idx) const { return m_fixit_hints[idx]; }
   fixit_hint *get_last_fixit_hint () const;
 
 private:
   bool reject_impossible_fixit (source_location where);
+  void add_fixit (fixit_hint *hint);
 
 public:
-  static const int MAX_RANGES = 3;
-  static const int MAX_FIXIT_HINTS = 2;
+  static const int STATICALLY_ALLOCATED_RANGES = 3;
 
 protected:
   line_maps *m_line_table;
-  unsigned int m_num_ranges;
-  location_range m_ranges[MAX_RANGES];
+  semi_embedded_vec <location_range, STATICALLY_ALLOCATED_RANGES> m_ranges;
 
   int m_column_override;
 
   bool m_have_expanded_location;
   expanded_location m_expanded_location;
 
-  unsigned int m_num_fixit_hints;
-  fixit_hint *m_fixit_hints[MAX_FIXIT_HINTS];
+  static const int MAX_STATIC_FIXIT_HINTS = 2;
+  semi_embedded_vec <fixit_hint *, MAX_STATIC_FIXIT_HINTS> m_fixit_hints;
+
   bool m_seen_impossible_fixit;
 };
 
index 318932646a9b931aaef5763f2f2f3ec575f18c62..72549ba0732d2debebe8c7dbcd1002e81f701c1d 100644 (file)
@@ -1983,10 +1983,10 @@ source_range::intersects_line_p (const char *file, int line) const
 
 rich_location::rich_location (line_maps *set, source_location loc) :
   m_line_table (set),
-  m_num_ranges (0),
+  m_ranges (),
   m_column_override (0),
   m_have_expanded_location (false),
-  m_num_fixit_hints (0),
+  m_fixit_hints (),
   m_seen_impossible_fixit (false)
 {
   add_range (loc, true);
@@ -1996,8 +1996,8 @@ rich_location::rich_location (line_maps *set, source_location loc) :
 
 rich_location::~rich_location ()
 {
-  for (unsigned int i = 0; i < m_num_fixit_hints; i++)
-    delete m_fixit_hints[i];
+  for (unsigned int i = 0; i < m_fixit_hints.count (); i++)
+    delete get_fixit_hint (i);
 }
 
 /* Get location IDX within this rich_location.  */
@@ -2005,8 +2005,24 @@ rich_location::~rich_location ()
 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;
+}
+
+/* Get range IDX within this rich_location.  */
+
+const location_range *
+rich_location::get_range (unsigned int idx) const
+{
+  return &m_ranges[idx];
+}
+
+/* Mutable access to range IDX within this rich_location.  */
+
+location_range *
+rich_location::get_range (unsigned int idx)
+{
+  return &m_ranges[idx];
 }
 
 /* Expand location IDX within this rich_location.  */
@@ -2049,11 +2065,10 @@ 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);
-
-  location_range *range = &m_ranges[m_num_ranges++];
-  range->m_loc = loc;
-  range->m_show_caret_p = show_caret_p;
+  location_range range;
+  range.m_loc = loc;
+  range.m_show_caret_p = show_caret_p;
+  m_ranges.push (range);
 }
 
 /* Add or overwrite the location given by IDX, setting its location to LOC,
@@ -2073,19 +2088,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;
+  linemap_assert (idx <= m_ranges.count ());
 
-  /* Are we adding a range onto the end?  */
-  if (idx == m_num_ranges)
-    m_num_ranges = idx + 1;
+  if (idx == m_ranges.count ())
+    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.  */
@@ -2114,10 +2128,7 @@ rich_location::add_fixit_insert (source_location where,
 
   if (reject_impossible_fixit (where))
     return;
-
-  linemap_assert (m_num_fixit_hints < MAX_FIXIT_HINTS);
-  m_fixit_hints[m_num_fixit_hints++]
-    = new fixit_insert (where, new_content);
+  add_fixit (new fixit_insert (where, new_content));
 }
 
 /* Methods for adding removal fix-it hints.  */
@@ -2217,8 +2228,6 @@ void
 rich_location::add_fixit_replace (source_range src_range,
                                  const char *new_content)
 {
-  linemap_assert (m_num_fixit_hints < MAX_FIXIT_HINTS);
-
   src_range.m_start = get_pure_location (m_line_table, src_range.m_start);
   src_range.m_finish = get_pure_location (m_line_table, src_range.m_finish);
 
@@ -2229,14 +2238,11 @@ rich_location::add_fixit_replace (source_range src_range,
 
   /* Consolidate neighboring fixits.  */
   fixit_hint *prev = get_last_fixit_hint ();
-  if (m_num_fixit_hints > 0)
-    {
-      if (prev->maybe_append_replace (m_line_table, src_range, new_content))
-       return;
-    }
+  if (prev)
+    if (prev->maybe_append_replace (m_line_table, src_range, new_content))
+      return;
 
-  m_fixit_hints[m_num_fixit_hints++]
-    = new fixit_replace (src_range, new_content);
+  add_fixit (new fixit_replace (src_range, new_content));
 }
 
 /* Get the last fix-it hint within this rich_location, or NULL if none.  */
@@ -2244,8 +2250,8 @@ rich_location::add_fixit_replace (source_range src_range,
 fixit_hint *
 rich_location::get_last_fixit_hint () const
 {
-  if (m_num_fixit_hints > 0)
-    return m_fixit_hints[m_num_fixit_hints - 1];
+  if (m_fixit_hints.count () > 0)
+    return get_fixit_hint (m_fixit_hints.count () - 1);
   else
     return NULL;
 }
@@ -2275,13 +2281,21 @@ rich_location::reject_impossible_fixit (source_location where)
   m_seen_impossible_fixit = true;
 
   /* Purge the rich_location of any fix-its that were already added. */
-  for (unsigned int i = 0; i < m_num_fixit_hints; i++)
-    delete m_fixit_hints[i];
-  m_num_fixit_hints = 0;
+  for (unsigned int i = 0; i < m_fixit_hints.count (); i++)
+    delete get_fixit_hint (i);
+  m_fixit_hints.truncate (0);
 
   return true;
 }
 
+/* Add HINT to the fix-it hints in this rich_location.  */
+
+void
+rich_location::add_fixit (fixit_hint *hint)
+{
+  m_fixit_hints.push (hint);
+}
+
 /* class fixit_insert.  */
 
 fixit_insert::fixit_insert (source_location where,