diagnostics: add SARIF output format

This patch adds support to gcc's diagnostic subsystem for emitting
diagnostics in SARIF, aka the Static Analysis Results Interchange Format:
  https://sarifweb.azurewebsites.net/
by extending -fdiagnostics-format= to add two new options:
  -fdiagnostics-format=sarif-stderr
and:
  -fdiagnostics-format=sarif-file

The patch targets SARIF v2.1.0

This is a JSON-based format suited for capturing the results of static
analysis tools (like GCC's -fanalyzer), but it can also be used for plain
GCC warnings and errors.

SARIF supports per-event metadata in diagnostic paths such as
["acquire", "resource"] and ["release", "lock"] (specifically, the
threadFlowLocation "kinds" property: SARIF v2.1.0 section 3.38.8), so
the patch extends GCC"s diagnostic_event subclass with a "struct meaning"
with similar purpose.  The patch implements this for -fanalyzer so that
the various state-machine-based warnings set these in the SARIF output.

The heart of the implementation is in the new file
diagnostic-format-sarif.cc.  Much of the rest of the patch is interface
classes, isolating the diagnostic subsystem (which has no knowledge of
e.g. tree or langhook) from the "client" code in the compiler proper
cc1 etc).

The patch adds a langhook for specifying the SARIF v2.1.0
"artifact.sourceLanguage" property, based on the list in
SARIF v2.1.0 Appendix J.

The patch adds automated DejaGnu tests to our testsuite via new
scan-sarif-file and scan-sarif-file-not directives (although these
merely use regexps, rather than attempting to use a proper JSON parser).

I've tested the patch by hand using the validator at:
  https://sarifweb.azurewebsites.net/Validation
and the react-based viewer at:
  https://microsoft.github.io/sarif-web-component/
which successfully shows most of the information (although not paths,
and not CWE IDs), and I've fixed all validation errors I've seen (though
bugs no doubt remain).

I've also tested the generated SARIF using the VS Code extension linked
to from the SARIF website; I'm a novice with VS Code, but it seems to be
able to handle my generated SARIF files (e.g. showing the data in the
SARIF tab, and showing squiggly underlines under issues, and when I
click on them, it visualizes the events in the path inline within the
source window).

Has anyone written an Emacs mode for SARIF files? (pretty please)

gcc/ChangeLog:
	* Makefile.in (OBJS): Add tree-diagnostic-client-data-hooks.o and
	tree-logical-location.o.
	(OBJS-libcommon): Add diagnostic-format-sarif.o; reorder.
	(CFLAGS-tree-diagnostic-client-data-hooks.o): Add TARGET_NAME.
	* common.opt (fdiagnostics-format=): Add sarif-stderr and sarif-file.
	(sarif-stderr, sarif-file): New enum values.
	* diagnostic-client-data-hooks.h: New file.
	* diagnostic-format-sarif.cc: New file.
	* diagnostic-path.h (enum diagnostic_event::verb): New enum.
	(enum diagnostic_event::noun): New enum.
	(enum diagnostic_event::property): New enum.
	(struct diagnostic_event::meaning): New struct.
	(diagnostic_event::get_logical_location): New vfunc.
	(diagnostic_event::get_meaning): New vfunc.
	(simple_diagnostic_event::get_logical_location): New vfunc impl.
	(simple_diagnostic_event::get_meaning): New vfunc impl.
	* diagnostic.cc: Include "diagnostic-client-data-hooks.h".
	(diagnostic_initialize): Initialize m_client_data_hooks.
	(diagnostic_finish): Clean up m_client_data_hooks.
	(diagnostic_event::meaning::dump_to_pp): New.
	(diagnostic_event::meaning::maybe_get_verb_str): New.
	(diagnostic_event::meaning::maybe_get_noun_str): New.
	(diagnostic_event::meaning::maybe_get_property_str): New.
	(get_cwe_url): Make non-static.
	(diagnostic_output_format_init): Handle
	DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR and
	DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE.
	* diagnostic.h (enum diagnostics_output_format): Add
	DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR and
	DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE.
	(class diagnostic_client_data_hooks): New forward decl.
	(class logical_location): New forward decl.
	(diagnostic_context::m_client_data_hooks): New field.
	(diagnostic_output_format_init_sarif_stderr): New decl.
	(diagnostic_output_format_init_sarif_file): New decl.
	(get_cwe_url): New decl.
	* doc/invoke.texi (-fdiagnostics-format=): Add sarif-stderr and
	sarif-file.
	* doc/sourcebuild.texi (Scan a particular file): Add
	scan-sarif-file and scan-sarif-file-not.
	* langhooks-def.h (lhd_get_sarif_source_language): New decl.
	(LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): New macro.
	(LANG_HOOKS_INITIALIZER): Add
	LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE.
	* langhooks.cc (lhd_get_sarif_source_language): New.
	* langhooks.h (lang_hooks::get_sarif_source_language): New field.
	* logical-location.h: New file.
	* plugin.cc (struct for_each_plugin_closure): New.
	(for_each_plugin_cb): New.
	(for_each_plugin): New.
	* plugin.h (for_each_plugin): New decl.
	* tree-diagnostic-client-data-hooks.cc: New file.
	* tree-diagnostic.cc: Include "diagnostic-client-data-hooks.h".
	(tree_diagnostics_defaults): Populate m_client_data_hooks.
	* tree-logical-location.cc: New file.
	* tree-logical-location.h: New file.

