PR 62314: add ability to add fixit-hints to a diagnostic
This is the combination of two patches: [PATCH 01/02] PR/62314: add ability to add fixit-hints [PATCH 02/02] C FE: add fix-it hint for . vs -> gcc/ChangeLog: PR 62314 * diagnostic-show-locus.c (colorizer::set_fixit_hint): New. (class layout): Update comment (layout::print_any_fixits): New method. (layout::move_to_column): New method. (diagnostic_show_locus): Add call to layout.print_any_fixits. gcc/c/ChangeLog: PR 62314 * c-typeck.c (should_suggest_deref_p): New function. (build_component_ref): Special-case POINTER_TYPE when generating a "not a structure of union" error message, and suggest a "->" rather than a ".", providing a fix-it hint. gcc/testsuite/ChangeLog: PR 62314 * gcc.dg/fixits.c: New file. * gcc.dg/plugin/diagnostic-test-show-locus-ascii-bw.c (test_fixit_insert): New. (test_fixit_remove): New. (test_fixit_replace): New. * gcc.dg/plugin/diagnostic-test-show-locus-ascii-color.c (test_fixit_insert): New. (test_fixit_remove): New. (test_fixit_replace): New. * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c (test_show_locus): Add tests of rendering fixit hints. libcpp/ChangeLog: PR 62314 * include/line-map.h (source_range::intersects_line_p): New method. (rich_location::~rich_location): New. (rich_location::add_fixit_insert): New method. (rich_location::add_fixit_remove): New method. (rich_location::add_fixit_replace): New method. (rich_location::get_num_fixit_hints): New accessor. (rich_location::get_fixit_hint): New accessor. (rich_location::MAX_FIXIT_HINTS): New constant. (rich_location::m_num_fixit_hints): New field. (rich_location::m_fixit_hints): New field. (class fixit_hint): New class. (class fixit_insert): New class. (class fixit_remove): New class. (class fixit_replace): New class. * line-map.c (source_range::intersects_line_p): New method. (rich_location::rich_location): Add initialization of m_num_fixit_hints to both ctors. (rich_location::~rich_location): New. (rich_location::add_fixit_insert): New method. (rich_location::add_fixit_remove): New method. (rich_location::add_fixit_replace): New method. (fixit_insert::fixit_insert): New. (fixit_insert::~fixit_insert): New. (fixit_insert::affects_line_p): New. (fixit_remove::fixit_remove): New. (fixit_remove::affects_line_p): New. (fixit_replace::fixit_replace): New. (fixit_replace::~fixit_replace): New. (fixit_replace::affects_line_p): New. From-SVN: r230674
This commit is contained in:
parent
48a78aee68
commit
a87a86e1e9
|
@ -1,3 +1,12 @@
|
||||||
|
2015-11-20 David Malcolm <dmalcolm@redhat.com>
|
||||||
|
|
||||||
|
PR 62314
|
||||||
|
* diagnostic-show-locus.c (colorizer::set_fixit_hint): New.
|
||||||
|
(class layout): Update comment
|
||||||
|
(layout::print_any_fixits): New method.
|
||||||
|
(layout::move_to_column): New method.
|
||||||
|
(diagnostic_show_locus): Add call to layout.print_any_fixits.
|
||||||
|
|
||||||
2015-11-20 Jakub Jelinek <jakub@redhat.com>
|
2015-11-20 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
PR middle-end/68221
|
PR middle-end/68221
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
2015-11-20 David Malcolm <dmalcolm@redhat.com>
|
||||||
|
|
||||||
|
PR 62314
|
||||||
|
* c-typeck.c (should_suggest_deref_p): New function.
|
||||||
|
(build_component_ref): Special-case POINTER_TYPE when
|
||||||
|
generating a "not a structure of union" error message, and
|
||||||
|
suggest a "->" rather than a ".", providing a fix-it hint.
|
||||||
|
|
||||||
2015-11-19 David Malcolm <dmalcolm@redhat.com>
|
2015-11-19 David Malcolm <dmalcolm@redhat.com>
|
||||||
|
|
||||||
* c-typeck.c (lookup_field_fuzzy): Move determination of closest
|
* c-typeck.c (lookup_field_fuzzy): Move determination of closest
|
||||||
|
|
|
@ -2277,6 +2277,33 @@ lookup_field_fuzzy (tree type, tree component)
|
||||||
return find_closest_identifier (component, &candidates);
|
return find_closest_identifier (component, &candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Support function for build_component_ref's error-handling.
|
||||||
|
|
||||||
|
Given DATUM_TYPE, and "DATUM.COMPONENT", where DATUM is *not* a
|
||||||
|
struct or union, should we suggest "DATUM->COMPONENT" as a hint? */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
should_suggest_deref_p (tree datum_type)
|
||||||
|
{
|
||||||
|
/* We don't do it for Objective-C, since Objective-C 2.0 dot-syntax
|
||||||
|
allows "." for ptrs; we could be handling a failed attempt
|
||||||
|
to access a property. */
|
||||||
|
if (c_dialect_objc ())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Only suggest it for pointers... */
|
||||||
|
if (TREE_CODE (datum_type) != POINTER_TYPE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* ...to structs/unions. */
|
||||||
|
tree underlying_type = TREE_TYPE (datum_type);
|
||||||
|
enum tree_code code = TREE_CODE (underlying_type);
|
||||||
|
if (code == RECORD_TYPE || code == UNION_TYPE)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make an expression to refer to the COMPONENT field of structure or
|
/* Make an expression to refer to the COMPONENT field of structure or
|
||||||
union value DATUM. COMPONENT is an IDENTIFIER_NODE. LOC is the
|
union value DATUM. COMPONENT is an IDENTIFIER_NODE. LOC is the
|
||||||
location of the COMPONENT_REF. */
|
location of the COMPONENT_REF. */
|
||||||
|
@ -2369,6 +2396,18 @@ build_component_ref (location_t loc, tree datum, tree component)
|
||||||
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
else if (should_suggest_deref_p (type))
|
||||||
|
{
|
||||||
|
/* Special-case the error message for "ptr.field" for the case
|
||||||
|
where the user has confused "." vs "->". */
|
||||||
|
rich_location richloc (line_table, loc);
|
||||||
|
/* "loc" should be the "." token. */
|
||||||
|
richloc.add_fixit_replace (source_range::from_location (loc), "->");
|
||||||
|
error_at_rich_loc (&richloc,
|
||||||
|
"%qE is a pointer; did you mean to use %<->%>?",
|
||||||
|
datum);
|
||||||
|
return error_mark_node;
|
||||||
|
}
|
||||||
else if (code != ERROR_MARK)
|
else if (code != ERROR_MARK)
|
||||||
error_at (loc,
|
error_at (loc,
|
||||||
"request for member %qE in something not a structure or union",
|
"request for member %qE in something not a structure or union",
|
||||||
|
|
|
@ -78,6 +78,7 @@ class colorizer
|
||||||
|
|
||||||
void set_range (int range_idx) { set_state (range_idx); }
|
void set_range (int range_idx) { set_state (range_idx); }
|
||||||
void set_normal_text () { set_state (STATE_NORMAL_TEXT); }
|
void set_normal_text () { set_state (STATE_NORMAL_TEXT); }
|
||||||
|
void set_fixit_hint () { set_state (0); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void set_state (int state);
|
void set_state (int state);
|
||||||
|
@ -139,8 +140,8 @@ struct line_bounds
|
||||||
/* A class to control the overall layout when printing a diagnostic.
|
/* A class to control the overall layout when printing a diagnostic.
|
||||||
|
|
||||||
The layout is determined within the constructor.
|
The layout is determined within the constructor.
|
||||||
It is then printed by repeatedly calling the "print_source_line"
|
It is then printed by repeatedly calling the "print_source_line",
|
||||||
and "print_annotation_line" methods.
|
"print_annotation_line" and "print_any_fixits" methods.
|
||||||
|
|
||||||
We assume we have disjoint ranges. */
|
We assume we have disjoint ranges. */
|
||||||
|
|
||||||
|
@ -155,6 +156,7 @@ class layout
|
||||||
|
|
||||||
bool print_source_line (int row, line_bounds *lbounds_out);
|
bool print_source_line (int row, line_bounds *lbounds_out);
|
||||||
void print_annotation_line (int row, const line_bounds lbounds);
|
void print_annotation_line (int row, const line_bounds lbounds);
|
||||||
|
void print_any_fixits (int row, const rich_location *richloc);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool
|
bool
|
||||||
|
@ -168,6 +170,9 @@ class layout
|
||||||
get_x_bound_for_row (int row, int caret_column,
|
get_x_bound_for_row (int row, int caret_column,
|
||||||
int last_non_ws);
|
int last_non_ws);
|
||||||
|
|
||||||
|
void
|
||||||
|
move_to_column (int *column, int dest_column);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
diagnostic_context *m_context;
|
diagnostic_context *m_context;
|
||||||
pretty_printer *m_pp;
|
pretty_printer *m_pp;
|
||||||
|
@ -593,6 +598,73 @@ layout::print_annotation_line (int row, const line_bounds lbounds)
|
||||||
pp_newline (m_pp);
|
pp_newline (m_pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If there are any fixit hints on source line ROW within RICHLOC, print them.
|
||||||
|
They are printed in order, attempting to combine them onto lines, but
|
||||||
|
starting new lines if necessary. */
|
||||||
|
|
||||||
|
void
|
||||||
|
layout::print_any_fixits (int row, const rich_location *richloc)
|
||||||
|
{
|
||||||
|
int column = 0;
|
||||||
|
for (unsigned int i = 0; i < richloc->get_num_fixit_hints (); i++)
|
||||||
|
{
|
||||||
|
fixit_hint *hint = richloc->get_fixit_hint (i);
|
||||||
|
if (hint->affects_line_p (m_exploc.file, row))
|
||||||
|
{
|
||||||
|
/* For now we assume each fixit hint can only touch one line. */
|
||||||
|
switch (hint->get_kind ())
|
||||||
|
{
|
||||||
|
case fixit_hint::INSERT:
|
||||||
|
{
|
||||||
|
fixit_insert *insert = static_cast <fixit_insert *> (hint);
|
||||||
|
/* This assumes the insertion just affects one line. */
|
||||||
|
int start_column
|
||||||
|
= LOCATION_COLUMN (insert->get_location ());
|
||||||
|
move_to_column (&column, start_column);
|
||||||
|
m_colorizer.set_fixit_hint ();
|
||||||
|
pp_string (m_pp, insert->get_string ());
|
||||||
|
m_colorizer.set_normal_text ();
|
||||||
|
column += insert->get_length ();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case fixit_hint::REMOVE:
|
||||||
|
{
|
||||||
|
fixit_remove *remove = static_cast <fixit_remove *> (hint);
|
||||||
|
/* This assumes the removal just affects one line. */
|
||||||
|
source_range src_range = remove->get_range ();
|
||||||
|
int start_column = LOCATION_COLUMN (src_range.m_start);
|
||||||
|
int finish_column = LOCATION_COLUMN (src_range.m_finish);
|
||||||
|
move_to_column (&column, start_column);
|
||||||
|
for (int column = start_column; column <= finish_column; column++)
|
||||||
|
{
|
||||||
|
m_colorizer.set_fixit_hint ();
|
||||||
|
pp_character (m_pp, '-');
|
||||||
|
m_colorizer.set_normal_text ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case fixit_hint::REPLACE:
|
||||||
|
{
|
||||||
|
fixit_replace *replace = static_cast <fixit_replace *> (hint);
|
||||||
|
int start_column
|
||||||
|
= LOCATION_COLUMN (replace->get_range ().m_start);
|
||||||
|
move_to_column (&column, start_column);
|
||||||
|
m_colorizer.set_fixit_hint ();
|
||||||
|
pp_string (m_pp, replace->get_string ());
|
||||||
|
m_colorizer.set_normal_text ();
|
||||||
|
column += replace->get_length ();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
gcc_unreachable ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Return true if (ROW/COLUMN) is within a range of the layout.
|
/* Return true if (ROW/COLUMN) is within a range of the layout.
|
||||||
If it returns true, OUT_STATE is written to, with the
|
If it returns true, OUT_STATE is written to, with the
|
||||||
range index, and whether we should draw the caret at
|
range index, and whether we should draw the caret at
|
||||||
|
@ -675,6 +747,27 @@ layout::get_x_bound_for_row (int row, int caret_column,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Given *COLUMN as an x-coordinate, print spaces to position
|
||||||
|
successive output at DEST_COLUMN, printing a newline if necessary,
|
||||||
|
and updating *COLUMN. */
|
||||||
|
|
||||||
|
void
|
||||||
|
layout::move_to_column (int *column, int dest_column)
|
||||||
|
{
|
||||||
|
/* Start a new line if we need to. */
|
||||||
|
if (*column > dest_column)
|
||||||
|
{
|
||||||
|
pp_newline (m_pp);
|
||||||
|
*column = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*column < dest_column)
|
||||||
|
{
|
||||||
|
pp_space (m_pp);
|
||||||
|
(*column)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} /* End of anonymous namespace. */
|
} /* End of anonymous namespace. */
|
||||||
|
|
||||||
/* Print the physical source code corresponding to the location of
|
/* Print the physical source code corresponding to the location of
|
||||||
|
@ -704,11 +797,14 @@ diagnostic_show_locus (diagnostic_context * context,
|
||||||
row++)
|
row++)
|
||||||
{
|
{
|
||||||
/* Print the source line, followed by an annotation line
|
/* Print the source line, followed by an annotation line
|
||||||
consisting of any caret/underlines. If the source line can't
|
consisting of any caret/underlines, then any fixits.
|
||||||
be read, print nothing. */
|
If the source line can't be read, print nothing. */
|
||||||
line_bounds lbounds;
|
line_bounds lbounds;
|
||||||
if (layout.print_source_line (row, &lbounds))
|
if (layout.print_source_line (row, &lbounds))
|
||||||
layout.print_annotation_line (row, lbounds);
|
{
|
||||||
|
layout.print_annotation_line (row, lbounds);
|
||||||
|
layout.print_any_fixits (row, diagnostic->richloc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The closing scope here leads to the dtor for layout and thus
|
/* The closing scope here leads to the dtor for layout and thus
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
2015-11-20 David Malcolm <dmalcolm@redhat.com>
|
||||||
|
|
||||||
|
PR 62314
|
||||||
|
* gcc.dg/fixits.c: New file.
|
||||||
|
* gcc.dg/plugin/diagnostic-test-show-locus-ascii-bw.c
|
||||||
|
(test_fixit_insert): New.
|
||||||
|
(test_fixit_remove): New.
|
||||||
|
(test_fixit_replace): New.
|
||||||
|
* gcc.dg/plugin/diagnostic-test-show-locus-ascii-color.c
|
||||||
|
(test_fixit_insert): New.
|
||||||
|
(test_fixit_remove): New.
|
||||||
|
(test_fixit_replace): New.
|
||||||
|
* gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
|
||||||
|
(test_show_locus): Add tests of rendering fixit hints.
|
||||||
|
|
||||||
2015-11-20 Jakub Jelinek <jakub@redhat.com>
|
2015-11-20 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
PR middle-end/68339
|
PR middle-end/68339
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/* { dg-do compile } */
|
||||||
|
/* { dg-options "-fdiagnostics-show-caret" } */
|
||||||
|
|
||||||
|
struct foo { int x; };
|
||||||
|
union u { int x; };
|
||||||
|
|
||||||
|
/* Verify that we issue a hint for "." used with a ptr to a struct. */
|
||||||
|
|
||||||
|
int test_1 (struct foo *ptr)
|
||||||
|
{
|
||||||
|
return ptr.x; /* { dg-error "'ptr' is a pointer; did you mean to use '->'?" } */
|
||||||
|
/* { dg-begin-multiline-output "" }
|
||||||
|
return ptr.x;
|
||||||
|
^
|
||||||
|
->
|
||||||
|
{ dg-end-multiline-output "" } */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Likewise for a ptr to a union. */
|
||||||
|
|
||||||
|
int test_2 (union u *ptr)
|
||||||
|
{
|
||||||
|
return ptr.x; /* { dg-error "'ptr' is a pointer; did you mean to use '->'?" } */
|
||||||
|
/* { dg-begin-multiline-output "" }
|
||||||
|
return ptr.x;
|
||||||
|
^
|
||||||
|
->
|
||||||
|
{ dg-end-multiline-output "" } */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify that we don't issue a hint for a ptr to something that isn't a
|
||||||
|
struct or union. */
|
||||||
|
|
||||||
|
int test_3 (void **ptr)
|
||||||
|
{
|
||||||
|
return ptr.x; /* { dg-error "request for member 'x' in something not a structure or union" } */
|
||||||
|
/* { dg-begin-multiline-output "" }
|
||||||
|
return ptr.x;
|
||||||
|
^
|
||||||
|
{ dg-end-multiline-output "" } */
|
||||||
|
}
|
|
@ -147,3 +147,46 @@ void test_caret_on_leading_whitespace (void)
|
||||||
{ dg-end-multiline-output "" } */
|
{ dg-end-multiline-output "" } */
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Unit test for rendering of insertion fixit hints
|
||||||
|
(example taken from PR 62316). */
|
||||||
|
|
||||||
|
void test_fixit_insert (void)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
int a[2][2] = { 0, 1 , 2, 3 }; /* { dg-warning "insertion hints" } */
|
||||||
|
/* { dg-begin-multiline-output "" }
|
||||||
|
int a[2][2] = { 0, 1 , 2, 3 };
|
||||||
|
^~~~
|
||||||
|
{ }
|
||||||
|
{ dg-end-multiline-output "" } */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unit test for rendering of "remove" fixit hints. */
|
||||||
|
|
||||||
|
void test_fixit_remove (void)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
int a;; /* { dg-warning "example of a removal hint" } */
|
||||||
|
/* { dg-begin-multiline-output "" }
|
||||||
|
int a;;
|
||||||
|
^
|
||||||
|
-
|
||||||
|
{ dg-end-multiline-output "" } */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unit test for rendering of "replace" fixit hints. */
|
||||||
|
|
||||||
|
void test_fixit_replace (void)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
gtk_widget_showall (dlg); /* { dg-warning "example of a replacement hint" } */
|
||||||
|
/* { dg-begin-multiline-output "" }
|
||||||
|
gtk_widget_showall (dlg);
|
||||||
|
^~~~~~~~~~~~~~~~~~
|
||||||
|
gtk_widget_show_all
|
||||||
|
{ dg-end-multiline-output "" } */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -156,3 +156,46 @@ void test_caret_on_leading_whitespace (void)
|
||||||
{ dg-end-multiline-output "" } */
|
{ dg-end-multiline-output "" } */
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Unit test for rendering of insertion fixit hints
|
||||||
|
(example taken from PR 62316). */
|
||||||
|
|
||||||
|
void test_fixit_insert (void)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
int a[2][2] = { 0, 1 , 2, 3 }; /* { dg-warning "insertion hints" } */
|
||||||
|
/* { dg-begin-multiline-output "" }
|
||||||
|
int a[2][2] = { [01;35m[K0, 1[m[K , 2, 3 };
|
||||||
|
[01;35m[K^~~~
|
||||||
|
{[m[K [01;35m[K}[m[K
|
||||||
|
{ dg-end-multiline-output "" } */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unit test for rendering of "remove" fixit hints. */
|
||||||
|
|
||||||
|
void test_fixit_remove (void)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
int a;; /* { dg-warning "example of a removal hint" } */
|
||||||
|
/* { dg-begin-multiline-output "" }
|
||||||
|
int a;[01;35m[K;[m[K
|
||||||
|
[01;35m[K^
|
||||||
|
-[m[K
|
||||||
|
{ dg-end-multiline-output "" } */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unit test for rendering of "replace" fixit hints. */
|
||||||
|
|
||||||
|
void test_fixit_replace (void)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
gtk_widget_showall (dlg); /* { dg-warning "example of a replacement hint" } */
|
||||||
|
/* { dg-begin-multiline-output "" }
|
||||||
|
[01;35m[Kgtk_widget_showall[m[K (dlg);
|
||||||
|
[01;35m[K^~~~~~~~~~~~~~~~~~
|
||||||
|
gtk_widget_show_all[m[K
|
||||||
|
{ dg-end-multiline-output "" } */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -258,6 +258,41 @@ test_show_locus (function *fun)
|
||||||
global_dc->caret_chars[1] = '^';
|
global_dc->caret_chars[1] = '^';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tests of rendering fixit hints. */
|
||||||
|
if (0 == strcmp (fnname, "test_fixit_insert"))
|
||||||
|
{
|
||||||
|
const int line = fnstart_line + 2;
|
||||||
|
source_range src_range;
|
||||||
|
src_range.m_start = get_loc (line, 19);
|
||||||
|
src_range.m_finish = get_loc (line, 22);
|
||||||
|
rich_location richloc (src_range);
|
||||||
|
richloc.add_fixit_insert (src_range.m_start, "{");
|
||||||
|
richloc.add_fixit_insert (get_loc (line, 23), "}");
|
||||||
|
warning_at_rich_loc (&richloc, 0, "example of insertion hints");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == strcmp (fnname, "test_fixit_remove"))
|
||||||
|
{
|
||||||
|
const int line = fnstart_line + 2;
|
||||||
|
source_range src_range;
|
||||||
|
src_range.m_start = get_loc (line, 8);
|
||||||
|
src_range.m_finish = get_loc (line, 8);
|
||||||
|
rich_location richloc (src_range);
|
||||||
|
richloc.add_fixit_remove (src_range);
|
||||||
|
warning_at_rich_loc (&richloc, 0, "example of a removal hint");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == strcmp (fnname, "test_fixit_replace"))
|
||||||
|
{
|
||||||
|
const int line = fnstart_line + 2;
|
||||||
|
source_range src_range;
|
||||||
|
src_range.m_start = get_loc (line, 2);
|
||||||
|
src_range.m_finish = get_loc (line, 19);
|
||||||
|
rich_location richloc (src_range);
|
||||||
|
richloc.add_fixit_replace (src_range, "gtk_widget_show_all");
|
||||||
|
warning_at_rich_loc (&richloc, 0, "example of a replacement hint");
|
||||||
|
}
|
||||||
|
|
||||||
/* Example of two carets where both carets appear to have an off-by-one
|
/* Example of two carets where both carets appear to have an off-by-one
|
||||||
error appearing one column early.
|
error appearing one column early.
|
||||||
Seen with gfortran.dg/associate_5.f03.
|
Seen with gfortran.dg/associate_5.f03.
|
||||||
|
|
|
@ -1,3 +1,37 @@
|
||||||
|
2015-11-20 David Malcolm <dmalcolm@redhat.com>
|
||||||
|
|
||||||
|
PR 62314
|
||||||
|
* include/line-map.h (source_range::intersects_line_p): New
|
||||||
|
method.
|
||||||
|
(rich_location::~rich_location): New.
|
||||||
|
(rich_location::add_fixit_insert): New method.
|
||||||
|
(rich_location::add_fixit_remove): New method.
|
||||||
|
(rich_location::add_fixit_replace): New method.
|
||||||
|
(rich_location::get_num_fixit_hints): New accessor.
|
||||||
|
(rich_location::get_fixit_hint): New accessor.
|
||||||
|
(rich_location::MAX_FIXIT_HINTS): New constant.
|
||||||
|
(rich_location::m_num_fixit_hints): New field.
|
||||||
|
(rich_location::m_fixit_hints): New field.
|
||||||
|
(class fixit_hint): New class.
|
||||||
|
(class fixit_insert): New class.
|
||||||
|
(class fixit_remove): New class.
|
||||||
|
(class fixit_replace): New class.
|
||||||
|
* line-map.c (source_range::intersects_line_p): New method.
|
||||||
|
(rich_location::rich_location): Add initialization of
|
||||||
|
m_num_fixit_hints to both ctors.
|
||||||
|
(rich_location::~rich_location): New.
|
||||||
|
(rich_location::add_fixit_insert): New method.
|
||||||
|
(rich_location::add_fixit_remove): New method.
|
||||||
|
(rich_location::add_fixit_replace): New method.
|
||||||
|
(fixit_insert::fixit_insert): New.
|
||||||
|
(fixit_insert::~fixit_insert): New.
|
||||||
|
(fixit_insert::affects_line_p): New.
|
||||||
|
(fixit_remove::fixit_remove): New.
|
||||||
|
(fixit_remove::affects_line_p): New.
|
||||||
|
(fixit_replace::fixit_replace): New.
|
||||||
|
(fixit_replace::~fixit_replace): New.
|
||||||
|
(fixit_replace::affects_line_p): New.
|
||||||
|
|
||||||
2015-11-19 Jakub Jelinek <jakub@redhat.com>
|
2015-11-19 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
PR preprocessor/60736
|
PR preprocessor/60736
|
||||||
|
|
|
@ -299,6 +299,9 @@ struct GTY(()) source_range
|
||||||
result.m_finish = loc;
|
result.m_finish = loc;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is there any part of this range on the given line? */
|
||||||
|
bool intersects_line_p (const char *file, int line) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Memory allocation function typedef. Works like xrealloc. */
|
/* Memory allocation function typedef. Works like xrealloc. */
|
||||||
|
@ -1267,6 +1270,11 @@ struct location_range
|
||||||
expanded_location m_caret;
|
expanded_location m_caret;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class fixit_hint;
|
||||||
|
class fixit_insert;
|
||||||
|
class fixit_remove;
|
||||||
|
class fixit_replace;
|
||||||
|
|
||||||
/* A "rich" source code location, for use when printing diagnostics.
|
/* A "rich" source code location, for use when printing diagnostics.
|
||||||
A rich_location has one or more ranges, each optionally with
|
A rich_location has one or more ranges, each optionally with
|
||||||
a caret. Typically the zeroth range has a caret; other ranges
|
a caret. Typically the zeroth range has a caret; other ranges
|
||||||
|
@ -1349,6 +1357,9 @@ class rich_location
|
||||||
/* Constructing from a source_range. */
|
/* Constructing from a source_range. */
|
||||||
rich_location (source_range src_range);
|
rich_location (source_range src_range);
|
||||||
|
|
||||||
|
/* Destructor. */
|
||||||
|
~rich_location ();
|
||||||
|
|
||||||
/* Accessors. */
|
/* Accessors. */
|
||||||
source_location get_loc () const { return m_loc; }
|
source_location get_loc () const { return m_loc; }
|
||||||
|
|
||||||
|
@ -1381,8 +1392,24 @@ class rich_location
|
||||||
void
|
void
|
||||||
override_column (int column);
|
override_column (int column);
|
||||||
|
|
||||||
|
/* Fix-it hints. */
|
||||||
|
void
|
||||||
|
add_fixit_insert (source_location where,
|
||||||
|
const char *new_content);
|
||||||
|
|
||||||
|
void
|
||||||
|
add_fixit_remove (source_range src_range);
|
||||||
|
|
||||||
|
void
|
||||||
|
add_fixit_replace (source_range src_range,
|
||||||
|
const char *new_content);
|
||||||
|
|
||||||
|
unsigned int get_num_fixit_hints () const { return m_num_fixit_hints; }
|
||||||
|
fixit_hint *get_fixit_hint (int idx) const { return m_fixit_hints[idx]; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const int MAX_RANGES = 3;
|
static const int MAX_RANGES = 3;
|
||||||
|
static const int MAX_FIXIT_HINTS = 2;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
source_location m_loc;
|
source_location m_loc;
|
||||||
|
@ -1392,8 +1419,77 @@ protected:
|
||||||
|
|
||||||
bool m_have_expanded_location;
|
bool m_have_expanded_location;
|
||||||
expanded_location m_expanded_location;
|
expanded_location m_expanded_location;
|
||||||
|
|
||||||
|
unsigned int m_num_fixit_hints;
|
||||||
|
fixit_hint *m_fixit_hints[MAX_FIXIT_HINTS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class fixit_hint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum kind {INSERT, REMOVE, REPLACE};
|
||||||
|
|
||||||
|
virtual ~fixit_hint () {}
|
||||||
|
|
||||||
|
virtual enum kind get_kind () const = 0;
|
||||||
|
virtual bool affects_line_p (const char *file, int line) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class fixit_insert : public fixit_hint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
fixit_insert (source_location where,
|
||||||
|
const char *new_content);
|
||||||
|
~fixit_insert ();
|
||||||
|
enum kind get_kind () const { return INSERT; }
|
||||||
|
bool affects_line_p (const char *file, int line);
|
||||||
|
|
||||||
|
source_location get_location () const { return m_where; }
|
||||||
|
const char *get_string () const { return m_bytes; }
|
||||||
|
size_t get_length () const { return m_len; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
source_location m_where;
|
||||||
|
char *m_bytes;
|
||||||
|
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:
|
||||||
|
fixit_replace (source_range src_range,
|
||||||
|
const char *new_content);
|
||||||
|
~fixit_replace ();
|
||||||
|
|
||||||
|
enum kind get_kind () const { return REPLACE; }
|
||||||
|
bool affects_line_p (const char *file, int line);
|
||||||
|
|
||||||
|
source_range get_range () const { return m_src_range; }
|
||||||
|
const char *get_string () const { return m_bytes; }
|
||||||
|
size_t get_length () const { return m_len; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
source_range m_src_range;
|
||||||
|
char *m_bytes;
|
||||||
|
size_t m_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* This is enum is used by the function linemap_resolve_location
|
/* This is enum is used by the function linemap_resolve_location
|
||||||
below. The meaning of the values is explained in the comment of
|
below. The meaning of the values is explained in the comment of
|
||||||
that function. */
|
that function. */
|
||||||
|
|
|
@ -1947,6 +1947,28 @@ line_table_dump (FILE *stream, struct line_maps *set, unsigned int num_ordinary,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* struct source_range. */
|
||||||
|
|
||||||
|
/* Is there any part of this range on the given line? */
|
||||||
|
|
||||||
|
bool
|
||||||
|
source_range::intersects_line_p (const char *file, int line) const
|
||||||
|
{
|
||||||
|
expanded_location exploc_start
|
||||||
|
= linemap_client_expand_location_to_spelling_point (m_start);
|
||||||
|
if (file != exploc_start.file)
|
||||||
|
return false;
|
||||||
|
if (line < exploc_start.line)
|
||||||
|
return false;
|
||||||
|
expanded_location exploc_finish
|
||||||
|
= linemap_client_expand_location_to_spelling_point (m_finish);
|
||||||
|
if (file != exploc_finish.file)
|
||||||
|
return false;
|
||||||
|
if (line > exploc_finish.line)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* class rich_location. */
|
/* class rich_location. */
|
||||||
|
|
||||||
/* Construct a rich_location with location LOC as its initial range. */
|
/* Construct a rich_location with location LOC as its initial range. */
|
||||||
|
@ -1954,7 +1976,8 @@ line_table_dump (FILE *stream, struct line_maps *set, unsigned int num_ordinary,
|
||||||
rich_location::rich_location (line_maps *set, source_location loc) :
|
rich_location::rich_location (line_maps *set, source_location loc) :
|
||||||
m_loc (loc),
|
m_loc (loc),
|
||||||
m_num_ranges (0),
|
m_num_ranges (0),
|
||||||
m_have_expanded_location (false)
|
m_have_expanded_location (false),
|
||||||
|
m_num_fixit_hints (0)
|
||||||
{
|
{
|
||||||
/* Set up the 0th range, extracting any range from LOC. */
|
/* Set up the 0th range, extracting any range from LOC. */
|
||||||
source_range src_range = get_range_from_loc (set, loc);
|
source_range src_range = get_range_from_loc (set, loc);
|
||||||
|
@ -1968,12 +1991,21 @@ rich_location::rich_location (line_maps *set, source_location loc) :
|
||||||
rich_location::rich_location (source_range src_range)
|
rich_location::rich_location (source_range src_range)
|
||||||
: m_loc (src_range.m_start),
|
: m_loc (src_range.m_start),
|
||||||
m_num_ranges (0),
|
m_num_ranges (0),
|
||||||
m_have_expanded_location (false)
|
m_have_expanded_location (false),
|
||||||
|
m_num_fixit_hints (0)
|
||||||
{
|
{
|
||||||
/* Set up the 0th range: */
|
/* Set up the 0th range: */
|
||||||
add_range (src_range, true);
|
add_range (src_range, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The destructor for class rich_location. */
|
||||||
|
|
||||||
|
rich_location::~rich_location ()
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < m_num_fixit_hints; i++)
|
||||||
|
delete m_fixit_hints[i];
|
||||||
|
}
|
||||||
|
|
||||||
/* Get an expanded_location for this rich_location's primary
|
/* Get an expanded_location for this rich_location's primary
|
||||||
location. */
|
location. */
|
||||||
|
|
||||||
|
@ -2077,3 +2109,103 @@ rich_location::set_range (unsigned int idx, source_range src_range,
|
||||||
m_have_expanded_location = false;
|
m_have_expanded_location = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add a fixit-hint, suggesting insertion of NEW_CONTENT
|
||||||
|
at WHERE. */
|
||||||
|
|
||||||
|
void
|
||||||
|
rich_location::add_fixit_insert (source_location where,
|
||||||
|
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 a fixit-hint, suggesting removal of the content at
|
||||||
|
SRC_RANGE. */
|
||||||
|
|
||||||
|
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 a fixit-hint, suggesting replacement of the content at
|
||||||
|
SRC_RANGE with NEW_CONTENT. */
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* class fixit_insert. */
|
||||||
|
|
||||||
|
fixit_insert::fixit_insert (source_location where,
|
||||||
|
const char *new_content)
|
||||||
|
: m_where (where),
|
||||||
|
m_bytes (xstrdup (new_content)),
|
||||||
|
m_len (strlen (new_content))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fixit_insert::~fixit_insert ()
|
||||||
|
{
|
||||||
|
free (m_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implementation of fixit_hint::affects_line_p for fixit_insert. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
fixit_insert::affects_line_p (const char *file, int line)
|
||||||
|
{
|
||||||
|
expanded_location exploc
|
||||||
|
= linemap_client_expand_location_to_spelling_point (m_where);
|
||||||
|
if (file == exploc.file)
|
||||||
|
if (line == exploc.line)
|
||||||
|
return true;
|
||||||
|
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. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
fixit_remove::affects_line_p (const char *file, int line)
|
||||||
|
{
|
||||||
|
return m_src_range.intersects_line_p (file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* class fixit_replace. */
|
||||||
|
|
||||||
|
fixit_replace::fixit_replace (source_range src_range,
|
||||||
|
const char *new_content)
|
||||||
|
: m_src_range (src_range),
|
||||||
|
m_bytes (xstrdup (new_content)),
|
||||||
|
m_len (strlen (new_content))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fixit_replace::~fixit_replace ()
|
||||||
|
{
|
||||||
|
free (m_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implementation of fixit_hint::affects_line_p for fixit_replace. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
fixit_replace::affects_line_p (const char *file, int line)
|
||||||
|
{
|
||||||
|
return m_src_range.intersects_line_p (file, line);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue