1 /* JSON output for diagnostics
2 Copyright (C) 2018 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
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
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
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/>. */
24 #include "coretypes.h"
25 #include "diagnostic.h"
28 /* The top-level JSON array of pending diagnostics. */
30 static json::array
*toplevel_array
;
32 /* The JSON object for the current diagnostic group. */
34 static json::object
*cur_group
;
36 /* The JSON array for the "children" array within the current diagnostic
39 static json::array
*cur_children_array
;
41 /* Generate a JSON object for LOC. */
44 json_from_expanded_location (location_t loc
)
46 expanded_location exploc
= expand_location (loc
);
47 json::object
*result
= new json::object ();
48 result
->set ("file", new json::string (exploc
.file
));
49 result
->set ("line", new json::number (exploc
.line
));
50 result
->set ("column", new json::number (exploc
.column
));
54 /* Generate a JSON object for LOC_RANGE. */
57 json_from_location_range (const location_range
*loc_range
, unsigned range_idx
)
59 location_t caret_loc
= get_pure_location (loc_range
->m_loc
);
61 if (caret_loc
== UNKNOWN_LOCATION
)
64 location_t start_loc
= get_start (loc_range
->m_loc
);
65 location_t finish_loc
= get_finish (loc_range
->m_loc
);
67 json::object
*result
= new json::object ();
68 result
->set ("caret", json_from_expanded_location (caret_loc
));
69 if (start_loc
!= caret_loc
)
70 result
->set ("start", json_from_expanded_location (start_loc
));
71 if (finish_loc
!= caret_loc
)
72 result
->set ("finish", json_from_expanded_location (finish_loc
));
74 if (loc_range
->m_label
)
77 text
= loc_range
->m_label
->get_text (range_idx
);
79 result
->set ("label", new json::string (text
.m_buffer
));
86 /* Generate a JSON object for HINT. */
89 json_from_fixit_hint (const fixit_hint
*hint
)
91 json::object
*fixit_obj
= new json::object ();
93 location_t start_loc
= hint
->get_start_loc ();
94 fixit_obj
->set ("start", json_from_expanded_location (start_loc
));
95 location_t next_loc
= hint
->get_next_loc ();
96 fixit_obj
->set ("next", json_from_expanded_location (next_loc
));
97 fixit_obj
->set ("string", new json::string (hint
->get_string ()));
102 /* No-op implementation of "begin_diagnostic" for JSON output. */
105 json_begin_diagnostic (diagnostic_context
*, diagnostic_info
*)
109 /* Implementation of "end_diagnostic" for JSON output.
110 Generate a JSON object for DIAGNOSTIC, and store for output
111 within current diagnostic group. */
114 json_end_diagnostic (diagnostic_context
*context
, diagnostic_info
*diagnostic
,
115 diagnostic_t orig_diag_kind
)
117 json::object
*diag_obj
= new json::object ();
119 /* Get "kind" of diagnostic. */
121 static const char *const diagnostic_kind_text
[] = {
122 #define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T),
123 #include "diagnostic.def"
124 #undef DEFINE_DIAGNOSTIC_KIND
127 /* Lose the trailing ": ". */
128 const char *kind_text
= diagnostic_kind_text
[diagnostic
->kind
];
129 size_t len
= strlen (kind_text
);
130 gcc_assert (len
> 2);
131 gcc_assert (kind_text
[len
- 2] == ':');
132 gcc_assert (kind_text
[len
- 1] == ' ');
133 char *rstrip
= xstrdup (kind_text
);
134 rstrip
[len
- 2] = '\0';
135 diag_obj
->set ("kind", new json::string (rstrip
));
139 // FIXME: encoding of the message (json::string requires UTF-8)
140 diag_obj
->set ("message",
141 new json::string (pp_formatted_text (context
->printer
)));
142 pp_clear_output_area (context
->printer
);
145 option_text
= context
->option_name (context
, diagnostic
->option_index
,
146 orig_diag_kind
, diagnostic
->kind
);
149 diag_obj
->set ("option", new json::string (option_text
));
153 /* If we've already emitted a diagnostic within this auto_diagnostic_group,
154 then add diag_obj to its "children" array. */
157 gcc_assert (cur_children_array
);
158 cur_children_array
->append (diag_obj
);
162 /* Otherwise, make diag_obj be the top-level object within the group;
163 add a "children" array. */
164 toplevel_array
->append (diag_obj
);
165 cur_group
= diag_obj
;
166 cur_children_array
= new json::array ();
167 diag_obj
->set ("children", cur_children_array
);
170 const rich_location
*richloc
= diagnostic
->richloc
;
172 json::array
*loc_array
= new json::array ();
173 diag_obj
->set ("locations", loc_array
);
175 for (unsigned int i
= 0; i
< richloc
->get_num_locations (); i
++)
177 const location_range
*loc_range
= richloc
->get_range (i
);
178 json::object
*loc_obj
= json_from_location_range (loc_range
, i
);
180 loc_array
->append (loc_obj
);
183 if (richloc
->get_num_fixit_hints ())
185 json::array
*fixit_array
= new json::array ();
186 diag_obj
->set ("fixits", fixit_array
);
187 for (unsigned int i
= 0; i
< richloc
->get_num_fixit_hints (); i
++)
189 const fixit_hint
*hint
= richloc
->get_fixit_hint (i
);
190 json::object
*fixit_obj
= json_from_fixit_hint (hint
);
191 fixit_array
->append (fixit_obj
);
195 /* TODO: tree-ish things:
197 TODO: inlining information
198 TODO: macro expansion information. */
201 /* No-op implementation of "begin_group_cb" for JSON output. */
204 json_begin_group (diagnostic_context
*)
208 /* Implementation of "end_group_cb" for JSON output. */
211 json_end_group (diagnostic_context
*)
214 cur_children_array
= NULL
;
217 /* Callback for final cleanup for JSON output. */
220 json_final_cb (diagnostic_context
*)
222 /* Flush the top-level array. */
223 toplevel_array
->dump (stderr
);
224 fprintf (stderr
, "\n");
225 delete toplevel_array
;
226 toplevel_array
= NULL
;
229 /* Set the output format for CONTEXT to FORMAT. */
232 diagnostic_output_format_init (diagnostic_context
*context
,
233 enum diagnostics_output_format format
)
239 case DIAGNOSTICS_OUTPUT_FORMAT_TEXT
:
240 /* The default; do nothing. */
243 case DIAGNOSTICS_OUTPUT_FORMAT_JSON
:
245 /* Set up top-level JSON array. */
246 if (toplevel_array
== NULL
)
247 toplevel_array
= new json::array ();
249 /* Override callbacks. */
250 context
->begin_diagnostic
= json_begin_diagnostic
;
251 context
->end_diagnostic
= json_end_diagnostic
;
252 context
->begin_group_cb
= json_begin_group
;
253 context
->end_group_cb
= json_end_group
;
254 context
->final_cb
= json_final_cb
;
256 /* The option is handled in JSON format, rather than as text. */
257 context
->show_option_requested
= false;
259 /* Don't colorize the text. */
260 pp_show_color (context
->printer
) = false;