gcc/ada/ChangeLog:
	* gcc-interface/misc.cc (gnat_get_sarif_source_language): New.
	(LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.

gcc/analyzer/ChangeLog:
	* checker-path.cc (checker_event::get_meaning): New.
	(function_entry_event::get_meaning): New.
	(state_change_event::get_desc): Add dump of meaning of the event
	to the -fanalyzer-verbose-state-changes output.
	(state_change_event::get_meaning): New.
	(cfg_edge_event::get_meaning): New.
	(call_event::get_meaning): New.
	(return_event::get_meaning): New.
	(start_consolidated_cfg_edges_event::get_meaning): New.
	(warning_event::get_meaning): New.
	* checker-path.h: Include "tree-logical-location.h".
	(checker_event::checker_event): Construct m_logical_loc.
	(checker_event::get_logical_location): New.
	(checker_event::get_meaning): New decl.
	(checker_event::m_logical_loc): New.
	(function_entry_event::get_meaning): New decl.
	(state_change_event::get_meaning): New decl.
	(cfg_edge_event::get_meaning): New decl.
	(call_event::get_meaning): New decl.
	(return_event::get_meaning): New decl.
	(start_consolidated_cfg_edges_event::get_meaning): New.
	(warning_event::get_meaning): New decl.
	* pending-diagnostic.h: Include "diagnostic-path.h".
	(pending_diagnostic::get_meaning_for_state_change): New vfunc.
	* sm-file.cc (file_diagnostic::get_meaning_for_state_change): New
	vfunc impl.
	* sm-malloc.cc (malloc_diagnostic::get_meaning_for_state_change):
	Likewise.
	* sm-sensitive.cc
	(exposure_through_output_file::get_meaning_for_state_change):
	Likewise.
	* sm-taint.cc (taint_diagnostic::get_meaning_for_state_change):
	Likewise.
	* varargs.cc
	(va_list_sm_diagnostic::get_meaning_for_state_change): Likewise.

gcc/c/ChangeLog:
	* c-lang.cc (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.
	(c_get_sarif_source_language): New.
	* c-tree.h (c_get_sarif_source_language): New decl.

gcc/cp/ChangeLog:
	* cp-lang.cc (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.
	(cp_get_sarif_source_language): New.

gcc/d/ChangeLog:
	* d-lang.cc (d_get_sarif_source_language): New.
	(LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.

gcc/fortran/ChangeLog:
	* f95-lang.cc (gfc_get_sarif_source_language): New.
	(LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.

gcc/go/ChangeLog:
	* go-lang.cc (go_get_sarif_source_language): New.
	(LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.

gcc/objc/ChangeLog:
	* objc-act.h (objc_get_sarif_source_language): New decl.
	* objc-lang.cc (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine.
	(objc_get_sarif_source_language): New.

gcc/testsuite/ChangeLog:
	* c-c++-common/diagnostic-format-sarif-file-1.c: New test.
	* c-c++-common/diagnostic-format-sarif-file-2.c: New test.
	* c-c++-common/diagnostic-format-sarif-file-3.c: New test.
	* c-c++-common/diagnostic-format-sarif-file-4.c: New test.
	* gcc.dg/analyzer/file-meaning-1.c: New test.
	* gcc.dg/analyzer/malloc-meaning-1.c: New test.
	* gcc.dg/analyzer/malloc-sarif-1.c: New test.
	* gcc.dg/plugin/analyzer_gil_plugin.c
	(gil_diagnostic::get_meaning_for_state_change): New vfunc impl.
	* gcc.dg/plugin/diagnostic-test-paths-5.c: New test.
	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add
	diagnostic-test-paths-5.c to tests for
	diagnostic_plugin_test_paths.c.
	* lib/gcc-dg.exp: Load scansarif.exp.
	* lib/scansarif.exp: New test.

libatomic/ChangeLog:
	* testsuite/lib/libatomic.exp: Add load_gcc_lib of scansarif.exp.

libgomp/ChangeLog:
	* testsuite/lib/libgomp.exp: Add load_gcc_lib of scansarif.exp.

libitm/ChangeLog:
	* testsuite/lib/libitm.exp: Add load_gcc_lib of scansarif.exp.

libphobos/ChangeLog:
	* testsuite/lib/libphobos-dg.exp: Add load_gcc_lib of scansarif.exp.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
David Malcolm 2022-06-02 15:40:22 -04:00
parent 5ab73173cc
commit 6cf276ddf2
52 changed files with 3005 additions and 13 deletions

View file

@ -1617,6 +1617,7 @@ OBJS = \
tree-data-ref.o \
tree-dfa.o \
tree-diagnostic.o \
tree-diagnostic-client-data-hooks.o \
tree-diagnostic-path.o \
tree-dump.o \
tree-eh.o \
@ -1625,6 +1626,7 @@ OBJS = \
tree-inline.o \
tree-into-ssa.o \
tree-iterator.o \
tree-logical-location.o \
tree-loop-distribution.o \
tree-nested.o \
tree-nrv.o \
@ -1728,9 +1730,12 @@ OBJS = \
# Objects in libcommon.a, potentially used by all host binaries and with
# no target dependencies.
OBJS-libcommon = diagnostic-spec.o diagnostic.o diagnostic-color.o \
diagnostic-show-locus.o diagnostic-format-json.o json.o \
diagnostic-format-json.o \
diagnostic-format-sarif.o \
diagnostic-show-locus.o \
edit-context.o \
pretty-print.o intl.o \
json.o \
sbitmap.o \
vec.o input.o hash-table.o ggc-none.o memory-block.o \
selftest.o selftest-diagnostic.o sort.o
@ -2368,6 +2373,7 @@ s-bversion: BASE-VER
$(STAMP) s-bversion
CFLAGS-toplev.o += -DTARGET_NAME=\"$(target_noncanonical)\"
CFLAGS-tree-diagnostic-client-data-hooks.o += -DTARGET_NAME=\"$(target_noncanonical)\"
CFLAGS-optinfo-emit-json.o += -DTARGET_NAME=\"$(target_noncanonical)\" $(ZLIBINC)
CFLAGS-analyzer/engine.o += $(ZLIBINC)

View file

@ -1292,6 +1292,15 @@ gnat_eh_personality (void)
return gnat_eh_personality_decl;
}
/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property,
based on the list in SARIF v2.1.0 Appendix J. */
static const char *
gnat_get_sarif_source_language (const char *)
{
return "ada";
}
/* Initialize language-specific bits of tree_contains_struct. */
static void
@ -1414,6 +1423,8 @@ get_lang_specific (tree node)
#define LANG_HOOKS_DEEP_UNSHARING true
#undef LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS
#define LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS true
#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE
#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE gnat_get_sarif_source_language
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;

View file

@ -112,6 +112,15 @@ event_kind_to_string (enum event_kind ek)
/* class checker_event : public diagnostic_event. */
/* No-op implementation of diagnostic_event::get_meaning vfunc for
checker_event: checker events have no meaning by default. */
diagnostic_event::meaning
checker_event::get_meaning () const
{
return meaning ();
}
/* Dump this event to PP (for debugging/logging purposes). */
void
@ -242,6 +251,15 @@ function_entry_event::get_desc (bool can_colorize) const
return make_label_text (can_colorize, "entry to %qE", m_fndecl);
}
/* Implementation of diagnostic_event::get_meaning vfunc for
function entry. */
diagnostic_event::meaning
function_entry_event::get_meaning () const
{
return meaning (VERB_enter, NOUN_function);
}
/* class state_change_event : public checker_event. */
/* state_change_event's ctor. */
@ -292,25 +310,33 @@ state_change_event::get_desc (bool can_colorize) const
{
if (flag_analyzer_verbose_state_changes)
{
/* Get any "meaning" of event. */
diagnostic_event::meaning meaning = get_meaning ();
pretty_printer meaning_pp;
meaning.dump_to_pp (&meaning_pp);
/* Append debug version. */
label_text result;
if (m_origin)
result = make_label_text
(can_colorize,
"%s (state of %qE: %qs -> %qs, origin: %qE)",
"%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
custom_desc.m_buffer,
var,
m_from->get_name (),
m_to->get_name (),
origin);
origin,
pp_formatted_text (&meaning_pp));
else
result = make_label_text
(can_colorize,
"%s (state of %qE: %qs -> %qs, NULL origin)",
"%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
custom_desc.m_buffer,
var,
m_from->get_name (),
m_to->get_name ());
m_to->get_name (),
pp_formatted_text (&meaning_pp));
custom_desc.maybe_free ();
return result;
}
@ -357,6 +383,26 @@ state_change_event::get_desc (bool can_colorize) const
}
}
/* Implementation of diagnostic_event::get_meaning vfunc for
state change events: delegate to the pending_diagnostic to
get any meaning. */
diagnostic_event::meaning
state_change_event::get_meaning () const
{
if (m_pending_diagnostic)
{
region_model *model = m_dst_state.m_region_model;
tree var = model->get_representative_tree (m_sval);
tree origin = model->get_representative_tree (m_origin);
return m_pending_diagnostic->get_meaning_for_state_change
(evdesc::state_change (false, var, origin,
m_from, m_to, m_emission_id, *this));
}
else
return meaning ();
}
/* class superedge_event : public checker_event. */
/* Get the callgraph_superedge for this superedge_event, which must be
@ -432,6 +478,21 @@ cfg_edge_event::cfg_edge_event (enum event_kind kind,
gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
}
/* Implementation of diagnostic_event::get_meaning vfunc for
CFG edge events. */
diagnostic_event::meaning
cfg_edge_event::get_meaning () const
{
const cfg_superedge& cfg_sedge = get_cfg_superedge ();
if (cfg_sedge.true_value_p ())
return meaning (VERB_branch, PROPERTY_true);
else if (cfg_sedge.false_value_p ())
return meaning (VERB_branch, PROPERTY_false);
else
return meaning ();
}
/* class start_cfg_edge_event : public cfg_edge_event. */
/* Implementation of diagnostic_event::get_desc vfunc for
@ -690,6 +751,15 @@ call_event::get_desc (bool can_colorize) const
get_caller_fndecl ());
}
/* Implementation of diagnostic_event::get_meaning vfunc for
function call events. */
diagnostic_event::meaning
call_event::get_meaning () const
{
return meaning (VERB_call, NOUN_function);
}
/* Override of checker_event::is_call_p for calls. */
bool
@ -760,6 +830,15 @@ return_event::get_desc (bool can_colorize) const
m_src_snode->m_fun->decl);
}
/* Implementation of diagnostic_event::get_meaning vfunc for
function return events. */
diagnostic_event::meaning
return_event::get_meaning () const
{
return meaning (VERB_return, NOUN_function);
}
/* Override of checker_event::is_return_p for returns. */
bool
@ -778,6 +857,16 @@ start_consolidated_cfg_edges_event::get_desc (bool can_colorize) const
m_edge_sense ? "true" : "false");
}
/* Implementation of diagnostic_event::get_meaning vfunc for
start_consolidated_cfg_edges_event. */
diagnostic_event::meaning
start_consolidated_cfg_edges_event::get_meaning () const
{
return meaning (VERB_branch,
(m_edge_sense ? PROPERTY_true : PROPERTY_false));
}
/* class setjmp_event : public checker_event. */
/* Implementation of diagnostic_event::get_desc vfunc for
@ -977,6 +1066,15 @@ warning_event::get_desc (bool can_colorize) const
return label_text::borrow ("here");
}
/* Implementation of diagnostic_event::get_meaning vfunc for
warning_event. */
diagnostic_event::meaning
warning_event::get_meaning () const
{
return meaning (VERB_danger, NOUN_unknown);
}
/* Print a single-line representation of this path to PP. */
void

View file

