aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/c/ChangeLog8
-rw-r--r--gcc/c/c-typeck.c39
-rw-r--r--gcc/diagnostic-show-locus.c106
-rw-r--r--gcc/testsuite/ChangeLog15
-rw-r--r--gcc/testsuite/gcc.dg/fixits.c41
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c43
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c43
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c35
9 files changed, 334 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 4d3e5b3..54ae922 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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>
PR middle-end/68221
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 9399053..96c5823 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -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>
* c-typeck.c (lookup_field_fuzzy): Move determination of closest
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 9284bfc..741c75c 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -2277,6 +2277,33 @@ lookup_field_fuzzy (tree type, tree component)
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
union value DATUM. COMPONENT is an IDENTIFIER_NODE. LOC is the
location of the COMPONENT_REF. */
@@ -2369,6 +2396,18 @@ build_component_ref (location_t loc, tree datum, tree component)
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)
error_at (loc,
"request for member %qE in something not a structure or union",
diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index 22203cd..9e51b95 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -78,6 +78,7 @@ class colorizer
void set_range (int range_idx) { set_state (range_idx); }
void set_normal_text () { set_state (STATE_NORMAL_TEXT); }
+ void set_fixit_hint () { set_state (0); }
private:
void set_state (int state);
@@ -139,8 +140,8 @@ struct line_bounds
/* A class to control the overall layout when printing a diagnostic.
The layout is determined within the constructor.
- It is then printed by repeatedly calling the "print_source_line"
- and "print_annotation_line" methods.
+ It is then printed by repeatedly calling the "print_source_line",
+ "print_annotation_line" and "print_any_fixits" methods.
We assume we have disjoint ranges. */
@@ -155,6 +156,7 @@ class layout
bool print_source_line (int row, line_bounds *lbounds_out);
void print_annotation_line (int row, const line_bounds lbounds);
+ void print_any_fixits (int row, const rich_location *richloc);
private:
bool
@@ -168,6 +170,9 @@ class layout
get_x_bound_for_row (int row, int caret_column,
int last_non_ws);
+ void
+ move_to_column (int *column, int dest_column);
+
private:
diagnostic_context *m_context;
pretty_printer *m_pp;
@@ -593,6 +598,73 @@ layout::print_annotation_line (int row, const line_bounds lbounds)
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.
If it returns true, OUT_STATE is written to, with the
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;
}
+/* 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. */
/* Print the physical source code corresponding to the location of
@@ -704,11 +797,14 @@ diagnostic_show_locus (diagnostic_context * context,
row++)
{
/* Print the source line, followed by an annotation line
- consisting of any caret/underlines. If the source line can't
- be read, print nothing. */
+ consisting of any caret/underlines, then any fixits.
+ If the source line can't be read, print nothing. */
line_bounds 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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index de70aae..84659a55 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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>
PR middle-end/68339
diff --git a/gcc/testsuite/gcc.dg/fixits.c b/gcc/testsuite/gcc.dg/fixits.c
new file mode 100644
index 0000000..06c9995
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/fixits.c
@@ -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 "" } */
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
index a4b16da..44b47e0 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
@@ -147,3 +147,46 @@ void test_caret_on_leading_whitespace (void)
{ dg-end-multiline-output "" } */
#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
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
index 47639b2..199e0b2 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
@@ -156,3 +156,46 @@ void test_caret_on_leading_whitespace (void)
{ dg-end-multiline-output "" } */
#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
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
index 158c612..7ff2cff 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
@@ -258,6 +258,41 @@ test_show_locus (function *fun)
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
error appearing one column early.
Seen with gfortran.dg/associate_5.f03.