From cc015f3abebcfe84c64a38d1198ad4601e36893c Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 18 Aug 2016 19:12:54 +0000 Subject: [PATCH] Allow calling diagnostic_show_locus without a diagnostic_info Much of diagnostic-show-locus.c currently expects a diagnostic_info *, but it only uses the rich_location and the diagnostic_t. Change the signature of diagnostic_show_locus from: void diagnostic_show_locus (diagnostic_context *, const diagnostic_info *); to: void diagnostic_show_locus (diagnostic_context *, rich_location *richloc, diagnostic_t diagnostic_kind); so that it can be used for things other than diagnostics. Use this flexibility to add selftests for diagnostic_show_locus. gcc/c-family/ChangeLog: * c-opts.c (c_diagnostic_finalizer): Update for change to diagnostic_show_locus. gcc/ChangeLog: * diagnostic-show-locus.c (colorizer::colorizer): Replace diagnostic param with diagnostic_kind. (class colorizer): Similarly replace field m_diagnostic with m_diagnostic_kind. (colorizer::colorizer): Replace diagnostic param with diagnostic_kind. (colorizer::begin_state): Update for above field change. (layout::layout): Replace diagnostic param with rich_location * and diagnostic_kind. (diagnostic_show_locus): Replace diagnostic param with richloc and diagnostic_kind. (class selftest::test_diagnostic_context): New class. (selftest::test_diagnostic_show_locus_unknown_location): New function. (selftest::test_one_liner_simple_caret): New function. (selftest::test_one_liner_caret_and_range): New function. (selftest::test_one_liner_multiple_carets_and_ranges): New function. (selftest::test_one_liner_fixit_remove): New function. (selftest::test_one_liner_fixit_replace): New function. (selftest::test_diagnostic_show_locus_one_liner): New function. (selftest::diagnostic_show_locus_c_tests): Call the new test functions. * diagnostic.c (diagnostic_initialize): Initialize colorize_source_p, show_ruler_p and parseable_fixits_p. (default_diagnostic_finalizer): Update for change to diagnostic_show_locus. (diagnostic_append_note): Likewise. * diagnostic.h (diagnostic_show_locus): Replace const diagnostic_info * param with location * and diagnostic_t. gcc/fortran/ChangeLog: * error.c (gfc_diagnostic_starter): Update for change to diagnostic_show_locus. gcc/testsuite/ChangeLog: * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c (custom_diagnostic_finalizer): Update for change to diagnostic_show_locus. From-SVN: r239586 --- gcc/ChangeLog | 33 +++ gcc/c-family/ChangeLog | 5 + gcc/c-family/c-opts.c | 2 +- gcc/diagnostic-show-locus.c | 243 ++++++++++++++++-- gcc/diagnostic.c | 7 +- gcc/diagnostic.h | 4 +- gcc/fortran/ChangeLog | 5 + gcc/fortran/error.c | 2 +- gcc/testsuite/ChangeLog | 6 + .../diagnostic_plugin_test_show_locus.c | 2 +- 10 files changed, 285 insertions(+), 24 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b53a9d2f316..c268e0001ab 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,36 @@ +2016-08-18 David Malcolm + + * diagnostic-show-locus.c (colorizer::colorizer): Replace diagnostic + param with diagnostic_kind. + (class colorizer): Similarly replace field m_diagnostic with + m_diagnostic_kind. + (colorizer::colorizer): Replace diagnostic + param with diagnostic_kind. + (colorizer::begin_state): Update for above field change. + (layout::layout): Replace diagnostic param with rich_location * + and diagnostic_kind. + (diagnostic_show_locus): Replace diagnostic param with richloc + and diagnostic_kind. + (class selftest::test_diagnostic_context): New class. + (selftest::test_diagnostic_show_locus_unknown_location): New + function. + (selftest::test_one_liner_simple_caret): New function. + (selftest::test_one_liner_caret_and_range): New function. + (selftest::test_one_liner_multiple_carets_and_ranges): New + function. + (selftest::test_one_liner_fixit_remove): New function. + (selftest::test_one_liner_fixit_replace): New function. + (selftest::test_diagnostic_show_locus_one_liner): New function. + (selftest::diagnostic_show_locus_c_tests): Call the new test + functions. + * diagnostic.c (diagnostic_initialize): Initialize + colorize_source_p, show_ruler_p and parseable_fixits_p. + (default_diagnostic_finalizer): Update for change to + diagnostic_show_locus. + (diagnostic_append_note): Likewise. + * diagnostic.h (diagnostic_show_locus): Replace + const diagnostic_info * param with location * and diagnostic_t. + 2016-08-18 David Malcolm * input.c (saved_line_table): New global. diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 1ed5268a91f..616ca132de3 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2016-08-18 David Malcolm + + * c-opts.c (c_diagnostic_finalizer): Update for change to + diagnostic_show_locus. + 2016-08-18 David Malcolm * c-common.c: Include "spellcheck.h". diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index 574718a9a98..e83944c90ad 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -164,7 +164,7 @@ static void c_diagnostic_finalizer (diagnostic_context *context, diagnostic_info *diagnostic) { - diagnostic_show_locus (context, diagnostic); + diagnostic_show_locus (context, diagnostic->richloc, diagnostic->kind); /* By default print macro expansion contexts in the diagnostic finalizer -- for tokens resulting from macro expansion. */ virt_loc_aware_diagnostic_finalizer (context, diagnostic); diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c index 49f7f119782..4498f7ce5da 100644 --- a/gcc/diagnostic-show-locus.c +++ b/gcc/diagnostic-show-locus.c @@ -74,7 +74,7 @@ class colorizer { public: colorizer (diagnostic_context *context, - const diagnostic_info *diagnostic); + diagnostic_t diagnostic_kind); ~colorizer (); void set_range (int range_idx) { set_state (range_idx); } @@ -90,7 +90,7 @@ class colorizer static const int STATE_NORMAL_TEXT = -1; diagnostic_context *m_context; - const diagnostic_info *m_diagnostic; + diagnostic_t m_diagnostic_kind; int m_current_state; const char *m_caret_cs; const char *m_caret_ce; @@ -187,7 +187,8 @@ class layout { public: layout (diagnostic_context *context, - const diagnostic_info *diagnostic); + rich_location *richloc, + diagnostic_t diagnostic_kind); int get_num_line_spans () const { return m_line_spans.length (); } const line_span *get_line_span (int idx) const { return &m_line_spans[idx]; } @@ -239,9 +240,9 @@ class layout different kinds of things we might need to print. */ colorizer::colorizer (diagnostic_context *context, - const diagnostic_info *diagnostic) : + diagnostic_t diagnostic_kind) : m_context (context), - m_diagnostic (diagnostic), + m_diagnostic_kind (diagnostic_kind), m_current_state (STATE_NORMAL_TEXT) { m_caret_ce = colorize_stop (pp_show_color (context->printer)); @@ -288,7 +289,7 @@ colorizer::begin_state (int state) pp_string (m_context->printer, colorize_start (pp_show_color (m_context->printer), - diagnostic_get_color_for_kind (m_diagnostic->kind))); + diagnostic_get_color_for_kind (m_diagnostic_kind))); break; case 1: @@ -699,18 +700,18 @@ compatible_locations_p (location_t loc_a, location_t loc_b) will fit within the max_width provided by the diagnostic_context. */ layout::layout (diagnostic_context * context, - const diagnostic_info *diagnostic) + rich_location *richloc, + diagnostic_t diagnostic_kind) : m_context (context), m_pp (context->printer), - m_diagnostic_kind (diagnostic->kind), - m_exploc (diagnostic->richloc->get_expanded_location (0)), - m_colorizer (context, diagnostic), + m_diagnostic_kind (diagnostic_kind), + m_exploc (richloc->get_expanded_location (0)), + m_colorizer (context, diagnostic_kind), m_colorize_source_p (context->colorize_source_p), m_layout_ranges (rich_location::MAX_RANGES), m_line_spans (1 + rich_location::MAX_RANGES), m_x_offset (0) { - rich_location *richloc = diagnostic->richloc; source_location primary_loc = richloc->get_range (0)->m_loc; for (unsigned int idx = 0; idx < richloc->get_num_locations (); idx++) @@ -1276,30 +1277,32 @@ layout::show_ruler (int max_column) const void diagnostic_show_locus (diagnostic_context * context, - const diagnostic_info *diagnostic) + rich_location *richloc, + diagnostic_t diagnostic_kind) { pp_newline (context->printer); + location_t loc = richloc->get_loc (); /* Do nothing if source-printing has been disabled. */ if (!context->show_caret) return; /* Don't attempt to print source for UNKNOWN_LOCATION and for builtins. */ - if (diagnostic_location (diagnostic, 0) <= BUILTINS_LOCATION) + if (loc <= BUILTINS_LOCATION) return; /* Don't print the same source location twice in a row, unless we have fix-it hints. */ - if (diagnostic_location (diagnostic, 0) == context->last_location - && diagnostic->richloc->get_num_fixit_hints () == 0) + if (loc == context->last_location + && richloc->get_num_fixit_hints () == 0) return; - context->last_location = diagnostic_location (diagnostic, 0); + context->last_location = loc; const char *saved_prefix = pp_get_prefix (context->printer); pp_set_prefix (context->printer, NULL); - layout layout (context, diagnostic); + layout layout (context, richloc, diagnostic_kind); for (int line_span_idx = 0; line_span_idx < layout.get_num_line_spans (); line_span_idx++) { @@ -1319,7 +1322,7 @@ diagnostic_show_locus (diagnostic_context * context, if (layout.print_source_line (row, &lbounds)) { layout.print_annotation_line (row, lbounds); - layout.print_any_fixits (row, diagnostic->richloc); + layout.print_any_fixits (row, richloc); } } } @@ -1331,6 +1334,206 @@ diagnostic_show_locus (diagnostic_context * context, namespace selftest { +/* Selftests for diagnostic_show_locus. */ + +/* Convenience subclass of diagnostic_context for testing + diagnostic_show_locus. */ + +class test_diagnostic_context : public diagnostic_context +{ + public: + test_diagnostic_context () + { + diagnostic_initialize (this, 0); + show_caret = true; + } + ~test_diagnostic_context () + { + diagnostic_finish (this); + } +}; + +/* Verify that diagnostic_show_locus works sanely on UNKNOWN_LOCATION. */ + +static void +test_diagnostic_show_locus_unknown_location () +{ + test_diagnostic_context dc; + rich_location richloc (line_table, UNKNOWN_LOCATION); + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n", pp_formatted_text (dc.printer)); +} + +/* Verify that diagnostic_show_locus works sanely for various + single-line cases. + + All of these work on the following 1-line source file: + .0000000001111111 + .1234567890123456 + "foo = bar.field;\n" + which is set up by test_diagnostic_show_locus_one_liner and calls + them. */ + +/* Just a caret. */ + +static void +test_one_liner_simple_caret () +{ + test_diagnostic_context dc; + location_t caret = linemap_position_for_column (line_table, 10); + rich_location richloc (line_table, caret); + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n" + " foo = bar.field;\n" + " ^\n", + pp_formatted_text (dc.printer)); +} + +/* Caret and range. */ + +static void +test_one_liner_caret_and_range () +{ + test_diagnostic_context dc; + location_t caret = linemap_position_for_column (line_table, 10); + location_t start = linemap_position_for_column (line_table, 7); + location_t finish = linemap_position_for_column (line_table, 15); + location_t loc = make_location (caret, start, finish); + rich_location richloc (line_table, loc); + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n" + " foo = bar.field;\n" + " ~~~^~~~~~\n", + pp_formatted_text (dc.printer)); +} + +/* Multiple ranges and carets. */ + +static void +test_one_liner_multiple_carets_and_ranges () +{ + test_diagnostic_context dc; + location_t foo + = make_location (linemap_position_for_column (line_table, 2), + linemap_position_for_column (line_table, 1), + linemap_position_for_column (line_table, 3)); + dc.caret_chars[0] = 'A'; + + location_t bar + = make_location (linemap_position_for_column (line_table, 8), + linemap_position_for_column (line_table, 7), + linemap_position_for_column (line_table, 9)); + dc.caret_chars[1] = 'B'; + + location_t field + = make_location (linemap_position_for_column (line_table, 13), + linemap_position_for_column (line_table, 11), + linemap_position_for_column (line_table, 15)); + dc.caret_chars[2] = 'C'; + + rich_location richloc (line_table, foo); + richloc.add_range (bar, true); + richloc.add_range (field, true); + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n" + " foo = bar.field;\n" + " ~A~ ~B~ ~~C~~\n", + pp_formatted_text (dc.printer)); +} + +/* Insertion fix-it hint: adding an "&" to the front of "bar.field". */ + +static void +test_one_liner_fixit_insert () +{ + test_diagnostic_context dc; + location_t caret = linemap_position_for_column (line_table, 7); + rich_location richloc (line_table, caret); + richloc.add_fixit_insert (caret, "&"); + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n" + " foo = bar.field;\n" + " ^\n" + " &\n", + pp_formatted_text (dc.printer)); +} + +/* Removal fix-it hint: removal of the ".field". */ + +static void +test_one_liner_fixit_remove () +{ + test_diagnostic_context dc; + location_t start = linemap_position_for_column (line_table, 10); + location_t finish = linemap_position_for_column (line_table, 15); + location_t dot = make_location (start, start, finish); + rich_location richloc (line_table, dot); + source_range range; + range.m_start = start; + range.m_finish = finish; + richloc.add_fixit_remove (range); + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n" + " foo = bar.field;\n" + " ^~~~~~\n" + " ------\n", + pp_formatted_text (dc.printer)); +} + +/* Replace fix-it hint: replacing "field" with "m_field". */ + +static void +test_one_liner_fixit_replace () +{ + test_diagnostic_context dc; + 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); + source_range range; + range.m_start = start; + range.m_finish = finish; + richloc.add_fixit_replace (range, "m_field"); + diagnostic_show_locus (&dc, &richloc, DK_ERROR); + ASSERT_STREQ ("\n" + " foo = bar.field;\n" + " ^~~~~\n" + " m_field\n", + pp_formatted_text (dc.printer)); +} + +/* Run the various one-liner tests. */ + +static void +test_diagnostic_show_locus_one_liner (const line_table_case &case_) +{ + /* Create a tempfile and write some text to it. + ....................0000000001111111. + ....................1234567890123456. */ + const char *content = "foo = bar.field;\n"; + temp_source_file tmp (SELFTEST_LOCATION, ".c", content); + line_table_test ltt (case_); + + linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1); + + location_t line_end = linemap_position_for_column (line_table, 16); + + /* Don't attempt to run the tests if column data might be unavailable. */ + if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS) + return; + + ASSERT_STREQ (tmp.get_filename (), LOCATION_FILE (line_end)); + ASSERT_EQ (1, LOCATION_LINE (line_end)); + ASSERT_EQ (16, LOCATION_COLUMN (line_end)); + + 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_remove (); + test_one_liner_fixit_replace (); +} + /* Run all of the selftests within this file. */ void @@ -1341,6 +1544,10 @@ diagnostic_show_locus_c_tests () test_range_contains_point_for_multiple_lines (); test_get_line_width_without_trailing_whitespace (); + + test_diagnostic_show_locus_unknown_location (); + + for_each_line_table_case (test_diagnostic_show_locus_one_liner); } } // namespace selftest diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c index bb41011afad..fec48c4e441 100644 --- a/gcc/diagnostic.c +++ b/gcc/diagnostic.c @@ -171,6 +171,9 @@ diagnostic_initialize (diagnostic_context *context, int n_opts) context->x_data = NULL; context->lock = 0; context->inhibit_notes_p = false; + context->colorize_source_p = false; + context->show_ruler_p = false; + context->parseable_fixits_p = false; } /* Maybe initialize the color support. We require clients to do this @@ -575,7 +578,7 @@ void default_diagnostic_finalizer (diagnostic_context *context, diagnostic_info *diagnostic) { - diagnostic_show_locus (context, diagnostic); + diagnostic_show_locus (context, diagnostic->richloc, diagnostic->kind); pp_destroy_prefix (context->printer); pp_flush (context->printer); } @@ -1025,7 +1028,7 @@ diagnostic_append_note (diagnostic_context *context, pp_output_formatted_text (context->printer); pp_destroy_prefix (context->printer); pp_set_prefix (context->printer, saved_prefix); - diagnostic_show_locus (context, &diagnostic); + diagnostic_show_locus (context, &richloc, DK_NOTE); va_end (ap); } diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index afce2850882..104e39c868a 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -284,7 +284,9 @@ extern void diagnostic_initialize (diagnostic_context *, int); extern void diagnostic_color_init (diagnostic_context *, int value = -1); extern void diagnostic_finish (diagnostic_context *); extern void diagnostic_report_current_module (diagnostic_context *, location_t); -extern void diagnostic_show_locus (diagnostic_context *, const diagnostic_info *); +extern void diagnostic_show_locus (diagnostic_context *, + rich_location *richloc, + diagnostic_t diagnostic_kind); /* Force diagnostics controlled by OPTIDX to be kind KIND. */ extern diagnostic_t diagnostic_classify_diagnostic (diagnostic_context *, diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 53c17042b7c..4d1c2ad4eab 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,8 @@ +2016-08-18 David Malcolm + + * error.c (gfc_diagnostic_starter): Update for change to + diagnostic_show_locus. + 2016-08-17 Jakub Jelinek PR fortran/67496 diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c index acba1c874cc..fe91419ce44 100644 --- a/gcc/fortran/error.c +++ b/gcc/fortran/error.c @@ -1093,7 +1093,7 @@ gfc_diagnostic_starter (diagnostic_context *context, free (locus_prefix); /* Fortran uses an empty line between locus and caret line. */ pp_newline (context->printer); - diagnostic_show_locus (context, diagnostic); + diagnostic_show_locus (context, diagnostic->richloc, diagnostic->kind); /* If the caret line was shown, the prefix does not contain the locus. */ pp_set_prefix (context->printer, kind_prefix); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 21e97704db6..7da55951e9a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2016-08-18 David Malcolm + + * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c + (custom_diagnostic_finalizer): Update for change to + diagnostic_show_locus. + 2016-08-18 David Malcolm * gcc.dg/cpp/misspelled-directive-1.c: New testcase. 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 a5f8f0cee93..d57400d90ff 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 @@ -133,7 +133,7 @@ custom_diagnostic_finalizer (diagnostic_context *context, bool old_show_color = pp_show_color (context->printer); if (force_show_locus_color) pp_show_color (context->printer) = true; - diagnostic_show_locus (context, diagnostic); + diagnostic_show_locus (context, diagnostic->richloc, diagnostic->kind); pp_show_color (context->printer) = old_show_color; pp_destroy_prefix (context->printer); -- 2.30.2