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
This commit is contained in:
David Malcolm 2018-05-01 00:10:10 +00:00 committed by David Malcolm
parent 47ae164c05
commit 1a3a7b4eeb
6 changed files with 224 additions and 0 deletions

View file

@ -1,3 +1,12 @@
2018-04-30 David Malcolm <dmalcolm@redhat.com>
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 <dmalcolm@redhat.com>
* selftest.c (assert_streq): Rename "expected" and "actual" to

View file

@ -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);
}

View file

@ -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 */

View file

@ -1,3 +1,15 @@
2018-04-30 David Malcolm <dmalcolm@redhat.com>
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 <dmalcolm@redhat.com>
* gcc.dg/plugin/diagnostic_plugin_test_show_locus.c

View file

@ -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 "" } */

View file

@ -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.