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 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 #ifndef GCC_ANALYZER_DIAGNOSTIC_MANAGER_H 22 #define GCC_ANALYZER_DIAGNOSTIC_MANAGER_H 23 24 namespace ana { 25 26 /* A to-be-emitted diagnostic stored within diagnostic_manager. */ 27 28 class saved_diagnostic 29 { 30 public: 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 set_feasible()48 void set_feasible () 49 { 50 gcc_assert (m_status == STATUS_NEW); 51 m_status = STATUS_FEASIBLE_PATH; 52 } set_infeasible(feasibility_problem * p)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 } get_feasibility_problem()59 const feasibility_problem *get_feasibility_problem () const 60 { 61 return m_problem; 62 } 63 get_status()64 enum status get_status () const { return m_status; } 65 set_epath_length(unsigned length)66 void set_epath_length (unsigned length) { m_epath_length = length; } get_epath_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 80 private: 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 88 class 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 99 class diagnostic_manager : public log_user 100 { 101 public: 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 get_num_diagnostics()124 unsigned get_num_diagnostics () const 125 { 126 return m_saved_diagnostics.length (); 127 } get_saved_diagnostic(unsigned idx)128 saved_diagnostic *get_saved_diagnostic (unsigned idx) 129 { 130 return m_saved_diagnostics[idx]; 131 } get_saved_diagnostic(unsigned idx)132 const saved_diagnostic *get_saved_diagnostic (unsigned idx) const 133 { 134 return m_saved_diagnostics[idx]; 135 } 136 137 private: 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