From 1a3a7b4eeb0444148adc4f007b91e120814c4cc5 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 1 May 2018 00:10:10 +0000 Subject: 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 --- gcc/gcc-rich-location.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) (limited to 'gcc/gcc-rich-location.c') diff --git a/gcc/gcc-rich-location.c b/gcc/gcc-rich-location.c index 3481425..0a0adf9 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); +} -- cgit v1.1