summaryrefslogtreecommitdiff
path: root/libcpp/line-map.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcpp/line-map.c')
-rw-r--r--libcpp/line-map.c441
1 files changed, 372 insertions, 69 deletions
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index 2e61895bb3..949489eb1a 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -1,5 +1,5 @@
/* Map (unsigned int) keys to (source file, line, column) triples.
- Copyright (C) 2001-2016 Free Software Foundation, Inc.
+ Copyright (C) 2001-2017 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
@@ -31,18 +31,6 @@ along with this program; see the file COPYING3. If not see
disabled). */
const unsigned int LINE_MAP_MAX_COLUMN_NUMBER = (1U << 12);
-/* Do not pack ranges if locations get higher than this.
- If you change this, update:
- gcc.dg/plugin/location_overflow_plugin.c
- gcc.dg/plugin/location-overflow-test-*.c. */
-const source_location LINE_MAP_MAX_LOCATION_WITH_PACKED_RANGES = 0x50000000;
-
-/* Do not track column numbers if locations get higher than this.
- If you change this, update:
- gcc.dg/plugin/location_overflow_plugin.c
- gcc.dg/plugin/location-overflow-test-*.c. */
-const source_location LINE_MAP_MAX_LOCATION_WITH_COLS = 0x60000000;
-
/* Highest possible source location encoded within an ordinary or
macro map. */
const source_location LINE_MAP_MAX_SOURCE_LOCATION = 0x70000000;
@@ -69,6 +57,14 @@ static source_location linemap_macro_loc_to_exp_point (struct line_maps *,
extern unsigned num_expanded_macros_counter;
extern unsigned num_macro_tokens_counter;
+/* Destructor for class line_maps.
+ Ensure non-GC-managed memory is released. */
+
+line_maps::~line_maps ()
+{
+ htab_delete (location_adhoc_data_map.htab);
+}
+
/* Hash function for location_adhoc_data hashtable. */
static hashval_t
@@ -102,7 +98,7 @@ location_adhoc_data_eq (const void *l1, const void *l2)
static int
location_adhoc_data_update (void **slot, void *data)
{
- *((char **) slot) += *((long long *) data);
+ *((char **) slot) += *((int64_t *) data);
return 1;
}
@@ -224,7 +220,7 @@ get_combined_adhoc_loc (struct line_maps *set,
set->location_adhoc_data_map.allocated)
{
char *orig_data = (char *) set->location_adhoc_data_map.data;
- long long offset;
+ int64_t offset;
/* Cast away extern "C" from the type of xrealloc. */
line_map_realloc reallocator = (set->reallocator
? set->reallocator
@@ -323,11 +319,26 @@ pure_location_p (line_maps *set, source_location loc)
return true;
}
-/* Finalize the location_adhoc_data structure. */
-void
-location_adhoc_data_fini (struct line_maps *set)
+/* Given location LOC within SET, strip away any packed range information
+ or ad-hoc information. */
+
+source_location
+get_pure_location (line_maps *set, source_location loc)
{
- htab_delete (set->location_adhoc_data_map.htab);
+ if (IS_ADHOC_LOC (loc))
+ loc
+ = set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].locus;
+
+ if (loc >= LINEMAPS_MACRO_LOWEST_LOCATION (set))
+ return loc;
+
+ if (loc < RESERVED_LOCATION_COUNT)
+ return loc;
+
+ const line_map *map = linemap_lookup (set, loc);
+ const line_map_ordinary *ordmap = linemap_check_ordinary (map);
+
+ return loc & ~((1 << ordmap->m_range_bits) - 1);
}
/* Initialize a line map set. */
@@ -741,7 +752,7 @@ linemap_line_start (struct line_maps *set, linenum_type to_line,
single line we can sometimes just increase its column_bits instead. */
if (line_delta < 0
|| last_line != ORDINARY_MAP_STARTING_LINE_NUMBER (map)
- || SOURCE_COLUMN (map, highest) >= (1U << column_bits)
+ || SOURCE_COLUMN (map, highest) >= (1U << (column_bits - range_bits))
|| range_bits < map->m_range_bits)
map = linemap_check_ordinary
(const_cast <line_map *>
@@ -805,8 +816,22 @@ linemap_position_for_column (struct line_maps *set, unsigned int to_column)
}
else
{
+ /* Otherwise, attempt to start a new line that can hold TO_COLUMN,
+ with some space to spare. This may or may not lead to a new
+ linemap being created. */
line_map_ordinary *map = LINEMAPS_LAST_ORDINARY_MAP (set);
r = linemap_line_start (set, SOURCE_LINE (map, r), to_column + 50);
+ map = LINEMAPS_LAST_ORDINARY_MAP (set);
+ if (map->m_column_and_range_bits == 0)
+ {
+ /* ...then the linemap has column-tracking disabled,
+ presumably due to exceeding either
+ LINE_MAP_MAX_LOCATION_WITH_COLS (overall) or
+ LINE_MAP_MAX_COLUMN_NUMBER (within this line).
+ Return the start of the linemap, which encodes column 0, for
+ the whole line. */
+ return r;
+ }
}
}
line_map_ordinary *map = LINEMAPS_LAST_ORDINARY_MAP (set);
@@ -894,7 +919,10 @@ linemap_position_for_loc_and_offset (struct line_maps *set,
}
column += column_offset;
- if (linemap_assert_fails (column < (1u << map->m_column_and_range_bits)))
+
+ /* Bail out if the column is not representable within the existing
+ linemap. */
+ if (column >= (1u << (map->m_column_and_range_bits - map->m_range_bits)))
return loc;
source_location r =
@@ -1213,9 +1241,8 @@ linemap_location_in_system_header_p (struct line_maps *set,
return false;
}
-/* Return TRUE if LOCATION is a source code location of a token coming
- from a macro replacement-list at a macro expansion point, FALSE
- otherwise. */
+/* Return TRUE if LOCATION is a source code location of a token that is part of
+ a macro expansion, FALSE otherwise. */
bool
linemap_location_from_macro_expansion_p (const struct line_maps *set,
@@ -1560,6 +1587,37 @@ linemap_resolve_location (struct line_maps *set,
return loc;
}
+/* TRUE if LOCATION is a source code location of a token that is part of the
+ definition of a macro, FALSE otherwise. */
+
+bool
+linemap_location_from_macro_definition_p (struct line_maps *set,
+ source_location loc)
+{
+ if (IS_ADHOC_LOC (loc))
+ loc = get_location_from_adhoc_loc (set, loc);
+
+ if (!linemap_location_from_macro_expansion_p (set, loc))
+ return false;
+
+ while (true)
+ {
+ const struct line_map_macro *map
+ = linemap_check_macro (linemap_lookup (set, loc));
+
+ source_location s_loc
+ = linemap_macro_map_loc_unwind_toward_spelling (set, map, loc);
+ if (linemap_location_from_macro_expansion_p (set, s_loc))
+ loc = s_loc;
+ else
+ {
+ source_location def_loc
+ = linemap_macro_map_loc_to_def_point (map, loc);
+ return s_loc == def_loc;
+ }
+ }
+}
+
/*
Suppose that LOC is the virtual location of a token T coming from
the expansion of a macro M. This function then steps up to get the
@@ -1971,11 +2029,13 @@ source_range::intersects_line_p (const char *file, int line) const
/* Construct a rich_location with location LOC as its initial range. */
-rich_location::rich_location (line_maps */*set*/, source_location loc) :
- m_num_ranges (0),
+rich_location::rich_location (line_maps *set, source_location loc) :
+ m_line_table (set),
+ 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);
}
@@ -1984,8 +2044,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. */
@@ -1993,8 +2053,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. */
@@ -2037,11 +2113,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,
@@ -2061,35 +2136,109 @@ 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);
+ linemap_assert (idx <= m_ranges.count ());
- 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;
+ 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. */
m_have_expanded_location = false;
}
+/* Methods for adding insertion fix-it hints. */
+
+/* Add a fixit-hint, suggesting insertion of NEW_CONTENT
+ immediately before the primary range's start location. */
+
+void
+rich_location::add_fixit_insert_before (const char *new_content)
+{
+ add_fixit_insert_before (get_loc (), new_content);
+}
+
+/* Add a fixit-hint, suggesting insertion of NEW_CONTENT
+ immediately before the start of WHERE. */
+
+void
+rich_location::add_fixit_insert_before (source_location where,
+ const char *new_content)
+{
+ source_location start = get_range_from_loc (m_line_table, where).m_start;
+
+ if (reject_impossible_fixit (start))
+ return;
+ /* We do not yet support newlines within fix-it hints. */
+ if (strchr (new_content, '\n'))
+ {
+ stop_supporting_fixits ();
+ return;
+ }
+ add_fixit (new fixit_insert (start, new_content));
+}
+
/* Add a fixit-hint, suggesting insertion of NEW_CONTENT
- at WHERE. */
+ immediately after the primary range's end-point. */
void
-rich_location::add_fixit_insert (source_location where,
- const char *new_content)
+rich_location::add_fixit_insert_after (const char *new_content)
{
- linemap_assert (m_num_fixit_hints < MAX_FIXIT_HINTS);
- m_fixit_hints[m_num_fixit_hints++]
- = new fixit_insert (where, new_content);
+ add_fixit_insert_after (get_loc (), new_content);
+}
+
+/* Add a fixit-hint, suggesting insertion of NEW_CONTENT
+ immediately after the end-point of WHERE. */
+
+void
+rich_location::add_fixit_insert_after (source_location where,
+ const char *new_content)
+{
+ source_location finish = get_range_from_loc (m_line_table, where).m_finish;
+
+ if (reject_impossible_fixit (finish))
+ return;
+
+ source_location next_loc
+ = linemap_position_for_loc_and_offset (m_line_table, finish, 1);
+
+ /* linemap_position_for_loc_and_offset can fail, if so, it returns
+ its input value. */
+ if (next_loc == finish)
+ {
+ stop_supporting_fixits ();
+ return;
+ }
+
+ add_fixit (new fixit_insert (next_loc, new_content));
+}
+
+/* Methods for adding removal fix-it hints. */
+
+/* Add a fixit-hint, suggesting removal of the content covered
+ by range 0. */
+
+void
+rich_location::add_fixit_remove ()
+{
+ add_fixit_remove (get_loc ());
+}
+
+/* Add a fixit-hint, suggesting removal of the content between
+ the start and finish of WHERE. */
+
+void
+rich_location::add_fixit_remove (source_location where)
+{
+ source_range range = get_range_from_loc (m_line_table, where);
+ add_fixit_remove (range);
}
/* Add a fixit-hint, suggesting removal of the content at
@@ -2098,8 +2247,67 @@ rich_location::add_fixit_insert (source_location where,
void
rich_location::add_fixit_remove (source_range src_range)
{
- linemap_assert (m_num_fixit_hints < MAX_FIXIT_HINTS);
- m_fixit_hints[m_num_fixit_hints++] = new fixit_remove (src_range);
+ add_fixit_replace (src_range, "");
+}
+
+/* Return true iff A is in the column directly before B, on the
+ same line of the same source file. */
+
+static bool
+column_before_p (line_maps *set, source_location a, source_location b)
+{
+ if (IS_ADHOC_LOC (a))
+ a = get_location_from_adhoc_loc (set, a);
+ if (IS_ADHOC_LOC (b))
+ b = get_location_from_adhoc_loc (set, b);
+
+ /* They must both be in ordinary maps. */
+ const struct line_map *linemap_a = linemap_lookup (set, a);
+ if (linemap_macro_expansion_map_p (linemap_a))
+ return false;
+ const struct line_map *linemap_b = linemap_lookup (set, b);
+ if (linemap_macro_expansion_map_p (linemap_b))
+ return false;
+
+ /* To be on the same line, they must be in the same ordinary map. */
+ if (linemap_a != linemap_b)
+ return false;
+
+ linenum_type line_a
+ = SOURCE_LINE (linemap_check_ordinary (linemap_a), a);
+ linenum_type line_b
+ = SOURCE_LINE (linemap_check_ordinary (linemap_b), b);
+ if (line_a != line_b)
+ return false;
+
+ linenum_type column_a
+ = SOURCE_COLUMN (linemap_check_ordinary (linemap_a), a);
+ linenum_type column_b
+ = SOURCE_COLUMN (linemap_check_ordinary (linemap_b), b);
+
+ return column_b == column_a + 1;
+}
+
+/* Add a fixit-hint, suggesting replacement of the content covered
+ by range 0 with NEW_CONTENT. */
+
+void
+rich_location::add_fixit_replace (const char *new_content)
+{
+ add_fixit_replace (get_loc (), new_content);
+}
+
+/* Methods for adding "replace" fix-it hints. */
+
+/* Add a fixit-hint, suggesting replacement of the content between
+ the start and finish of WHERE with NEW_CONTENT. */
+
+void
+rich_location::add_fixit_replace (source_location where,
+ const char *new_content)
+{
+ source_range range = get_range_from_loc (m_line_table, where);
+ add_fixit_replace (range, new_content);
}
/* Add a fixit-hint, suggesting replacement of the content at
@@ -2109,9 +2317,87 @@ void
rich_location::add_fixit_replace (source_range src_range,
const char *new_content)
{
- linemap_assert (m_num_fixit_hints < MAX_FIXIT_HINTS);
- m_fixit_hints[m_num_fixit_hints++]
- = new fixit_replace (src_range, new_content);
+ 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);
+
+ if (reject_impossible_fixit (src_range.m_start))
+ return;
+ if (reject_impossible_fixit (src_range.m_finish))
+ return;
+
+ /* We do not yet support newlines within fix-it hints. */
+ if (strchr (new_content, '\n'))
+ {
+ stop_supporting_fixits ();
+ return;
+ }
+
+ /* Consolidate neighboring fixits. */
+ fixit_hint *prev = get_last_fixit_hint ();
+ if (prev)
+ if (prev->maybe_append_replace (m_line_table, src_range, new_content))
+ return;
+
+ add_fixit (new fixit_replace (src_range, new_content));
+}
+
+/* Get the last fix-it hint within this rich_location, or NULL if none. */
+
+fixit_hint *
+rich_location::get_last_fixit_hint () const
+{
+ if (m_fixit_hints.count () > 0)
+ return get_fixit_hint (m_fixit_hints.count () - 1);
+ else
+ return NULL;
+}
+
+/* If WHERE is an "awkward" location, then mark this rich_location as not
+ supporting fixits, purging any thay were already added, and return true.
+
+ Otherwise (the common case), return false. */
+
+bool
+rich_location::reject_impossible_fixit (source_location where)
+{
+ /* Fix-its within a rich_location should either all be suggested, or
+ none of them should be suggested.
+ Once we've rejected a fixit, we reject any more, even those
+ with reasonable locations. */
+ if (m_seen_impossible_fixit)
+ return true;
+
+ if (where <= LINE_MAP_MAX_LOCATION_WITH_COLS)
+ /* WHERE is a reasonable location for a fix-it; don't reject it. */
+ return false;
+
+ /* Otherwise we have an attempt to add a fix-it with an "awkward"
+ location: either one that we can't obtain column information
+ for (within an ordinary map), or one within a macro expansion. */
+ stop_supporting_fixits ();
+ return true;
+}
+
+/* Mark this rich_location as not supporting fixits, purging any that were
+ already added. */
+
+void
+rich_location::stop_supporting_fixits ()
+{
+ m_seen_impossible_fixit = true;
+
+ /* Purge the rich_location of any fix-its that were already added. */
+ for (unsigned int i = 0; i < m_fixit_hints.count (); i++)
+ delete get_fixit_hint (i);
+ m_fixit_hints.truncate (0);
+}
+
+/* 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. */
@@ -2132,7 +2418,7 @@ fixit_insert::~fixit_insert ()
/* Implementation of fixit_hint::affects_line_p for fixit_insert. */
bool
-fixit_insert::affects_line_p (const char *file, int line)
+fixit_insert::affects_line_p (const char *file, int line) const
{
expanded_location exploc
= linemap_client_expand_location_to_spelling_point (m_where);
@@ -2142,19 +2428,13 @@ fixit_insert::affects_line_p (const char *file, int line)
return false;
}
-/* class fixit_remove. */
-
-fixit_remove::fixit_remove (source_range src_range)
-: m_src_range (src_range)
-{
-}
-
-/* Implementation of fixit_hint::affects_line_p for fixit_remove. */
+/* Implementation of maybe_append_replace for fixit_insert. Reject
+ the attempt to consolidate fix-its. */
bool
-fixit_remove::affects_line_p (const char *file, int line)
+fixit_insert::maybe_append_replace (line_maps *, source_range, const char *)
{
- return m_src_range.intersects_line_p (file, line);
+ return false;
}
/* class fixit_replace. */
@@ -2175,7 +2455,30 @@ fixit_replace::~fixit_replace ()
/* Implementation of fixit_hint::affects_line_p for fixit_replace. */
bool
-fixit_replace::affects_line_p (const char *file, int line)
+fixit_replace::affects_line_p (const char *file, int line) const
{
return m_src_range.intersects_line_p (file, line);
}
+
+/* Implementation of maybe_append_replace for fixit_replace. If
+ possible, merge the new replacement into this one and return true.
+ Otherwise return false. */
+
+bool
+fixit_replace::maybe_append_replace (line_maps *set,
+ source_range src_range,
+ const char *new_content)
+{
+ /* Does SRC_RANGE start immediately after this one finishes? */
+ if (!column_before_p (set, m_src_range.m_finish, src_range.m_start))
+ return false;
+
+ /* We have neighboring replacements; merge them. */
+ m_src_range.m_finish = src_range.m_finish;
+ size_t extra_len = strlen (new_content);
+ m_bytes = (char *)xrealloc (m_bytes, m_len + extra_len + 1);
+ memcpy (m_bytes + m_len, new_content, extra_len);
+ m_len += extra_len;
+ m_bytes[m_len] = '\0';
+ return true;
+}