@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ANALYZER_CHECKER_PATH_H
#define GCC_ANALYZER_CHECKER_PATH_H
#include "tree-logical-location.h"
namespace ana {
/* An enum for discriminating between the concrete subclasses of
@ -85,7 +87,8 @@ public:
checker_event (enum event_kind kind,
location_t loc, tree fndecl, int depth)
: m_kind (kind), m_loc (loc), m_fndecl (fndecl), m_depth (depth),
m_pending_diagnostic (NULL), m_emission_id ()
m_pending_diagnostic (NULL), m_emission_id (),
m_logical_loc (fndecl)
{
}
@ -94,6 +97,14 @@ public:
location_t get_location () const final override { return m_loc; }
tree get_fndecl () const final override { return m_fndecl; }
int get_stack_depth () const final override { return m_depth; }
const logical_location *get_logical_location () const final override
{
if (m_fndecl)
return &m_logical_loc;
else
return NULL;
}
meaning get_meaning () const override;
/* Additional functionality. */
@ -122,6 +133,7 @@ public:
int m_depth;
pending_diagnostic *m_pending_diagnostic;
diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
tree_logical_location m_logical_loc;
};
/* A concrete event subclass for a purely textual event, for use in
@ -222,6 +234,7 @@ public:
}
label_text get_desc (bool can_colorize) const final override;
meaning get_meaning () const override;
bool is_function_entry_p () const final override { return true; }
};
@ -241,6 +254,7 @@ public:
const program_state &dst_state);
label_text get_desc (bool can_colorize) const final override;
meaning get_meaning () const override;
function *get_dest_function () const
{
@ -295,6 +309,8 @@ public:
class cfg_edge_event : public superedge_event
{
public:
meaning get_meaning () const override;
const cfg_superedge& get_cfg_superedge () const;
protected:
@ -353,6 +369,7 @@ public:
location_t loc, tree fndecl, int depth);
label_text get_desc (bool can_colorize) const override;
meaning get_meaning () const override;
bool is_call_p () const final override;
@ -373,6 +390,7 @@ public:
location_t loc, tree fndecl, int depth);
label_text get_desc (bool can_colorize) const final override;
meaning get_meaning () const override;
bool is_return_p () const final override;
@ -394,6 +412,7 @@ public:
}
label_text get_desc (bool can_colorize) const final override;
meaning get_meaning () const override;
private:
bool m_edge_sense;
@ -521,6 +540,7 @@ public:
}
label_text get_desc (bool can_colorize) const final override;
meaning get_meaning () const override;
private:
const state_machine *m_sm;

View file

@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ANALYZER_PENDING_DIAGNOSTIC_H
#define GCC_ANALYZER_PENDING_DIAGNOSTIC_H
#include "diagnostic-path.h"
namespace ana {
/* A bundle of information about things that are of interest to a
@ -232,6 +234,15 @@ class pending_diagnostic
return label_text ();
}
/* Vfunc for implementing diagnostic_event::get_meaning for
state_change_event. */
virtual diagnostic_event::meaning
get_meaning_for_state_change (const evdesc::state_change &) const
{
/* Default no-op implementation. */
return diagnostic_event::meaning ();
}
/* Precision-of-wording vfunc for describing an interprocedural call
carrying critial state for the diagnostic, from caller to callee.

View file

@ -143,6 +143,20 @@ public:
return label_text ();
}
diagnostic_event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
if (change.m_old_state == m_sm.get_start_state ()
&& change.m_new_state == m_sm.m_unchecked)
return diagnostic_event::meaning (diagnostic_event::VERB_acquire,
diagnostic_event::NOUN_resource);
if (change.m_new_state == m_sm.m_closed)
return diagnostic_event::meaning (diagnostic_event::VERB_release,
diagnostic_event::NOUN_resource);
return diagnostic_event::meaning ();
}
protected:
const fileptr_state_machine &m_sm;
tree m_arg;

View file

@ -736,6 +736,20 @@ public:
return label_text ();
}
diagnostic_event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
if (change.m_old_state == m_sm.get_start_state ()
&& unchecked_p (change.m_new_state))
return diagnostic_event::meaning (diagnostic_event::VERB_acquire,
diagnostic_event::NOUN_memory);
if (freed_p (change.m_new_state))
return diagnostic_event::meaning (diagnostic_event::VERB_release,
diagnostic_event::NOUN_memory);
return diagnostic_event::meaning ();
}
protected:
const malloc_state_machine &m_sm;
tree m_arg;

View file

@ -117,6 +117,15 @@ public:
return label_text ();
}
diagnostic_event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
if (change.m_new_state == m_sm.m_sensitive)
return diagnostic_event::meaning (diagnostic_event::VERB_acquire,
diagnostic_event::NOUN_sensitive);
return diagnostic_event::meaning ();
}
label_text describe_call_with_state (const evdesc::call_with_state &info)
final override
{

View file

@ -163,6 +163,17 @@ public:
change.m_expr);
return label_text ();
}
diagnostic_event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
if (change.m_new_state == m_sm.m_tainted)
return diagnostic_event::meaning (diagnostic_event::VERB_acquire,
diagnostic_event::NOUN_taint);
return diagnostic_event::meaning ();
}
protected:
const taint_state_machine &m_sm;
tree m_arg;

View file

@ -335,6 +335,19 @@ public:
return label_text ();
}
diagnostic_event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
if (change.m_new_state == m_sm.m_started)
return diagnostic_event::meaning (diagnostic_event::VERB_acquire,
diagnostic_event::NOUN_resource);
if (change.m_new_state == m_sm.m_ended)
return diagnostic_event::meaning (diagnostic_event::VERB_release,
diagnostic_event::NOUN_resource);
return diagnostic_event::meaning ();
}
protected:
va_list_sm_diagnostic (const va_list_state_machine &sm,
const svalue *ap_sval, tree ap_tree)

View file

@ -46,9 +46,21 @@ enum c_language_kind c_language = clk_c;
#undef LANG_HOOKS_GET_SUBSTRING_LOCATION
#define LANG_HOOKS_GET_SUBSTRING_LOCATION c_get_substring_location
#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE
#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE c_get_sarif_source_language
/* Each front end provides its own lang hook initializer. */
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property,
based on the list in SARIF v2.1.0 Appendix J. */
const char *
c_get_sarif_source_language (const char *)
{
return "c";
}
#if CHECKING_P
namespace selftest {

View file

@ -837,6 +837,8 @@ set_c_expr_source_range (c_expr *expr,
/* In c-fold.cc */
extern vec<tree> incomplete_record_decls;
extern const char *c_get_sarif_source_language (const char *filename);
#if CHECKING_P
namespace selftest {
extern void run_c_tests (void);

View file

@ -1390,7 +1390,7 @@ Common Joined RejectNegative UInteger
fdiagnostics-format=
Common Joined RejectNegative Enum(diagnostics_output_format)
-fdiagnostics-format=[text|json|json-stderr|json-file] Select output format.
-fdiagnostics-format=[text|sarif-stderr|sarif-file|json|json-stderr|json-file] Select output format.
fdiagnostics-escape-format=
Common Joined RejectNegative Enum(diagnostics_escape_format)
@ -1433,6 +1433,12 @@ Enum(diagnostics_output_format) String(json-stderr) Value(DIAGNOSTICS_OUTPUT_FOR
EnumValue
Enum(diagnostics_output_format) String(json-file) Value(DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE)
EnumValue
Enum(diagnostics_output_format) String(sarif-stderr) Value(DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR)
EnumValue
Enum(diagnostics_output_format) String(sarif-file) Value(DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE)
fdiagnostics-parseable-fixits
Common Var(flag_diagnostics_parseable_fixits)
Print fix-it hints in machine-readable form.

View file

@ -36,6 +36,7 @@ static tree get_template_argument_pack_elems_folded (const_tree);
static tree cxx_enum_underlying_base_type (const_tree);
static tree *cxx_omp_get_decl_init (tree);
static void cxx_omp_finish_decl_inits (void);
static const char *cp_get_sarif_source_language (const char *);
/* Lang hooks common to C++ and ObjC++ are declared in cp/cp-objcp-common.h;
consequently, there should be very few hooks below. */
@ -100,6 +101,9 @@ static void cxx_omp_finish_decl_inits (void);
#undef LANG_HOOKS_OMP_FINISH_DECL_INITS
#define LANG_HOOKS_OMP_FINISH_DECL_INITS cxx_omp_finish_decl_inits
#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE
#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE cp_get_sarif_source_language
/* Each front end provides its own lang hook initializer. */
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
@ -265,6 +269,15 @@ cxx_omp_finish_decl_inits (void)
dynamic_initializers = NULL;
}
/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property,
based on the list in SARIF v2.1.0 Appendix J. */
static const char *
cp_get_sarif_source_language (const char *)
{
return "cplusplus";
}
#if CHECKING_P
namespace selftest {

View file

@ -1933,6 +1933,15 @@ d_enum_underlying_base_type (const_tree type)
return TREE_TYPE (type);
}
/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property,
based on the list in SARIF v2.1.0 Appendix J. */
static const char *
d_get_sarif_source_language (const char *)
{
return "d";
}
/* Definitions for our language-specific hooks. */
#undef LANG_HOOKS_NAME
@ -1966,6 +1975,7 @@ d_enum_underlying_base_type (const_tree type)
#undef LANG_HOOKS_TYPE_FOR_MODE
#undef LANG_HOOKS_TYPE_FOR_SIZE
#undef LANG_HOOKS_TYPE_PROMOTES_TO
#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE
#define LANG_HOOKS_NAME "GNU D"
#define LANG_HOOKS_INIT d_init
@ -1998,6 +2008,7 @@ d_enum_underlying_base_type (const_tree type)
#define LANG_HOOKS_TYPE_FOR_MODE d_type_for_mode
#define LANG_HOOKS_TYPE_FOR_SIZE d_type_for_size
#define LANG_HOOKS_TYPE_PROMOTES_TO d_type_promotes_to
#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE d_get_sarif_source_language
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;

View file

@ -0,0 +1,105 @@
/* Additional metadata about a client for a diagnostic context.
Copyright (C) 2022 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H
#define GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H
class client_version_info;
/* A bundle of additional metadata, owned by the diagnostic_context,
for querying things about the client, like version data. */
class diagnostic_client_data_hooks
{
public:
virtual ~diagnostic_client_data_hooks () {}
/* Get version info for this client, or NULL. */
virtual const client_version_info *get_any_version_info () const = 0;
/* Get the current logical_location for this client, or NULL. */
virtual const logical_location *get_current_logical_location () const = 0;
/* Get a sourceLanguage value for FILENAME, or return NULL.
See SARIF v2.1.0 Appendix J for suggested values. */
virtual const char *
maybe_get_sarif_source_language (const char *filename) const = 0;
};
/* Factory function for making an instance of diagnostic_client_data_hooks
for use in the compiler (i.e. with knowledge of "tree", access to
langhooks, etc). */
extern diagnostic_client_data_hooks *make_compiler_data_hooks ();
class diagnostic_client_plugin_info;
/* Abstract base class for a diagnostic_context to get at
version information about the client. */
class client_version_info
{
public:
class plugin_visitor
{
public:
virtual void on_plugin (const diagnostic_client_plugin_info &) = 0;
};
virtual ~client_version_info () {}
/* Get a string suitable for use as the value of the "name" property
(SARIF v2.1.0 section 3.19.8). */
virtual const char *get_tool_name () const = 0;
/* Create a string suitable for use as the value of the "fullName" property
(SARIF v2.1.0 section 3.19.9). */
virtual char *maybe_make_full_name () const = 0;
/* Get a string suitable for use as the value of the "version" property
(SARIF v2.1.0 section 3.19.13). */
virtual const char *get_version_string () const = 0;
/* Create a string suitable for use as the value of the "informationUri"
property (SARIF v2.1.0 section 3.19.17). */
virtual char *maybe_make_version_url () const = 0;
virtual void for_each_plugin (plugin_visitor &v) const = 0;
};
/* Abstract base class for a diagnostic_context to get at
information about a specific plugin within a client. */
class diagnostic_client_plugin_info
{
public:
/* For use e.g. by SARIF "name" property (SARIF v2.1.0 section 3.19.8). */
virtual const char *get_short_name () const = 0;
/* For use e.g. by SARIF "fullName" property
(SARIF v2.1.0 section 3.19.9). */
virtual const char *get_full_name () const = 0;
/* For use e.g. by SARIF "version" property
(SARIF v2.1.0 section 3.19.13). */
virtual const char *get_version () const = 0;
};
#endif /* ! GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H */

File diff suppressed because it is too large Load diff

View file

@ -69,6 +69,75 @@ along with GCC; see the file COPYING3. If not see
class diagnostic_event
{
public:
/* Enums for giving a sense of what this event means.
Roughly corresponds to SARIF v2.1.0 section 3.38.8. */
enum verb
{
VERB_unknown,
VERB_acquire,
VERB_release,
VERB_enter,
VERB_exit,
VERB_call,
VERB_return,
VERB_branch,
VERB_danger
};
enum noun
{
NOUN_unknown,
NOUN_taint,
NOUN_sensitive, // this one isn't in SARIF v2.1.0; filed as https://github.com/oasis-tcs/sarif-spec/issues/530
NOUN_function,
NOUN_lock,
NOUN_memory,
NOUN_resource
};
enum property
{
PROPERTY_unknown,
PROPERTY_true,
PROPERTY_false
};
/* A bundle of such enums, allowing for descriptions of the meaning of
an event, such as
- "acquire memory": meaning (VERB_acquire, NOUN_memory)
- "take true branch"": meaning (VERB_branch, PROPERTY_true)
- "return from function": meaning (VERB_return, NOUN_function)
etc, as per SARIF's threadFlowLocation "kinds" property
(SARIF v2.1.0 section 3.38.8). */
struct meaning
{
meaning ()
: m_verb (VERB_unknown),
m_noun (NOUN_unknown),
m_property (PROPERTY_unknown)
{
}
meaning (enum verb verb, enum noun noun)
: m_verb (verb), m_noun (noun), m_property (PROPERTY_unknown)
{
}
meaning (enum verb verb, enum property property)
: m_verb (verb), m_noun (NOUN_unknown), m_property (property)
{
}
void dump_to_pp (pretty_printer *pp) const;
static const char *maybe_get_verb_str (enum verb);
static const char *maybe_get_noun_str (enum noun);
static const char *maybe_get_property_str (enum property);
enum verb m_verb;
enum noun m_noun;
enum property m_property;
};
virtual ~diagnostic_event () {}
virtual location_t get_location () const = 0;
@ -81,6 +150,11 @@ class diagnostic_event
/* Get a localized (and possibly colorized) description of this event. */
virtual label_text get_desc (bool can_colorize) const = 0;
/* Get a logical_location for this event, or NULL. */
virtual const logical_location *get_logical_location () const = 0;
virtual meaning get_meaning () const = 0;
};
/* Abstract base class for getting at a sequence of events. */
@ -113,6 +187,14 @@ class simple_diagnostic_event : public diagnostic_event
{
return label_text::borrow (m_desc);
}
const logical_location *get_logical_location () const final override
{
return NULL;
}
meaning get_meaning () const final override
{
return meaning ();
}
private:
location_t m_loc;

View file

@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-url.h"
#include "diagnostic-metadata.h"
#include "diagnostic-path.h"
#include "diagnostic-client-data-hooks.h"
#include "edit-context.h"
#include "selftest.h"
#include "selftest-diagnostic.h"
@ -240,6 +241,7 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
context->end_group_cb = NULL;
context->final_cb = default_diagnostic_final_cb;
context->includes_seen = NULL;
context->m_client_data_hooks = NULL;
}
/* Maybe initialize the color support. We require clients to do this
@ -338,6 +340,12 @@ diagnostic_finish (diagnostic_context *context)
delete context->includes_seen;
context->includes_seen = nullptr;
}
if (context->m_client_data_hooks)
{
delete context->m_client_data_hooks;
context->m_client_data_hooks = NULL;
}
}
/* Initialize DIAGNOSTIC, where the message MSG has already been
@ -820,6 +828,116 @@ diagnostic_show_any_path (diagnostic_context *context,
context->print_path (context, path);
}
/* class diagnostic_event. */
/* struct diagnostic_event::meaning. */
void
diagnostic_event::meaning::dump_to_pp (pretty_printer *pp) const
{
bool need_comma = false;
pp_character (pp, '{');
if (const char *verb_str = maybe_get_verb_str (m_verb))
{
pp_printf (pp, "verb: %qs", verb_str);
need_comma = true;
}
if (const char *noun_str = maybe_get_noun_str (m_noun))
{
if (need_comma)
pp_string (pp, ", ");
pp_printf (pp, "noun: %qs", noun_str);
need_comma = true;
}
if (const char *property_str = maybe_get_property_str (m_property))
{
if (need_comma)
pp_string (pp, ", ");
pp_printf (pp, "property: %qs", property_str);
need_comma = true;
}
pp_character (pp, '}');
}
/* Get a string (or NULL) for V suitable for use within a SARIF
threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
const char *
diagnostic_event::meaning::maybe_get_verb_str (enum verb v)
{
switch (v)
{
default:
gcc_unreachable ();
case VERB_unknown:
return NULL;
case VERB_acquire:
return "acquire";
case VERB_release:
return "release";
case VERB_enter:
return "enter";
case VERB_exit:
return "exit";
case VERB_call:
return "call";
case VERB_return:
return "return";
case VERB_branch:
return "branch";
case VERB_danger:
return "danger";
}
}
/* Get a string (or NULL) for N suitable for use within a SARIF
threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
const char *
diagnostic_event::meaning::maybe_get_noun_str (enum noun n)
{
switch (n)
{
default:
gcc_unreachable ();
case NOUN_unknown:
return NULL;
case NOUN_taint:
return "taint";
case NOUN_sensitive:
return "sensitive";
case NOUN_function:
return "function";
case NOUN_lock:
return "lock";
case NOUN_memory:
return "memory";
case NOUN_resource:
return "resource";
}
}
/* Get a string (or NULL) for P suitable for use within a SARIF
threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
const char *
diagnostic_event::meaning::maybe_get_property_str (enum property p)
{
switch (p)
{
default:
gcc_unreachable ();
case PROPERTY_unknown:
return NULL;
case PROPERTY_true:
return "true";
case PROPERTY_false:
return "false";
}
}
/* class diagnostic_path. */
/* Return true if the events in this path involve more than one
function, or false if it is purely intraprocedural. */
@ -1131,7 +1249,7 @@ update_effective_level_from_pragmas (diagnostic_context *context,
/* Generate a URL string describing CWE. The caller is responsible for
freeing the string. */
static char *
char *
get_cwe_url (int cwe)
{
return xasprintf ("https://cwe.mitre.org/data/definitions/%i.html", cwe);
@ -2095,6 +2213,14 @@ diagnostic_output_format_init (diagnostic_context *context,
case DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE:
diagnostic_output_format_init_json_file (context, base_file_name);
break;
case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR:
diagnostic_output_format_init_sarif_stderr (context);
break;
case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE:
diagnostic_output_format_init_sarif_file (context, base_file_name);
break;
}
}

View file

@ -63,7 +63,13 @@ enum diagnostics_output_format
DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR,
/* JSON-based output, to a file. */
DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE
DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE,
/* SARIF-based output, to stderr. */
DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR,
/* SARIF-based output, to a file. */
DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE
};
/* An enum for controlling how diagnostic_paths should be printed. */
@ -162,6 +168,8 @@ typedef void (*diagnostic_finalizer_fn) (diagnostic_context *,
class edit_context;
namespace json { class value; }
class diagnostic_client_data_hooks;
class logical_location;
/* This data structure bundles altogether any information relevant to
the context of a diagnostic message. */
@ -397,6 +405,12 @@ struct diagnostic_context
/* Include files that diagnostic_report_current_module has already listed the
include path for. */
hash_set<location_t, false, location_hash> *includes_seen;
/* A bundle of hooks for providing data to the context about its client
e.g. version information, plugins, etc.
Used by SARIF output to give metadata about the client that's
producing diagnostics. */
diagnostic_client_data_hooks *m_client_data_hooks;
};
static inline void
@ -585,6 +599,9 @@ extern void diagnostic_output_format_init (diagnostic_context *,
extern void diagnostic_output_format_init_json_stderr (diagnostic_context *context);
extern void diagnostic_output_format_init_json_file (diagnostic_context *context,
const char *base_file_name);
extern void diagnostic_output_format_init_sarif_stderr (diagnostic_context *context);
extern void diagnostic_output_format_init_sarif_file (diagnostic_context *context,
const char *base_file_name);
/* Compute the number of digits in the decimal representation of an integer. */
extern int num_digits (int);
@ -594,4 +611,6 @@ extern json::value *json_from_expanded_location (diagnostic_context *context,
extern bool warning_enabled_at (location_t, int);
extern char *get_cwe_url (int cwe);
#endif /* ! GCC_DIAGNOSTIC_H */

View file

@ -301,7 +301,7 @@ Objective-C and Objective-C++ Dialects}.
-fdiagnostics-show-location=@r{[}once@r{|}every-line@r{]} @gol
-fdiagnostics-color=@r{[}auto@r{|}never@r{|}always@r{]} @gol
-fdiagnostics-urls=@r{[}auto@r{|}never@r{|}always@r{]} @gol
-fdiagnostics-format=@r{[}text@r{|}json@r{|}json-stderr@r{|}json-file@r{]} @gol
-fdiagnostics-format=@r{[}text@r{|}sarif-stderr@r{|}sarif-file@r{|}json@r{|}json-stderr@r{|}json-file@r{]} @gol
-fno-diagnostics-show-option -fno-diagnostics-show-caret @gol
-fno-diagnostics-show-labels -fno-diagnostics-show-line-numbers @gol
-fno-diagnostics-show-cwe @gol
@ -5305,11 +5305,15 @@ Unicode characters. For the example above, the following will be printed:
@item -fdiagnostics-format=@var{FORMAT}
@opindex fdiagnostics-format
Select a different format for printing diagnostics.
@var{FORMAT} is @samp{text}, @samp{json}, @samp{json-stderr},
or @samp{json-file}.
@var{FORMAT} is @samp{text}, @samp{sarif-stderr}, @samp{sarif-file},
@samp{json}, @samp{json-stderr}, or @samp{json-file}.
The default is @samp{text}.
The @samp{sarif-stderr} and @samp{sarif-file} formats both emit
diagnostics in SARIF Version 2.1.0 format, either to stderr, or to a file
named @file{@var{source}.sarif}, respectively.
The @samp{json} format is a synonym for @samp{json-stderr}.
The @samp{json-stderr} and @samp{json-file} formats are identical, apart from
where the JSON is emitted to - with the former, the JSON is emitted to stderr,

View file

@ -3152,6 +3152,12 @@ Passes if @var{regexp} matches in Fortran module @var{module}.
@item dg-check-dot @var{filename}
Passes if @var{filename} is a valid @file{.dot} file (by running
@code{dot -Tpng} on it, and verifying the exit code is 0).
@item scan-sarif-file @var{regexp} [@{ target/xfail @var{selector} @}]
Passes if @var{regexp} matches text in the file generated by
@option{-fdiagnostics-format=sarif-file}.
@item scan-sarif-file-not @var{regexp} [@{ target/xfail @var{selector} @}]
Passes if @var{regexp} does not match text in the file generated by
@option{-fdiagnostics-format=sarif-file}.
@end table
@subsubsection Scan the assembly output

View file

@ -100,6 +100,15 @@ static const struct attribute_spec gfc_attribute_table[] =
{ NULL, 0, 0, false, false, false, false, NULL, NULL }
};
/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property,
based on the list in SARIF v2.1.0 Appendix J. */
static const char *
gfc_get_sarif_source_language (const char *)
{
return "fortran";
}
#undef LANG_HOOKS_NAME
#undef LANG_HOOKS_INIT
#undef LANG_HOOKS_FINISH
@ -138,6 +147,7 @@ static const struct attribute_spec gfc_attribute_table[] =
#undef LANG_HOOKS_BUILTIN_FUNCTION
#undef LANG_HOOKS_GET_ARRAY_DESCR_INFO
#undef LANG_HOOKS_ATTRIBUTE_TABLE
#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE
/* Define lang hooks. */
#define LANG_HOOKS_NAME "GNU Fortran"
@ -177,6 +187,7 @@ static const struct attribute_spec gfc_attribute_table[] =
#define LANG_HOOKS_BUILTIN_FUNCTION gfc_builtin_function
#define LANG_HOOKS_GET_ARRAY_DESCR_INFO gfc_get_array_descr_info
#define LANG_HOOKS_ATTRIBUTE_TABLE gfc_attribute_table
#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE gfc_get_sarif_source_language
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;

View file

@ -545,6 +545,15 @@ go_langhook_eh_personality (void)
return personality_decl;
}
/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property,
based on the list in SARIF v2.1.0 Appendix J. */
static const char *
go_get_sarif_source_language (const char *)
{
return "go";
}
/* Functions called directly by the generic backend. */
tree
@ -615,6 +624,7 @@ go_localize_identifier (const char *ident)
#undef LANG_HOOKS_GETDECLS
#undef LANG_HOOKS_GIMPLIFY_EXPR
#undef LANG_HOOKS_EH_PERSONALITY
#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE
#define LANG_HOOKS_NAME "GNU Go"
#define LANG_HOOKS_INIT go_langhook_init
@ -631,6 +641,7 @@ go_localize_identifier (const char *ident)
#define LANG_HOOKS_GETDECLS go_langhook_getdecls
#define LANG_HOOKS_GIMPLIFY_EXPR go_langhook_gimplify_expr
#define LANG_HOOKS_EH_PERSONALITY go_langhook_eh_personality
#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE go_get_sarif_source_language
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;

View file

@ -98,6 +98,7 @@ extern const char *lhd_get_substring_location (const substring_loc &,
extern int lhd_decl_dwarf_attribute (const_tree, int);
extern int lhd_type_dwarf_attribute (const_tree, int);
extern void lhd_finalize_early_debug (void);
extern const char *lhd_get_sarif_source_language (const char *);
#define LANG_HOOKS_NAME "GNU unknown"
#define LANG_HOOKS_IDENTIFIER_SIZE sizeof (struct lang_identifier)
@ -150,6 +151,7 @@ extern void lhd_finalize_early_debug (void);
#define LANG_HOOKS_RUN_LANG_SELFTESTS lhd_do_nothing
#define LANG_HOOKS_GET_SUBSTRING_LOCATION lhd_get_substring_location
#define LANG_HOOKS_FINALIZE_EARLY_DEBUG lhd_finalize_early_debug
#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE lhd_get_sarif_source_language
/* Attribute hooks. */
#define LANG_HOOKS_ATTRIBUTE_TABLE NULL
@ -394,7 +396,8 @@ extern void lhd_end_section (void);
LANG_HOOKS_EMITS_BEGIN_STMT, \
LANG_HOOKS_RUN_LANG_SELFTESTS, \
LANG_HOOKS_GET_SUBSTRING_LOCATION, \
LANG_HOOKS_FINALIZE_EARLY_DEBUG \
LANG_HOOKS_FINALIZE_EARLY_DEBUG, \
LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE \
}
#endif /* GCC_LANG_HOOKS_DEF_H */

View file

@ -925,6 +925,14 @@ lhd_finalize_early_debug (void)
(*debug_hooks->early_global_decl) (cnode->decl);
}
/* Default implementation of LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE. */
const char *
lhd_get_sarif_source_language (const char *)
{
return NULL;
}
/* Returns true if the current lang_hooks represents the GNU C frontend. */
bool

