diff options
author | dmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-09-13 16:08:59 +0000 |
---|---|---|
committer | dmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-09-13 16:08:59 +0000 |
commit | 68ef907cd5704cca533b3cdf6db112b973e52b74 (patch) | |
tree | f49ba2c7c6f8a048ee6c7db0ecc48ec1bbe3d897 | |
parent | f339fac19fcd0eb730be8b0bee8f0c5e178ffb8c (diff) | |
download | gcc-68ef907cd5704cca533b3cdf6db112b973e52b74.tar.gz |
fix-it hints: insert_before vs insert_after
The API for adding "insert text" fix-it hints was unclear
about exactly where the text should be inserted relative
to the given insertion point.
This patch clarifies things by renaming the pertinent methods from
richloc.add_fixit_insert
to
richloc.add_fixit_insert_before
and adding:
richloc.add_fixit_insert_after
The latter allows us to consolidate some failure-handling into
class rich_location, rather than having to have every such diagnostic
check for it.
The patch also adds a description of how fix-it hints work to the
comment for class rich_location within libcpp/include/line-map.h.
gcc/c-family/ChangeLog:
* c-common.c (warn_logical_not_parentheses): Replace
rich_location::add_fixit_insert calls with add_fixit_insert_before
and add_fixit_insert_after, eliminating the "next_loc" calculation.
gcc/c/ChangeLog:
* c-parser.c (c_parser_declaration_or_fndef): Update for renaming
of add_fixit_insert to add_fixit_insert_before.
gcc/cp/ChangeLog:
* parser.c (cp_parser_class_specifier_1): Update for renaming of
add_fixit_insert to add_fixit_insert_before.
(cp_parser_class_head): Likewise.
gcc/ChangeLog:
* diagnostic-show-locus.c (selftest::test_one_liner_fixit_insert):
Rename to...
(selftest::test_one_liner_fixit_insert_before): ...this, and update
for renaming of add_fixit_insert to add_fixit_insert_before.
(selftest::test_one_liner_fixit_insert_after): New function.
(selftest::test_one_liner_fixit_validation_adhoc_locations):
Update for renaming of add_fixit_insert to
add_fixit_insert_before.
(selftest::test_one_liner_many_fixits): Likewise.
(selftest::test_diagnostic_show_locus_one_liner): Update for
renaming, call new test function.
(selftest::test_diagnostic_show_locus_fixit_lines): Update for
renaming of add_fixit_insert to add_fixit_insert_before.
(selftest::test_fixit_consolidation): Likewise.
* diagnostic.c (selftest::test_print_parseable_fixits_insert):
Likewise.
* edit-context.c (selftest::test_applying_fixits_insert): Rename
to...
(selftest::test_applying_fixits_insert_before): ...this.
(selftest::test_applying_fixits_insert): Update for renaming of
add_fixit_insert to add_fixit_insert_before.
(selftest::test_applying_fixits_insert_after): New function.
(selftest::test_applying_fixits_insert_after_at_line_end): New
function.
(selftest::test_applying_fixits_insert_after_failure): New
function.
(selftest::test_applying_fixits_multiple): Update for renaming of
add_fixit_insert to add_fixit_insert_before.
(selftest::change_line): Likewise.
(selftest::test_applying_fixits_unreadable_file): Likewise.
(selftest::test_applying_fixits_line_out_of_range): Likewise.
(selftest::test_applying_fixits_column_validation): Likewise.
(selftest::test_applying_fixits_column_validation): Likewise.
(selftest::edit_context_c_tests): Update for renamed test
function; call new test functions.
gcc/testsuite/ChangeLog:
* gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
(test_show_locus): Replace rich_location::add_fixit_insert calls
with add_fixit_insert_before and add_fixit_insert_after.
libcpp/ChangeLog:
* include/line-map.h (class rich_location): Add description of
fix-it hints to leading comment.
(rich_location::add_fixit_insert): Rename both overloaded methods
to..
(rich_location::add_fixit_insert_before): ...this, updating their
comments.
(rich_location::add_fixit_insert_after): Two new overloaded
methods.
(rich_location::stop_supporting_fixits): New method.
* line-map.c (rich_location::add_fixit_insert): Rename both
overloaded methods to..
(rich_location::add_fixit_insert_before): ...this, updating their
comments.
(rich_location::add_fixit_insert_after): Two new methods.
(rich_location::reject_impossible_fixit): Split out
failure-handling into...
(rich_location::stop_supporting_fixits): New method.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@240115 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 38 | ||||
-rw-r--r-- | gcc/c-family/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/c-family/c-common.c | 7 | ||||
-rw-r--r-- | gcc/c/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/c/c-parser.c | 6 | ||||
-rw-r--r-- | gcc/cp/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cp/parser.c | 5 | ||||
-rw-r--r-- | gcc/diagnostic-show-locus.c | 42 | ||||
-rw-r--r-- | gcc/diagnostic.c | 2 | ||||
-rw-r--r-- | gcc/edit-context.c | 163 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c | 4 | ||||
-rw-r--r-- | libcpp/ChangeLog | 20 | ||||
-rw-r--r-- | libcpp/include/line-map.h | 101 | ||||
-rw-r--r-- | libcpp/line-map.c | 65 |
15 files changed, 423 insertions, 53 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 58ab8355a75..93c90ce0785 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,41 @@ +2016-09-13 David Malcolm <dmalcolm@redhat.com> + + * diagnostic-show-locus.c (selftest::test_one_liner_fixit_insert): + Rename to... + (selftest::test_one_liner_fixit_insert_before): ...this, and update + for renaming of add_fixit_insert to add_fixit_insert_before. + (selftest::test_one_liner_fixit_insert_after): New function. + (selftest::test_one_liner_fixit_validation_adhoc_locations): + Update for renaming of add_fixit_insert to + add_fixit_insert_before. + (selftest::test_one_liner_many_fixits): Likewise. + (selftest::test_diagnostic_show_locus_one_liner): Update for + renaming, call new test function. + (selftest::test_diagnostic_show_locus_fixit_lines): Update for + renaming of add_fixit_insert to add_fixit_insert_before. + (selftest::test_fixit_consolidation): Likewise. + * diagnostic.c (selftest::test_print_parseable_fixits_insert): + Likewise. + * edit-context.c (selftest::test_applying_fixits_insert): Rename + to... + (selftest::test_applying_fixits_insert_before): ...this. + (selftest::test_applying_fixits_insert): Update for renaming of + add_fixit_insert to add_fixit_insert_before. + (selftest::test_applying_fixits_insert_after): New function. + (selftest::test_applying_fixits_insert_after_at_line_end): New + function. + (selftest::test_applying_fixits_insert_after_failure): New + function. + (selftest::test_applying_fixits_multiple): Update for renaming of + add_fixit_insert to add_fixit_insert_before. + (selftest::change_line): Likewise. + (selftest::test_applying_fixits_unreadable_file): Likewise. + (selftest::test_applying_fixits_line_out_of_range): Likewise. + (selftest::test_applying_fixits_column_validation): Likewise. + (selftest::test_applying_fixits_column_validation): Likewise. + (selftest::edit_context_c_tests): Update for renamed test + function; call new test functions. + 2016-09-13 Pat Haugen <pthaugen@us.ibm.com> PR tree-optimization/77536 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index d8f1808e699..5a2cbbef416 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2016-09-13 David Malcolm <dmalcolm@redhat.com> + + * c-common.c (warn_logical_not_parentheses): Replace + rich_location::add_fixit_insert calls with add_fixit_insert_before + and add_fixit_insert_after, eliminating the "next_loc" calculation. + 2016-09-13 Jason Merrill <jason@redhat.com> Tom de Vries <tom@codesourcery.com> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 73bd43f8703..1132a031384 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -1544,11 +1544,8 @@ warn_logical_not_parentheses (location_t location, enum tree_code code, { location_t lhs_loc = EXPR_LOCATION (lhs); rich_location richloc (line_table, lhs_loc); - richloc.add_fixit_insert (lhs_loc, "("); - location_t finish = get_finish (lhs_loc); - location_t next_loc - = linemap_position_for_loc_and_offset (line_table, finish, 1); - richloc.add_fixit_insert (next_loc, ")"); + richloc.add_fixit_insert_before (lhs_loc, "("); + richloc.add_fixit_insert_after (lhs_loc, ")"); inform_at_rich_loc (&richloc, "add parentheses around left hand side " "expression to silence this warning"); } diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index c8563749939..4a9881d351a 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,8 @@ +2016-09-13 David Malcolm <dmalcolm@redhat.com> + + * c-parser.c (c_parser_declaration_or_fndef): Update for renaming + of add_fixit_insert to add_fixit_insert_before. + 2016-09-13 Marek Polacek <polacek@redhat.com> * c-typeck.c (build_unary_op): Rename FLAG parameter to NOCONVERT. Use diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index a3044244f6c..e71c0d5b9b5 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1685,7 +1685,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, if (tag_exists_p (RECORD_TYPE, name)) { /* This is not C++ with its implicit typedef. */ - richloc.add_fixit_insert ("struct "); + richloc.add_fixit_insert_before ("struct "); error_at_rich_loc (&richloc, "unknown type name %qE;" " use %<struct%> keyword to refer to the type", @@ -1693,7 +1693,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, } else if (tag_exists_p (UNION_TYPE, name)) { - richloc.add_fixit_insert ("union "); + richloc.add_fixit_insert_before ("union "); error_at_rich_loc (&richloc, "unknown type name %qE;" " use %<union%> keyword to refer to the type", @@ -1701,7 +1701,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, } else if (tag_exists_p (ENUMERAL_TYPE, name)) { - richloc.add_fixit_insert ("enum "); + richloc.add_fixit_insert_before ("enum "); error_at_rich_loc (&richloc, "unknown type name %qE;" " use %<enum%> keyword to refer to the type", diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f572c851b62..79691bf6892 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2016-09-13 David Malcolm <dmalcolm@redhat.com> + + * parser.c (cp_parser_class_specifier_1): Update for renaming of + add_fixit_insert to add_fixit_insert_before. + (cp_parser_class_head): Likewise. + 2016-09-12 Bernd Edlinger <bernd.edlinger@hotmail.de> PR c++/77496 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index ca9f8b9761a..73a37814b59 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -21594,7 +21594,7 @@ cp_parser_class_specifier_1 (cp_parser* parser) next_loc = linemap_position_for_loc_and_offset (line_table, loc, 1); rich_location richloc (line_table, next_loc); - richloc.add_fixit_insert (next_loc, ";"); + richloc.add_fixit_insert_before (next_loc, ";"); if (CLASSTYPE_DECLARED_CLASS (type)) error_at_rich_loc (&richloc, @@ -22037,7 +22037,8 @@ cp_parser_class_head (cp_parser* parser, class_head_start_location, get_finish (type_start_token->location)); rich_location richloc (line_table, reported_loc); - richloc.add_fixit_insert (class_head_start_location, "template <> "); + richloc.add_fixit_insert_before (class_head_start_location, + "template <> "); error_at_rich_loc (&richloc, "an explicit specialization must be preceded by %<template <>%>"); diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c index 00a95a19cc0..331eb92f968 100644 --- a/gcc/diagnostic-show-locus.c +++ b/gcc/diagnostic-show-locus.c @@ -1661,12 +1661,12 @@ test_one_liner_multiple_carets_and_ranges () /* Insertion fix-it hint: adding an "&" to the front of "bar.field". */ static void -test_one_liner_fixit_insert () +test_one_liner_fixit_insert_before () { test_diagnostic_context dc; location_t caret = linemap_position_for_column (line_table, 7); rich_location richloc (line_table, caret); - richloc.add_fixit_insert ("&"); + richloc.add_fixit_insert_before ("&"); diagnostic_show_locus (&dc, &richloc, DK_ERROR); ASSERT_STREQ ("\n" " foo = bar.field;\n" @@ -1675,6 +1675,25 @@ test_one_liner_fixit_insert () pp_formatted_text (dc.printer)); } +/* Insertion fix-it hint: adding a "[0]" after "foo". */ + +static void +test_one_liner_fixit_insert_after () +{ + test_diagnostic_context dc; + location_t start = linemap_position_for_column (line_table, 1); + location_t finish = linemap_position_for_column (line_table, 3); + location_t foo = make_location (start, start, finish); + rich_location richloc (line_table, foo); + richloc.add_fixit_insert_after ("[0]"); + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n" + " foo = bar.field;\n" + " ^~~\n" + " [0]\n", + pp_formatted_text (dc.printer)); +} + /* Removal fix-it hint: removal of the ".field". */ static void @@ -1785,7 +1804,7 @@ test_one_liner_fixit_validation_adhoc_locations () /* Insert. */ { rich_location richloc (line_table, loc); - richloc.add_fixit_insert (loc, "test"); + richloc.add_fixit_insert_before (loc, "test"); /* It should not have been discarded by the validator. */ ASSERT_EQ (1, richloc.get_num_fixit_hints ()); @@ -1843,7 +1862,7 @@ test_one_liner_many_fixits () location_t equals = linemap_position_for_column (line_table, 5); rich_location richloc (line_table, equals); for (int i = 0; i < 19; i++) - richloc.add_fixit_insert ("a"); + richloc.add_fixit_insert_before ("a"); ASSERT_EQ (19, richloc.get_num_fixit_hints ()); diagnostic_show_locus (&dc, &richloc, DK_ERROR); ASSERT_STREQ ("\n" @@ -1898,7 +1917,8 @@ test_diagnostic_show_locus_one_liner (const line_table_case &case_) test_one_liner_simple_caret (); test_one_liner_caret_and_range (); test_one_liner_multiple_carets_and_ranges (); - test_one_liner_fixit_insert (); + test_one_liner_fixit_insert_before (); + test_one_liner_fixit_insert_after (); test_one_liner_fixit_remove (); test_one_liner_fixit_replace (); test_one_liner_fixit_replace_non_equal_range (); @@ -1949,7 +1969,7 @@ test_diagnostic_show_locus_fixit_lines (const line_table_case &case_) const location_t colon = linemap_position_for_line_and_column (line_table, ord_map, 2, 25); rich_location richloc (line_table, colon); - richloc.add_fixit_insert (x, "."); + richloc.add_fixit_insert_before (x, "."); richloc.add_fixit_replace (colon, "="); diagnostic_show_locus (&dc, &richloc, DK_ERROR); ASSERT_STREQ ("\n" @@ -1970,7 +1990,7 @@ test_diagnostic_show_locus_fixit_lines (const line_table_case &case_) const location_t colon = linemap_position_for_line_and_column (line_table, ord_map, 6, 25); rich_location richloc (line_table, colon); - richloc.add_fixit_insert (y, "."); + richloc.add_fixit_insert_before (y, "."); richloc.add_fixit_replace (colon, "="); diagnostic_show_locus (&dc, &richloc, DK_ERROR); ASSERT_STREQ ("\n" @@ -2012,8 +2032,8 @@ test_fixit_consolidation (const line_table_case &case_) /* Insert + insert. */ { rich_location richloc (line_table, caret); - richloc.add_fixit_insert (c10, "foo"); - richloc.add_fixit_insert (c15, "bar"); + richloc.add_fixit_insert_before (c10, "foo"); + richloc.add_fixit_insert_before (c15, "bar"); if (c15 > LINE_MAP_MAX_LOCATION_WITH_COLS) /* Bogus column info for 2nd fixit, so no fixits. */ @@ -2026,7 +2046,7 @@ test_fixit_consolidation (const line_table_case &case_) /* Insert + replace. */ { rich_location richloc (line_table, caret); - richloc.add_fixit_insert (c10, "foo"); + richloc.add_fixit_insert_before (c10, "foo"); richloc.add_fixit_replace (source_range::from_locations (c15, c17), "bar"); @@ -2043,7 +2063,7 @@ test_fixit_consolidation (const line_table_case &case_) rich_location richloc (line_table, caret); richloc.add_fixit_replace (source_range::from_locations (c10, c15), "bar"); - richloc.add_fixit_insert (c17, "foo"); + richloc.add_fixit_insert_before (c17, "foo"); if (c17 > LINE_MAP_MAX_LOCATION_WITH_COLS) /* Bogus column info for 2nd fixit, so no fixits. */ diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c index 46cdb629e8d..585028ec211 100644 --- a/gcc/diagnostic.c +++ b/gcc/diagnostic.c @@ -1504,7 +1504,7 @@ test_print_parseable_fixits_insert () linemap_line_start (line_table, 5, 100); linemap_add (line_table, LC_LEAVE, false, NULL, 0); location_t where = linemap_position_for_column (line_table, 10); - richloc.add_fixit_insert (where, "added content"); + richloc.add_fixit_insert_before (where, "added content"); print_parseable_fixits (&pp, &richloc); ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:10}:\"added content\"\n", diff --git a/gcc/edit-context.c b/gcc/edit-context.c index 087764ec2de..5945f423d29 100644 --- a/gcc/edit-context.c +++ b/gcc/edit-context.c @@ -918,10 +918,10 @@ test_get_content () } } -/* Test applying an "insert" fixit. */ +/* Test applying an "insert" fixit, using insert_before. */ static void -test_applying_fixits_insert (const line_table_case &case_) +test_applying_fixits_insert_before (const line_table_case &case_) { /* Create a tempfile and write some text to it. .........................0000000001111111. @@ -937,7 +937,7 @@ test_applying_fixits_insert (const line_table_case &case_) /* Add a comment in front of "bar.field". */ location_t start = linemap_position_for_column (line_table, 7); rich_location richloc (line_table, start); - richloc.add_fixit_insert ("/* inserted */"); + richloc.add_fixit_insert_before ("/* inserted */"); if (start > LINE_MAP_MAX_LOCATION_WITH_COLS) return; @@ -971,6 +971,142 @@ test_applying_fixits_insert (const line_table_case &case_) " /* after */\n", diff); } +/* Test applying an "insert" fixit, using insert_after, with + a range of length > 1 (to ensure that the end-point of + the input range is used). */ + +static void +test_applying_fixits_insert_after (const line_table_case &case_) +{ + /* Create a tempfile and write some text to it. + .........................0000000001111111. + .........................1234567890123456. */ + const char *old_content = ("/* before */\n" + "foo = bar.field;\n" + "/* after */\n"); + temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content); + const char *filename = tmp.get_filename (); + line_table_test ltt (case_); + linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 2); + + /* Add a comment after "field". */ + location_t start = linemap_position_for_column (line_table, 11); + location_t finish = linemap_position_for_column (line_table, 15); + location_t field = make_location (start, start, finish); + rich_location richloc (line_table, field); + richloc.add_fixit_insert_after ("/* inserted */"); + + if (finish > LINE_MAP_MAX_LOCATION_WITH_COLS) + return; + + /* Verify that the text was inserted after the end of "field". */ + edit_context edit; + edit.add_fixits (&richloc); + auto_free <char *> new_content = edit.get_content (filename); + ASSERT_STREQ ("/* before */\n" + "foo = bar.field/* inserted */;\n" + "/* after */\n", new_content); + + /* Verify diff. */ + auto_free <char *> diff = edit.generate_diff (false); + ASSERT_STREQ ("@@ -1,3 +1,3 @@\n" + " /* before */\n" + "-foo = bar.field;\n" + "+foo = bar.field/* inserted */;\n" + " /* after */\n", diff); +} + +/* Test applying an "insert" fixit, using insert_after at the end of + a line (contrast with test_applying_fixits_insert_after_failure + below). */ + +static void +test_applying_fixits_insert_after_at_line_end (const line_table_case &case_) +{ + /* Create a tempfile and write some text to it. + .........................0000000001111111. + .........................1234567890123456. */ + const char *old_content = ("/* before */\n" + "foo = bar.field;\n" + "/* after */\n"); + temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content); + const char *filename = tmp.get_filename (); + line_table_test ltt (case_); + linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 2); + + /* Add a comment after the semicolon. */ + location_t loc = linemap_position_for_column (line_table, 16); + rich_location richloc (line_table, loc); + richloc.add_fixit_insert_after ("/* inserted */"); + + if (loc > LINE_MAP_MAX_LOCATION_WITH_COLS) + return; + + edit_context edit; + edit.add_fixits (&richloc); + auto_free <char *> new_content = edit.get_content (filename); + ASSERT_STREQ ("/* before */\n" + "foo = bar.field;/* inserted */\n" + "/* after */\n", new_content); + + /* Verify diff. */ + auto_free <char *> diff = edit.generate_diff (false); + ASSERT_STREQ ("@@ -1,3 +1,3 @@\n" + " /* before */\n" + "-foo = bar.field;\n" + "+foo = bar.field;/* inserted */\n" + " /* after */\n", diff); +} + +/* Test of a failed attempt to apply an "insert" fixit, using insert_after, + due to the relevant linemap ending. Contrast with + test_applying_fixits_insert_after_at_line_end above. */ + +static void +test_applying_fixits_insert_after_failure (const line_table_case &case_) +{ + /* Create a tempfile and write some text to it. + .........................0000000001111111. + .........................1234567890123456. */ + const char *old_content = ("/* before */\n" + "foo = bar.field;\n" + "/* after */\n"); + temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content); + const char *filename = tmp.get_filename (); + line_table_test ltt (case_); + linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 2); + + /* Add a comment after the semicolon. */ + location_t loc = linemap_position_for_column (line_table, 16); + rich_location richloc (line_table, loc); + + /* We want a failure of linemap_position_for_loc_and_offset. + We can do this by starting a new linemap at line 3, so that + there is no appropriate location value for the insertion point + within the linemap for line 2. */ + linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 3); + + /* The failure fails to happen at the transition point from + packed ranges to unpacked ranges (where there are some "spare" + location_t values). Skip the test there. */ + if (loc >= LINE_MAP_MAX_LOCATION_WITH_PACKED_RANGES) + return; + + /* Offsetting "loc" should now fail (by returning the input loc. */ + ASSERT_EQ (loc, linemap_position_for_loc_and_offset (line_table, loc, 1)); + + /* Hence attempting to use add_fixit_insert_after at the end of the line + should now fail. */ + richloc.add_fixit_insert_after ("/* inserted */"); + ASSERT_TRUE (richloc.seen_impossible_fixit_p ()); + + edit_context edit; + edit.add_fixits (&richloc); + ASSERT_FALSE (edit.valid_p ()); + ASSERT_EQ (NULL, edit.get_content (filename)); + ASSERT_EQ (NULL, edit.generate_diff (false)); +} + /* Test applying a "replace" fixit that grows the affected line. */ static void @@ -1135,11 +1271,11 @@ test_applying_fixits_multiple (const line_table_case &case_) /* Add a comment in front of "bar.field". */ rich_location insert_a (line_table, c7); - insert_a.add_fixit_insert (c7, "/* alpha */"); + insert_a.add_fixit_insert_before (c7, "/* alpha */"); /* Add a comment after "bar.field;". */ rich_location insert_b (line_table, c17); - insert_b.add_fixit_insert (c17, "/* beta */"); + insert_b.add_fixit_insert_before (c17, "/* beta */"); /* Replace "bar" with "pub". */ rich_location replace_a (line_table, c7); @@ -1203,7 +1339,7 @@ change_line (edit_context &edit, int line_num) } rich_location insert (line_table, loc); - insert.add_fixit_insert ("CHANGED: "); + insert.add_fixit_insert_before ("CHANGED: "); edit.add_fixits (&insert); return loc; } @@ -1371,8 +1507,8 @@ test_applying_fixits_unreadable_file () location_t loc = linemap_position_for_column (line_table, 1); rich_location insert (line_table, loc); - insert.add_fixit_insert ("change 1"); - insert.add_fixit_insert ("change 2"); + insert.add_fixit_insert_before ("change 1"); + insert.add_fixit_insert_before ("change 2"); edit_context edit; /* Attempting to add the fixits affecting the unreadable file @@ -1403,7 +1539,7 @@ test_applying_fixits_line_out_of_range () location_t loc = linemap_position_for_column (line_table, 1); rich_location insert (line_table, loc); - insert.add_fixit_insert ("change"); + insert.add_fixit_insert_before ("change"); /* Verify that attempting the insertion puts an edit_context into an invalid state. */ @@ -1440,7 +1576,7 @@ test_applying_fixits_column_validation (const line_table_case &case_) /* Verify inserting at the end of the line. */ { rich_location richloc (line_table, c11); - richloc.add_fixit_insert (c15, " change"); + richloc.add_fixit_insert_before (c15, " change"); /* Col 15 is at the end of the line, so the insertion should succeed. */ @@ -1456,7 +1592,7 @@ test_applying_fixits_column_validation (const line_table_case &case_) /* Verify inserting beyond the end of the line. */ { rich_location richloc (line_table, c11); - richloc.add_fixit_insert (c16, " change"); + richloc.add_fixit_insert_before (c16, " change"); /* Col 16 is beyond the end of the line, so the insertion should fail gracefully. */ @@ -1510,7 +1646,10 @@ void edit_context_c_tests () { test_get_content (); - for_each_line_table_case (test_applying_fixits_insert); + for_each_line_table_case (test_applying_fixits_insert_before); + for_each_line_table_case (test_applying_fixits_insert_after); + for_each_line_table_case (test_applying_fixits_insert_after_at_line_end); + for_each_line_table_case (test_applying_fixits_insert_after_failure); for_each_line_table_case (test_applying_fixits_growing_replace); for_each_line_table_case (test_applying_fixits_shrinking_replace); for_each_line_table_case (test_applying_fixits_remove); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2ebe9e68f90..d6f6b32ba4b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2016-09-13 David Malcolm <dmalcolm@redhat.com> + + * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c + (test_show_locus): Replace rich_location::add_fixit_insert calls + with add_fixit_insert_before and add_fixit_insert_after. + 2016-09-13 Jason Merrill <jason@redhat.com> Tom de Vries <tom@codesourcery.com> 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 ea28f046e8d..3efc7dfa0b4 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 @@ -263,8 +263,8 @@ test_show_locus (function *fun) location_t start = get_loc (line, 19); location_t finish = get_loc (line, 22); rich_location richloc (line_table, make_location (start, start, finish)); - richloc.add_fixit_insert (start, "{"); - richloc.add_fixit_insert (get_loc (line, 23), "}"); + richloc.add_fixit_insert_before ("{"); + richloc.add_fixit_insert_after ("}"); warning_at_rich_loc (&richloc, 0, "example of insertion hints"); } diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 792f76ae3b5..95e12a9ba6b 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,23 @@ +2016-09-13 David Malcolm <dmalcolm@redhat.com> + + * include/line-map.h (class rich_location): Add description of + fix-it hints to leading comment. + (rich_location::add_fixit_insert): Rename both overloaded methods + to.. + (rich_location::add_fixit_insert_before): ...this, updating their + comments. + (rich_location::add_fixit_insert_after): Two new overloaded + methods. + (rich_location::stop_supporting_fixits): New method. + * line-map.c (rich_location::add_fixit_insert): Rename both + overloaded methods to.. + (rich_location::add_fixit_insert_before): ...this, updating their + comments. + (rich_location::add_fixit_insert_after): Two new methods. + (rich_location::reject_impossible_fixit): Split out + failure-handling into... + (rich_location::stop_supporting_fixits): New method. + 2016-09-02 David Malcolm <dmalcolm@redhat.com> * include/line-map.h (rich_location::seen_impossible_fixit_p): New diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h index 6b3c474a0de..939bfcc5712 100644 --- a/libcpp/include/line-map.h +++ b/libcpp/include/line-map.h @@ -1484,7 +1484,84 @@ 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. + + 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 { @@ -1522,14 +1599,25 @@ class rich_location /* Methods for adding insertion fix-it hints. */ - /* Suggest inserting NEW_CONTENT at the primary range's caret. */ + /* Suggest inserting NEW_CONTENT immediately before the primary + range's start. */ void - add_fixit_insert (const char *new_content); + add_fixit_insert_before (const char *new_content); - /* Suggest inserting NEW_CONTENT at WHERE. */ + /* Suggest inserting NEW_CONTENT immediately before the start of WHERE. */ void - add_fixit_insert (source_location where, - const char *new_content); + 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. */ @@ -1571,6 +1659,7 @@ class rich_location private: bool reject_impossible_fixit (source_location where); + void stop_supporting_fixits (); void add_fixit (fixit_hint *hint); public: diff --git a/libcpp/line-map.c b/libcpp/line-map.c index f69c60c7837..742af0a07bb 100644 --- a/libcpp/line-map.c +++ b/libcpp/line-map.c @@ -2109,26 +2109,61 @@ rich_location::set_range (line_maps * /*set*/, unsigned int idx, /* Methods for adding insertion fix-it hints. */ /* Add a fixit-hint, suggesting insertion of NEW_CONTENT - at the primary range's caret location. */ + immediately before the primary range's start location. */ void -rich_location::add_fixit_insert (const char *new_content) +rich_location::add_fixit_insert_before (const char *new_content) { - add_fixit_insert (get_loc (), new_content); + add_fixit_insert_before (get_loc (), new_content); } /* Add a fixit-hint, suggesting insertion of NEW_CONTENT - at WHERE. */ + immediately before the start of WHERE. */ void -rich_location::add_fixit_insert (source_location where, - const char *new_content) +rich_location::add_fixit_insert_before (source_location where, + const char *new_content) { - where = get_pure_location (m_line_table, where); + source_location start = get_range_from_loc (m_line_table, where).m_start; - if (reject_impossible_fixit (where)) + if (reject_impossible_fixit (start)) return; - add_fixit (new fixit_insert (where, new_content)); + add_fixit (new fixit_insert (start, new_content)); +} + +/* Add a fixit-hint, suggesting insertion of NEW_CONTENT + immediately after the primary range's end-point. */ + +void +rich_location::add_fixit_insert_after (const char *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. */ @@ -2278,14 +2313,22 @@ rich_location::reject_impossible_fixit (source_location where) /* 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); - - return true; } /* Add HINT to the fix-it hints in this rich_location. */ |