diff options
Diffstat (limited to 'gcc/diagnostics/lazy-paths.cc')
-rw-r--r-- | gcc/diagnostics/lazy-paths.cc | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/gcc/diagnostics/lazy-paths.cc b/gcc/diagnostics/lazy-paths.cc new file mode 100644 index 0000000..4934651 --- /dev/null +++ b/gcc/diagnostics/lazy-paths.cc @@ -0,0 +1,236 @@ +/* Helper class for deferring path creation until a diagnostic is emitted. + Copyright (C) 2019-2025 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/>. */ + + +#include "config.h" +#define INCLUDE_VECTOR +#include "system.h" +#include "coretypes.h" +#include "diagnostic.h" +#include "diagnostics/lazy-paths.h" +#include "selftest.h" +#include "diagnostics/selftest-context.h" +#include "diagnostics/selftest-paths.h" +#include "diagnostics/text-sink.h" + +using namespace diagnostics::paths; + +/* class lazy_path : public path. */ + +/* Implementation of path vfuncs in terms of a lazily-generated + path. */ + +unsigned +lazy_path::num_events () const +{ + lazily_generate_path (); + return m_inner_path->num_events (); +} + +const event & +lazy_path::get_event (int idx) const +{ + lazily_generate_path (); + return m_inner_path->get_event (idx); +} + +unsigned +lazy_path::num_threads () const +{ + lazily_generate_path (); + return m_inner_path->num_threads (); +} + +const thread & +lazy_path::get_thread (thread_id_t idx) const +{ + lazily_generate_path (); + return m_inner_path->get_thread (idx); +} + +bool +lazy_path::same_function_p (int event_idx_a, + int event_idx_b) const +{ + lazily_generate_path (); + return m_inner_path->same_function_p (event_idx_a, event_idx_b); +} + +void +lazy_path::lazily_generate_path () const +{ + if (!m_inner_path) + m_inner_path = make_inner_path (); + gcc_assert (m_inner_path != nullptr); +} + +#if CHECKING_P + +namespace diagnostics { +namespace selftest { + +using auto_fix_quotes = ::selftest::auto_fix_quotes; + +class test_lazy_path : public lazy_path +{ +public: + test_lazy_path (pretty_printer &pp) + : lazy_path (m_logical_loc_mgr), + m_pp (pp) + { + } + std::unique_ptr<path> make_inner_path () const final override + { + auto path + = std::make_unique<paths::selftest::test_path> (m_logical_loc_mgr, + &m_pp); + path->add_event (UNKNOWN_LOCATION, "foo", 0, "first %qs", "free"); + path->add_event (UNKNOWN_LOCATION, "foo", 0, "double %qs", "free"); + return path; + } +private: + mutable logical_locations::selftest::test_manager m_logical_loc_mgr; + pretty_printer &m_pp; +}; + +static void +test_intraprocedural_path (pretty_printer *event_pp) +{ + test_lazy_path path (*event_pp); + ASSERT_FALSE (path.generated_p ()); + ASSERT_EQ (path.num_events (), 2); + ASSERT_TRUE (path.generated_p ()); + ASSERT_EQ (path.num_threads (), 1); + ASSERT_FALSE (path.interprocedural_p ()); + ASSERT_STREQ (path.get_event (0).get_desc (*event_pp).get (), + "first `free'"); + ASSERT_STREQ (path.get_event (1).get_desc (*event_pp).get (), + "double `free'"); +} + +/* Implementation of diagnostics::option_manager for which all + options are disabled, for use in selftests. + Note that this is *not* called for option_id (0), which + means "always warn" */ + +class all_warnings_disabled : public diagnostics::option_manager +{ +public: + int option_enabled_p (diagnostics::option_id) const final override + { + /* Treat all options as disabled. */ + return 0; + } + char *make_option_name (diagnostics::option_id, + enum kind, + enum kind) const final override + { + return nullptr; + } + char *make_option_url (diagnostics::option_id) const final override + { + return nullptr; + } +}; + +static void +test_emission (pretty_printer *event_pp) +{ + struct test_rich_location : public rich_location + { + test_rich_location (pretty_printer &event_pp) + : rich_location (line_table, UNKNOWN_LOCATION), + m_path (event_pp) + { + set_path (&m_path); + } + test_lazy_path m_path; + }; + + /* Verify that we don't bother generating the inner path if the warning + is skipped. */ + { + test_context dc; + dc.set_option_manager (std::make_unique<all_warnings_disabled> (), 0); + + test_rich_location rich_loc (*event_pp); + ASSERT_FALSE (rich_loc.m_path.generated_p ()); + + diagnostics::option_id opt_id (42); // has to be non-zero + bool emitted + = dc.emit_diagnostic_with_group (kind::warning, rich_loc, nullptr, + opt_id, + "this warning should be skipped"); + ASSERT_FALSE (emitted); + ASSERT_FALSE (rich_loc.m_path.generated_p ()); + } + + /* Verify that we *do* generate the inner path for a diagnostic that + is emitted, such as an error. */ + { + test_context dc; + + test_rich_location rich_loc (*event_pp); + ASSERT_FALSE (rich_loc.m_path.generated_p ()); + + bool emitted + = dc.emit_diagnostic_with_group (kind::error, rich_loc, nullptr, 0, + "this is a test"); + ASSERT_TRUE (emitted); + ASSERT_TRUE (rich_loc.m_path.generated_p ()); + + /* Verify that the path works as expected. */ + dc.set_path_format (DPF_INLINE_EVENTS); + diagnostics::text_sink sink_ (dc); + pp_buffer (sink_.get_printer ())->m_flush_p = false; + sink_.print_path (rich_loc.m_path); + ASSERT_STREQ (pp_formatted_text (sink_.get_printer ()), + " `foo': event 1\n" + " (1): first `free'\n" + " `foo': event 2\n" + " (2): double `free'\n"); + } +} + +/* Run all of the selftests within this file. */ + +void +lazy_paths_cc_tests () +{ + /* In a few places we use the global dc's printer to determine + colorization so ensure this off during the tests. */ + pretty_printer *global_pp = global_dc->get_reference_printer (); + const bool saved_show_color = pp_show_color (global_pp); + pp_show_color (global_pp) = false; + + auto_fix_quotes fix_quotes; + std::unique_ptr<pretty_printer> event_pp + = std::unique_ptr<pretty_printer> (global_pp->clone ()); + + test_intraprocedural_path (event_pp.get ()); + test_emission (event_pp.get ()); + + pp_show_color (global_pp) = saved_show_color; +} + +} // namespace diagnostics::selftest +} // namespace diagnostics + +#endif /* #if CHECKING_P */ |