View file

@ -640,6 +640,12 @@ struct lang_hooks
/* Invoked before the early_finish debug hook is invoked. */
void (*finalize_early_debug) (void);
/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property
for FILENAME, or return NULL.
See SARIF v2.1.0 Appendix J for suggested values for common programming
languages. */
const char *(*get_sarif_source_language) (const char *filename);
/* Whenever you add entries here, make sure you adjust langhooks-def.h
and langhooks.cc accordingly. */
};

72
gcc/logical-location.h Normal file
View file

@ -0,0 +1,72 @@
/* Logical location support, without knowledge of "tree".
Copyright (C) 2022 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_LOGICAL_LOCATION_H
#define GCC_LOGICAL_LOCATION_H
/* An enum for discriminating between different kinds of logical location
for a diagnostic.
Roughly corresponds to logicalLocation's "kind" property in SARIF v2.1.0
(section 3.33.7). */
enum logical_location_kind
{
LOGICAL_LOCATION_KIND_UNKNOWN,
LOGICAL_LOCATION_KIND_FUNCTION,
LOGICAL_LOCATION_KIND_MEMBER,
LOGICAL_LOCATION_KIND_MODULE,
LOGICAL_LOCATION_KIND_NAMESPACE,
LOGICAL_LOCATION_KIND_TYPE,
LOGICAL_LOCATION_KIND_RETURN_TYPE,
LOGICAL_LOCATION_KIND_PARAMETER,
LOGICAL_LOCATION_KIND_VARIABLE
};
/* Abstract base class for passing around logical locations in the
diagnostics subsystem, such as:
- "within function 'foo'", or
- "within method 'bar'",
but *without* requiring knowledge of trees
(see tree-logical-location.h for subclasses relating to trees). */
class logical_location
{
public:
virtual ~logical_location () {}
/* Get a string (or NULL) suitable for use by the SARIF logicalLocation
"name" property (SARIF v2.1.0 section 3.33.4). */
virtual const char *get_short_name () const = 0;
/* Get a string (or NULL) suitable for use by the SARIF logicalLocation
"fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
virtual const char *get_name_with_scope () const = 0;
/* Get a string (or NULL) suitable for use by the SARIF logicalLocation
"decoratedName" property (SARIF v2.1.0 section 3.33.6). */
virtual const char *get_internal_name () const = 0;
/* Get what kind of SARIF logicalLocation this is (if any). */
virtual enum logical_location_kind get_kind () const = 0;
};
#endif /* GCC_LOGICAL_LOCATION_H. */

