mirror of https://github.com/gcc-mirror/gcc.git
diagnostics, analyzer: add CFG edge visualization to path-printing
This patch adds some ability for links between labelled ranges when quoting the user's source code, and uses this to add links between events when printing diagnostic_paths, chopping them up further into event ranges that can be printed together. It adds links to the various "from..." - "...to" events in the analyzer. For example, previously we emitted this for c-c++-common/analyzer/infinite-loop-linked-list.c's while_loop_missing_next': infinite-loop-linked-list.c:30:10: warning: infinite loop [CWE-835] [-Wanalyzer-infinite-loop] 30 | while (n) | ^ 'while_loop_missing_next': events 1-5 30 | while (n) | ^ | | | (1) infinite loop here | (2) when 'n' is non-NULL: always following 'true' branch... | (5) ...to here 31 | { 32 | sum += n->val; | ~~~~~~~~~~~~~ | | | | | (3) ...to here | (4) looping back... whereas with the patch we now emit: infinite-loop-linked-list.c:30:10: warning: infinite loop [CWE-835] [-Wanalyzer-infinite-loop] 30 | while (n) | ^ 'while_loop_missing_next': events 1-3 30 | while (n) | ^ | | | (1) infinite loop here | (2) when 'n' is non-NULL: always following 'true' branch... ->-+ | | | | |+------------------------------------------------------------------------+ 31 || { 32 || sum += n->val; || ~~~~~~ || | |+------------->(3) ...to here 'while_loop_missing_next': event 4 32 | sum += n->val; | ~~~~^~~~~~~~~ | | | (4) looping back... ->-+ | | 'while_loop_missing_next': event 5 | | |+---------------------------------+ 30 || while (n) || ^ || | |+-------->(5) ...to here which I believe is easier to understand. The patch also implements the use of unicode characters and colorization for the lines (not shown in the above example). There is a new option -fno-diagnostics-show-event-links for getting back the old behavior (added to -fdiagnostics-plain-output). gcc/analyzer/ChangeLog: * checker-event.h (checker_event::connect_to_next_event_p): Implement new diagnostic_event::connect_to_next_event_p vfunc. (start_cfg_edge_event::connect_to_next_event_p): Likewise. (start_consolidated_cfg_edges_event::connect_to_next_event_p): Likewise. * infinite-loop.cc (class looping_back_event): New subclass. (infinite_loop_diagnostic::add_final_event): Use it. gcc/ChangeLog: * common.opt (fdiagnostics-show-event-links): New option. * diagnostic-label-effects.h: New file. * diagnostic-path.h (diagnostic_event::connect_to_next_event_p): New pure virtual function. (simple_diagnostic_event::connect_to_next_event_p): Implement it. (simple_diagnostic_event::connect_to_next_event): New. (simple_diagnostic_event::m_connected_to_next_event): New field. (simple_diagnostic_path::connect_to_next_event): New decl. * diagnostic-show-locus.cc: Include "text-art/theme.h" and "diagnostic-label-effects.h". (colorizer::set_cfg_edge): New. (layout::m_fallback_theme): New field. (layout::m_theme): New field. (layout::m_effect_info): New field. (layout::m_link_lhs_state): New enum and field. (layout::m_link_rhs_column): New field. (layout_range::has_in_edge): New. (layout_range::has_out_edge): New. (layout::layout): Add "effect_info" optional param. Initialize m_theme, m_link_lhs_state, and m_link_rhs_column. (layout::maybe_add_location_range): Remove stray "FIXME" from leading comment. (layout::print_source_line): Replace space after margin with a call to print_leftmost_column. (layout::print_leftmost_column): New. (layout::start_annotation_line): Make non-const. Gain responsibility for printing the leftmost column after the margin. (layout::print_annotation_line): Drop pp_space, as this is now added by start_annotation_line. (line_label::line_label): Add "has_in_edge" and "has_out_edge" params and initialize... (line_label::m_has_in_edge): New field. (line_label::m_has_out_edge): New field. (layout::print_any_labels): Pass edge information to line_label ctor. Keep track of in-edges and out-edges, adding visualizations of these links between labels. (layout::print_leading_fixits): Drop pp_character, as this is now added by start_annotation_line. (layout::print_trailing_fixits): Fix off-by-one errors in column calculation. (layout::move_to_column): Add comment about debugging. (layout::show_ruler): Make non-const. Drop pp_space calls, as this is now added by start_annotation_line. (layout::print_line): Call print_any_right_to_left_edge_lines. (layout::print_any_right_to_left_edge_lines): New. (layout::update_any_effects): New. (gcc_rich_location::add_location_if_nearby): Initialize loc_range.m_label. (diagnostic_context::maybe_show_locus): Add "effects" param and pass it to diagnostic_context::show_locus. (diagnostic_context::show_locus): Add "effects" param, passing it to layout's ctor. Call update_any_effects on the layout after printing the lines. (selftest::test_layout_x_offset_display_utf8): Update expected result for eliminated trailing newline. (selftest::test_layout_x_offset_display_utf8): Likewise. (selftest::test_layout_x_offset_display_tab): Likewise. * diagnostic.cc (diagnostic_context::initialize): Initialize m_source_printing.show_event_links_p. (simple_diagnostic_path::connect_to_next_event): New. (simple_diagnostic_event::simple_diagnostic_event): Initialize m_connected_to_next_event. * diagnostic.h (class diagnostic_source_effect_info): New forward decl. (diagnostic_source_printing_options::show_event_links_p): New field. (diagnostic_context::maybe_show_locus): Add optional "effect_info" param. (diagnostic_context::show_locus): Add "effect_info" param. (diagnostic_show_locus): Add optional "effect_info" param. * doc/invoke.texi: Add -fno-diagnostics-show-event-links. * lto-wrapper.cc (merge_and_complain): Add OPT_fdiagnostics_show_event_links to switch. (append_compiler_options): Likewise. (append_diag_options): Likewise. * opts-common.cc (decode_cmdline_options_to_array): Add "-fno-diagnostics-show-event-links" to -fdiagnostics-plain-output. * opts.cc (common_handle_option): Add case for OPT_fdiagnostics_show_event_links. * text-art/theme.cc (ascii_theme::get_cppchar): Handle cell_kind::CFG_*. (unicode_theme::get_cppchar): Likewise. * text-art/theme.h (theme::cell_kind): Add CFG_*. * toplev.cc (general_init): Initialize global_dc->m_source_printing.show_event_links_p. * tree-diagnostic-path.cc: Define INCLUDE_ALGORITHM, INCLUDE_MEMORY, and INCLUDE_STRING. Include "diagnostic-label-effects.h". (path_label::path_label): Initialize m_effects. (path_label::get_effects): New. (class path_label::path_label_effects): New. (path_label::m_effects): New field. (class per_thread_summary): Add "friend struct event_range;". (per_thread_summary::per_thread_summary): Initialize m_last_event. (per_thread_summary::m_last_event): New field. (struct event_range::per_source_line_info): New. (event_range::event_range): Make "t" non-const. Add "show_event_links" param and use it to initialize m_show_event_links. Add info for initial event. (event_range::get_per_source_line_info): New. (event_range::maybe_add_event): Verify compatibility of the new label and existing labels with respect to the link-printing code. Update per-source-line info when an event is added. (event_range::print): Add"effect_info" param and pass to diagnostic_show_locus. (event_range::m_per_thread_summary): Make non-const. (event_range::m_source_line_info_map): New field. (event_range::m_show_event_links): New field. (path_summary::path_summary): Add "show_event_links" optional param, passing it to event_range ctor calls. Update pts.m_last_event. (thread_event_printer::print_swimlane_for_event_range): Add "effect_info" param and pass it to range->print. (print_path_summary_as_text): Keep track of the column for any out-edges at the end of printing each event_range and use as the leading in-edge for the next event_range. (default_tree_diagnostic_path_printer): Pass in show_event_links_p to path_summary ctor. (selftest::path_events_have_column_data_p): New. (class selftest::control_flow_test): New. (selftest::test_control_flow_1): New. (selftest::test_control_flow_2): New. (selftest::test_control_flow_3): New. (selftest::assert_cfg_edge_path_streq): New. (ASSERT_CFG_EDGE_PATH_STREQ): New macro. (selftest::test_control_flow_4): New. (selftest::test_control_flow_5): New. (selftest::test_control_flow_6): New. (selftest::control_flow_tests): New. (selftest::tree_diagnostic_path_cc_tests): Disable colorization on global_dc's printer. Convert event_pp to a std::unique_ptr. Call control_flow_tests via for_each_line_table_case. (gen_command_line_string): Likewise. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/event-links-ascii.c: New test. * gcc.dg/analyzer/event-links-color.c: New test. * gcc.dg/analyzer/event-links-disabled.c: New test. * gcc.dg/analyzer/event-links-unicode.c: New test. libcpp/ChangeLog: * include/rich-location.h (class label_effects): New forward decl. (range_label::get_effects): New vfunc. Signed-off-by: David Malcolm <dmalcolm@redhat.com>pull/91/merge
parent
6daed96154
commit
770657d02c
|
@ -113,6 +113,7 @@ public:
|
|||
return NULL;
|
||||
}
|
||||
meaning get_meaning () const override;
|
||||
bool connect_to_next_event_p () const override { return false; }
|
||||
diagnostic_thread_id_t get_thread_id () const final override
|
||||
{
|
||||
return 0;
|
||||
|
@ -451,6 +452,7 @@ public:
|
|||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const override;
|
||||
bool connect_to_next_event_p () const final override { return true; }
|
||||
|
||||
protected:
|
||||
label_text maybe_describe_condition (bool can_colorize) const;
|
||||
|
@ -534,6 +536,7 @@ public:
|
|||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
bool connect_to_next_event_p () const final override { return true; }
|
||||
|
||||
private:
|
||||
bool m_edge_sense;
|
||||
|
|
|
@ -162,6 +162,21 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class looping_back_event : public start_cfg_edge_event
|
||||
{
|
||||
public:
|
||||
looping_back_event (const exploded_edge &eedge,
|
||||
const event_loc_info &loc_info)
|
||||
: start_cfg_edge_event (eedge, loc_info)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override
|
||||
{
|
||||
return label_text::borrow ("looping back...");
|
||||
}
|
||||
};
|
||||
|
||||
/* A subclass of pending_diagnostic for complaining about suspected
|
||||
infinite loops. */
|
||||
|
||||
|
@ -300,8 +315,7 @@ public:
|
|||
else if (cfg_sedge->back_edge_p ())
|
||||
{
|
||||
emission_path->add_event
|
||||
(make_unique<precanned_custom_event>
|
||||
(loc_info_from, "looping back..."));
|
||||
(make_unique<looping_back_event> (*eedge, loc_info_from));
|
||||
emission_path->add_event
|
||||
(make_unique<end_cfg_edge_event>
|
||||
(*eedge,
|
||||
|
|
|
@ -1368,6 +1368,10 @@ fdiagnostics-show-caret
|
|||
Common Var(flag_diagnostics_show_caret) Init(1)
|
||||
Show the source line with a caret indicating the column.
|
||||
|
||||
fdiagnostics-show-event-links
|
||||
Common Var(flag_diagnostics_show_event_links) Init(1)
|
||||
Show lines linking related events in diagnostic paths.
|
||||
|
||||
fdiagnostics-show-labels
|
||||
Common Var(flag_diagnostics_show_labels) Init(1)
|
||||
Show labels annotating ranges of source code when showing source.
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/* Classes for adding special effects when quoting source code.
|
||||
Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
Contributed by David Malcolm <dmalcolm@redhat.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GCC_DIAGNOSTIC_LABEL_EFFECTS_H
|
||||
#define GCC_DIAGNOSTIC_LABEL_EFFECTS_H
|
||||
|
||||
/* Abstract base class for describing special effects when printing
|
||||
a label when quoting source code. */
|
||||
|
||||
class label_effects
|
||||
{
|
||||
public:
|
||||
virtual ~label_effects () {}
|
||||
|
||||
/* Adding links between labels, e.g. for visualizing control flow
|
||||
in execution paths. */
|
||||
virtual bool has_in_edge (unsigned range_idx) const = 0;
|
||||
virtual bool has_out_edge (unsigned range_idx) const = 0;
|
||||
};
|
||||
|
||||
/* A class to hold state when quoting a run of lines of source code. */
|
||||
|
||||
class diagnostic_source_effect_info
|
||||
{
|
||||
public:
|
||||
diagnostic_source_effect_info ()
|
||||
: m_leading_in_edge_column (-1),
|
||||
m_trailing_out_edge_column (-1)
|
||||
{
|
||||
}
|
||||
|
||||
/* The column for an incoming link to the first label,
|
||||
or -1 if no such link. */
|
||||
int m_leading_in_edge_column;
|
||||
|
||||
/* The column for an outgoing link from the final label,
|
||||
or -1 if no such link. */
|
||||
int m_trailing_out_edge_column;
|
||||
};
|
||||
|
||||
#endif /* GCC_DIAGNOSTIC_LABEL_EFFECTS_H */
|
|
@ -156,6 +156,10 @@ class diagnostic_event
|
|||
|
||||
virtual meaning get_meaning () const = 0;
|
||||
|
||||
/* True iff we should draw a line connecting this event to the
|
||||
next event (e.g. to highlight control flow). */
|
||||
virtual bool connect_to_next_event_p () const = 0;
|
||||
|
||||
virtual diagnostic_thread_id_t get_thread_id () const = 0;
|
||||
|
||||
/* Hook for SARIF output to allow for adding diagnostic-specific
|
||||
|
@ -224,16 +228,26 @@ class simple_diagnostic_event : public diagnostic_event
|
|||
{
|
||||
return meaning ();
|
||||
}
|
||||
bool connect_to_next_event_p () const final override
|
||||
{
|
||||
return m_connected_to_next_event;
|
||||
}
|
||||
diagnostic_thread_id_t get_thread_id () const final override
|
||||
{
|
||||
return m_thread_id;
|
||||
}
|
||||
|
||||
void connect_to_next_event ()
|
||||
{
|
||||
m_connected_to_next_event = true;
|
||||
}
|
||||
|
||||
private:
|
||||
location_t m_loc;
|
||||
tree m_fndecl;
|
||||
int m_depth;
|
||||
char *m_desc; // has been i18n-ed and formatted
|
||||
bool m_connected_to_next_event;
|
||||
diagnostic_thread_id_t m_thread_id;
|
||||
};
|
||||
|
||||
|
@ -277,6 +291,8 @@ class simple_diagnostic_path : public diagnostic_path
|
|||
const char *fmt, ...)
|
||||
ATTRIBUTE_GCC_DIAG(6,7);
|
||||
|
||||
void connect_to_next_event ();
|
||||
|
||||
private:
|
||||
auto_delete_vec<simple_diagnostic_thread> m_threads;
|
||||
auto_delete_vec<simple_diagnostic_event> m_events;
|
||||
|
|
|
@ -33,6 +33,8 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "selftest-diagnostic.h"
|
||||
#include "cpplib.h"
|
||||
#include "text-art/types.h"
|
||||
#include "text-art/theme.h"
|
||||
#include "diagnostic-label-effects.h"
|
||||
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
# include <termios.h>
|
||||
|
@ -100,6 +102,7 @@ class colorizer
|
|||
else
|
||||
set_state (range_idx);
|
||||
}
|
||||
void set_cfg_edge () { set_state (0); }
|
||||
void set_normal_text () { set_state (STATE_NORMAL_TEXT); }
|
||||
void set_fixit_insert () { set_state (STATE_FIXIT_INSERT); }
|
||||
void set_fixit_delete () { set_state (STATE_FIXIT_DELETE); }
|
||||
|
@ -236,6 +239,9 @@ class layout_range
|
|||
enum column_unit col_unit) const;
|
||||
bool intersects_line_p (linenum_type row) const;
|
||||
|
||||
bool has_in_edge () const;
|
||||
bool has_out_edge () const;
|
||||
|
||||
layout_point m_start;
|
||||
layout_point m_finish;
|
||||
enum range_display_kind m_range_display_kind;
|
||||
|
@ -371,7 +377,8 @@ class layout
|
|||
layout (const diagnostic_context &context,
|
||||
const rich_location &richloc,
|
||||
diagnostic_t diagnostic_kind,
|
||||
pretty_printer *pp);
|
||||
pretty_printer *pp,
|
||||
diagnostic_source_effect_info *effect_info = nullptr);
|
||||
|
||||
bool maybe_add_location_range (const location_range *loc_range,
|
||||
unsigned original_idx,
|
||||
|
@ -390,22 +397,27 @@ class layout
|
|||
|
||||
void print_line (linenum_type row);
|
||||
|
||||
void print_any_right_to_left_edge_lines ();
|
||||
|
||||
void on_bad_codepoint (const char *ptr, cppchar_t ch, size_t ch_sz);
|
||||
|
||||
void update_any_effects () const;
|
||||
|
||||
private:
|
||||
bool will_show_line_p (linenum_type row) const;
|
||||
void print_leading_fixits (linenum_type row);
|
||||
line_bounds print_source_line (linenum_type row, const char *line,
|
||||
int line_bytes);
|
||||
bool should_print_annotation_line_p (linenum_type row) const;
|
||||
void start_annotation_line (char margin_char = ' ') const;
|
||||
void print_leftmost_column ();
|
||||
void start_annotation_line (char margin_char = ' ');
|
||||
void print_annotation_line (linenum_type row, const line_bounds lbounds);
|
||||
void print_any_labels (linenum_type row);
|
||||
void print_trailing_fixits (linenum_type row);
|
||||
|
||||
bool annotation_line_showed_range_p (linenum_type line, int start_column,
|
||||
int finish_column) const;
|
||||
void show_ruler (int max_column) const;
|
||||
void show_ruler (int max_column);
|
||||
|
||||
bool validate_fixit_hint_p (const fixit_hint *hint);
|
||||
|
||||
|
@ -437,6 +449,9 @@ class layout
|
|||
const line_maps *m_line_table;
|
||||
file_cache &m_file_cache;
|
||||
pretty_printer *m_pp;
|
||||
const text_art::ascii_theme m_fallback_theme;
|
||||
const text_art::theme &m_theme;
|
||||
diagnostic_source_effect_info *m_effect_info;
|
||||
char_display_policy m_policy;
|
||||
location_t m_primary_loc;
|
||||
exploc_with_display_col m_exploc;
|
||||
|
@ -448,6 +463,55 @@ class layout
|
|||
int m_linenum_width;
|
||||
int m_x_offset_display;
|
||||
bool m_escape_on_output;
|
||||
|
||||
/* Fields for handling links between labels (e.g. for showing CFG edges
|
||||
in execution paths).
|
||||
Note that the logic for printing such links makes various simplifying
|
||||
assumptions about the set of labels in the rich_location, and users
|
||||
of this code will need to split up labels into separate rich_location
|
||||
instances to respect these assumptions, or the output will look wrong.
|
||||
See the diagnostic_path-printing code for more information. */
|
||||
|
||||
/* An enum for describing the state of the leftmost column,
|
||||
used for showing links between labels.
|
||||
Consider e.g.
|
||||
.x0000000001111111111222222222233333333334444444444.
|
||||
.x1234567890123456789012345678901234567890123456789.
|
||||
| | <- none
|
||||
| (9) following ‘false’ branch... ->-+ <- none
|
||||
| | <- none
|
||||
| | <- none
|
||||
|+----------------------------------------+ <- rewinding to lhs
|
||||
|| result->i = i; <- at lhs
|
||||
|| ~~~~~~~~~~^~~ <- at lhs
|
||||
|| | <- at lhs
|
||||
|+----------->(10) ...to here <- indenting to dest
|
||||
^^
|
||||
||
|
||||
|leftmost column ("x" above).
|
||||
"margin". */
|
||||
enum class link_lhs_state {
|
||||
none,
|
||||
rewinding_to_lhs,
|
||||
at_lhs,
|
||||
indenting_to_dest
|
||||
} m_link_lhs_state;
|
||||
|
||||
/* The column of the current link on the RHS, if any, or
|
||||
-1 if there is none.
|
||||
Consider e.g.
|
||||
.x0000000001111111111222222222233333333334444444444.
|
||||
.x1234567890123456789012345678901234567890123456789.
|
||||
| | <- -1
|
||||
| (10) following ‘false’ branch... ->-+ <- 42
|
||||
| | <- 42
|
||||
| | <- 42
|
||||
|+-----------------------------------------+ <- 42
|
||||
|| result->i = i; <- -1
|
||||
|| ~~~~~~~~~~^~~ <- -1
|
||||
|| | <- -1
|
||||
|+----------->(11) ...to here <- -1. */
|
||||
int m_link_rhs_column;
|
||||
};
|
||||
|
||||
/* Implementation of "class colorizer". */
|
||||
|
@ -691,6 +755,34 @@ layout_range::intersects_line_p (linenum_type row) const
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Return true if this layout_range should have an in-edge. */
|
||||
|
||||
bool
|
||||
layout_range::has_in_edge () const
|
||||
{
|
||||
if (!m_label)
|
||||
return false;
|
||||
const label_effects *effects = m_label->get_effects (m_original_idx);
|
||||
if (!effects)
|
||||
return false;
|
||||
|
||||
return effects->has_in_edge (m_original_idx);
|
||||
}
|
||||
|
||||
/* Return true if this layout_range should have an out-edge. */
|
||||
|
||||
bool
|
||||
layout_range::has_out_edge () const
|
||||
{
|
||||
if (!m_label)
|
||||
return false;
|
||||
const label_effects *effects = m_label->get_effects (m_original_idx);
|
||||
if (!effects)
|
||||
return false;
|
||||
|
||||
return effects->has_out_edge (m_original_idx);
|
||||
}
|
||||
|
||||
#if CHECKING_P
|
||||
|
||||
/* Default for when we don't care what the tab expansion is set to. */
|
||||
|
@ -1196,11 +1288,17 @@ make_policy (const diagnostic_context &dc,
|
|||
layout::layout (const diagnostic_context &context,
|
||||
const rich_location &richloc,
|
||||
diagnostic_t diagnostic_kind,
|
||||
pretty_printer *pp)
|
||||
pretty_printer *pp,
|
||||
diagnostic_source_effect_info *effect_info)
|
||||
: m_options (context.m_source_printing),
|
||||
m_line_table (richloc.get_line_table ()),
|
||||
m_file_cache (context.get_file_cache ()),
|
||||
m_pp (pp ? pp : context.printer),
|
||||
/* Ensure we have a non-null m_theme. */
|
||||
m_theme (context.get_diagram_theme ()
|
||||
? *context.get_diagram_theme ()
|
||||
: *static_cast <const text_art::theme *> (&m_fallback_theme)),
|
||||
m_effect_info (effect_info),
|
||||
m_policy (make_policy (context, richloc)),
|
||||
m_primary_loc (richloc.get_range (0)->m_loc),
|
||||
m_exploc (m_file_cache,
|
||||
|
@ -1213,8 +1311,15 @@ layout::layout (const diagnostic_context &context,
|
|||
m_line_spans (1 + richloc.get_num_locations ()),
|
||||
m_linenum_width (0),
|
||||
m_x_offset_display (0),
|
||||
m_escape_on_output (richloc.escape_on_output_p ())
|
||||
m_escape_on_output (richloc.escape_on_output_p ()),
|
||||
m_link_lhs_state (link_lhs_state::none),
|
||||
m_link_rhs_column (-1)
|
||||
{
|
||||
if (m_options.show_event_links_p)
|
||||
if (effect_info)
|
||||
if (effect_info->m_leading_in_edge_column)
|
||||
m_link_rhs_column = effect_info->m_leading_in_edge_column;
|
||||
|
||||
for (unsigned int idx = 0; idx < richloc.get_num_locations (); idx++)
|
||||
{
|
||||
/* This diagnostic printer can only cope with "sufficiently sane" ranges.
|
||||
|
@ -1249,7 +1354,7 @@ layout::layout (const diagnostic_context &context,
|
|||
those that we can sanely print.
|
||||
|
||||
ORIGINAL_IDX is the index of LOC_RANGE within its rich_location,
|
||||
(for use as extrinsic state by label ranges FIXME).
|
||||
(for use as extrinsic state by label ranges).
|
||||
|
||||
If RESTRICT_TO_CURRENT_LINE_SPANS is true, then LOC_RANGE is also
|
||||
filtered against this layout instance's current line spans: it
|
||||
|
@ -1718,10 +1823,10 @@ layout::print_source_line (linenum_type row, const char *line, int line_bytes)
|
|||
int width = num_digits (row);
|
||||
for (int i = 0; i < m_linenum_width - width; i++)
|
||||
pp_space (m_pp);
|
||||
pp_printf (m_pp, "%i | ", row);
|
||||
pp_printf (m_pp, "%i |", row);
|
||||
}
|
||||
else
|
||||
pp_space (m_pp);
|
||||
|
||||
print_leftmost_column ();
|
||||
|
||||
/* We will stop printing the source line at any trailing whitespace. */
|
||||
line_bytes = get_line_bytes_without_trailing_whitespace (line,
|
||||
|
@ -1824,11 +1929,59 @@ layout::should_print_annotation_line_p (linenum_type row) const
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Begin an annotation line. If m_show_line_numbers_p, print the left
|
||||
margin, which is empty for annotation lines. Otherwise, do nothing. */
|
||||
/* Print the leftmost column after the margin, which is used for showing
|
||||
links between labels (e.g. for CFG edges in execution paths). */
|
||||
|
||||
void
|
||||
layout::start_annotation_line (char margin_char) const
|
||||
layout::print_leftmost_column ()
|
||||
{
|
||||
if (!m_options.show_event_links_p)
|
||||
gcc_assert (m_link_lhs_state == link_lhs_state::none);
|
||||
|
||||
switch (m_link_lhs_state)
|
||||
{
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
case link_lhs_state::none:
|
||||
pp_space (m_pp);
|
||||
break;
|
||||
case link_lhs_state::rewinding_to_lhs:
|
||||
{
|
||||
m_colorizer.set_cfg_edge ();
|
||||
const cppchar_t ch= m_theme.get_cppchar
|
||||
(text_art::theme::cell_kind::CFG_FROM_LEFT_TO_DOWN);
|
||||
pp_unicode_character (m_pp, ch);
|
||||
m_colorizer.set_normal_text ();
|
||||
}
|
||||
break;
|
||||
case link_lhs_state::at_lhs:
|
||||
{
|
||||
m_colorizer.set_cfg_edge ();
|
||||
const cppchar_t ch= m_theme.get_cppchar
|
||||
(text_art::theme::cell_kind::CFG_DOWN);
|
||||
pp_unicode_character (m_pp, ch);
|
||||
m_colorizer.set_normal_text ();
|
||||
}
|
||||
break;
|
||||
case link_lhs_state::indenting_to_dest:
|
||||
{
|
||||
m_colorizer.set_cfg_edge ();
|
||||
const cppchar_t ch= m_theme.get_cppchar
|
||||
(text_art::theme::cell_kind::CFG_FROM_DOWN_TO_RIGHT);
|
||||
pp_unicode_character (m_pp, ch);
|
||||
m_colorizer.set_normal_text ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Begin an annotation line. If m_show_line_numbers_p, print the left
|
||||
margin, which is empty for annotation lines.
|
||||
After any left margin, print a leftmost column, which is used for
|
||||
showing links between labels (e.g. for CFG edges in execution paths). */
|
||||
|
||||
void
|
||||
layout::start_annotation_line (char margin_char)
|
||||
{
|
||||
pp_emit_prefix (m_pp);
|
||||
if (m_options.show_line_numbers_p)
|
||||
|
@ -1842,6 +1995,10 @@ layout::start_annotation_line (char margin_char) const
|
|||
pp_character (m_pp, margin_char);
|
||||
pp_string (m_pp, " |");
|
||||
}
|
||||
if (margin_char == ' ')
|
||||
print_leftmost_column ();
|
||||
else
|
||||
pp_character (m_pp, margin_char);
|
||||
}
|
||||
|
||||
/* Print a line consisting of the caret/underlines for the given
|
||||
|
@ -1854,7 +2011,6 @@ layout::print_annotation_line (linenum_type row, const line_bounds lbounds)
|
|||
lbounds.m_last_non_ws_disp_col);
|
||||
|
||||
start_annotation_line ();
|
||||
pp_space (m_pp);
|
||||
|
||||
for (int column = 1 + m_x_offset_display; column < x_bound; column++)
|
||||
{
|
||||
|
@ -1926,9 +2082,13 @@ class line_label
|
|||
{
|
||||
public:
|
||||
line_label (int state_idx, int column,
|
||||
label_text text)
|
||||
label_text text,
|
||||
bool has_in_edge,
|
||||
bool has_out_edge)
|
||||
: m_state_idx (state_idx), m_column (column),
|
||||
m_text (std::move (text)), m_label_line (0), m_has_vbar (true)
|
||||
m_text (std::move (text)), m_label_line (0), m_has_vbar (true),
|
||||
m_has_in_edge (has_in_edge),
|
||||
m_has_out_edge (has_out_edge)
|
||||
{
|
||||
/* Using styled_string rather than cpp_display_width here
|
||||
lets us skip SGR formatting characters for color and URLs.
|
||||
|
@ -1959,6 +2119,8 @@ public:
|
|||
size_t m_display_width;
|
||||
int m_label_line;
|
||||
bool m_has_vbar;
|
||||
bool m_has_in_edge;
|
||||
bool m_has_out_edge;
|
||||
};
|
||||
|
||||
/* Print any labels in this row. */
|
||||
|
@ -1996,7 +2158,9 @@ layout::print_any_labels (linenum_type row)
|
|||
if (text.get () == NULL)
|
||||
continue;
|
||||
|
||||
labels.safe_push (line_label (i, disp_col, std::move (text)));
|
||||
labels.safe_push (line_label (i, disp_col, std::move (text),
|
||||
range->has_in_edge (),
|
||||
range->has_out_edge ()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2040,6 +2204,7 @@ layout::print_any_labels (linenum_type row)
|
|||
label 1 : label line 3. */
|
||||
|
||||
int max_label_line = 1;
|
||||
int label_line_with_in_edge = -1;
|
||||
{
|
||||
int next_column = INT_MAX;
|
||||
line_label *label;
|
||||
|
@ -2058,18 +2223,28 @@ layout::print_any_labels (linenum_type row)
|
|||
}
|
||||
|
||||
label->m_label_line = max_label_line;
|
||||
if (m_options.show_event_links_p)
|
||||
if (label->m_has_in_edge)
|
||||
label_line_with_in_edge = max_label_line;
|
||||
next_column = label->m_column;
|
||||
}
|
||||
}
|
||||
|
||||
gcc_assert (labels.length () > 0);
|
||||
|
||||
/* Print the "label lines". For each label within the line, print
|
||||
either a vertical bar ('|') for the labels that are lower down, or the
|
||||
labels themselves once we've reached their line. */
|
||||
{
|
||||
for (int label_line = 0; label_line <= max_label_line; label_line++)
|
||||
{
|
||||
if (label_line == label_line_with_in_edge)
|
||||
{
|
||||
gcc_assert (m_options.show_event_links_p);
|
||||
m_link_lhs_state = link_lhs_state::indenting_to_dest;
|
||||
}
|
||||
start_annotation_line ();
|
||||
pp_space (m_pp);
|
||||
|
||||
int column = 1 + m_x_offset_display;
|
||||
line_label *label;
|
||||
FOR_EACH_VEC_ELT (labels, i, label)
|
||||
|
@ -2081,7 +2256,35 @@ layout::print_any_labels (linenum_type row)
|
|||
if (label_line == label->m_label_line)
|
||||
{
|
||||
gcc_assert (column <= label->m_column);
|
||||
move_to_column (&column, label->m_column, true);
|
||||
|
||||
if (label_line == label_line_with_in_edge)
|
||||
{
|
||||
/* Print a prefix showing an incoming
|
||||
link from another label.
|
||||
.|+----------->(10) ...to here
|
||||
. ^~~~~~~~~~~~~
|
||||
. this text. */
|
||||
gcc_assert (m_options.show_event_links_p);
|
||||
m_colorizer.set_cfg_edge ();
|
||||
const cppchar_t right= m_theme.get_cppchar
|
||||
(text_art::theme::cell_kind::CFG_RIGHT);
|
||||
while (column < label->m_column - 1)
|
||||
{
|
||||
pp_unicode_character (m_pp, right);
|
||||
column++;
|
||||
}
|
||||
if (column == label->m_column - 1)
|
||||
{
|
||||
pp_character (m_pp, '>');
|
||||
column++;
|
||||
}
|
||||
m_colorizer.set_normal_text ();
|
||||
m_link_lhs_state = link_lhs_state::none;
|
||||
label_line_with_in_edge = -1;
|
||||
}
|
||||
else
|
||||
move_to_column (&column, label->m_column, true);
|
||||
gcc_assert (column == label->m_column);
|
||||
/* Colorize the text, unless it's for events in a
|
||||
diagnostic_path. */
|
||||
if (!m_diagnostic_path_p)
|
||||
|
@ -2089,6 +2292,29 @@ layout::print_any_labels (linenum_type row)
|
|||
pp_string (m_pp, label->m_text.m_buffer);
|
||||
m_colorizer.set_normal_text ();
|
||||
column += label->m_display_width;
|
||||
if (m_options.show_event_links_p && label->m_has_out_edge)
|
||||
{
|
||||
/* Print a suffix showing the start of a linkage
|
||||
to another label e.g. " ->-+" which will be the
|
||||
first part of e.g.
|
||||
. (9) following ‘false’ branch... ->-+ <- HERE
|
||||
. |
|
||||
. |
|
||||
. */
|
||||
const cppchar_t right= m_theme.get_cppchar
|
||||
(text_art::theme::cell_kind::CFG_RIGHT);
|
||||
const cppchar_t from_right_to_down= m_theme.get_cppchar
|
||||
(text_art::theme::cell_kind::CFG_FROM_RIGHT_TO_DOWN);
|
||||
m_colorizer.set_cfg_edge ();
|
||||
pp_space (m_pp);
|
||||
pp_unicode_character (m_pp, right);
|
||||
pp_unicode_character (m_pp, '>');
|
||||
pp_unicode_character (m_pp, right);
|
||||
pp_unicode_character (m_pp, from_right_to_down);
|
||||
m_colorizer.set_normal_text ();
|
||||
column += 5;
|
||||
m_link_rhs_column = column - 1;
|
||||
}
|
||||
}
|
||||
else if (label->m_has_vbar)
|
||||
{
|
||||
|
@ -2100,10 +2326,38 @@ layout::print_any_labels (linenum_type row)
|
|||
column++;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a vertical link line on the RHS, print the
|
||||
'|' on this annotation line after the labels. */
|
||||
if (m_link_rhs_column != -1 && column < m_link_rhs_column)
|
||||
{
|
||||
move_to_column (&column, m_link_rhs_column, true);
|
||||
m_colorizer.set_cfg_edge ();
|
||||
const cppchar_t down= m_theme.get_cppchar
|
||||
(text_art::theme::cell_kind::CFG_DOWN);
|
||||
pp_unicode_character (m_pp, down);
|
||||
m_colorizer.set_normal_text ();
|
||||
}
|
||||
|
||||
print_newline ();
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a vertical link line on the RHS, print a trailing
|
||||
annotation line showing the vertical line. */
|
||||
if (m_link_rhs_column != -1)
|
||||
{
|
||||
int column = 1 + m_x_offset_display;
|
||||
start_annotation_line ();
|
||||
move_to_column (&column, m_link_rhs_column, true);
|
||||
m_colorizer.set_cfg_edge ();
|
||||
const cppchar_t down= m_theme.get_cppchar
|
||||
(text_art::theme::cell_kind::CFG_DOWN);
|
||||
pp_unicode_character (m_pp, down);
|
||||
m_colorizer.set_normal_text ();
|
||||
print_newline ();
|
||||
}
|
||||
|
||||
/* Clean up. */
|
||||
{
|
||||
line_label *label;
|
||||
|
@ -2139,7 +2393,6 @@ layout::print_leading_fixits (linenum_type row)
|
|||
the surrounding text. */
|
||||
m_colorizer.set_normal_text ();
|
||||
start_annotation_line ('+');
|
||||
pp_character (m_pp, '+');
|
||||
m_colorizer.set_fixit_insert ();
|
||||
/* Print all but the trailing newline of the fix-it hint.
|
||||
We have to print the newline separately to avoid
|
||||
|
@ -2598,7 +2851,7 @@ layout::print_trailing_fixits (linenum_type row)
|
|||
/* Now print the corrections. */
|
||||
unsigned i;
|
||||
correction *c;
|
||||
int column = m_x_offset_display;
|
||||
int column = 1 + m_x_offset_display;
|
||||
|
||||
if (!corrections.m_corrections.is_empty ())
|
||||
start_annotation_line ();
|
||||
|
@ -2649,7 +2902,7 @@ layout::print_trailing_fixits (linenum_type row)
|
|||
}
|
||||
|
||||
/* Add a trailing newline, if necessary. */
|
||||
move_to_column (&column, 0, false);
|
||||
move_to_column (&column, 1 + m_x_offset_display, false);
|
||||
}
|
||||
|
||||
/* Disable any colorization and emit a newline. */
|
||||
|
@ -2766,11 +3019,15 @@ layout::move_to_column (int *column, int dest_column, bool add_left_margin)
|
|||
print_newline ();
|
||||
if (add_left_margin)
|
||||
start_annotation_line ();
|
||||
*column = m_x_offset_display;
|
||||
*column = 1 + m_x_offset_display;
|
||||
}
|
||||
|
||||
while (*column < dest_column)
|
||||
{
|
||||
/* For debugging column issues, it can be helpful to replace this
|
||||
pp_space call with
|
||||
pp_character (m_pp, '0' + (*column % 10));
|
||||
to visualize the changing value of "*column". */
|
||||
pp_space (m_pp);
|
||||
(*column)++;
|
||||
}
|
||||
|
@ -2780,13 +3037,12 @@ layout::move_to_column (int *column, int dest_column, bool add_left_margin)
|
|||
(after the 1-column indent). */
|
||||
|
||||
void
|
||||
layout::show_ruler (int max_column) const
|
||||
layout::show_ruler (int max_column)
|
||||
{
|
||||
/* Hundreds. */
|
||||
if (max_column > 99)
|
||||
{
|
||||
start_annotation_line ();
|
||||
pp_space (m_pp);
|
||||
for (int column = 1 + m_x_offset_display; column <= max_column; column++)
|
||||
if (column % 10 == 0)
|
||||
pp_character (m_pp, '0' + (column / 100) % 10);
|
||||
|
@ -2797,7 +3053,6 @@ layout::show_ruler (int max_column) const
|
|||
|
||||
/* Tens. */
|
||||
start_annotation_line ();
|
||||
pp_space (m_pp);
|
||||
for (int column = 1 + m_x_offset_display; column <= max_column; column++)
|
||||
if (column % 10 == 0)
|
||||
pp_character (m_pp, '0' + (column / 10) % 10);
|
||||
|
@ -2807,7 +3062,6 @@ layout::show_ruler (int max_column) const
|
|||
|
||||
/* Units. */
|
||||
start_annotation_line ();
|
||||
pp_space (m_pp);
|
||||
for (int column = 1 + m_x_offset_display; column <= max_column; column++)
|
||||
pp_character (m_pp, '0' + (column % 10));
|
||||
pp_newline (m_pp);
|
||||
|
@ -2824,6 +3078,7 @@ layout::print_line (linenum_type row)
|
|||
if (!line)
|
||||
return;
|
||||
|
||||
print_any_right_to_left_edge_lines ();
|
||||
print_leading_fixits (row);
|
||||
const line_bounds lbounds
|
||||
= print_source_line (row, line.get_buffer (), line.length ());
|
||||
|
@ -2834,6 +3089,63 @@ layout::print_line (linenum_type row)
|
|||
print_trailing_fixits (row);
|
||||
}
|
||||
|
||||
/* If there's a link column in the RHS, print something like this:
|
||||
" │\n"
|
||||
"┌──────────────────────────────────────────┘\n"
|
||||
showing the link entering at the top right and emerging
|
||||
at the bottom left. */
|
||||
|
||||
void
|
||||
layout::print_any_right_to_left_edge_lines ()
|
||||
{
|
||||
if (m_link_rhs_column == -1)
|
||||
/* Can also happen if the out-edge had UNKNOWN_LOCATION. */
|
||||
return;
|
||||
|
||||
gcc_assert (m_options.show_event_links_p);
|
||||
|
||||
/* Print the line with "|". */
|
||||
start_annotation_line ();
|
||||
int column = 1 + m_x_offset_display;
|
||||
move_to_column (&column, m_link_rhs_column, true);
|
||||
m_colorizer.set_cfg_edge ();
|
||||
const cppchar_t down= m_theme.get_cppchar
|
||||
(text_art::theme::cell_kind::CFG_DOWN);
|
||||
pp_unicode_character (m_pp, down);
|
||||
m_colorizer.set_normal_text ();
|
||||
pp_newline (m_pp);
|
||||
|
||||
/* Print the line with "┌──────────────────────────────────────────┘". */
|
||||
m_link_lhs_state = link_lhs_state::rewinding_to_lhs;
|
||||
start_annotation_line ();
|
||||
m_colorizer.set_cfg_edge ();
|
||||
const cppchar_t left= m_theme.get_cppchar
|
||||
(text_art::theme::cell_kind::CFG_LEFT);
|
||||
for (int column = 1 + m_x_offset_display; column < m_link_rhs_column;
|
||||
column++)
|
||||
pp_unicode_character (m_pp, left);
|
||||
const cppchar_t from_down_to_left = m_theme.get_cppchar
|
||||
(text_art::theme::cell_kind::CFG_FROM_DOWN_TO_LEFT);
|
||||
pp_unicode_character (m_pp, from_down_to_left);
|
||||
m_colorizer.set_normal_text ();
|
||||
pp_newline (m_pp);
|
||||
|
||||
/* We now have a link line on the LHS,
|
||||
and no longer have one on the RHS. */
|
||||
m_link_lhs_state = link_lhs_state::at_lhs;
|
||||
m_link_rhs_column = -1;
|
||||
}
|
||||
|
||||
/* Update this layout's m_effect_info (if any) after printing this
|
||||
layout. */
|
||||
|
||||
void
|
||||
layout::update_any_effects () const
|
||||
{
|
||||
if (m_effect_info)
|
||||
m_effect_info->m_trailing_out_edge_column = m_link_rhs_column;
|
||||
}
|
||||
|
||||
} /* End of anonymous namespace. */
|
||||
|
||||
/* If LOC is within the spans of lines that will already be printed for
|
||||
|
@ -2853,6 +3165,7 @@ gcc_rich_location::add_location_if_nearby (location_t loc,
|
|||
location_range loc_range;
|
||||
loc_range.m_loc = loc;
|
||||
loc_range.m_range_display_kind = SHOW_RANGE_WITHOUT_CARET;
|
||||
loc_range.m_label = nullptr;
|
||||
if (!layout.maybe_add_location_range (&loc_range, 0,
|
||||
restrict_to_current_line_spans))
|
||||
return false;
|
||||
|
@ -2867,7 +3180,8 @@ gcc_rich_location::add_location_if_nearby (location_t loc,
|
|||
void
|
||||
diagnostic_context::maybe_show_locus (const rich_location &richloc,
|
||||
diagnostic_t diagnostic_kind,
|
||||
pretty_printer *pp)
|
||||
pretty_printer *pp,
|
||||
diagnostic_source_effect_info *effects)
|
||||
{
|
||||
const location_t loc = richloc.get_loc ();
|
||||
/* Do nothing if source-printing has been disabled. */
|
||||
|
@ -2888,19 +3202,22 @@ diagnostic_context::maybe_show_locus (const rich_location &richloc,
|
|||
|
||||
m_last_location = loc;
|
||||
|
||||
show_locus (richloc, diagnostic_kind, pp);
|
||||
show_locus (richloc, diagnostic_kind, pp, effects);
|
||||
}
|
||||
|
||||
/* Print the physical source code corresponding to the location of
|
||||
this diagnostic, with additional annotations.
|
||||
If PP is non-null, then use it rather than this context's printer. */
|
||||
If PP is non-null, then use it rather than this context's printer.
|
||||
If EFFECTS is non-null, then use and update it. */
|
||||
|
||||
void
|
||||
diagnostic_context::show_locus (const rich_location &richloc,
|
||||
diagnostic_t diagnostic_kind,
|
||||
pretty_printer *pp)
|
||||
pretty_printer *pp,
|
||||
diagnostic_source_effect_info *effects)
|
||||
{
|
||||
layout layout (*this, richloc, diagnostic_kind, pp);
|
||||
layout layout (*this, richloc, diagnostic_kind, pp, effects);
|
||||
|
||||
for (int line_span_idx = 0; line_span_idx < layout.get_num_line_spans ();
|
||||
line_span_idx++)
|
||||
{
|
||||
|
@ -2929,6 +3246,8 @@ diagnostic_context::show_locus (const rich_location &richloc,
|
|||
row <= last_line; row++)
|
||||
layout.print_line (row);
|
||||
}
|
||||
|
||||
layout.update_any_effects ();
|
||||
}
|
||||
|
||||
#if CHECKING_P
|
||||
|
@ -3137,7 +3456,7 @@ test_layout_x_offset_display_utf8 (const line_table_case &case_)
|
|||
" 1 | \xf0\x9f\x98\x82\xf0\x9f\x98\x82 is a pair of emojis "
|
||||
"that occupies 8 bytes and 4 display columns, starting at "
|
||||
"column #102.\n"
|
||||
" | ^\n\n",
|
||||
" | ^\n",
|
||||
pp_formatted_text (dc.printer));
|
||||
}
|
||||
|
||||
|
@ -3162,7 +3481,7 @@ test_layout_x_offset_display_utf8 (const line_table_case &case_)
|
|||
" 1 | \xf0\x9f\x98\x82 is a pair of emojis "
|
||||
"that occupies 8 bytes and 4 display columns, starting at "
|
||||
"column #102.\n"
|
||||
" | ^\n\n",
|
||||
" | ^\n",
|
||||
pp_formatted_text (dc.printer));
|
||||
}
|
||||
|
||||
|
@ -3266,11 +3585,11 @@ test_layout_x_offset_display_tab (const line_table_case &case_)
|
|||
const char *output1
|
||||
= " 1 | ' is a tab that occupies 1 byte and a variable number of "
|
||||
"display columns, starting at column #103.\n"
|
||||
" | ^\n\n";
|
||||
" | ^\n";
|
||||
const char *output2
|
||||
= " 1 | ` ' is a tab that occupies 1 byte and a variable number of "
|
||||
"display columns, starting at column #103.\n"
|
||||
" | ^\n\n";
|
||||
" | ^\n";
|
||||
const char *expected_output = (extra_width[tabstop] ? output1 : output2);
|
||||
ASSERT_STREQ (expected_output, pp_formatted_text (dc.printer));
|
||||
}
|
||||
|
|
|
@ -253,6 +253,7 @@ diagnostic_context::initialize (int n_opts)
|
|||
m_source_printing.show_line_numbers_p = false;
|
||||
m_source_printing.min_margin_width = 0;
|
||||
m_source_printing.show_ruler_p = false;
|
||||
m_source_printing.show_event_links_p = false;
|
||||
m_report_bug = false;
|
||||
m_extra_output_kind = EXTRA_DIAGNOSTIC_OUTPUT_none;
|
||||
if (const char *var = getenv ("GCC_EXTRA_DIAGNOSTIC_OUTPUT"))
|
||||
|
@ -2627,6 +2628,16 @@ simple_diagnostic_path::add_thread_event (diagnostic_thread_id_t thread_id,
|
|||
return diagnostic_event_id_t (m_events.length () - 1);
|
||||
}
|
||||
|
||||
/* Mark the most recent event on this path (which must exist) as being
|
||||
connected to the next one to be added. */
|
||||
|
||||
void
|
||||
simple_diagnostic_path::connect_to_next_event ()
|
||||
{
|
||||
gcc_assert (m_events.length () > 0);
|
||||
m_events[m_events.length () - 1]->connect_to_next_event ();
|
||||
}
|
||||
|
||||
/* struct simple_diagnostic_event. */
|
||||
|
||||
/* simple_diagnostic_event's ctor. */
|
||||
|
@ -2638,6 +2649,7 @@ simple_diagnostic_event (location_t loc,
|
|||
const char *desc,
|
||||
diagnostic_thread_id_t thread_id)
|
||||
: m_loc (loc), m_fndecl (fndecl), m_depth (depth), m_desc (xstrdup (desc)),
|
||||
m_connected_to_next_event (false),
|
||||
m_thread_id (thread_id)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -194,6 +194,7 @@ namespace json { class value; }
|
|||
class diagnostic_client_data_hooks;
|
||||
class logical_location;
|
||||
class diagnostic_diagram;
|
||||
class diagnostic_source_effect_info;
|
||||
|
||||
/* Abstract base class for a particular output format for diagnostics;
|
||||
each value of -fdiagnostics-output-format= will have its own
|
||||
|
@ -360,6 +361,11 @@ struct diagnostic_source_printing_options
|
|||
/* Usable by plugins; if true, print a debugging ruler above the
|
||||
source output. */
|
||||
bool show_ruler_p;
|
||||
|
||||
/* When printing events in an inline path, should we print lines
|
||||
visualizing links between related events (e.g. for CFG paths)?
|
||||
Corresponds to -fdiagnostics-show-event-links. */
|
||||
bool show_event_links_p;
|
||||
};
|
||||
|
||||
/* This data structure bundles altogether any information relevant to
|
||||
|
@ -433,7 +439,8 @@ public:
|
|||
|
||||
void maybe_show_locus (const rich_location &richloc,
|
||||
diagnostic_t diagnostic_kind,
|
||||
pretty_printer *pp);
|
||||
pretty_printer *pp,
|
||||
diagnostic_source_effect_info *effect_info);
|
||||
|
||||
void emit_diagram (const diagnostic_diagram &diagram);
|
||||
|
||||
|
@ -573,7 +580,8 @@ private:
|
|||
|
||||
void show_locus (const rich_location &richloc,
|
||||
diagnostic_t diagnostic_kind,
|
||||
pretty_printer *pp);
|
||||
pretty_printer *pp,
|
||||
diagnostic_source_effect_info *effect_info);
|
||||
|
||||
/* Data members.
|
||||
Ideally, all of these would be private and have "m_" prefixes. */
|
||||
|
@ -920,10 +928,11 @@ inline void
|
|||
diagnostic_show_locus (diagnostic_context *context,
|
||||
rich_location *richloc,
|
||||
diagnostic_t diagnostic_kind,
|
||||
pretty_printer *pp = nullptr)
|
||||
pretty_printer *pp = nullptr,
|
||||
diagnostic_source_effect_info *effect_info = nullptr)
|
||||
{
|
||||
gcc_assert (richloc);
|
||||
context->maybe_show_locus (*richloc, diagnostic_kind, pp);
|
||||
context->maybe_show_locus (*richloc, diagnostic_kind, pp, effect_info);
|
||||
}
|
||||
|
||||
/* Because we read source files a second time after the frontend did it the
|
||||
|
|
|
@ -307,6 +307,7 @@ Objective-C and Objective-C++ Dialects}.
|
|||
-fdiagnostics-format=@r{[}text@r{|}sarif-stderr@r{|}sarif-file@r{|}json@r{|}json-stderr@r{|}json-file@r{]}
|
||||
-fno-diagnostics-json-formatting
|
||||
-fno-diagnostics-show-option -fno-diagnostics-show-caret
|
||||
-fno-diagnostics-show-event-links
|
||||
-fno-diagnostics-show-labels -fno-diagnostics-show-line-numbers
|
||||
-fno-diagnostics-show-cwe
|
||||
-fno-diagnostics-show-rule
|
||||
|
@ -5211,7 +5212,8 @@ options:
|
|||
-fdiagnostics-color=never
|
||||
-fdiagnostics-urls=never
|
||||
-fdiagnostics-path-format=separate-events
|
||||
-fdiagnostics-text-art-charset=none}
|
||||
-fdiagnostics-text-art-charset=none
|
||||
-fno-diagnostics-show-event-links}
|
||||
In the future, if GCC changes the default appearance of its diagnostics, the
|
||||
corresponding option to disable the new behavior will be added to this list.
|
||||
|
||||
|
@ -5446,6 +5448,31 @@ as the types of expressions:
|
|||
This option suppresses the printing of these labels (in the example above,
|
||||
the vertical bars and the ``char *'' and ``long int'' text).
|
||||
|
||||
@opindex fno-diagnostics-show-event-links
|
||||
@opindex fdiagnostics-show-event-links
|
||||
@item -fno-diagnostics-show-event-links
|
||||
By default, when printing execution paths (via
|
||||
@option{-fdiagnostics-path-format=inline-events}), GCC will print lines
|
||||
connecting related events, such as the line connecting events 1 and 2 in:
|
||||
|
||||
@smallexample
|
||||
3 | if (p)
|
||||
| ^
|
||||
| |
|
||||
| (1) following `false' branch (when `p' is NULL)... ->-+
|
||||
| |
|
||||
| |
|
||||
|+------------------------------------------------------------+
|
||||
4 || return 0;
|
||||
5 || return *p;
|
||||
|| ~
|
||||
|| |
|
||||
|+-------->(2) ...to here
|
||||
| (3) dereference of NULL `p'
|
||||
@end smallexample
|
||||
|
||||
This option suppresses the printing of such connector lines.
|
||||
|
||||
@opindex fno-diagnostics-show-cwe
|
||||
@opindex fdiagnostics-show-cwe
|
||||
@item -fno-diagnostics-show-cwe
|
||||
|
|
|
@ -310,6 +310,7 @@ merge_and_complain (vec<cl_decoded_option> &decoded_options,
|
|||
|
||||
/* Fallthru. */
|
||||
case OPT_fdiagnostics_show_caret:
|
||||
case OPT_fdiagnostics_show_event_links:
|
||||
case OPT_fdiagnostics_show_labels:
|
||||
case OPT_fdiagnostics_show_line_numbers:
|
||||
case OPT_fdiagnostics_show_option:
|
||||
|
@ -726,6 +727,7 @@ append_compiler_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
|
|||
switch (option->opt_index)
|
||||
{
|
||||
case OPT_fdiagnostics_show_caret:
|
||||
case OPT_fdiagnostics_show_event_links:
|
||||
case OPT_fdiagnostics_show_labels:
|
||||
case OPT_fdiagnostics_show_line_numbers:
|
||||
case OPT_fdiagnostics_show_option:
|
||||
|
@ -785,6 +787,7 @@ append_diag_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
|
|||
case OPT_fdiagnostics_color_:
|
||||
case OPT_fdiagnostics_format_:
|
||||
case OPT_fdiagnostics_show_caret:
|
||||
case OPT_fdiagnostics_show_event_links:
|
||||
case OPT_fdiagnostics_show_labels:
|
||||
case OPT_fdiagnostics_show_line_numbers:
|
||||
case OPT_fdiagnostics_show_option:
|
||||
|
|
|
@ -1090,7 +1090,8 @@ decode_cmdline_options_to_array (unsigned int argc, const char **argv,
|
|||
"-fdiagnostics-color=never",
|
||||
"-fdiagnostics-urls=never",
|
||||
"-fdiagnostics-path-format=separate-events",
|
||||
"-fdiagnostics-text-art-charset=none"
|
||||
"-fdiagnostics-text-art-charset=none",
|
||||
"-fno-diagnostics-show-event-links"
|
||||
};
|
||||
const int num_expanded = ARRAY_SIZE (expanded_args);
|
||||
opt_array_len += num_expanded - 1;
|
||||
|
|
|
@ -2937,6 +2937,10 @@ common_handle_option (struct gcc_options *opts,
|
|||
dc->m_source_printing.enabled = value;
|
||||
break;
|
||||
|
||||
case OPT_fdiagnostics_show_event_links:
|
||||
dc->m_source_printing.show_event_links_p = value;
|
||||
break;
|
||||
|
||||
case OPT_fdiagnostics_show_labels:
|
||||
dc->m_source_printing.show_labels_p = value;
|
||||
break;
|
||||
|
@ -3818,6 +3822,7 @@ gen_command_line_string (cl_decoded_option *options,
|
|||
case OPT_fdiagnostics_show_location_:
|
||||
case OPT_fdiagnostics_show_option:
|
||||
case OPT_fdiagnostics_show_caret:
|
||||
case OPT_fdiagnostics_show_event_links:
|
||||
case OPT_fdiagnostics_show_labels:
|
||||
case OPT_fdiagnostics_show_line_numbers:
|
||||
case OPT_fdiagnostics_color_:
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/* Verify that we print event links for the analyzer, using ASCII.
|
||||
C only: we don't care about any C/C++ differences between source
|
||||
locations here. */
|
||||
|
||||
/* { dg-additional-options "-fdiagnostics-path-format=inline-events" } */
|
||||
/* { dg-additional-options "-fdiagnostics-show-line-numbers" } */
|
||||
/* { dg-additional-options "-fdiagnostics-show-caret" } */
|
||||
/* { dg-additional-options "-fdiagnostics-show-event-links" } */
|
||||
/* { dg-enable-nn-line-numbers "" } */
|
||||
|
||||
void test (int flag_a, int val, void *p)
|
||||
{
|
||||
if (flag_a)
|
||||
__builtin_free (p);
|
||||
switch (val)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
case 41:
|
||||
break;
|
||||
case 42:
|
||||
__builtin_free (p); /* { dg-warning "double-'free' of 'p'" } */
|
||||
break;
|
||||
case 43:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | __builtin_free (p);
|
||||
| ^~~~~~~~~~~~~~~~~~
|
||||
'test': events 1-6
|
||||
NN | if (flag_a)
|
||||
| ^
|
||||
| |
|
||||
| (1) following 'true' branch (when 'flag_a != 0')... ->-+
|
||||
| |
|
||||
| |
|
||||
|+------------------------------------------------------------+
|
||||
NN || __builtin_free (p);
|
||||
|| ~~~~~~~~~~~~~~~~~~
|
||||
|| |
|
||||
|+--->(2) ...to here
|
||||
| (3) first 'free' here
|
||||
NN | switch (val)
|
||||
| ~~~~~~
|
||||
| |
|
||||
| (4) following 'case 42:' branch... ->-+
|
||||
| |
|
||||
......
|
||||
| |
|
||||
|+----------------------------------------+
|
||||
NN || case 42:
|
||||
|| ~~~~
|
||||
|| |
|
||||
|+--->(5) ...to here
|
||||
NN | __builtin_free (p);
|
||||
| ~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| (6) second 'free' here; first 'free' was at (3)
|
||||
{ dg-end-multiline-output "" } */
|
|
@ -0,0 +1,66 @@
|
|||
/* Verify colorization of event links (using ASCII).
|
||||
C only: we don't care about any C/C++ differences between source
|
||||
locations here. */
|
||||
|
||||
/* { dg-additional-options "-fdiagnostics-path-format=inline-events" } */
|
||||
/* { dg-additional-options "-fdiagnostics-show-line-numbers" } */
|
||||
/* { dg-additional-options "-fdiagnostics-show-caret" } */
|
||||
/* { dg-additional-options "-fdiagnostics-show-event-links" } */
|
||||
/* { dg-additional-options "-fdiagnostics-color=always" } */
|
||||
/* { dg-enable-nn-line-numbers "" } */
|
||||
|
||||
void test (int flag_a, int val, void *p)
|
||||
{
|
||||
if (flag_a)
|
||||
__builtin_free (p);
|
||||
switch (val)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
case 41:
|
||||
break;
|
||||
case 42:
|
||||
__builtin_free (p);
|
||||
break;
|
||||
case 43:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | [01;35m[K__builtin_free (p)[m[K;
|
||||
| [01;35m[K^~~~~~~~~~~~~~~~~~[m[K
|
||||
'[01m[Ktest[m[K': events 1-6
|
||||
NN | if [01;36m[K([m[Kflag_a)
|
||||
| [01;36m[K^[m[K
|
||||
| [01;36m[K|[m[K
|
||||
| [01;36m[K(1)[m[K following '[01m[Ktrue[m[K' branch (when '[01m[Kflag_a != 0[m[K')...[01;36m[K ->-+[m[K
|
||||
| [01;36m[K|[m[K
|
||||
| [01;36m[K|[m[K
|
||||
|[01;36m[K+[m[K[01;36m[K------------------------------------------------------------+[m[K
|
||||
NN |[01;36m[K|[m[K [01;36m[K__builtin_free (p)[m[K;
|
||||
|[01;36m[K|[m[K [01;36m[K~~~~~~~~~~~~~~~~~~[m[K
|
||||
|[01;36m[K|[m[K [01;36m[K|[m[K
|
||||
|[01;36m[K+[m[K[01;36m[K--->[m[K[01;36m[K(2)[m[K ...to here
|
||||
| [01;36m[K(3)[m[K first '[01m[Kfree[m[K' here
|
||||
NN | [01;36m[Kswitch[m[K (val)
|
||||
| [01;36m[K~~~~~~[m[K
|
||||
| [01;36m[K|[m[K
|
||||
| [01;36m[K(4)[m[K following '[01m[Kcase 42:[m[K' branch...[01;36m[K ->-+[m[K
|
||||
| [01;36m[K|[m[K
|
||||
......
|
||||
| [01;36m[K|[m[K
|
||||
|[01;36m[K+[m[K[01;36m[K----------------------------------------+[m[K
|
||||
NN |[01;36m[K|[m[K [01;36m[Kcase[m[K 42:
|
||||
|[01;36m[K|[m[K [01;36m[K~~~~[m[K
|
||||
|[01;36m[K|[m[K [01;36m[K|[m[K
|
||||
|[01;36m[K+[m[K[01;36m[K--->[m[K[01;36m[K(5)[m[K ...to here
|
||||
NN | [01;36m[K__builtin_free (p)[m[K;
|
||||
| [01;36m[K~~~~~~~~~~~~~~~~~~[m[K
|
||||
| [01;36m[K|[m[K
|
||||
| [01;36m[K(6)[m[K second '[01m[Kfree[m[K' here; first '[01m[Kfree[m[K' was at [01;36m[K(3)[m[K
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
/* DejaGnu won't recognize the warning due to the colorization codes,
|
||||
so skip it. */
|
||||
/* { dg-prune-output ".*" } */
|
|
@ -0,0 +1,55 @@
|
|||
/* Verify that -fno-diagnostics-show-event-links works.
|
||||
C only: we don't care about any C/C++ differences between source
|
||||
locations here. */
|
||||
|
||||
/* { dg-additional-options "-fdiagnostics-path-format=inline-events" } */
|
||||
/* { dg-additional-options "-fdiagnostics-show-line-numbers" } */
|
||||
/* { dg-additional-options "-fdiagnostics-show-caret" } */
|
||||
/* { dg-additional-options "-fno-diagnostics-show-event-links" } */
|
||||
/* { dg-enable-nn-line-numbers "" } */
|
||||
|
||||
void test (int flag_a, int val, void *p)
|
||||
{
|
||||
if (flag_a)
|
||||
__builtin_free (p);
|
||||
switch (val)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
case 41:
|
||||
break;
|
||||
case 42:
|
||||
__builtin_free (p); /* { dg-warning "double-'free' of 'p'" } */
|
||||
break;
|
||||
case 43:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | __builtin_free (p);
|
||||
| ^~~~~~~~~~~~~~~~~~
|
||||
'test': events 1-6
|
||||
NN | if (flag_a)
|
||||
| ^
|
||||
| |
|
||||
| (1) following 'true' branch (when 'flag_a != 0')...
|
||||
NN | __builtin_free (p);
|
||||
| ~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| (2) ...to here
|
||||
| (3) first 'free' here
|
||||
NN | switch (val)
|
||||
| ~~~~~~
|
||||
| |
|
||||
| (4) following 'case 42:' branch...
|
||||
......
|
||||
NN | case 42:
|
||||
| ~~~~
|
||||
| |
|
||||
| (5) ...to here
|
||||
NN | __builtin_free (p);
|
||||
| ~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| (6) second 'free' here; first 'free' was at (3)
|
||||
{ dg-end-multiline-output "" } */
|
|
@ -0,0 +1,62 @@
|
|||
/* Verify that we print event links for the analyzer, using Unicode.
|
||||
C only: we don't care about any C/C++ differences between source
|
||||
locations here. */
|
||||
|
||||
/* { dg-additional-options "-fdiagnostics-path-format=inline-events" } */
|
||||
/* { dg-additional-options "-fdiagnostics-show-line-numbers" } */
|
||||
/* { dg-additional-options "-fdiagnostics-show-caret" } */
|
||||
/* { dg-additional-options "-fdiagnostics-show-event-links" } */
|
||||
/* { dg-additional-options "-fdiagnostics-text-art-charset=unicode" } */
|
||||
/* { dg-enable-nn-line-numbers "" } */
|
||||
|
||||
void test (int flag_a, int val, void *p)
|
||||
{
|
||||
if (flag_a)
|
||||
__builtin_free (p);
|
||||
switch (val)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
case 41:
|
||||
break;
|
||||
case 42:
|
||||
__builtin_free (p); /* { dg-warning "double-'free' of 'p'" } */
|
||||
break;
|
||||
case 43:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | __builtin_free (p);
|
||||
| ^~~~~~~~~~~~~~~~~~
|
||||
'test': events 1-6
|
||||
NN | if (flag_a)
|
||||
| ^
|
||||
| |
|
||||
| (1) following 'true' branch (when 'flag_a != 0')... ─>─┐
|
||||
| │
|
||||
| │
|
||||
|┌────────────────────────────────────────────────────────────┘
|
||||
NN |│ __builtin_free (p);
|
||||
|│ ~~~~~~~~~~~~~~~~~~
|
||||
|│ |
|
||||
|└───>(2) ...to here
|
||||
| (3) first 'free' here
|
||||
NN | switch (val)
|
||||
| ~~~~~~
|
||||
| |
|
||||
| (4) following 'case 42:' branch... ─>─┐
|
||||
| │
|
||||
......
|
||||
| │
|
||||
|┌────────────────────────────────────────┘
|
||||
NN |│ case 42:
|
||||
|│ ~~~~
|
||||
|│ |
|
||||
|└───>(5) ...to here
|
||||
NN | __builtin_free (p);
|
||||
| ~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| (6) second 'free' here; first 'free' was at (3)
|
||||
{ dg-end-multiline-output "" } */
|
|
@ -140,6 +140,21 @@ ascii_theme::get_cppchar (enum cell_kind kind) const
|
|||
return '-';
|
||||
case cell_kind::INTERPROCEDURAL_POP_FRAMES_RIGHT:
|
||||
return '+';
|
||||
|
||||
case cell_kind::CFG_RIGHT:
|
||||
return '-';
|
||||
case cell_kind::CFG_FROM_RIGHT_TO_DOWN:
|
||||
return '+';
|
||||
case cell_kind::CFG_DOWN:
|
||||
return '|';
|
||||
case cell_kind::CFG_FROM_DOWN_TO_LEFT:
|
||||
return '+';
|
||||
case cell_kind::CFG_LEFT:
|
||||
return '-';
|
||||
case cell_kind::CFG_FROM_LEFT_TO_DOWN:
|
||||
return '+';
|
||||
case cell_kind::CFG_FROM_DOWN_TO_RIGHT:
|
||||
return '+';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,5 +225,20 @@ unicode_theme::get_cppchar (enum cell_kind kind) const
|
|||
return 0x2500; /* "─": U+2500: BOX DRAWINGS LIGHT HORIZONTAL */
|
||||
case cell_kind::INTERPROCEDURAL_POP_FRAMES_RIGHT:
|
||||
return 0x2518; /* "┘": U+2518: BOX DRAWINGS LIGHT UP AND LEFT. */
|
||||
|
||||
case cell_kind::CFG_RIGHT:
|
||||
return 0x2500; /* "─": U+2500: BOX DRAWINGS LIGHT HORIZONTAL */
|
||||
case cell_kind::CFG_FROM_RIGHT_TO_DOWN:
|
||||
return 0x2510; /* "┐": U+2510: BOX DRAWINGS LIGHT DOWN AND LEFT */
|
||||
case cell_kind::CFG_DOWN:
|
||||
return 0x2502; /* "│": U+2502: BOX DRAWINGS LIGHT VERTICAL */
|
||||
case cell_kind::CFG_FROM_DOWN_TO_LEFT:
|
||||
return 0x2518; /* "┘": U+2518: BOX DRAWINGS LIGHT UP AND LEFT. */
|
||||
case cell_kind::CFG_LEFT:
|
||||
return 0x2500; /* "─": U+2500: BOX DRAWINGS LIGHT HORIZONTAL */
|
||||
case cell_kind::CFG_FROM_LEFT_TO_DOWN:
|
||||
return 0x250c; /* "┌" U+250C: BOX DRAWINGS LIGHT DOWN AND RIGHT */
|
||||
case cell_kind::CFG_FROM_DOWN_TO_RIGHT:
|
||||
return 0x2514; /* "└": U+2514: BOX DRAWINGS LIGHT UP AND RIGHT */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,16 @@ class theme
|
|||
INTERPROCEDURAL_DEPTH_MARKER, /* e.g. "|". */
|
||||
INTERPROCEDURAL_POP_FRAMES_LEFT, /* e.g. "<". */
|
||||
INTERPROCEDURAL_POP_FRAMES_MIDDLE, /* e.g. "-". */
|
||||
INTERPROCEDURAL_POP_FRAMES_RIGHT /* e.g. "+". */
|
||||
INTERPROCEDURAL_POP_FRAMES_RIGHT, /* e.g. "+". */
|
||||
|
||||
/* CFG stuff. */
|
||||
CFG_RIGHT, /* e.g. "-". */
|
||||
CFG_FROM_RIGHT_TO_DOWN, /* e.g. "+". */
|
||||
CFG_DOWN, /* e.g. "|". */
|
||||
CFG_FROM_DOWN_TO_LEFT, /* e.g. "+". */
|
||||
CFG_LEFT, /* e.g. "-". */
|
||||
CFG_FROM_LEFT_TO_DOWN, /* e.g. "+". */
|
||||
CFG_FROM_DOWN_TO_RIGHT /* e.g. "+". */
|
||||
};
|
||||
|
||||
virtual ~theme () = default;
|
||||
|
|
|
@ -1029,6 +1029,8 @@ general_init (const char *argv0, bool init_signals)
|
|||
|
||||
global_dc->m_source_printing.enabled
|
||||
= global_options_init.x_flag_diagnostics_show_caret;
|
||||
global_dc->m_source_printing.show_event_links_p
|
||||
= global_options_init.x_flag_diagnostics_show_event_links;
|
||||
global_dc->m_source_printing.show_labels_p
|
||||
= global_options_init.x_flag_diagnostics_show_labels;
|
||||
global_dc->m_source_printing.show_line_numbers_p
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,6 +23,7 @@ along with this program; see the file COPYING3. If not see
|
|||
#define LIBCPP_RICH_LOCATION_H
|
||||
|
||||
class range_label;
|
||||
class label_effects;
|
||||
|
||||
/* A hint to diagnostic_show_locus on how to print a source range within a
|
||||
rich_location.
|
||||
|
@ -641,6 +642,12 @@ class range_label
|
|||
The RANGE_IDX is provided, allowing for range_label instances to be
|
||||
shared by multiple ranges if need be (the "flyweight" design pattern). */
|
||||
virtual label_text get_text (unsigned range_idx) const = 0;
|
||||
|
||||
/* Get any special effects for the label (e.g. links to other labels). */
|
||||
virtual const label_effects *get_effects (unsigned /*range_idx*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
/* A fix-it hint: a suggested insertion, replacement, or deletion of text.
|
||||
|
|
Loading…
Reference in New Issue