Line data Source code
1 : /* Support for -fdiagnostics-add-output= and -fdiagnostics-set-output=.
2 : Copyright (C) 2024-2026 Free Software Foundation, Inc.
3 :
4 : This file is part of GCC.
5 :
6 : GCC is free software; you can redistribute it and/or modify it under
7 : the terms of the GNU General Public License as published by the Free
8 : Software Foundation; either version 3, or (at your option) any later
9 : version.
10 :
11 : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 : for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with GCC; see the file COPYING3. If not see
18 : <http://www.gnu.org/licenses/>. */
19 :
20 :
21 : /* This file implements the options -fdiagnostics-add-output=,
22 : -fdiagnostics-set-output=. Most of the work is done
23 : by diagnostics/output-spec.cc so it can be shared by libgdiagnostics. */
24 :
25 : #include "config.h"
26 : #define INCLUDE_ARRAY
27 : #define INCLUDE_LIST
28 : #define INCLUDE_STRING
29 : #define INCLUDE_VECTOR
30 : #include "system.h"
31 : #include "coretypes.h"
32 : #include "version.h"
33 : #include "intl.h"
34 : #include "diagnostic.h"
35 : #include "diagnostics/output-spec.h"
36 : #include "diagnostics/logging.h"
37 : #include "diagnostics/sarif-sink.h"
38 : #include "opts.h"
39 : #include "options.h"
40 : #include "tree-diagnostic-sink-extensions.h"
41 : #include "opts-diagnostic.h"
42 : #include "pub-sub.h"
43 :
44 : /* Decls. */
45 :
46 : namespace {
47 :
48 : class gcc_extra_keys : public diagnostics::output_spec::key_handler
49 : {
50 : public:
51 50 : gcc_extra_keys ()
52 50 : : m_cfgs (false)
53 : {
54 : }
55 : enum result
56 2 : maybe_handle_kv (const diagnostics::output_spec::context &ctxt,
57 : const std::string &key,
58 : const std::string &value) final override
59 : {
60 2 : if (key == "cfgs")
61 2 : return parse_bool_value (ctxt, key, value, m_cfgs);
62 : return result::unrecognized;
63 : }
64 :
65 : void
66 0 : get_keys (auto_vec<const char *> &out_known_keys) const final override
67 : {
68 0 : out_known_keys.safe_push ("cfgs");
69 0 : }
70 :
71 : bool m_cfgs;
72 : };
73 :
74 50 : struct opt_spec_context : public diagnostics::output_spec::dc_spec_context
75 : {
76 : public:
77 50 : opt_spec_context (const gcc_options &opts,
78 : diagnostics::context &dc,
79 : line_maps *location_mgr,
80 : location_t loc,
81 : const char *option_name,
82 : const char *option_value,
83 : diagnostics::output_spec::key_handler *client_keys)
84 50 : : dc_spec_context (option_name,
85 : option_value,
86 : client_keys,
87 : location_mgr,
88 : dc,
89 : location_mgr,
90 : loc),
91 50 : m_opts (opts)
92 : {}
93 :
94 : const char *
95 36 : get_base_filename () const final override
96 : {
97 36 : return get_diagnostic_file_output_basename (m_opts);
98 : }
99 :
100 : const gcc_options &m_opts;
101 : };
102 :
103 : static void
104 50 : handle_gcc_specific_keys (const gcc_extra_keys &gcc_keys,
105 : diagnostics::sink &sink,
106 : const gcc_extension_factory &ext_factory)
107 : {
108 50 : if (gcc_keys.m_cfgs)
109 2 : sink.add_extension (ext_factory.make_cfg_extension (sink));
110 50 : }
111 :
112 : static std::unique_ptr<diagnostics::sink>
113 50 : try_to_make_sink (const gcc_options &opts,
114 : diagnostics::context &dc,
115 : const char *option_name,
116 : const char *unparsed_spec,
117 : location_t loc)
118 : {
119 50 : gcc_assert (line_table);
120 :
121 50 : gcc_extra_keys gcc_keys;
122 50 : opt_spec_context ctxt (opts, dc, line_table, loc, option_name, unparsed_spec,
123 50 : &gcc_keys);
124 50 : auto sink = ctxt.parse_and_make_sink (dc);
125 50 : if (!sink)
126 0 : return nullptr;
127 :
128 50 : sink->set_main_input_filename (opts.x_main_input_filename);
129 :
130 50 : if (auto ext_factory = gcc_extension_factory::singleton)
131 50 : handle_gcc_specific_keys (gcc_keys, *sink, *ext_factory);
132 :
133 50 : return sink;
134 50 : }
135 :
136 : } // anon namespace
137 :
138 : // class gcc_extension_factory
139 :
140 : const gcc_extension_factory *gcc_extension_factory::singleton;
141 :
142 : void
143 36 : handle_OPT_fdiagnostics_add_output_ (const gcc_options &opts,
144 : diagnostics::context &dc,
145 : const char *unparsed_spec,
146 : location_t loc)
147 : {
148 36 : gcc_assert (unparsed_spec);
149 :
150 36 : const char *const option_name = "-fdiagnostics-add-output=";
151 36 : DIAGNOSTICS_LOG_SCOPE_PRINTF2 (dc.get_logger (),
152 36 : "handling: %s%s", option_name, unparsed_spec);
153 36 : if (auto sink = try_to_make_sink (opts, dc, option_name, unparsed_spec, loc))
154 36 : dc.add_sink (std::move (sink));
155 36 : }
156 :
157 : void
158 14 : handle_OPT_fdiagnostics_set_output_ (const gcc_options &opts,
159 : diagnostics::context &dc,
160 : const char *unparsed_spec,
161 : location_t loc)
162 : {
163 14 : gcc_assert (unparsed_spec);
164 :
165 14 : const char *const option_name = "-fdiagnostics-set-output=";
166 14 : DIAGNOSTICS_LOG_SCOPE_PRINTF2 (dc.get_logger (),
167 14 : "handling: %s%s", option_name, unparsed_spec);
168 14 : if (auto sink = try_to_make_sink (opts, dc, option_name, unparsed_spec, loc))
169 14 : dc.set_sink (std::move (sink));
170 14 : }
171 :
172 : /* Return the base name to use when choosing names for output file for
173 : diagnostic sinks (e.g. BASENAME.sarif or BASENAME.html). */
174 :
175 : const char *
176 126 : get_diagnostic_file_output_basename (const gcc_options &opts)
177 : {
178 : /* This might have been called before finish_options, which prepends
179 : the dump dir to the dump base name. If so, make a prepended copy
180 : now and use it. */
181 126 : if (opts.x_dump_base_name
182 118 : && ! opts.x_dump_base_name_prefixed)
183 236 : if (const char *prepended_dump_base_name
184 118 : = maybe_prepend_dump_dir_name (opts))
185 : /* Allocated in opts_obstack. */
186 : return prepended_dump_base_name;
187 :
188 126 : return (opts.x_dump_base_name
189 : ? opts.x_dump_base_name
190 126 : : opts.x_main_input_basename);
191 : }
|