View file

@ -27,6 +27,7 @@ bool objc_init (void);
const char *objc_printable_name (tree, int);
int objc_gimplify_expr (tree *, gimple_seq *, gimple_seq *);
void objc_common_init_ts (void);
const char *objc_get_sarif_source_language (const char *);
/* NB: The remaining public functions are prototyped in c-common.h, for the
benefit of stub-objc.cc and objc-act.cc. */

View file

@ -46,10 +46,18 @@ enum c_language_kind c_language = clk_objc;
#define LANG_HOOKS_INIT_TS objc_common_init_ts
#undef LANG_HOOKS_TREE_SIZE
#define LANG_HOOKS_TREE_SIZE objc_common_tree_size
#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE
#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE objc_get_sarif_source_language
/* Each front end provides its own lang hook initializer. */
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
const char *
objc_get_sarif_source_language (const char *)
{
return "objectivec";
}
/* Lang hook routines common to C and ObjC appear in c-objc-common.cc;
there should be very few (if any) routines below. */

View file

@ -815,6 +815,44 @@ finalize_plugins (void)
plugin_name_args_tab = NULL;
}
/* Implementation detail of for_each_plugin. */
struct for_each_plugin_closure
{
void (*cb) (const plugin_name_args *,
void *user_data);
void *user_data;
};
/* Implementation detail of for_each_plugin: callback for htab_traverse_noresize
that calls the user-provided callback. */
static int
for_each_plugin_cb (void **slot, void *info)
{
struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
for_each_plugin_closure *c = (for_each_plugin_closure *)info;
c->cb (plugin, c->user_data);
return 1;
}
/* Call CB with USER_DATA on each plugin. */
void
for_each_plugin (void (*cb) (const plugin_name_args *,
void *user_data),
void *user_data)
{
if (!plugin_name_args_tab)
return;
for_each_plugin_closure c;
c.cb = cb;
c.user_data = user_data;
htab_traverse_noresize (plugin_name_args_tab, for_each_plugin_cb, &c);
}
/* Used to pass options to htab_traverse callbacks. */
struct print_options

