diff options
author | Manuel López-Ibáñez <manu@gcc.gnu.org> | 2012-04-11 09:26:48 +0000 |
---|---|---|
committer | Manuel López-Ibáñez <manu@gcc.gnu.org> | 2012-04-11 09:26:48 +0000 |
commit | 9fec00429dd36ea51798afeaf5f6b9c1987b85cd (patch) | |
tree | 9e780906c85f6be0ad543abba26314c0c15e5512 /gcc/diagnostic.c | |
parent | 13a7578b180de6d8bb91a2f340817e71c61a9988 (diff) | |
download | gcc-9fec00429dd36ea51798afeaf5f6b9c1987b85cd.zip gcc-9fec00429dd36ea51798afeaf5f6b9c1987b85cd.tar.gz gcc-9fec00429dd36ea51798afeaf5f6b9c1987b85cd.tar.bz2 |
re PR c++/24985 (caret diagnostics)
2012-04-11 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR 24985
gcc/
* diagnostic.h (show_caret): Declare.
(caret_max_width): Declare.
(diagnostic_show_locus): Declare.
* diagnostic.c (diagnostic_initialize): Initialize to false.
(diagnostic_show_locus): New.
(diagnostic_report_diagnostic): Call it.
(getenv_columns): New.
(adjust_line): New.
(diagnostic_set_caret_max_width): New.
* input.c (read_line): New.
(location_get_source_line): New.
* input.h (location_get_source_line): Declare.
* toplev.c (general_init): Initialize show_caret from options.
* dwarf2out.c (gen_producer_string): Handle fdiagnostics-show-caret.
* opts.c (common_handle_option): Likewise.
* pretty-print.h (pp_get_prefix): New.
(pp_base_get_prefix): New.
* common.opt (fdiagnostics-show-caret): New option.
* doc/invoke.texi (fdiagnostics-show-caret): Document it.
testsuite/
* lib/prune.exp: Add -fno-diagnostics-show-caret.
libstdc++-v3/
* testsuite/lib/prune.exp: Handle caret.
libmudflap/
* testsuite/lib/libmudflap.exp: Handle caret.
From-SVN: r186305
Diffstat (limited to 'gcc/diagnostic.c')
-rw-r--r-- | gcc/diagnostic.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c index a68d6ce..60773d3 100644 --- a/gcc/diagnostic.c +++ b/gcc/diagnostic.c @@ -78,6 +78,35 @@ file_name_as_prefix (const char *f) +/* Return the value of the getenv("COLUMNS") as an integer. If the + value is not set to a positive integer, then return INT_MAX. */ +static int +getenv_columns (void) +{ + const char * s = getenv ("COLUMNS"); + if (s != NULL) { + int n = atoi (s); + if (n > 0) + return n; + } + return INT_MAX; +} + +/* Set caret_max_width to value. */ +void +diagnostic_set_caret_max_width (diagnostic_context *context, int value) +{ + /* One minus to account for the leading empty space. */ + value = value ? value - 1 + : (isatty (fileno (context->printer->buffer->stream)) + ? getenv_columns () - 1: INT_MAX); + + if (value <= 0) + value = INT_MAX; + + context->caret_max_width = value; +} + /* Initialize the diagnostic message outputting machinery. */ void diagnostic_initialize (diagnostic_context *context, int n_opts) @@ -100,6 +129,8 @@ diagnostic_initialize (diagnostic_context *context, int n_opts) context->classify_diagnostic = XNEWVEC (diagnostic_t, n_opts); for (i = 0; i < n_opts; i++) context->classify_diagnostic[i] = DK_UNSPECIFIED; + context->show_caret = false; + diagnostic_set_caret_max_width (context, pp_line_cutoff (context->printer)); context->show_option_requested = false; context->abort_on_error = false; context->show_column = false; @@ -196,6 +227,72 @@ diagnostic_build_prefix (diagnostic_context *context, : build_message_string ("%s:%d: %s", s.file, s.line, text)); } +/* If LINE is longer than MAX_WIDTH, and COLUMN is not smaller than + MAX_WIDTH by some margin, then adjust the start of the line such + that the COLUMN is smaller than MAX_WIDTH minus the margin. The + margin is either 10 characters or the difference between the column + and the length of the line, whatever is smaller. */ +static const char * +adjust_line (const char *line, int max_width, int *column_p) +{ + int right_margin = 10; + int line_width = strlen (line); + int column = *column_p; + + right_margin = MIN(line_width - column, right_margin); + right_margin = max_width - right_margin; + if (line_width >= max_width && column > right_margin) + { + line += column - right_margin; + *column_p = right_margin; + } + return line; +} + +/* Print the physical source line corresponding to the location of + this diagnostics, and a caret indicating the precise column. */ +void +diagnostic_show_locus (diagnostic_context * context, + const diagnostic_info *diagnostic) +{ + const char *line; + char *buffer; + expanded_location s; + int max_width; + const char *saved_prefix; + + + if (!context->show_caret + || diagnostic->location <= BUILTINS_LOCATION) + return; + + s = expand_location(diagnostic->location); + line = location_get_source_line (s); + if (line == NULL) + return; + + max_width = context->caret_max_width; + line = adjust_line (line, max_width, &(s.column)); + + pp_newline (context->printer); + saved_prefix = pp_get_prefix (context->printer); + pp_set_prefix (context->printer, NULL); + pp_character (context->printer, ' '); + while (max_width > 0 && *line != '\0') + { + char c = *line == '\t' ? ' ' : *line; + pp_character (context->printer, c); + max_width--; + line++; + } + pp_newline (context->printer); + /* pp_printf does not implement %*c. */ + buffer = XALLOCAVEC (char, s.column + 3); + snprintf (buffer, s.column + 3, " %*c", s.column, '^'); + pp_string (context->printer, buffer); + pp_set_prefix (context->printer, saved_prefix); +} + /* Take any action which is expected to happen after the diagnostic is written out. This function does not always return. */ static void @@ -547,6 +644,7 @@ diagnostic_report_diagnostic (diagnostic_context *context, pp_format (context->printer, &diagnostic->message); (*diagnostic_starter (context)) (context, diagnostic); pp_output_formatted_text (context->printer); + diagnostic_show_locus (context, diagnostic); (*diagnostic_finalizer (context)) (context, diagnostic); pp_flush (context->printer); diagnostic_action_after_output (context, diagnostic); |