Branch data Line data Source code
1 : : /* Helper class for deferring path creation until a diagnostic is emitted.
2 : : Copyright (C) 2019-2025 Free Software Foundation, Inc.
3 : : Contributed by David Malcolm <dmalcolm@redhat.com>
4 : :
5 : : This file is part of GCC.
6 : :
7 : : GCC is free software; you can redistribute it and/or modify it under
8 : : the terms of the GNU General Public License as published by the Free
9 : : Software Foundation; either version 3, or (at your option) any later
10 : : version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : : for more details.
16 : :
17 : : You should have received a copy of the GNU General Public License
18 : : along with GCC; see the file COPYING3. If not see
19 : : <http://www.gnu.org/licenses/>. */
20 : :
21 : :
22 : : #include "config.h"
23 : : #define INCLUDE_VECTOR
24 : : #include "system.h"
25 : : #include "coretypes.h"
26 : : #include "diagnostics/lazy-paths.h"
27 : : #include "selftest.h"
28 : : #include "diagnostics/selftest-context.h"
29 : : #include "diagnostics/selftest-paths.h"
30 : : #include "diagnostics/text-sink.h"
31 : :
32 : : using namespace diagnostics::paths;
33 : :
34 : : /* class lazy_path : public path. */
35 : :
36 : : /* Implementation of path vfuncs in terms of a lazily-generated
37 : : path. */
38 : :
39 : : unsigned
40 : 5794 : lazy_path::num_events () const
41 : : {
42 : 5794 : lazily_generate_path ();
43 : 5794 : return m_inner_path->num_events ();
44 : : }
45 : :
46 : : const event &
47 : 166 : lazy_path::get_event (int idx) const
48 : : {
49 : 166 : lazily_generate_path ();
50 : 166 : return m_inner_path->get_event (idx);
51 : : }
52 : :
53 : : unsigned
54 : 4 : lazy_path::num_threads () const
55 : : {
56 : 4 : lazily_generate_path ();
57 : 4 : return m_inner_path->num_threads ();
58 : : }
59 : :
60 : : const thread &
61 : 19 : lazy_path::get_thread (thread_id_t idx) const
62 : : {
63 : 19 : lazily_generate_path ();
64 : 19 : return m_inner_path->get_thread (idx);
65 : : }
66 : :
67 : : bool
68 : 56 : lazy_path::same_function_p (int event_idx_a,
69 : : int event_idx_b) const
70 : : {
71 : 56 : lazily_generate_path ();
72 : 56 : return m_inner_path->same_function_p (event_idx_a, event_idx_b);
73 : : }
74 : :
75 : : void
76 : 6039 : lazy_path::lazily_generate_path () const
77 : : {
78 : 6039 : if (!m_inner_path)
79 : 5758 : m_inner_path = make_inner_path ();
80 : 6039 : gcc_assert (m_inner_path != nullptr);
81 : 6039 : }
82 : :
83 : : #if CHECKING_P
84 : :
85 : : namespace diagnostics {
86 : : namespace selftest {
87 : :
88 : : using auto_fix_quotes = ::selftest::auto_fix_quotes;
89 : :
90 : : class test_lazy_path : public lazy_path
91 : : {
92 : : public:
93 : 12 : test_lazy_path (pretty_printer &pp)
94 : 12 : : lazy_path (m_logical_loc_mgr),
95 : 24 : m_pp (pp)
96 : : {
97 : : }
98 : 8 : std::unique_ptr<path> make_inner_path () const final override
99 : : {
100 : 8 : auto path
101 : 8 : = std::make_unique<paths::selftest::test_path> (m_logical_loc_mgr,
102 : 8 : &m_pp);
103 : 8 : path->add_event (UNKNOWN_LOCATION, "foo", 0, "first %qs", "free");
104 : 8 : path->add_event (UNKNOWN_LOCATION, "foo", 0, "double %qs", "free");
105 : 8 : return path;
106 : 8 : }
107 : : private:
108 : : mutable logical_locations::selftest::test_manager m_logical_loc_mgr;
109 : : pretty_printer &m_pp;
110 : : };
111 : :
112 : : static void
113 : 4 : test_intraprocedural_path (pretty_printer *event_pp)
114 : : {
115 : 4 : test_lazy_path path (*event_pp);
116 : 4 : ASSERT_FALSE (path.generated_p ());
117 : 4 : ASSERT_EQ (path.num_events (), 2);
118 : 4 : ASSERT_TRUE (path.generated_p ());
119 : 4 : ASSERT_EQ (path.num_threads (), 1);
120 : 4 : ASSERT_FALSE (path.interprocedural_p ());
121 : 4 : ASSERT_STREQ (path.get_event (0).get_desc (*event_pp).get (),
122 : : "first `free'");
123 : 4 : ASSERT_STREQ (path.get_event (1).get_desc (*event_pp).get (),
124 : : "double `free'");
125 : 4 : }
126 : :
127 : : /* Implementation of diagnostics::option_id_manager for which all
128 : : options are disabled, for use in selftests.
129 : : Note that this is *not* called for option_id (0), which
130 : : means "always warn" */
131 : :
132 : 4 : class all_warnings_disabled : public diagnostics::option_id_manager
133 : : {
134 : : public:
135 : 4 : int option_enabled_p (diagnostics::option_id) const final override
136 : : {
137 : : /* Treat all options as disabled. */
138 : 4 : return 0;
139 : : }
140 : 0 : char *make_option_name (diagnostics::option_id,
141 : : enum kind,
142 : : enum kind) const final override
143 : : {
144 : 0 : return nullptr;
145 : : }
146 : 0 : char *make_option_url (diagnostics::option_id) const final override
147 : : {
148 : 0 : return nullptr;
149 : : }
150 : : };
151 : :
152 : : static void
153 : 4 : test_emission (pretty_printer *event_pp)
154 : : {
155 : 8 : struct test_rich_location : public rich_location
156 : : {
157 : 8 : test_rich_location (pretty_printer &event_pp)
158 : 8 : : rich_location (line_table, UNKNOWN_LOCATION),
159 : 8 : m_path (event_pp)
160 : : {
161 : 8 : set_path (&m_path);
162 : 8 : }
163 : : test_lazy_path m_path;
164 : : };
165 : :
166 : : /* Verify that we don't bother generating the inner path if the warning
167 : : is skipped. */
168 : 4 : {
169 : 4 : test_context dc;
170 : 4 : dc.set_option_id_manager (std::make_unique<all_warnings_disabled> (), 0);
171 : :
172 : 4 : test_rich_location rich_loc (*event_pp);
173 : 4 : ASSERT_FALSE (rich_loc.m_path.generated_p ());
174 : :
175 : 4 : diagnostics::option_id opt_id (42); // has to be non-zero
176 : 4 : bool emitted
177 : 4 : = dc.emit_diagnostic_with_group (kind::warning, rich_loc, nullptr,
178 : : opt_id,
179 : : "this warning should be skipped");
180 : 4 : ASSERT_FALSE (emitted);
181 : 4 : ASSERT_FALSE (rich_loc.m_path.generated_p ());
182 : 4 : }
183 : :
184 : : /* Verify that we *do* generate the inner path for a diagnostic that
185 : : is emitted, such as an error. */
186 : 4 : {
187 : 4 : test_context dc;
188 : :
189 : 4 : test_rich_location rich_loc (*event_pp);
190 : 4 : ASSERT_FALSE (rich_loc.m_path.generated_p ());
191 : :
192 : 4 : bool emitted
193 : 4 : = dc.emit_diagnostic_with_group (kind::error, rich_loc, nullptr, 0,
194 : : "this is a test");
195 : 4 : ASSERT_TRUE (emitted);
196 : 4 : ASSERT_TRUE (rich_loc.m_path.generated_p ());
197 : :
198 : : /* Verify that the path works as expected. */
199 : 4 : dc.set_path_format (DPF_INLINE_EVENTS);
200 : 4 : diagnostics::text_sink sink_ (dc);
201 : 4 : pp_buffer (sink_.get_printer ())->m_flush_p = false;
202 : 4 : sink_.print_path (rich_loc.m_path);
203 : 4 : ASSERT_STREQ (pp_formatted_text (sink_.get_printer ()),
204 : : " `foo': event 1\n"
205 : : " (1): first `free'\n"
206 : : " `foo': event 2\n"
207 : : " (2): double `free'\n");
208 : 8 : }
209 : 4 : }
210 : :
211 : : /* Run all of the selftests within this file. */
212 : :
213 : : void
214 : 4 : lazy_paths_cc_tests ()
215 : : {
216 : : /* In a few places we use the global dc's printer to determine
217 : : colorization so ensure this off during the tests. */
218 : 4 : pretty_printer *global_pp = global_dc->get_reference_printer ();
219 : 4 : const bool saved_show_color = pp_show_color (global_pp);
220 : 4 : pp_show_color (global_pp) = false;
221 : :
222 : 4 : auto_fix_quotes fix_quotes;
223 : 4 : std::unique_ptr<pretty_printer> event_pp
224 : 4 : = std::unique_ptr<pretty_printer> (global_pp->clone ());
225 : :
226 : 4 : test_intraprocedural_path (event_pp.get ());
227 : 4 : test_emission (event_pp.get ());
228 : :
229 : 4 : pp_show_color (global_pp) = saved_show_color;
230 : 4 : }
231 : :
232 : : } // namespace diagnostics::selftest
233 : : } // namespace diagnostics
234 : :
235 : : #endif /* #if CHECKING_P */
|