1/* Classes for saving, deduplicating, and emitting analyzer diagnostics.
2   Copyright (C) 2019-2020 Free Software Foundation, Inc.
3   Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3.  If not see
19<http://www.gnu.org/licenses/>.  */
20
21#ifndef GCC_ANALYZER_DIAGNOSTIC_MANAGER_H
22#define GCC_ANALYZER_DIAGNOSTIC_MANAGER_H
23
24namespace ana {
25
26/* A to-be-emitted diagnostic stored within diagnostic_manager.  */
27
28class saved_diagnostic
29{
30public:
31  enum status
32  {
33   STATUS_NEW,
34   STATUS_INFEASIBLE_PATH,
35   STATUS_FEASIBLE_PATH
36  };
37
38  saved_diagnostic (const state_machine *sm,
39		    const exploded_node *enode,
40		    const supernode *snode, const gimple *stmt,
41		    stmt_finder *stmt_finder,
42		    tree var, state_machine::state_t state,
43		    pending_diagnostic *d);
44  ~saved_diagnostic ();
45
46  bool operator== (const saved_diagnostic &other) const;
47
48  void set_feasible ()
49  {
50    gcc_assert (m_status == STATUS_NEW);
51    m_status = STATUS_FEASIBLE_PATH;
52  }
53  void set_infeasible (feasibility_problem *p)
54  {
55    gcc_assert (m_status == STATUS_NEW);
56    m_status = STATUS_INFEASIBLE_PATH;
57    m_problem = p; // take ownership
58  }
59  const feasibility_problem *get_feasibility_problem () const
60  {
61    return m_problem;
62  }
63
64  enum status get_status () const { return m_status; }
65
66  void set_epath_length (unsigned length) { m_epath_length = length; }
67  unsigned get_epath_length () const { return m_epath_length; }
68
69  //private:
70  const state_machine *m_sm;
71  const exploded_node *m_enode;
72  const supernode *m_snode;
73  const gimple *m_stmt;
74  stmt_finder *m_stmt_finder;
75  tree m_var;
76  state_machine::state_t m_state;
77  pending_diagnostic *m_d;
78  exploded_edge *m_trailing_eedge;
79
80private:
81  DISABLE_COPY_AND_ASSIGN (saved_diagnostic);
82
83  enum status m_status;
84  unsigned m_epath_length;
85  feasibility_problem *m_problem;
86};
87
88class path_builder;
89
90/* A class with responsibility for saving pending diagnostics, so that
91   they can be emitted after the exploded_graph is complete.
92   This lets us de-duplicate diagnostics, and find the shortest path
93   for each similar diagnostic, potentially using edges that might
94   not have been found when each diagnostic was first saved.
95
96   This also lets us compute shortest_paths once, rather than
97   per-diagnostic.  */
98
99class diagnostic_manager : public log_user
100{
101public:
102  diagnostic_manager (logger *logger, int verbosity);
103
104  void add_diagnostic (const state_machine *sm,
105		       const exploded_node *enode,
106		       const supernode *snode, const gimple *stmt,
107		       stmt_finder *finder,
108		       tree var, state_machine::state_t state,
109		       pending_diagnostic *d);
110
111  void add_diagnostic (const exploded_node *enode,
112		       const supernode *snode, const gimple *stmt,
113		       stmt_finder *finder,
114		       pending_diagnostic *d);
115
116  void emit_saved_diagnostics (const exploded_graph &eg);
117
118  void emit_saved_diagnostic (const exploded_graph &eg,
119			      const saved_diagnostic &sd,
120			      const exploded_path &epath,
121			      const gimple *stmt,
122			      int num_dupes);
123
124  unsigned get_num_diagnostics () const
125  {
126    return m_saved_diagnostics.length ();
127  }
128  saved_diagnostic *get_saved_diagnostic (unsigned idx)
129  {
130    return m_saved_diagnostics[idx];
131  }
132  const saved_diagnostic *get_saved_diagnostic (unsigned idx) const
133  {
134    return m_saved_diagnostics[idx];
135  }
136
137private:
138  void build_emission_path (const path_builder &pb,
139			    const exploded_path &epath,
140			    checker_path *emission_path) const;
141
142  void add_events_for_eedge (const path_builder &pb,
143			     const exploded_edge &eedge,
144			     checker_path *emission_path) const;
145
146  bool significant_edge_p (const path_builder &pb,
147			   const exploded_edge &eedge) const;
148
149  void add_events_for_superedge (const path_builder &pb,
150				 const exploded_edge &eedge,
151				 checker_path *emission_path) const;
152
153  void prune_path (checker_path *path,
154		   const state_machine *sm,
155		   tree var, state_machine::state_t state) const;
156
157  void prune_for_sm_diagnostic (checker_path *path,
158				const state_machine *sm,
159				tree var,
160				state_machine::state_t state) const;
161  void update_for_unsuitable_sm_exprs (tree *expr) const;
162  void prune_interproc_events (checker_path *path) const;
163  void finish_pruning (checker_path *path) const;
164
165  auto_delete_vec<saved_diagnostic> m_saved_diagnostics;
166  const int m_verbosity;
167};
168
169} // namespace ana
170
171#endif /* GCC_ANALYZER_DIAGNOSTIC_MANAGER_H */
172