View file

@ -170,6 +170,9 @@ extern void warn_if_plugins (void);
extern void print_plugins_versions (FILE *file, const char *indent);
extern void print_plugins_help (FILE *file, const char *indent);
extern void finalize_plugins (void);
extern void for_each_plugin (void (*cb) (const plugin_name_args *,
void *user_data),
void *user_data);
extern bool flag_plugin_added;

View file

@ -0,0 +1,43 @@
/* { dg-do compile } */
/* { dg-options "-fdiagnostics-format=sarif-file" } */
#warning message
/* Verify that some JSON was written to a file with the expected name. */
/* We expect various properties.
The indentation here reflects the expected hierarchy, though these tests
don't check for that, merely the string fragments we expect.
{ dg-final { scan-sarif-file "\"version\": \"2.1.0\"" } }
{ dg-final { scan-sarif-file "\"runs\": \\\[" } }
{ dg-final { scan-sarif-file "\"artifacts\": \\\[" } }
{ dg-final { scan-sarif-file "\"location\": " } }
{ dg-final { scan-sarif-file "\"uri\": " } }
{ dg-final { scan-sarif-file "\"sourceLanguage\": \"c\"" { target c } } }
{ dg-final { scan-sarif-file "\"sourceLanguage\": \"cplusplus\"" { target c++ } } }
{ dg-final { scan-sarif-file "\"contents\": " } }
{ dg-final { scan-sarif-file "\"text\": " } }
{ dg-final { scan-sarif-file "\"tool\": " } }
{ dg-final { scan-sarif-file "\"driver\": " } }
{ dg-final { scan-sarif-file "\"name\": \"GNU C" } }
{ dg-final { scan-sarif-file "\"fullName\": \"GNU C" } }
{ dg-final { scan-sarif-file "\"informationUri\": \"" } }
{ dg-final { scan-sarif-file "\"results\": \\\[" } }
{ dg-final { scan-sarif-file "\"level\": \"warning\"" } }
{ dg-final { scan-sarif-file "\"ruleId\": \"-Wcpp\"" } }
{ dg-final { scan-sarif-file "\"locations\": \\\[" } }
{ dg-final { scan-sarif-file "\"physicalLocation\": " } }
{ dg-final { scan-sarif-file "\"contextRegion\": " } }
{ dg-final { scan-sarif-file "\"artifactLocation\": " } }
{ dg-final { scan-sarif-file "\"region\": " } }
{ dg-final { scan-sarif-file "\"startLine\": 4" } }
{ dg-final { scan-sarif-file "\"startColumn\": 2" } }
{ dg-final { scan-sarif-file "\"endColumn\": 9" } }
We don't expect logical locations for a top-level warning:
{ dg-final { scan-sarif-file-not "\"logicalLocations\": " } }
{ dg-final { scan-sarif-file "\"message\": " } }
{ dg-final { scan-sarif-file "\"text\": \"#warning message" } } */

View file

@ -0,0 +1,29 @@
/* { dg-do compile } */
/* { dg-options "-fdiagnostics-format=sarif-file -Wmisleading-indentation" } */
int test (void)
{
if (1)
return 3;
return 4;
return 5;
}
/*
{ dg-final { scan-sarif-file "\"level\": \"warning\"" } }
{ dg-final { scan-sarif-file "\"ruleId\": \"-Wmisleading-indentation\"" } }
{ dg-final { scan-sarif-file "\"text\": \" if " } }
{ dg-final { scan-sarif-file "\"locations\": \\\[" } }
We expect a logical location for the error (within fn "test"):
{ dg-final { scan-sarif-file "\"logicalLocations\": \\\[" } }
{ dg-final { scan-sarif-file "\"kind\": \"function\"" } }
{ dg-final { scan-sarif-file "\"name\": \"test\"" } }
{ dg-final { scan-sarif-file "\"fullyQualifiedName\": \"test\"" } }
{ dg-final { scan-sarif-file "\"decoratedName\": \"" } }
We expect the "note" to become a "relatedLocations" entry:
{ dg-final { scan-sarif-file "\"relatedLocations\": \\\[" } }
{ dg-final { scan-sarif-file "\"text\": \" return 4;" } }
*/

View file

