diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/c/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/c/c-typeck.c | 39 | ||||
-rw-r--r-- | gcc/diagnostic-show-locus.c | 106 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/fixits.c | 41 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c | 43 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c | 43 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c | 35 |
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] = { [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 +} 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. |