Branch data Line data Source code
1 : : /* Subclasses of diagnostic_event for analyzer diagnostics.
2 : : Copyright (C) 2019-2024 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
8 : : under the terms of the GNU General Public License as published by
9 : : the Free Software Foundation; either version 3, or (at your option)
10 : : any later version.
11 : :
12 : : GCC is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : General Public License 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 : : #include "config.h"
22 : : #define INCLUDE_MEMORY
23 : : #include "system.h"
24 : : #include "coretypes.h"
25 : : #include "tree.h"
26 : : #include "function.h"
27 : : #include "basic-block.h"
28 : : #include "gimple.h"
29 : : #include "diagnostic-core.h"
30 : : #include "gimple-pretty-print.h"
31 : : #include "fold-const.h"
32 : : #include "diagnostic-path.h"
33 : : #include "options.h"
34 : : #include "cgraph.h"
35 : : #include "cfg.h"
36 : : #include "digraph.h"
37 : : #include "diagnostic-event-id.h"
38 : : #include "analyzer/analyzer.h"
39 : : #include "analyzer/analyzer-logging.h"
40 : : #include "analyzer/sm.h"
41 : : #include "sbitmap.h"
42 : : #include "bitmap.h"
43 : : #include "ordered-hash-map.h"
44 : : #include "analyzer/call-string.h"
45 : : #include "analyzer/program-point.h"
46 : : #include "analyzer/store.h"
47 : : #include "analyzer/region-model.h"
48 : : #include "analyzer/program-state.h"
49 : : #include "analyzer/checker-path.h"
50 : : #include "gimple-iterator.h"
51 : : #include "inlining-iterator.h"
52 : : #include "analyzer/supergraph.h"
53 : : #include "analyzer/pending-diagnostic.h"
54 : : #include "analyzer/diagnostic-manager.h"
55 : : #include "analyzer/constraint-manager.h"
56 : : #include "analyzer/checker-event.h"
57 : : #include "analyzer/exploded-graph.h"
58 : : #include "diagnostic-format-sarif.h"
59 : : #include "tree-logical-location.h"
60 : :
61 : : #if ENABLE_ANALYZER
62 : :
63 : : namespace ana {
64 : :
65 : : /* Get a string for EK. */
66 : :
67 : : const char *
68 : 50 : event_kind_to_string (enum event_kind ek)
69 : : {
70 : 50 : switch (ek)
71 : : {
72 : 0 : default:
73 : 0 : gcc_unreachable ();
74 : : case EK_DEBUG:
75 : : return "EK_DEBUG";
76 : 0 : case EK_CUSTOM:
77 : 0 : return "EK_CUSTOM";
78 : 0 : case EK_STMT:
79 : 0 : return "EK_STMT";
80 : 15 : case EK_REGION_CREATION:
81 : 15 : return "EK_REGION_CREATION";
82 : 0 : case EK_FUNCTION_ENTRY:
83 : 0 : return "EK_FUNCTION_ENTRY";
84 : 10 : case EK_STATE_CHANGE:
85 : 10 : return "EK_STATE_CHANGE";
86 : 5 : case EK_START_CFG_EDGE:
87 : 5 : return "EK_START_CFG_EDGE";
88 : 5 : case EK_END_CFG_EDGE:
89 : 5 : return "EK_END_CFG_EDGE";
90 : 0 : case EK_CALL_EDGE:
91 : 0 : return "EK_CALL_EDGE";
92 : 0 : case EK_RETURN_EDGE:
93 : 0 : return "EK_RETURN_EDGE";
94 : 0 : case EK_START_CONSOLIDATED_CFG_EDGES:
95 : 0 : return "EK_START_CONSOLIDATED_CFG_EDGES";
96 : 0 : case EK_END_CONSOLIDATED_CFG_EDGES:
97 : 0 : return "EK_END_CONSOLIDATED_CFG_EDGES";
98 : 0 : case EK_INLINED_CALL:
99 : 0 : return "EK_INLINED_CALL";
100 : 0 : case EK_SETJMP:
101 : 0 : return "EK_SETJMP";
102 : 0 : case EK_REWIND_FROM_LONGJMP:
103 : 0 : return "EK_REWIND_FROM_LONGJMP";
104 : 0 : case EK_REWIND_TO_SETJMP:
105 : 0 : return "EK_REWIND_TO_SETJMP";
106 : 15 : case EK_WARNING:
107 : 15 : return "EK_WARNING";
108 : : }
109 : : }
110 : :
111 : : /* class checker_event : public diagnostic_event. */
112 : :
113 : : /* checker_event's ctor. */
114 : :
115 : 65968 : checker_event::checker_event (enum event_kind kind,
116 : 65968 : const event_loc_info &loc_info)
117 : 65968 : : m_kind (kind), m_loc (loc_info.m_loc),
118 : 65968 : m_original_fndecl (loc_info.m_fndecl),
119 : 65968 : m_effective_fndecl (loc_info.m_fndecl),
120 : 65968 : m_original_depth (loc_info.m_depth),
121 : 65968 : m_effective_depth (loc_info.m_depth),
122 : 65968 : m_pending_diagnostic (NULL), m_emission_id (),
123 : 65968 : m_logical_loc (loc_info.m_fndecl)
124 : : {
125 : : /* Update effective fndecl and depth if inlining has been recorded. */
126 : 65968 : if (flag_analyzer_undo_inlining)
127 : : {
128 : 65933 : inlining_info info (m_loc);
129 : 65933 : if (info.get_inner_fndecl ())
130 : : {
131 : 49690 : m_effective_fndecl = info.get_inner_fndecl ();
132 : 49690 : m_effective_depth += info.get_extra_frames ();
133 : 49690 : m_logical_loc = tree_logical_location (m_effective_fndecl);
134 : : }
135 : : }
136 : 65968 : }
137 : :
138 : : /* No-op implementation of diagnostic_event::get_meaning vfunc for
139 : : checker_event: checker events have no meaning by default. */
140 : :
141 : : diagnostic_event::meaning
142 : 15 : checker_event::get_meaning () const
143 : : {
144 : 15 : return meaning ();
145 : : }
146 : :
147 : : /* Implementation of diagnostic_event::maybe_add_sarif_properties
148 : : for checker_event. */
149 : :
150 : : void
151 : 50 : checker_event::
152 : : maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj) const
153 : : {
154 : 50 : sarif_property_bag &props = thread_flow_loc_obj.get_or_create_properties ();
155 : : #define PROPERTY_PREFIX "gcc/analyzer/checker_event/"
156 : 50 : props.set (PROPERTY_PREFIX "emission_id",
157 : 50 : diagnostic_event_id_to_json (m_emission_id));
158 : 50 : props.set_string (PROPERTY_PREFIX "kind", event_kind_to_string (m_kind));
159 : :
160 : 50 : if (m_original_fndecl != m_effective_fndecl)
161 : : {
162 : 0 : tree_logical_location logical_loc (m_original_fndecl);
163 : 0 : props.set (PROPERTY_PREFIX "original_fndecl",
164 : 0 : make_sarif_logical_location_object (logical_loc));
165 : 0 : }
166 : 50 : if (m_original_depth != m_effective_depth)
167 : 0 : props.set_integer (PROPERTY_PREFIX "original_depth", m_original_depth);
168 : : #undef PROPERTY_PREFIX
169 : 50 : }
170 : :
171 : : /* Dump this event to PP (for debugging/logging purposes). */
172 : :
173 : : void
174 : 0 : checker_event::dump (pretty_printer *pp) const
175 : : {
176 : 0 : label_text event_desc (get_desc (false));
177 : 0 : pp_printf (pp, "\"%s\" (depth %i",
178 : 0 : event_desc.get (), m_effective_depth);
179 : :
180 : 0 : if (m_effective_depth != m_original_depth)
181 : 0 : pp_printf (pp, " corrected from %i",
182 : : m_original_depth);
183 : 0 : if (m_effective_fndecl)
184 : : {
185 : 0 : pp_printf (pp, ", fndecl %qE", m_effective_fndecl);
186 : 0 : if (m_effective_fndecl != m_original_fndecl)
187 : 0 : pp_printf (pp, " corrected from %qE", m_original_fndecl);
188 : : }
189 : 0 : pp_printf (pp, ", m_loc=%x)",
190 : : get_location ());
191 : 0 : }
192 : :
193 : : /* Dump this event to stderr (for debugging/logging purposes). */
194 : :
195 : : DEBUG_FUNCTION void
196 : 0 : checker_event::debug () const
197 : : {
198 : 0 : pretty_printer pp;
199 : 0 : pp_format_decoder (&pp) = default_tree_printer;
200 : 0 : pp_show_color (&pp) = pp_show_color (global_dc->printer);
201 : 0 : pp.buffer->stream = stderr;
202 : 0 : dump (&pp);
203 : 0 : pp_newline (&pp);
204 : 0 : pp_flush (&pp);
205 : 0 : }
206 : :
207 : : /* Hook for being notified when this event has its final id EMISSION_ID
208 : : and is about to emitted for PD.
209 : :
210 : : Base implementation of checker_event::prepare_for_emission vfunc;
211 : : subclasses that override this should chain up to it.
212 : :
213 : : Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
214 : : side-effects of the call to get_desc take place before
215 : : pending_diagnostic::emit is called.
216 : :
217 : : For example, state_change_event::get_desc can call
218 : : pending_diagnostic::describe_state_change; free_of_non_heap can use this
219 : : to tweak the message (TODO: would be neater to simply capture the
220 : : pertinent data within the sm-state). */
221 : :
222 : : void
223 : 19180 : checker_event::prepare_for_emission (checker_path *,
224 : : pending_diagnostic *pd,
225 : : diagnostic_event_id_t emission_id)
226 : : {
227 : 19180 : m_pending_diagnostic = pd;
228 : 19180 : m_emission_id = emission_id;
229 : :
230 : 19180 : label_text desc = get_desc (false);
231 : 19180 : }
232 : :
233 : : /* class debug_event : public checker_event. */
234 : :
235 : : /* Implementation of diagnostic_event::get_desc vfunc for
236 : : debug_event.
237 : : Use the saved string as the event's description. */
238 : :
239 : : label_text
240 : 0 : debug_event::get_desc (bool) const
241 : : {
242 : 0 : return label_text::borrow (m_desc);
243 : : }
244 : :
245 : : /* class precanned_custom_event : public custom_event. */
246 : :
247 : : /* Implementation of diagnostic_event::get_desc vfunc for
248 : : precanned_custom_event.
249 : : Use the saved string as the event's description. */
250 : :
251 : : label_text
252 : 222 : precanned_custom_event::get_desc (bool) const
253 : : {
254 : 222 : return label_text::borrow (m_desc);
255 : : }
256 : :
257 : : /* class statement_event : public checker_event. */
258 : :
259 : : /* statement_event's ctor. */
260 : :
261 : 20362 : statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
262 : 20362 : const program_state &dst_state)
263 : : : checker_event (EK_STMT,
264 : 20362 : event_loc_info (gimple_location (stmt), fndecl, depth)),
265 : 20362 : m_stmt (stmt),
266 : 20362 : m_dst_state (dst_state)
267 : : {
268 : 20362 : }
269 : :
270 : : /* Implementation of diagnostic_event::get_desc vfunc for
271 : : statement_event.
272 : : Use the statement's dump form as the event's description. */
273 : :
274 : : label_text
275 : 0 : statement_event::get_desc (bool) const
276 : : {
277 : 0 : pretty_printer pp;
278 : 0 : pp_string (&pp, "stmt: ");
279 : 0 : pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
280 : 0 : return label_text::take (xstrdup (pp_formatted_text (&pp)));
281 : 0 : }
282 : :
283 : : /* class region_creation_event : public checker_event. */
284 : :
285 : 1724 : region_creation_event::region_creation_event (const event_loc_info &loc_info)
286 : 1724 : : checker_event (EK_REGION_CREATION, loc_info)
287 : : {
288 : 1724 : }
289 : :
290 : : /* The various region_creation_event subclasses' get_desc
291 : : implementations. */
292 : :
293 : : label_text
294 : 1380 : region_creation_event_memory_space::get_desc (bool) const
295 : : {
296 : 1380 : switch (m_mem_space)
297 : : {
298 : 32 : default:
299 : 32 : return label_text::borrow ("region created here");
300 : 1222 : case MEMSPACE_STACK:
301 : 1222 : return label_text::borrow ("region created on stack here");
302 : 126 : case MEMSPACE_HEAP:
303 : 126 : return label_text::borrow ("region created on heap here");
304 : : }
305 : : }
306 : :
307 : : label_text
308 : 1864 : region_creation_event_capacity::get_desc (bool can_colorize) const
309 : : {
310 : 1864 : gcc_assert (m_capacity);
311 : 1864 : if (TREE_CODE (m_capacity) == INTEGER_CST)
312 : : {
313 : 1622 : unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
314 : 1622 : return make_label_text_n (can_colorize,
315 : : hwi,
316 : : "capacity: %wu byte",
317 : : "capacity: %wu bytes",
318 : 1622 : hwi);
319 : : }
320 : : else
321 : 242 : return make_label_text (can_colorize,
322 : 242 : "capacity: %qE bytes", m_capacity);
323 : : }
324 : :
325 : : label_text
326 : 204 : region_creation_event_allocation_size::get_desc (bool can_colorize) const
327 : : {
328 : 204 : if (m_capacity)
329 : : {
330 : 194 : if (TREE_CODE (m_capacity) == INTEGER_CST)
331 : 134 : return make_label_text_n (can_colorize,
332 : : tree_to_uhwi (m_capacity),
333 : : "allocated %E byte here",
334 : : "allocated %E bytes here",
335 : 134 : m_capacity);
336 : : else
337 : 60 : return make_label_text (can_colorize,
338 : : "allocated %qE bytes here",
339 : 60 : m_capacity);
340 : : }
341 : 10 : return make_label_text (can_colorize, "allocated here");
342 : : }
343 : :
344 : : label_text
345 : 0 : region_creation_event_debug::get_desc (bool) const
346 : : {
347 : 0 : pretty_printer pp;
348 : 0 : pp_format_decoder (&pp) = default_tree_printer;
349 : 0 : pp_string (&pp, "region creation: ");
350 : 0 : m_reg->dump_to_pp (&pp, true);
351 : 0 : if (m_capacity)
352 : 0 : pp_printf (&pp, " capacity: %qE", m_capacity);
353 : 0 : return label_text::take (xstrdup (pp_formatted_text (&pp)));
354 : 0 : }
355 : :
356 : : /* class function_entry_event : public checker_event. */
357 : :
358 : 5880 : function_entry_event::function_entry_event (const program_point &dst_point)
359 : : : checker_event (EK_FUNCTION_ENTRY,
360 : 5880 : event_loc_info (dst_point.get_supernode
361 : : ()->get_start_location (),
362 : : dst_point.get_fndecl (),
363 : 11760 : dst_point.get_stack_depth ()))
364 : : {
365 : 5880 : }
366 : :
367 : : /* Implementation of diagnostic_event::get_desc vfunc for
368 : : function_entry_event.
369 : :
370 : : Use a string such as "entry to 'foo'" as the event's description. */
371 : :
372 : : label_text
373 : 3032 : function_entry_event::get_desc (bool can_colorize) const
374 : : {
375 : 3032 : return make_label_text (can_colorize, "entry to %qE", m_effective_fndecl);
376 : : }
377 : :
378 : : /* Implementation of diagnostic_event::get_meaning vfunc for
379 : : function entry. */
380 : :
381 : : diagnostic_event::meaning
382 : 0 : function_entry_event::get_meaning () const
383 : : {
384 : 0 : return meaning (VERB_enter, NOUN_function);
385 : : }
386 : :
387 : : /* class state_change_event : public checker_event. */
388 : :
389 : : /* state_change_event's ctor. */
390 : :
391 : 5341 : state_change_event::state_change_event (const supernode *node,
392 : : const gimple *stmt,
393 : : int stack_depth,
394 : : const state_machine &sm,
395 : : const svalue *sval,
396 : : state_machine::state_t from,
397 : : state_machine::state_t to,
398 : : const svalue *origin,
399 : : const program_state &dst_state,
400 : 5341 : const exploded_node *enode)
401 : : : checker_event (EK_STATE_CHANGE,
402 : 10682 : event_loc_info (stmt->location,
403 : 5341 : node->m_fun->decl,
404 : : stack_depth)),
405 : 5341 : m_node (node), m_stmt (stmt), m_sm (sm),
406 : 5341 : m_sval (sval), m_from (from), m_to (to),
407 : 5341 : m_origin (origin),
408 : 5341 : m_dst_state (dst_state),
409 : 5341 : m_enode (enode)
410 : : {
411 : 5341 : }
412 : :
413 : : /* Implementation of diagnostic_event::get_desc vfunc for
414 : : state_change_event.
415 : :
416 : : Attempt to generate a nicer human-readable description.
417 : : For greatest precision-of-wording, give the pending diagnostic
418 : : a chance to describe this state change (in terms of the
419 : : diagnostic).
420 : : Note that we only have a pending_diagnostic set on the event once
421 : : the diagnostic is about to being emitted, so the description for
422 : : an event can change. */
423 : :
424 : : label_text
425 : 5294 : state_change_event::get_desc (bool can_colorize) const
426 : : {
427 : 5294 : if (m_pending_diagnostic)
428 : : {
429 : 5294 : region_model *model = m_dst_state.m_region_model;
430 : 5294 : tree var = model->get_representative_tree (m_sval);
431 : 5294 : tree origin = model->get_representative_tree (m_origin);
432 : 5294 : label_text custom_desc
433 : 5294 : = m_pending_diagnostic->describe_state_change
434 : 10588 : (evdesc::state_change (can_colorize, var, origin,
435 : 5294 : m_from, m_to, m_emission_id, *this));
436 : 5294 : if (custom_desc.get ())
437 : : {
438 : 5292 : if (flag_analyzer_verbose_state_changes)
439 : : {
440 : : /* Get any "meaning" of event. */
441 : 180 : diagnostic_event::meaning meaning = get_meaning ();
442 : 180 : pretty_printer meaning_pp;
443 : 180 : meaning.dump_to_pp (&meaning_pp);
444 : :
445 : : /* Append debug version. */
446 : 180 : if (var)
447 : : {
448 : 170 : if (m_origin)
449 : 0 : return make_label_text
450 : : (can_colorize,
451 : : "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
452 : : custom_desc.get (),
453 : : var,
454 : 0 : m_from->get_name (),
455 : 0 : m_to->get_name (),
456 : : origin,
457 : 0 : pp_formatted_text (&meaning_pp));
458 : : else
459 : 170 : return make_label_text
460 : : (can_colorize,
461 : : "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
462 : : custom_desc.get (),
463 : : var,
464 : 170 : m_from->get_name (),
465 : 170 : m_to->get_name (),
466 : 170 : pp_formatted_text (&meaning_pp));
467 : : }
468 : : else
469 : : {
470 : 10 : if (m_origin)
471 : 0 : return make_label_text
472 : : (can_colorize,
473 : : "%s (state: %qs -> %qs, origin: %qE, meaning: %s)",
474 : : custom_desc.get (),
475 : 0 : m_from->get_name (),
476 : 0 : m_to->get_name (),
477 : : origin,
478 : 0 : pp_formatted_text (&meaning_pp));
479 : : else
480 : 10 : return make_label_text
481 : : (can_colorize,
482 : : "%s (state: %qs -> %qs, NULL origin, meaning: %s)",
483 : : custom_desc.get (),
484 : 10 : m_from->get_name (),
485 : 10 : m_to->get_name (),
486 : 10 : pp_formatted_text (&meaning_pp));
487 : : }
488 : 180 : }
489 : : else
490 : 5112 : return custom_desc;
491 : : }
492 : 5294 : }
493 : :
494 : : /* Fallback description. */
495 : 2 : if (m_sval)
496 : : {
497 : 2 : label_text sval_desc = m_sval->get_desc ();
498 : 2 : if (m_origin)
499 : : {
500 : 0 : label_text origin_desc = m_origin->get_desc ();
501 : 0 : return make_label_text
502 : : (can_colorize,
503 : : "state of %qs: %qs -> %qs (origin: %qs)",
504 : : sval_desc.get (),
505 : 0 : m_from->get_name (),
506 : 0 : m_to->get_name (),
507 : 0 : origin_desc.get ());
508 : 0 : }
509 : : else
510 : 2 : return make_label_text
511 : : (can_colorize,
512 : : "state of %qs: %qs -> %qs (NULL origin)",
513 : : sval_desc.get (),
514 : 2 : m_from->get_name (),
515 : 2 : m_to->get_name ());
516 : 2 : }
517 : : else
518 : : {
519 : 0 : gcc_assert (m_origin == NULL);
520 : 0 : return make_label_text
521 : : (can_colorize,
522 : : "global state: %qs -> %qs",
523 : 0 : m_from->get_name (),
524 : 0 : m_to->get_name ());
525 : : }
526 : : }
527 : :
528 : : /* Implementation of diagnostic_event::get_meaning vfunc for
529 : : state change events: delegate to the pending_diagnostic to
530 : : get any meaning. */
531 : :
532 : : diagnostic_event::meaning
533 : 190 : state_change_event::get_meaning () const
534 : : {
535 : 190 : if (m_pending_diagnostic)
536 : : {
537 : 190 : region_model *model = m_dst_state.m_region_model;
538 : 190 : tree var = model->get_representative_tree (m_sval);
539 : 190 : tree origin = model->get_representative_tree (m_origin);
540 : 190 : return m_pending_diagnostic->get_meaning_for_state_change
541 : 190 : (evdesc::state_change (false, var, origin,
542 : 190 : m_from, m_to, m_emission_id, *this));
543 : : }
544 : : else
545 : 0 : return meaning ();
546 : : }
547 : :
548 : : /* class superedge_event : public checker_event. */
549 : :
550 : : /* Implementation of diagnostic_event::maybe_add_sarif_properties
551 : : for superedge_event. */
552 : :
553 : : void
554 : 10 : superedge_event::maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj)
555 : : const
556 : : {
557 : 10 : checker_event::maybe_add_sarif_properties (thread_flow_loc_obj);
558 : 10 : sarif_property_bag &props = thread_flow_loc_obj.get_or_create_properties ();
559 : : #define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
560 : 10 : if (m_sedge)
561 : 10 : props.set (PROPERTY_PREFIX "superedge", m_sedge->to_json ());
562 : : #undef PROPERTY_PREFIX
563 : 10 : }
564 : :
565 : : /* Get the callgraph_superedge for this superedge_event, which must be
566 : : for an interprocedural edge, rather than a CFG edge. */
567 : :
568 : : const callgraph_superedge&
569 : 1833 : superedge_event::get_callgraph_superedge () const
570 : : {
571 : 1833 : gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
572 : 1833 : return *m_sedge->dyn_cast_callgraph_superedge ();
573 : : }
574 : :
575 : : /* Determine if this event should be filtered at the given verbosity
576 : : level. */
577 : :
578 : : bool
579 : 12240 : superedge_event::should_filter_p (int verbosity) const
580 : : {
581 : 12240 : switch (m_sedge->m_kind)
582 : : {
583 : 12240 : case SUPEREDGE_CFG_EDGE:
584 : 12240 : {
585 : 12240 : if (verbosity < 2)
586 : : return true;
587 : :
588 : 11995 : if (verbosity < 4)
589 : : {
590 : : /* Filter events with empty descriptions. This ought to filter
591 : : FALLTHRU, but retain true/false/switch edges. */
592 : 11995 : label_text desc = get_desc (false);
593 : 11995 : gcc_assert (desc.get ());
594 : 11995 : if (desc.get ()[0] == '\0')
595 : 9045 : return true;
596 : 11995 : }
597 : : }
598 : : break;
599 : :
600 : : default:
601 : : break;
602 : : }
603 : : return false;
604 : : }
605 : :
606 : : /* superedge_event's ctor. */
607 : :
608 : 26784 : superedge_event::superedge_event (enum event_kind kind,
609 : : const exploded_edge &eedge,
610 : 26784 : const event_loc_info &loc_info)
611 : : : checker_event (kind, loc_info),
612 : 26784 : m_eedge (eedge), m_sedge (eedge.m_sedge),
613 : 26784 : m_var (NULL_TREE), m_critical_state (0)
614 : : {
615 : : /* Note that m_sedge can be nullptr for e.g. jumps through
616 : : function pointers. */
617 : 26784 : }
618 : :
619 : : /* class cfg_edge_event : public superedge_event. */
620 : :
621 : : /* Get the cfg_superedge for this cfg_edge_event. */
622 : :
623 : : const cfg_superedge &
624 : 8830 : cfg_edge_event::get_cfg_superedge () const
625 : : {
626 : 8830 : return *m_sedge->dyn_cast_cfg_superedge ();
627 : : }
628 : :
629 : : /* cfg_edge_event's ctor. */
630 : :
631 : 24693 : cfg_edge_event::cfg_edge_event (enum event_kind kind,
632 : : const exploded_edge &eedge,
633 : 24693 : const event_loc_info &loc_info)
634 : 24693 : : superedge_event (kind, eedge, loc_info)
635 : : {
636 : 24693 : gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
637 : 24693 : }
638 : :
639 : : /* Implementation of diagnostic_event::get_meaning vfunc for
640 : : CFG edge events. */
641 : :
642 : : diagnostic_event::meaning
643 : 10 : cfg_edge_event::get_meaning () const
644 : : {
645 : 10 : const cfg_superedge& cfg_sedge = get_cfg_superedge ();
646 : 10 : if (cfg_sedge.true_value_p ())
647 : 10 : return meaning (VERB_branch, PROPERTY_true);
648 : 0 : else if (cfg_sedge.false_value_p ())
649 : 0 : return meaning (VERB_branch, PROPERTY_false);
650 : : else
651 : 0 : return meaning ();
652 : : }
653 : :
654 : : /* class start_cfg_edge_event : public cfg_edge_event. */
655 : :
656 : : /* Implementation of diagnostic_event::get_desc vfunc for
657 : : start_cfg_edge_event.
658 : :
659 : : If -fanalyzer-verbose-edges, then generate low-level descriptions, such
660 : : as
661 : : "taking 'true' edge SN:7 -> SN:8".
662 : :
663 : : Otherwise, generate strings using the label of the underlying CFG if
664 : : any, such as:
665 : : "following 'true' branch..." or
666 : : "following 'case 3' branch..."
667 : : "following 'default' branch..."
668 : :
669 : : For conditionals, attempt to supply a description of the condition that
670 : : holds, such as:
671 : : "following 'false' branch (when 'ptr' is non-NULL)..."
672 : :
673 : : Failing that, return an empty description (which will lead to this event
674 : : being filtered). */
675 : :
676 : : label_text
677 : 17319 : start_cfg_edge_event::get_desc (bool can_colorize) const
678 : : {
679 : 17319 : bool user_facing = !flag_analyzer_verbose_edges;
680 : 17319 : label_text edge_desc (m_sedge->get_description (user_facing));
681 : 17319 : if (user_facing)
682 : : {
683 : 17319 : if (edge_desc.get () && strlen (edge_desc.get ()) > 0)
684 : : {
685 : 8274 : label_text cond_desc = maybe_describe_condition (can_colorize);
686 : 8274 : label_text result;
687 : 8274 : if (cond_desc.get ())
688 : 4619 : return make_label_text (can_colorize,
689 : : "following %qs branch (%s)...",
690 : 4619 : edge_desc.get (), cond_desc.get ());
691 : : else
692 : 3655 : return make_label_text (can_colorize,
693 : : "following %qs branch...",
694 : 3655 : edge_desc.get ());
695 : 12821 : }
696 : : else
697 : 9045 : return label_text::borrow ("");
698 : : }
699 : : else
700 : : {
701 : 0 : if (strlen (edge_desc.get ()) > 0)
702 : 0 : return make_label_text (can_colorize,
703 : : "taking %qs edge SN:%i -> SN:%i",
704 : : edge_desc.get (),
705 : 0 : m_sedge->m_src->m_index,
706 : 0 : m_sedge->m_dest->m_index);
707 : : else
708 : 0 : return make_label_text (can_colorize,
709 : : "taking edge SN:%i -> SN:%i",
710 : 0 : m_sedge->m_src->m_index,
711 : 0 : m_sedge->m_dest->m_index);
712 : : }
713 : 17319 : }
714 : :
715 : : /* Attempt to generate a description of any condition that holds at this edge.
716 : :
717 : : The intent is to make the user-facing messages more clear, especially for
718 : : cases where there's a single or double-negative, such as
719 : : when describing the false branch of an inverted condition.
720 : :
721 : : For example, rather than printing just:
722 : :
723 : : | if (!ptr)
724 : : | ~
725 : : | |
726 : : | (1) following 'false' branch...
727 : :
728 : : it's clearer to spell out the condition that holds:
729 : :
730 : : | if (!ptr)
731 : : | ~
732 : : | |
733 : : | (1) following 'false' branch (when 'ptr' is non-NULL)...
734 : : ^^^^^^^^^^^^^^^^^^^^^^
735 : :
736 : : In the above example, this function would generate the highlighted
737 : : string: "when 'ptr' is non-NULL".
738 : :
739 : : If the edge is not a condition, or it's not clear that a description of
740 : : the condition would be helpful to the user, return NULL. */
741 : :
742 : : label_text
743 : 8406 : start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
744 : : {
745 : 8406 : const cfg_superedge& cfg_sedge = get_cfg_superedge ();
746 : :
747 : 8406 : if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
748 : : {
749 : 7960 : const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
750 : 7960 : if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
751 : : {
752 : 7960 : enum tree_code op = gimple_cond_code (cond_stmt);
753 : 7960 : tree lhs = gimple_cond_lhs (cond_stmt);
754 : 7960 : tree rhs = gimple_cond_rhs (cond_stmt);
755 : 7960 : if (cfg_sedge.false_value_p ())
756 : 3583 : op = invert_tree_comparison (op, false /* honor_nans */);
757 : 7960 : return maybe_describe_condition (can_colorize,
758 : 7960 : lhs, op, rhs);
759 : : }
760 : : }
761 : 446 : return label_text::borrow (NULL);
762 : : }
763 : :
764 : : /* Subroutine of maybe_describe_condition above.
765 : :
766 : : Attempt to generate a user-facing description of the condition
767 : : LHS OP RHS, but only if it is likely to make it easier for the
768 : : user to understand a condition. */
769 : :
770 : : label_text
771 : 7960 : start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
772 : : tree lhs,
773 : : enum tree_code op,
774 : : tree rhs)
775 : : {
776 : : /* In theory we could just build a tree via
777 : : fold_build2 (op, boolean_type_node, lhs, rhs)
778 : : and print it with %qE on it, but this leads to warts such as
779 : : parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
780 : :
781 : : /* Special-case: describe testing the result of strcmp, as figuring
782 : : out what the "true" or "false" path is can be confusing to the user. */
783 : 7960 : if (TREE_CODE (lhs) == SSA_NAME
784 : 7960 : && zerop (rhs))
785 : : {
786 : 6093 : if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
787 : 2163 : if (is_special_named_call_p (call, "strcmp", 2))
788 : : {
789 : 72 : if (op == EQ_EXPR)
790 : 9 : return label_text::borrow ("when the strings are equal");
791 : 63 : if (op == NE_EXPR)
792 : 63 : return label_text::borrow ("when the strings are non-equal");
793 : : }
794 : : }
795 : :
796 : : /* Only attempt to generate text for sufficiently simple expressions. */
797 : 7888 : if (!should_print_expr_p (lhs))
798 : 3161 : return label_text::borrow (NULL);
799 : 4727 : if (!should_print_expr_p (rhs))
800 : 68 : return label_text::borrow (NULL);
801 : :
802 : : /* Special cases for pointer comparisons against NULL. */
803 : 7535 : if (POINTER_TYPE_P (TREE_TYPE (lhs))
804 : 1783 : && POINTER_TYPE_P (TREE_TYPE (rhs))
805 : 6442 : && zerop (rhs))
806 : : {
807 : 1702 : if (op == EQ_EXPR)
808 : 445 : return make_label_text (can_colorize, "when %qE is NULL",
809 : 445 : lhs);
810 : 1257 : if (op == NE_EXPR)
811 : 1257 : return make_label_text (can_colorize, "when %qE is non-NULL",
812 : 1257 : lhs);
813 : : }
814 : :
815 : 2957 : return make_label_text (can_colorize, "when %<%E %s %E%>",
816 : 2957 : lhs, op_symbol_code (op), rhs);
817 : : }
818 : :
819 : : /* Subroutine of maybe_describe_condition.
820 : :
821 : : Return true if EXPR is we will get suitable user-facing output
822 : : from %E on it. */
823 : :
824 : : bool
825 : 12615 : start_cfg_edge_event::should_print_expr_p (tree expr)
826 : : {
827 : 17731 : if (TREE_CODE (expr) == SSA_NAME)
828 : : {
829 : 8345 : if (SSA_NAME_VAR (expr))
830 : : return should_print_expr_p (SSA_NAME_VAR (expr));
831 : : else
832 : : return false;
833 : : }
834 : :
835 : 9386 : if (DECL_P (expr))
836 : : return true;
837 : :
838 : 4270 : if (CONSTANT_CLASS_P (expr))
839 : 4270 : return true;
840 : :
841 : : return false;
842 : : }
843 : :
844 : : /* class call_event : public superedge_event. */
845 : :
846 : : /* call_event's ctor. */
847 : :
848 : 1349 : call_event::call_event (const exploded_edge &eedge,
849 : 1349 : const event_loc_info &loc_info)
850 : 1349 : : superedge_event (EK_CALL_EDGE, eedge, loc_info)
851 : : {
852 : 1349 : if (eedge.m_sedge)
853 : 1307 : gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
854 : :
855 : 1349 : m_src_snode = eedge.m_src->get_supernode ();
856 : 1349 : m_dest_snode = eedge.m_dest->get_supernode ();
857 : 1349 : }
858 : :
859 : : /* Implementation of diagnostic_event::get_desc vfunc for
860 : : call_event.
861 : :
862 : : If this call event passes critical state for an sm-based warning,
863 : : allow the diagnostic to generate a precise description, such as:
864 : :
865 : : "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
866 : :
867 : : Otherwise, generate a description of the form
868 : : "calling 'foo' from 'bar'". */
869 : :
870 : : label_text
871 : 1943 : call_event::get_desc (bool can_colorize) const
872 : : {
873 : 1943 : if (m_critical_state && m_pending_diagnostic)
874 : : {
875 : 433 : gcc_assert (m_var);
876 : 433 : tree var = fixup_tree_for_diagnostic (m_var);
877 : 433 : label_text custom_desc
878 : 433 : = m_pending_diagnostic->describe_call_with_state
879 : 866 : (evdesc::call_with_state (can_colorize,
880 : 433 : m_src_snode->m_fun->decl,
881 : 433 : m_dest_snode->m_fun->decl,
882 : : var,
883 : 433 : m_critical_state));
884 : 433 : if (custom_desc.get ())
885 : 186 : return custom_desc;
886 : 433 : }
887 : :
888 : 1757 : return make_label_text (can_colorize,
889 : : "calling %qE from %qE",
890 : : get_callee_fndecl (),
891 : 1757 : get_caller_fndecl ());
892 : : }
893 : :
894 : : /* Implementation of diagnostic_event::get_meaning vfunc for
895 : : function call events. */
896 : :
897 : : diagnostic_event::meaning
898 : 0 : call_event::get_meaning () const
899 : : {
900 : 0 : return meaning (VERB_call, NOUN_function);
901 : : }
902 : :
903 : : /* Override of checker_event::is_call_p for calls. */
904 : :
905 : : bool
906 : 2270 : call_event::is_call_p () const
907 : : {
908 : 2270 : return true;
909 : : }
910 : :
911 : : tree
912 : 1829 : call_event::get_caller_fndecl () const
913 : : {
914 : 1829 : return m_src_snode->m_fun->decl;
915 : : }
916 : :
917 : : tree
918 : 1829 : call_event::get_callee_fndecl () const
919 : : {
920 : 1829 : return m_dest_snode->m_fun->decl;
921 : : }
922 : :
923 : : /* class return_event : public superedge_event. */
924 : :
925 : : /* return_event's ctor. */
926 : :
927 : 742 : return_event::return_event (const exploded_edge &eedge,
928 : 742 : const event_loc_info &loc_info)
929 : 742 : : superedge_event (EK_RETURN_EDGE, eedge, loc_info)
930 : : {
931 : 742 : if (eedge.m_sedge)
932 : 719 : gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
933 : :
934 : 742 : m_src_snode = eedge.m_src->get_supernode ();
935 : 742 : m_dest_snode = eedge.m_dest->get_supernode ();
936 : 742 : }
937 : :
938 : : /* Implementation of diagnostic_event::get_desc vfunc for
939 : : return_event.
940 : :
941 : : If this return event returns critical state for an sm-based warning,
942 : : allow the diagnostic to generate a precise description, such as:
943 : :
944 : : "possible of NULL to 'foo' from 'bar'"
945 : :
946 : : Otherwise, generate a description of the form
947 : : "returning to 'foo' from 'bar'. */
948 : :
949 : : label_text
950 : 811 : return_event::get_desc (bool can_colorize) const
951 : : {
952 : : /* For greatest precision-of-wording, if this is returning the
953 : : state involved in the pending diagnostic, give the pending
954 : : diagnostic a chance to describe this return (in terms of
955 : : itself). */
956 : 811 : if (m_critical_state && m_pending_diagnostic)
957 : : {
958 : 114 : label_text custom_desc
959 : : = m_pending_diagnostic->describe_return_of_state
960 : 228 : (evdesc::return_of_state (can_colorize,
961 : 114 : m_dest_snode->m_fun->decl,
962 : 114 : m_src_snode->m_fun->decl,
963 : 114 : m_critical_state));
964 : 114 : if (custom_desc.get ())
965 : 62 : return custom_desc;
966 : 114 : }
967 : 749 : return make_label_text (can_colorize,
968 : : "returning to %qE from %qE",
969 : 749 : m_dest_snode->m_fun->decl,
970 : 749 : m_src_snode->m_fun->decl);
971 : : }
972 : :
973 : : /* Implementation of diagnostic_event::get_meaning vfunc for
974 : : function return events. */
975 : :
976 : : diagnostic_event::meaning
977 : 0 : return_event::get_meaning () const
978 : : {
979 : 0 : return meaning (VERB_return, NOUN_function);
980 : : }
981 : :
982 : : /* Override of checker_event::is_return_p for returns. */
983 : :
984 : : bool
985 : 745 : return_event::is_return_p () const
986 : : {
987 : 745 : return true;
988 : : }
989 : :
990 : : /* class start_consolidated_cfg_edges_event : public checker_event. */
991 : :
992 : : label_text
993 : 139 : start_consolidated_cfg_edges_event::get_desc (bool can_colorize) const
994 : : {
995 : 139 : return make_label_text (can_colorize,
996 : : "following %qs branch...",
997 : 191 : m_edge_sense ? "true" : "false");
998 : : }
999 : :
1000 : : /* Implementation of diagnostic_event::get_meaning vfunc for
1001 : : start_consolidated_cfg_edges_event. */
1002 : :
1003 : : diagnostic_event::meaning
1004 : 0 : start_consolidated_cfg_edges_event::get_meaning () const
1005 : : {
1006 : 0 : return meaning (VERB_branch,
1007 : 0 : (m_edge_sense ? PROPERTY_true : PROPERTY_false));
1008 : : }
1009 : :
1010 : : /* class inlined_call_event : public checker_event. */
1011 : :
1012 : : label_text
1013 : 409 : inlined_call_event::get_desc (bool can_colorize) const
1014 : : {
1015 : 409 : return make_label_text (can_colorize,
1016 : : "inlined call to %qE from %qE",
1017 : 409 : m_apparent_callee_fndecl,
1018 : 409 : m_apparent_caller_fndecl);
1019 : : }
1020 : :
1021 : : /* Implementation of diagnostic_event::get_meaning vfunc for
1022 : : reconstructed inlined function calls. */
1023 : :
1024 : : diagnostic_event::meaning
1025 : 0 : inlined_call_event::get_meaning () const
1026 : : {
1027 : 0 : return meaning (VERB_call, NOUN_function);
1028 : : }
1029 : :
1030 : : /* class setjmp_event : public checker_event. */
1031 : :
1032 : : /* Implementation of diagnostic_event::get_desc vfunc for
1033 : : setjmp_event. */
1034 : :
1035 : : label_text
1036 : 46 : setjmp_event::get_desc (bool can_colorize) const
1037 : : {
1038 : 46 : return make_label_text (can_colorize,
1039 : : "%qs called here",
1040 : 46 : get_user_facing_name (m_setjmp_call));
1041 : : }
1042 : :
1043 : : /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1044 : :
1045 : : Record this setjmp's event ID into the path, so that rewind events can
1046 : : use it. */
1047 : :
1048 : : void
1049 : 23 : setjmp_event::prepare_for_emission (checker_path *path,
1050 : : pending_diagnostic *pd,
1051 : : diagnostic_event_id_t emission_id)
1052 : : {
1053 : 23 : checker_event::prepare_for_emission (path, pd, emission_id);
1054 : 23 : path->record_setjmp_event (m_enode, emission_id);
1055 : 23 : }
1056 : :
1057 : : /* class rewind_event : public checker_event. */
1058 : :
1059 : : /* Get the fndecl containing the site of the longjmp call. */
1060 : :
1061 : : tree
1062 : 102 : rewind_event::get_longjmp_caller () const
1063 : : {
1064 : 102 : return m_eedge->m_src->get_function ()->decl;
1065 : : }
1066 : :
1067 : : /* Get the fndecl containing the site of the setjmp call. */
1068 : :
1069 : : tree
1070 : 97 : rewind_event::get_setjmp_caller () const
1071 : : {
1072 : 97 : return m_eedge->m_dest->get_function ()->decl;
1073 : : }
1074 : :
1075 : : /* rewind_event's ctor. */
1076 : :
1077 : 34 : rewind_event::rewind_event (const exploded_edge *eedge,
1078 : : enum event_kind kind,
1079 : : const event_loc_info &loc_info,
1080 : 34 : const rewind_info_t *rewind_info)
1081 : : : checker_event (kind, loc_info),
1082 : 34 : m_rewind_info (rewind_info),
1083 : 34 : m_eedge (eedge)
1084 : : {
1085 : 34 : gcc_assert (m_eedge->m_custom_info.get () == m_rewind_info);
1086 : 34 : }
1087 : :
1088 : : /* class rewind_from_longjmp_event : public rewind_event. */
1089 : :
1090 : : /* Implementation of diagnostic_event::get_desc vfunc for
1091 : : rewind_from_longjmp_event. */
1092 : :
1093 : : label_text
1094 : 34 : rewind_from_longjmp_event::get_desc (bool can_colorize) const
1095 : : {
1096 : 34 : const char *src_name
1097 : 34 : = get_user_facing_name (m_rewind_info->get_longjmp_call ());
1098 : :
1099 : 34 : if (get_longjmp_caller () == get_setjmp_caller ())
1100 : : /* Special-case: purely intraprocedural rewind. */
1101 : 10 : return make_label_text (can_colorize,
1102 : : "rewinding within %qE from %qs...",
1103 : : get_longjmp_caller (),
1104 : 10 : src_name);
1105 : : else
1106 : 24 : return make_label_text (can_colorize,
1107 : : "rewinding from %qs in %qE...",
1108 : : src_name,
1109 : 24 : get_longjmp_caller ());
1110 : : }
1111 : :
1112 : : /* class rewind_to_setjmp_event : public rewind_event. */
1113 : :
1114 : : /* Implementation of diagnostic_event::get_desc vfunc for
1115 : : rewind_to_setjmp_event. */
1116 : :
1117 : : label_text
1118 : 34 : rewind_to_setjmp_event::get_desc (bool can_colorize) const
1119 : : {
1120 : 34 : const char *dst_name
1121 : 34 : = get_user_facing_name (m_rewind_info->get_setjmp_call ());
1122 : :
1123 : : /* If we can, identify the ID of the setjmp_event. */
1124 : 34 : if (m_original_setjmp_event_id.known_p ())
1125 : : {
1126 : 17 : if (get_longjmp_caller () == get_setjmp_caller ())
1127 : : /* Special-case: purely intraprocedural rewind. */
1128 : 5 : return make_label_text (can_colorize,
1129 : : "...to %qs (saved at %@)",
1130 : : dst_name,
1131 : 5 : &m_original_setjmp_event_id);
1132 : : else
1133 : 12 : return make_label_text (can_colorize,
1134 : : "...to %qs in %qE (saved at %@)",
1135 : : dst_name,
1136 : : get_setjmp_caller (),
1137 : 12 : &m_original_setjmp_event_id);
1138 : : }
1139 : : else
1140 : : {
1141 : 17 : if (get_longjmp_caller () == get_setjmp_caller ())
1142 : : /* Special-case: purely intraprocedural rewind. */
1143 : 5 : return make_label_text (can_colorize,
1144 : : "...to %qs",
1145 : : dst_name,
1146 : 5 : get_setjmp_caller ());
1147 : : else
1148 : 12 : return make_label_text (can_colorize,
1149 : : "...to %qs in %qE",
1150 : : dst_name,
1151 : 12 : get_setjmp_caller ());
1152 : : }
1153 : : }
1154 : :
1155 : : /* Implementation of checker_event::prepare_for_emission vfunc for
1156 : : rewind_to_setjmp_event.
1157 : :
1158 : : Attempt to look up the setjmp event ID that recorded the jmp_buf
1159 : : for this rewind. */
1160 : :
1161 : : void
1162 : 17 : rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
1163 : : pending_diagnostic *pd,
1164 : : diagnostic_event_id_t emission_id)
1165 : : {
1166 : 17 : checker_event::prepare_for_emission (path, pd, emission_id);
1167 : 17 : path->get_setjmp_event (m_rewind_info->get_enode_origin (),
1168 : : &m_original_setjmp_event_id);
1169 : 17 : }
1170 : :
1171 : : /* class warning_event : public checker_event. */
1172 : :
1173 : : /* Implementation of diagnostic_event::get_desc vfunc for
1174 : : warning_event.
1175 : :
1176 : : If the pending diagnostic implements describe_final_event, use it,
1177 : : generating a precise description e.g.
1178 : : "second 'free' here; first 'free' was at (7)"
1179 : :
1180 : : Otherwise generate a generic description. */
1181 : :
1182 : : label_text
1183 : 8929 : warning_event::get_desc (bool can_colorize) const
1184 : : {
1185 : 8929 : if (m_pending_diagnostic)
1186 : : {
1187 : 8929 : tree var = fixup_tree_for_diagnostic (m_var);
1188 : 8929 : label_text ev_desc
1189 : 8929 : = m_pending_diagnostic->describe_final_event
1190 : 8929 : (evdesc::final_event (can_colorize, var, m_state, *this));
1191 : 8929 : if (ev_desc.get ())
1192 : : {
1193 : 8487 : if (m_sm && flag_analyzer_verbose_state_changes)
1194 : : {
1195 : 90 : if (var)
1196 : 80 : return make_label_text (can_colorize,
1197 : : "%s (%qE is in state %qs)",
1198 : : ev_desc.get (),
1199 : 80 : var, m_state->get_name ());
1200 : : else
1201 : 10 : return make_label_text (can_colorize,
1202 : : "%s (in global state %qs)",
1203 : : ev_desc.get (),
1204 : 10 : m_state->get_name ());
1205 : : }
1206 : : else
1207 : 8397 : return ev_desc;
1208 : : }
1209 : 8929 : }
1210 : :
1211 : 442 : if (m_sm)
1212 : : {
1213 : 76 : if (m_var)
1214 : 76 : return make_label_text (can_colorize,
1215 : : "here (%qE is in state %qs)",
1216 : 76 : m_var, m_state->get_name ());
1217 : : else
1218 : 0 : return make_label_text (can_colorize,
1219 : : "here (in global state %qs)",
1220 : 0 : m_state->get_name ());
1221 : : }
1222 : : else
1223 : 366 : return label_text::borrow ("here");
1224 : : }
1225 : :
1226 : : /* Implementation of diagnostic_event::get_meaning vfunc for
1227 : : warning_event. */
1228 : :
1229 : : diagnostic_event::meaning
1230 : 15 : warning_event::get_meaning () const
1231 : : {
1232 : 15 : return meaning (VERB_danger, NOUN_unknown);
1233 : : }
1234 : :
1235 : : } // namespace ana
1236 : :
1237 : : #endif /* #if ENABLE_ANALYZER */
|