From: David Malcolm Date: Tue, 1 May 2018 00:10:10 +0000 (+0000) Subject: Add gcc_rich_location::add_fixit_insert_formatted X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=1a3a7b4eeb0444148adc4f007b91e120814c4cc5;p=gcc.git Add gcc_rich_location::add_fixit_insert_formatted This patch adds a support function to class gcc_rich_location to make it easier for fix-it hints to use idiomatic C/C++ indentation, for use by the patch for PR c++/85523. gcc/ChangeLog: PR c++/85523 * gcc-rich-location.c (blank_line_before_p): New function. (use_new_line): New function. (gcc_rich_location::add_fixit_insert_formatted): New function. * gcc-rich-location.h (gcc_rich_location::add_fixit_insert_formatted): New function. gcc/testsuite/ChangeLog: PR c++/85523 * gcc.dg/plugin/diagnostic-test-show-locus-generate-patch.c (test_add_fixit_insert_formatted_single_line): New function. (test_add_fixit_insert_formatted_multiline): New function. Extend expected output of generated patch to include fix-it hints for these. * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c: Include "gcc-rich-location.h". Add test coverage for gcc_rich_location::add_fixit_insert_formatted. From-SVN: r259783 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 84d5bd1d350..60ca47c0ad0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2018-04-30 David Malcolm + + PR c++/85523 + * gcc-rich-location.c (blank_line_before_p): New function. + (use_new_line): New function. + (gcc_rich_location::add_fixit_insert_formatted): New function. + * gcc-rich-location.h + (gcc_rich_location::add_fixit_insert_formatted): New function. + 2018-04-30 David Malcolm * selftest.c (assert_streq): Rename "expected" and "actual" to diff --git a/gcc/gcc-rich-location.c b/gcc/gcc-rich-location.c index 34814252585..0a0adf932c1 100644 --- a/gcc/gcc-rich-location.c +++ b/gcc/gcc-rich-location.c @@ -69,3 +69,114 @@ gcc_rich_location::add_fixit_misspelled_id (location_t misspelled_token_loc, add_fixit_replace (misspelled_token_loc, IDENTIFIER_POINTER (hint_id)); } + +/* Return true if there is nothing on LOC's line before LOC. */ + +static bool +blank_line_before_p (location_t loc) +{ + expanded_location exploc = expand_location (loc); + char_span line = location_get_source_line (exploc.file, exploc.line); + if (!line) + return false; + if (line.length () < (size_t)exploc.column) + return false; + /* Columns are 1-based. */ + for (int column = 1; column < exploc.column; ++column) + if (!ISSPACE (line[column - 1])) + return false; + return true; +} + +/* Subroutine of gcc_rich_location::add_fixit_insert_formatted. + Return true if we should add the content on its own line, + false otherwise. + If true is returned then *OUT_START_OF_LINE is written to. */ + +static bool +use_new_line (location_t insertion_point, location_t indent, + location_t *out_start_of_line) +{ + if (indent == UNKNOWN_LOCATION) + return false; + const line_map *indent_map = linemap_lookup (line_table, indent); + if (linemap_macro_expansion_map_p (indent_map)) + return false; + + if (!blank_line_before_p (insertion_point)) + return false; + + /* Locate the start of the line containing INSERTION_POINT. */ + const line_map *insertion_point_map + = linemap_lookup (line_table, insertion_point); + if (linemap_macro_expansion_map_p (insertion_point_map)) + return false; + const line_map_ordinary *ordmap + = linemap_check_ordinary (insertion_point_map); + expanded_location exploc_insertion_point = expand_location (insertion_point); + location_t start_of_line + = linemap_position_for_line_and_column (line_table, ordmap, + exploc_insertion_point.line, 1); + *out_start_of_line = start_of_line; + return true; +} + +/* Add a fix-it hint suggesting the insertion of CONTENT before + INSERTION_POINT. + + Attempt to handle formatting: if INSERTION_POINT is the first thing on + its line, and INDENT is sufficiently sane, then add CONTENT on its own + line, using the indentation of INDENT. + Otherwise, add CONTENT directly before INSERTION_POINT. + + For example, adding "CONTENT;" with the closing brace as the insertion + point and "INDENT;" as the indentation point: + + if () + { + INDENT; + } + + would lead to: + + if () + { + INDENT; + CONTENT; + } + + but adding it to: + + if () {INDENT;} + + would lead to: + + if () {INDENT;CONTENT;} +*/ + +void +gcc_rich_location::add_fixit_insert_formatted (const char *content, + location_t insertion_point, + location_t indent) +{ + location_t start_of_line; + if (use_new_line (insertion_point, indent, &start_of_line)) + { + /* Add CONTENT on its own line, using the indentation of INDENT. */ + + /* Generate an insertion string, indenting by the amount INDENT + was indented. */ + int indent_column = LOCATION_COLUMN (get_start (indent)); + pretty_printer tmp_pp; + pretty_printer *pp = &tmp_pp; + /* Columns are 1-based. */ + for (int column = 1; column < indent_column; ++column) + pp_space (pp); + pp_string (pp, content); + pp_newline (pp); + + add_fixit_insert_before (start_of_line, pp_formatted_text (pp)); + } + else + add_fixit_insert_before (insertion_point, content); +} diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h index bdcf8aee872..9c705c86a72 100644 --- a/gcc/gcc-rich-location.h +++ b/gcc/gcc-rich-location.h @@ -61,6 +61,42 @@ class gcc_rich_location : public rich_location Implemented in diagnostic-show-locus.c. */ bool add_location_if_nearby (location_t loc); + + /* Add a fix-it hint suggesting the insertion of CONTENT before + INSERTION_POINT. + + Attempt to handle formatting: if INSERTION_POINT is the first thing on + its line, and INDENT is sufficiently sane, then add CONTENT on its own + line, using the indentation of INDENT. + Otherwise, add CONTENT directly before INSERTION_POINT. + + For example, adding "CONTENT;" with the closing brace as the insertion + point and using "INDENT;" for indentation: + + if () + { + INDENT; + } + + would lead to: + + if () + { + INDENT; + CONTENT; + } + + but adding it to: + + if () {INDENT;} + + would lead to: + + if () {INDENT;CONTENT;} + */ + void add_fixit_insert_formatted (const char *content, + location_t insertion_point, + location_t indent); }; #endif /* GCC_RICH_LOCATION_H */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 557ac8db20f..7e0a41ee7af 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2018-04-30 David Malcolm + + PR c++/85523 + * gcc.dg/plugin/diagnostic-test-show-locus-generate-patch.c + (test_add_fixit_insert_formatted_single_line): New function. + (test_add_fixit_insert_formatted_multiline): New function. + Extend expected output of generated patch to include fix-it hints + for these. + * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c: Include + "gcc-rich-location.h". Add test coverage for + gcc_rich_location::add_fixit_insert_formatted. + 2018-04-30 David Malcolm * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-generate-patch.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-generate-patch.c index f1963dd20c1..cfdc20819be 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-generate-patch.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-generate-patch.c @@ -64,6 +64,21 @@ void test_mutually_exclusive_suggestions (void) #endif } +/* Unit tests for add_fixit_insert_formatted. */ + +void test_add_fixit_insert_formatted_single_line (void) +{ + {} +} + +void test_add_fixit_insert_formatted_multiline (void) +{ + if (1) + { + } +} + + /* Verify the output from -fdiagnostics-generate-patch. We expect a header, containing the filename. This is the absolute path, so we can only capture it via regexps. */ @@ -108,4 +123,21 @@ void test_mutually_exclusive_suggestions (void) case 'b': x = b; } +@@ -68,7 +69,7 @@ + + void test_add_fixit_insert_formatted_single_line (void) + { +- {} ++ {INSERTED-CONTENT} + } + + void test_add_fixit_insert_formatted_multiline (void) +@@ -76,6 +77,7 @@ + if (1) + { + } ++ INSERTED-CONTENT + } + + { dg-end-multiline-output "" } */ 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 dabc0e42130..1d340aa0e6a 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 @@ -60,6 +60,7 @@ #include "diagnostic.h" #include "context.h" #include "print-tree.h" +#include "gcc-rich-location.h" int plugin_is_GPL_compatible; @@ -333,6 +334,29 @@ test_show_locus (function *fun) } } + /* Tests of gcc_rich_location::add_fixit_insert_formatted. */ + + if (0 == strcmp (fnname, "test_add_fixit_insert_formatted_single_line")) + { + const int line = fnstart_line + 1; + location_t insertion_point = get_loc (line, 3); + location_t indent = get_loc (line, 2); + gcc_rich_location richloc (insertion_point); + richloc.add_fixit_insert_formatted ("INSERTED-CONTENT", + insertion_point, indent); + inform (&richloc, "single-line insertion"); + } + + if (0 == strcmp (fnname, "test_add_fixit_insert_formatted_multiline")) + { + location_t insertion_point = fun->function_end_locus; + location_t indent = get_loc (fnstart_line + 1, 2); + gcc_rich_location richloc (insertion_point); + richloc.add_fixit_insert_formatted ("INSERTED-CONTENT", + insertion_point, indent); + inform (&richloc, "multiline insertion"); + } + /* 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.