@ -0,0 +1,30 @@
/* { dg-do compile } */
/* { dg-options "-fdiagnostics-format=sarif-file" } */
/* { dg-excess-errors "The error is sent to the SARIF file, rather than stderr" } */
struct s { int color; };
int test (struct s *ptr)
{
return ptr->colour;
}
/*
{ dg-final { scan-sarif-file "\"level\": \"error\"" } }
We expect a logical location for the error (within fn "test"):
{ dg-final { scan-sarif-file "\"locations\": \\\[" } }
{ dg-final { scan-sarif-file "\"logicalLocations\": \\\[" } }
{ dg-final { scan-sarif-file "\"kind\": \"function\"" } }
{ dg-final { scan-sarif-file "\"name\": \"test\"" } }
{ dg-final { scan-sarif-file "\"fullyQualifiedName\": \"test\"" } }
{ dg-final { scan-sarif-file "\"decoratedName\": \"" } }
We expect a "fixes" array for the fix-it hint (SARIF v2.1.0 section 3.27.30):
{ dg-final { scan-sarif-file "\"fixes\": \\\[" } }
{ dg-final { scan-sarif-file "\"artifactChanges\": \\\[" } }
{ dg-final { scan-sarif-file "\"replacements\": \\\[" } }
{ dg-final { scan-sarif-file "\"insertedContent\": " } }
{ dg-final { scan-sarif-file "\"text\": \"color\"" } }
{ dg-final { scan-sarif-file "\"deletedRegion\": " } }
*/

View file

@ -0,0 +1,19 @@
/* { dg-do compile } */
/* { dg-options "-fdiagnostics-format=sarif-file" } */
/* { dg-excess-errors "The error is sent to the SARIF file, rather than stderr" } */
int test (void)
{
int = *42;
}
/*
{ dg-final { scan-sarif-file "\"level\": \"error\"" } }
We expect the region expressed in display columns:
{ dg-final { scan-sarif-file "\"startLine\": 7" } }
{ dg-final { scan-sarif-file "\"startColumn\": 18" } }
{ dg-final { scan-sarif-file "\"endColumn\": 21" } }
{ dg-final { scan-sarif-file "\"text\": \" int \\u6587\\u5b57\\u5316\\u3051 = " } }
*/

View file

@ -0,0 +1,15 @@
/* { dg-additional-options "-fanalyzer-verbose-state-changes" } */
typedef struct FILE FILE;
FILE* fopen (const char*, const char*);
int fclose (FILE*);
void test_1 (const char *path)
{
FILE *f = fopen (path, "r"); /* { dg-message "meaning: \\{verb: 'acquire', noun: 'resource'\\}" } */
if (!f)
return;
fclose (f); /* { dg-message "meaning: \\{verb: 'release', noun: 'resource'\\}" } */
fclose (f); /* { dg-warning "double 'fclose' of FILE 'f'" "warning" } */
}

View file

@ -0,0 +1,10 @@
/* { dg-additional-options "-fanalyzer-verbose-state-changes" } */
#include <stdlib.h>
void test_1 (void)
{
void *ptr = malloc (1024); /* { dg-message "meaning: \\{verb: 'acquire', noun: 'memory'\\}" } */
free (ptr); /* { dg-message "meaning: \\{verb: 'release', noun: 'memory'\\}" } */
free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
}

View file

@ -0,0 +1,20 @@
/* { dg-do compile } */
/* { dg-additional-options "-fdiagnostics-format=sarif-file" } */
#include <stdlib.h>
void test_1 (void)
{
void *ptr = malloc (1024);
free (ptr);
free (ptr);
}
/* Verify SARIF output.
The threadFlowLocation objects should have "kinds" properties
reflecting the meanings of the events:
{ dg-final { scan-sarif-file "\"kinds\": \\\[\"acquire\", \"memory\"\\\]" } }
{ dg-final { scan-sarif-file "\"kinds\": \\\[\"release\", \"memory\"\\\]" } }
{ dg-final { scan-sarif-file "\"kinds\": \\\[\"danger\"\\\]" } }
*/

View file

