summaryrefslogtreecommitdiff
path: root/libcpp/include/line-map.h
diff options
context:
space:
mode:
Diffstat (limited to 'libcpp/include/line-map.h')
-rw-r--r--libcpp/include/line-map.h377
1 files changed, 330 insertions, 47 deletions
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index 292abce3ec..522e8bb17e 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -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
@@ -227,10 +227,10 @@ typedef unsigned int linenum_type;
11111111112
12345678901234567890
- 521
+ 522
523 return foo + bar;
~~~~^~~~~
- 523
+ 524
The location's caret is at the "+", line 523 column 15, but starts
earlier, at the "f" of "foo" at column 11. The finish is at the "r"
@@ -260,6 +260,16 @@ typedef unsigned int linenum_type;
worked example in libcpp/location-example.txt. */
typedef unsigned int source_location;
+/* Do not pack ranges if locations get higher than this.
+ If you change this, update:
+ 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-test-*.c. */
+const source_location LINE_MAP_MAX_LOCATION_WITH_COLS = 0x60000000;
+
/* A range of source locations.
Ranges are closed:
@@ -286,6 +296,16 @@ struct GTY(()) source_range
return result;
}
+ /* Make a source_range from a pair of source_location. */
+ static source_range from_locations (source_location start,
+ source_location finish)
+ {
+ source_range result;
+ result.m_start = start;
+ result.m_finish = finish;
+ return result;
+ }
+
/* Is there any part of this range on the given line? */
bool intersects_line_p (const char *file, int line) const;
};
@@ -679,6 +699,8 @@ struct GTY(()) location_adhoc_data_map {
/* A set of chronological line_map structures. */
struct GTY(()) line_maps {
+
+ ~line_maps ();
maps_info_ordinary info_ordinary;
@@ -886,7 +908,7 @@ LINEMAPS_LAST_ALLOCATED_ORDINARY_MAP (const line_maps *set)
}
/* Returns a pointer to the beginning of the region where macro maps
- are allcoated. */
+ are allocated. */
inline line_map_macro *
LINEMAPS_MACRO_MAPS (const line_maps *set)
{
@@ -957,7 +979,6 @@ LINEMAPS_LAST_ALLOCATED_MACRO_MAP (const line_maps *set)
return (line_map_macro *)LINEMAPS_LAST_ALLOCATED_MAP (set, true);
}
-extern void location_adhoc_data_fini (struct line_maps *);
extern source_location get_combined_adhoc_loc (struct line_maps *,
source_location,
source_range,
@@ -982,6 +1003,12 @@ IS_ADHOC_LOC (source_location loc)
bool
pure_location_p (line_maps *set, source_location loc);
+/* Given location LOC within SET, strip away any packed range information
+ or ad-hoc information. */
+
+extern source_location get_pure_location (line_maps *set,
+ source_location loc);
+
/* Combine LOC and BLOCK, giving a combined adhoc location. */
inline source_location
@@ -1060,12 +1087,16 @@ const char* linemap_map_get_macro_name (const line_map_macro *);
int linemap_location_in_system_header_p (struct line_maps *,
source_location);
-/* 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 *,
source_location);
+/* 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 *,
+ source_location);
+
/* With the precondition that LOCATION is the locus of a token that is
an argument of a function-like macro MACRO_MAP and appears in the
expansion of MACRO_MAP, return the locus of that argument in the
@@ -1262,9 +1293,130 @@ 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;
class fixit_replace;
/* A "rich" source code location, for use when printing diagnostics.
@@ -1337,7 +1489,86 @@ class fixit_hint;
- range 0 is at the "%s" with start = caret = "%" and finish at
the "s".
- range 1 has start/finish covering the "101" and is not flagged for
- caret printing; it is perhaps at the start of "101". */
+ caret printing; it is perhaps at the start of "101".
+
+
+ Fix-it hints
+ ------------
+
+ Rich locations can also contain "fix-it hints", giving suggestions
+ for the user on how to edit their code to fix a problem. These
+ can be expressed as insertions, replacements, and removals of text.
+ The edits by default are relative to the zeroth range within the
+ rich_location, but optionally they can be expressed relative to
+ other locations (using various overloaded methods of the form
+ rich_location::add_fixit_*).
+
+ For example:
+
+ Example F: fix-it hint: insert_before
+ *************************************
+ ptr = arr[0];
+ ^~~~~~
+ &
+ This rich location has a single range (range 0) covering "arr[0]",
+ with the caret at the start. The rich location has a single
+ insertion fix-it hint, inserted before range 0, added via
+ richloc.add_fixit_insert_before ("&");
+
+ Example G: multiple fix-it hints: insert_before and insert_after
+ ****************************************************************
+ #define FN(ARG0, ARG1, ARG2) fn(ARG0, ARG1, ARG2)
+ ^~~~ ^~~~ ^~~~
+ ( ) ( ) ( )
+ This rich location has three ranges, covering "arg0", "arg1",
+ and "arg2", all with caret-printing enabled.
+ The rich location has 6 insertion fix-it hints: each arg
+ has a pair of insertion fix-it hints, suggesting wrapping
+ them with parentheses: one a '(' inserted before,
+ the other a ')' inserted after, added via
+ richloc.add_fixit_insert_before (LOC, "(");
+ and
+ richloc.add_fixit_insert_after (LOC, ")");
+
+ Example H: fix-it hint: removal
+ *******************************
+ struct s {int i};;
+ ^
+ -
+ This rich location has a single range at the stray trailing
+ semicolon, along with a single removal fix-it hint, covering
+ the same range, added via:
+ richloc.add_fixit_remove ();
+
+ Example I: fix-it hint: replace
+ *******************************
+ c = s.colour;
+ ^~~~~~
+ color
+ This rich location has a single range (range 0) covering "colour",
+ and a single "replace" fix-it hint, covering the same range,
+ added via
+ richloc.add_fixit_replace ("color");
+
+ Adding a fix-it hint can fail: for example, attempts to insert content
+ at the transition between two line maps may fail due to there being no
+ source_location (aka location_t) value to express the new location.
+
+ Attempts to add a fix-it hint within a macro expansion will fail.
+
+ We do not yet support newlines in fix-it text; attempts to do so will fail.
+
+ The rich_location API handles these failures gracefully, so that
+ diagnostics can attempt to add fix-it hints without each needing
+ extensive checking.
+
+ Fix-it hints within a rich_location are "atomic": if any hints can't
+ be applied, none of them will be (tracked by the m_seen_impossible_fixit
+ flag), and no fix-its hints will be displayed for that rich_location.
+ This implies that diagnostic messages need to be worded in such a way
+ that they make sense whether or not the fix-it hints are displayed,
+ or that richloc.seen_impossible_fixit_p () should be checked before
+ issuing the diagnostics. */
class rich_location
{
@@ -1347,9 +1578,6 @@ class rich_location
/* Constructing from a location. */
rich_location (line_maps *set, source_location loc);
- /* Constructing from a source_range. */
- rich_location (source_range src_range);
-
/* Destructor. */
~rich_location ();
@@ -1364,13 +1592,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);
@@ -1378,46 +1603,105 @@ class rich_location
override_column (int column);
/* Fix-it hints. */
+
+ /* Methods for adding insertion fix-it hints. */
+
+ /* Suggest inserting NEW_CONTENT immediately before the primary
+ range's start. */
+ void
+ add_fixit_insert_before (const char *new_content);
+
+ /* Suggest inserting NEW_CONTENT immediately before the start of WHERE. */
+ void
+ add_fixit_insert_before (source_location where,
+ const char *new_content);
+
+ /* Suggest inserting NEW_CONTENT immediately after the end of the primary
+ range. */
+ void
+ add_fixit_insert_after (const char *new_content);
+
+ /* Suggest inserting NEW_CONTENT immediately after the end of WHERE. */
+ void
+ add_fixit_insert_after (source_location where,
+ const char *new_content);
+
+ /* Methods for adding removal fix-it hints. */
+
+ /* Suggest removing the content covered by range 0. */
void
- add_fixit_insert (source_location where,
- const char *new_content);
+ add_fixit_remove ();
+ /* Suggest removing the content covered between the start and finish
+ of WHERE. */
+ void
+ add_fixit_remove (source_location where);
+
+ /* Suggest removing the content covered by SRC_RANGE. */
void
add_fixit_remove (source_range src_range);
+ /* Methods for adding "replace" fix-it hints. */
+
+ /* Suggest replacing the content covered by range 0 with NEW_CONTENT. */
+ void
+ add_fixit_replace (const char *new_content);
+
+ /* Suggest replacing the content between the start and finish of
+ WHERE with NEW_CONTENT. */
+ void
+ add_fixit_replace (source_location where,
+ const char *new_content);
+
+ /* Suggest replacing the content covered by SRC_RANGE with
+ NEW_CONTENT. */
void
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;
+ bool seen_impossible_fixit_p () const { return m_seen_impossible_fixit; }
+
+private:
+ bool reject_impossible_fixit (source_location where);
+ void stop_supporting_fixits ();
+ 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:
- unsigned int m_num_ranges;
- location_range m_ranges[MAX_RANGES];
+ line_maps *m_line_table;
+ 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;
};
class fixit_hint
{
public:
- enum kind {INSERT, REMOVE, REPLACE};
+ enum kind {INSERT, REPLACE};
virtual ~fixit_hint () {}
virtual enum kind get_kind () const = 0;
- virtual bool affects_line_p (const char *file, int line) = 0;
+ virtual bool affects_line_p (const char *file, int line) const = 0;
+ virtual source_location get_start_loc () const = 0;
+ virtual bool maybe_get_end_loc (source_location *out) const = 0;
+ /* Vfunc for consolidating successor fixits. */
+ virtual bool maybe_append_replace (line_maps *set,
+ source_range src_range,
+ const char *new_content) = 0;
};
class fixit_insert : public fixit_hint
@@ -1427,7 +1711,12 @@ class fixit_insert : public fixit_hint
const char *new_content);
~fixit_insert ();
enum kind get_kind () const { return INSERT; }
- bool affects_line_p (const char *file, int line);
+ bool affects_line_p (const char *file, int line) const;
+ source_location get_start_loc () const { return m_where; }
+ bool maybe_get_end_loc (source_location *) const { return false; }
+ bool maybe_append_replace (line_maps *set,
+ source_range src_range,
+ const char *new_content);
source_location get_location () const { return m_where; }
const char *get_string () const { return m_bytes; }
@@ -1439,21 +1728,6 @@ class fixit_insert : public fixit_hint
size_t m_len;
};
-class fixit_remove : public fixit_hint
-{
- public:
- fixit_remove (source_range src_range);
- ~fixit_remove () {}
-
- enum kind get_kind () const { return REMOVE; }
- bool affects_line_p (const char *file, int line);
-
- source_range get_range () const { return m_src_range; }
-
- private:
- source_range m_src_range;
-};
-
class fixit_replace : public fixit_hint
{
public:
@@ -1462,7 +1736,16 @@ class fixit_replace : public fixit_hint
~fixit_replace ();
enum kind get_kind () const { return REPLACE; }
- bool affects_line_p (const char *file, int line);
+ bool affects_line_p (const char *file, int line) const;
+ source_location get_start_loc () const { return m_src_range.m_start; }
+ bool maybe_get_end_loc (source_location *out) const
+ {
+ *out = m_src_range.m_finish;
+ return true;
+ }
+ bool maybe_append_replace (line_maps *set,
+ source_range src_range,
+ const char *new_content);
source_range get_range () const { return m_src_range; }
const char *get_string () const { return m_bytes; }