@ -109,6 +109,21 @@ public:
return label_text ();
}
diagnostic_event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
if (change.is_global_p ())
{
if (change.m_new_state == m_sm.m_released_gil)
return diagnostic_event::meaning (diagnostic_event::VERB_release,
diagnostic_event::NOUN_lock);
else if (change.m_new_state == m_sm.get_start_state ())
return diagnostic_event::meaning (diagnostic_event::VERB_acquire,
diagnostic_event::NOUN_lock);
}
return diagnostic_event::meaning ();
}
protected:
gil_diagnostic (const gil_state_machine &sm) : m_sm (sm)
{

View file

@ -0,0 +1,56 @@
/* { dg-do compile } */
/* { dg-options "-fdiagnostics-format=sarif-file" } */
/* { dg-excess-errors "The error is sent to the SARIF file, rather than stderr" } */
#include <stddef.h>
#include <stdlib.h>
/* Minimal reimplementation of cpython API. */
typedef struct PyObject {} PyObject;
extern int PyArg_ParseTuple (PyObject *args, const char *fmt, ...);
extern PyObject *PyList_New (int);
extern PyObject *PyLong_FromLong(long);
extern void PyList_Append(PyObject *list, PyObject *item);
PyObject *
make_a_list_of_random_ints_badly(PyObject *self,
PyObject *args)
{
PyObject *list, *item;
long count, i;
if (!PyArg_ParseTuple(args, "i", &count)) {
return NULL;
}
list = PyList_New(0);
for (i = 0; i < count; i++) {
item = PyLong_FromLong(random());
PyList_Append(list, item);
}
return list;
}
/*
{ dg-final { scan-sarif-file "\"tool\": " } }
We expect info about the plugin:
{ dg-final { scan-sarif-file "\"extensions\": \\\[" } }
{ dg-final { scan-sarif-file "\"name\": \"diagnostic_plugin_test_paths\"" } }
{ dg-final { scan-sarif-file "\"fullName\": \"" } }
{ dg-final { scan-sarif-file "\"results\": \\\[" } }
{ dg-final { scan-sarif-file "\"level\": \"error\"" } }
{ dg-final { scan-sarif-file "\"text\": \"passing NULL as argument 1 to 'PyList_Append' which requires a non-NULL parameter\"" } }
We expect a path for the diagnostic:
{ dg-final { scan-sarif-file "\"codeFlows\": \\\[" } }
{ dg-final { scan-sarif-file "\"threadFlows\": \\\[" } }
{ dg-final { scan-sarif-file "\"locations\": \\\[" } }
{ dg-final { scan-sarif-file "\"text\": \"when 'PyList_New' fails, returning NULL\"" } }
{ dg-final { scan-sarif-file "\"text\": \"when 'i < count'\"" } }
{ dg-final { scan-sarif-file "\"text\": \"when calling 'PyList_Append', passing NULL from \\(1\\) as argument 1\"" } }
*/

View file

@ -102,6 +102,7 @@ set plugin_test_list [list \
diagnostic-test-paths-2.c \
diagnostic-test-paths-3.c \
diagnostic-test-paths-4.c \
diagnostic-test-paths-5.c \
diagnostic-path-format-plain.c \
diagnostic-path-format-none.c \
diagnostic-path-format-separate-events.c \

View file

@ -25,6 +25,7 @@ load_lib scanltranstree.exp
load_lib scanipa.exp
load_lib scanwpaipa.exp
load_lib scanlang.exp
load_lib scansarif.exp
load_lib timeout.exp
load_lib timeout-dg.exp
load_lib prune.exp

View file

@ -0,0 +1,42 @@
# Copyright (C) 2000-2022 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
# Various utilities for scanning SARIF output, used by gcc-dg.exp and
# g++-dg.exp.
#
# This is largely borrowed from scanasm.exp.
# Look for a pattern in the .sarif file produced by the compiler. See
# dg-scan for details.
proc scan-sarif-file { args } {
set testcase [testname-for-summary]
# The name might include a list of options; extract the file name.
set filename [lindex $testcase 0]
set output_file "[file tail $filename].sarif"
dg-scan "scan-sarif-file" 1 $testcase $output_file $args
}
# Check that a pattern is not present in the .sarif file. See dg-scan
# for details.
proc scan-sarif-file-not { args } {
set testcase [testname-for-summary]
# The name might include a list of options; extract the file name.
set filename [lindex $testcase 0]
set output_file "[file tail $filename].sarif"
dg-scan "scan-sarif-file-not" 0 $testcase $output_file $args
}

View file

@ -0,0 +1,150 @@
/* Implementation of diagnostic_client_data_hooks for the compilers
(e.g. with knowledge of "tree" and lang_hooks).
Copyright (C) 2022 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "version.h"
#include "tree.h"
#include "diagnostic.h"
#include "tree-logical-location.h"
#include "diagnostic-client-data-hooks.h"
#include "langhooks.h"
#include "plugin.h"
/* Concrete class for supplying a diagnostic_context with information
about a specific plugin within the client, when the client is the
compiler (i.e. a GCC plugin). */
class compiler_diagnostic_client_plugin_info
: public diagnostic_client_plugin_info
{
public:
compiler_diagnostic_client_plugin_info (const plugin_name_args *args)
: m_args (args)
{
}
const char *get_short_name () const final override
{
return m_args->base_name;
}
const char *get_full_name () const final override
{
return m_args->full_name;
}
const char *get_version () const final override
{
return m_args->version;
}
private:
const plugin_name_args *m_args;
};
/* Concrete subclass of client_version_info for use by compilers proper,
(i.e. using lang_hooks, and with knowledge of GCC plugins). */
class compiler_version_info : public client_version_info
{
public:
const char *get_tool_name () const final override
{
return lang_hooks.name;
}
/* Compare with toplev.cc: print_version.
TARGET_NAME is passed in by the Makefile. */
char *
maybe_make_full_name () const final override
{
return xasprintf ("%s %sversion %s (%s)",
get_tool_name (), pkgversion_string, version_string,
TARGET_NAME);
}
const char *get_version_string () const final override
{
return version_string;
}
char *maybe_make_version_url () const final override
{
return xasprintf ("https://gcc.gnu.org/gcc-%i/", GCC_major_version);
}
void for_each_plugin (plugin_visitor &visitor) const final override
{
::for_each_plugin (on_plugin_cb, &visitor);
}
private:
static void
on_plugin_cb (const plugin_name_args *args,
void *user_data)
{
compiler_diagnostic_client_plugin_info cpi (args);
client_version_info::plugin_visitor *visitor
= (client_version_info::plugin_visitor *)user_data;
visitor->on_plugin (cpi);
}
};
/* Subclass of diagnostic_client_data_hooks for use by compilers proper
i.e. with knowledge of "tree", access to langhooks, etc. */
class compiler_data_hooks : public diagnostic_client_data_hooks
{
public:
const client_version_info *get_any_version_info () const final override
{
return &m_version_info;
}
const logical_location *get_current_logical_location () const final override
{
if (current_function_decl)
return &m_current_fndecl_logical_loc;
else
return NULL;
}
const char *
maybe_get_sarif_source_language (const char *filename) const final override
{
return lang_hooks.get_sarif_source_language (filename);
}
private:
compiler_version_info m_version_info;
current_fndecl_logical_location m_current_fndecl_logical_loc;
};
/* Create a compiler_data_hooks (so that the class can be local
to this file). */
diagnostic_client_data_hooks *
make_compiler_data_hooks ()
{
return new compiler_data_hooks ();
}

View file

@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print.h"
#include "gimple-pretty-print.h"
#include "tree-diagnostic.h"
#include "diagnostic-client-data-hooks.h"
#include "langhooks.h"
#include "intl.h"
@ -373,4 +374,5 @@ tree_diagnostics_defaults (diagnostic_context *context)
context->print_path = default_tree_diagnostic_path_printer;
context->make_json_for_path = default_tree_make_json_for_path;
context->set_locations_cb = set_inlining_locations;
context->m_client_data_hooks = make_compiler_data_hooks ();
}

View file

@ -0,0 +1,148 @@
/* Subclasses of logical_location with knowledge of "tree".
Copyright (C) 2022 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "pretty-print.h"
#include "tree-logical-location.h"
#include "langhooks.h"
/* class compiler_logical_location : public logical_location. */
/* Get a string for DECL suitable for use by the SARIF logicalLocation
"name" property (SARIF v2.1.0 section 3.33.4). */
const char *
compiler_logical_location::get_short_name_for_tree (tree decl)
{
gcc_assert (decl);
return identifier_to_locale (lang_hooks.decl_printable_name (decl, 0));
}
/* Get a string for DECL suitable for use by the SARIF logicalLocation
"fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */
const char *
compiler_logical_location::get_name_with_scope_for_tree (tree decl)
{
gcc_assert (decl);
return identifier_to_locale (lang_hooks.decl_printable_name (decl, 1));
}
/* Get a string for DECL suitable for use by the SARIF logicalLocation
"decoratedName" property (SARIF v2.1.0 section 3.33.6). */
const char *
compiler_logical_location::get_internal_name_for_tree (tree decl)
{
gcc_assert (decl);
if (HAS_DECL_ASSEMBLER_NAME_P (decl))
if (tree id = DECL_ASSEMBLER_NAME (decl))
return IDENTIFIER_POINTER (id);
return NULL;
}
/* Get what kind of SARIF logicalLocation DECL is (if any). */
enum logical_location_kind
compiler_logical_location::get_kind_for_tree (tree decl)
{
if (!decl)
return LOGICAL_LOCATION_KIND_UNKNOWN;
switch (TREE_CODE (decl))
{
default:
return LOGICAL_LOCATION_KIND_UNKNOWN;
case FUNCTION_DECL:
return LOGICAL_LOCATION_KIND_FUNCTION;
case PARM_DECL:
return LOGICAL_LOCATION_KIND_PARAMETER;
case VAR_DECL:
return LOGICAL_LOCATION_KIND_VARIABLE;
}
}
/* class tree_logical_location : public compiler_logical_location. */
/* Implementation of the logical_location vfuncs, using m_decl. */
const char *
tree_logical_location::get_short_name () const
{
gcc_assert (m_decl);
return get_short_name_for_tree (m_decl);
}
const char *
tree_logical_location::get_name_with_scope () const
{
gcc_assert (m_decl);
return get_name_with_scope_for_tree (m_decl);
}
const char *
tree_logical_location::get_internal_name () const
{
gcc_assert (m_decl);
return get_internal_name_for_tree (m_decl);
}
enum logical_location_kind
tree_logical_location::get_kind () const
{
gcc_assert (m_decl);
return get_kind_for_tree (m_decl);
}
/* class current_fndecl_logical_location : public compiler_logical_location. */
/* Implementation of the logical_location vfuncs, using
current_function_decl. */
const char *
current_fndecl_logical_location::get_short_name () const
{
gcc_assert (current_function_decl);
return get_short_name_for_tree (current_function_decl);
}
const char *
current_fndecl_logical_location::get_name_with_scope () const
{
gcc_assert (current_function_decl);
return get_name_with_scope_for_tree (current_function_decl);
}
const char *
current_fndecl_logical_location::get_internal_name () const
{
gcc_assert (current_function_decl);
return get_internal_name_for_tree (current_function_decl);
}
enum logical_location_kind
current_fndecl_logical_location::get_kind () const
{
gcc_assert (current_function_decl);
return get_kind_for_tree (current_function_decl);
}

View file

@ -0,0 +1,67 @@
/* Subclasses of logical_location with knowledge of "tree".
Copyright (C) 2022 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_TREE_LOGICAL_LOCATION_H
#define GCC_TREE_LOGICAL_LOCATION_H
#include "logical-location.h"
/* Abstract subclass of logical_location, with knowledge of "tree", but
for no specific tree. */
class compiler_logical_location : public logical_location
{
protected:
static const char *get_short_name_for_tree (tree);
static const char *get_name_with_scope_for_tree (tree);
static const char *get_internal_name_for_tree (tree);
static enum logical_location_kind get_kind_for_tree (tree);
};
/* Concrete subclass of logical_location, with reference to a specific
tree. */
class tree_logical_location : public compiler_logical_location
{
public:
tree_logical_location (tree decl) : m_decl (decl) {}
const char *get_short_name () const final override;
const char *get_name_with_scope () const final override;
const char *get_internal_name () const final override;
enum logical_location_kind get_kind () const final override;
private:
tree m_decl;
};
/* Concrete subclass of logical_location, with reference to
current_function_decl. */
class current_fndecl_logical_location : public compiler_logical_location
{
public:
const char *get_short_name () const final override;
const char *get_name_with_scope () const final override;
const char *get_internal_name () const final override;
enum logical_location_kind get_kind () const final override;
};
#endif /* GCC_TREE_LOGICAL_LOCATION_H. */

View file

@ -36,6 +36,7 @@ load_gcc_lib scanasm.exp
load_gcc_lib scandump.exp
load_gcc_lib scanlang.exp
load_gcc_lib scanrtl.exp
load_gcc_lib scansarif.exp
load_gcc_lib scantree.exp
load_gcc_lib scanltranstree.exp
load_gcc_lib scanipa.exp

View file

@ -28,6 +28,7 @@ load_gcc_lib scanasm.exp
load_gcc_lib scandump.exp
load_gcc_lib scanlang.exp
load_gcc_lib scanrtl.exp
load_gcc_lib scansarif.exp
load_gcc_lib scantree.exp
load_gcc_lib scanltranstree.exp
load_gcc_lib scanoffload.exp

View file

@ -42,6 +42,7 @@ load_gcc_lib scanasm.exp
load_gcc_lib scandump.exp
load_gcc_lib scanlang.exp
load_gcc_lib scanrtl.exp
load_gcc_lib scansarif.exp
load_gcc_lib scantree.exp
load_gcc_lib scanltranstree.exp
load_gcc_lib scanipa.exp

View file

@ -23,6 +23,7 @@ load_gcc_lib file-format.exp
load_gcc_lib scanasm.exp
load_gcc_lib scanlang.exp
load_gcc_lib scanrtl.exp
load_gcc_lib scansarif.exp
load_gcc_lib scantree.exp
load_gcc_lib scanipa.exp
load_gcc_lib torture-options.exp