diff options
Diffstat (limited to 'gcc/testsuite/gcc.dg/plugin')
48 files changed, 1068 insertions, 1241 deletions
diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc index 467af16..01ab766 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc @@ -2,6 +2,7 @@ /* { dg-options "-g" } */ #define INCLUDE_MEMORY +#define INCLUDE_STRING #define INCLUDE_VECTOR #include "gcc-plugin.h" #include "config.h" @@ -22,14 +23,14 @@ #include "target.h" #include "fold-const.h" #include "tree-pretty-print.h" -#include "diagnostic-color.h" -#include "diagnostic-metadata.h" +#include "diagnostics/color.h" +#include "diagnostics/metadata.h" #include "tristate.h" #include "bitmap.h" #include "selftest.h" #include "function.h" #include "json.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" #include "analyzer/analyzer-language.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" @@ -46,7 +47,6 @@ #include "analyzer/call-details.h" #include "analyzer/call-info.h" #include "analyzer/exploded-graph.h" -#include "make-unique.h" int plugin_is_GPL_compatible; @@ -207,7 +207,7 @@ public: std::unique_ptr<stmt_finder> clone () const final override { - return make_unique<refcnt_stmt_finder> (m_eg, m_var); + return std::make_unique<refcnt_stmt_finder> (m_eg, m_var); } const gimple * @@ -451,8 +451,9 @@ check_refcnt (const region_model *model, const auto &eg = ctxt->get_eg (); refcnt_stmt_finder finder (*eg, reg_tree); - auto pd = make_unique<refcnt_mismatch> (curr_region, ob_refcnt_sval, - actual_refcnt_sval, reg_tree); + auto pd = std::make_unique<refcnt_mismatch> (curr_region, ob_refcnt_sval, + actual_refcnt_sval, + reg_tree); if (pd && eg) ctxt->warn (std::move (pd), &finder); } @@ -680,7 +681,7 @@ kf_PyList_Append::impl_call_post (const call_details &cd) const = old_ptr_sval->dyn_cast_region_svalue ()) { const region *freed_reg = old_reg->get_pointee (); - model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED); + model->unbind_region_and_descendents (freed_reg, poison_kind::freed); model->unset_dynamic_extents (freed_reg); } @@ -885,7 +886,7 @@ kf_PyList_Append::impl_call_post (const call_details &cd) const model->mark_region_as_unknown (freed_reg, cd.get_uncertainty ()); } - model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED); + model->unbind_region_and_descendents (freed_reg, poison_kind::freed); model->unset_dynamic_extents (freed_reg); } @@ -943,9 +944,9 @@ kf_PyList_Append::impl_call_post (const call_details &cd) const /* Body of kf_PyList_Append::impl_call_post. */ if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<realloc_failure> (cd)); - cd.get_ctxt ()->bifurcate (make_unique<realloc_success_no_move> (cd)); - cd.get_ctxt ()->bifurcate (make_unique<realloc_success_move> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<realloc_failure> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<realloc_success_no_move> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<realloc_success_move> (cd)); cd.get_ctxt ()->terminate_path (); } } @@ -1078,8 +1079,8 @@ kf_PyList_New::impl_call_post (const call_details &cd) const if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<pyobj_init_fail> (cd)); - cd.get_ctxt ()->bifurcate (make_unique<success> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<pyobj_init_fail> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<success> (cd)); cd.get_ctxt ()->terminate_path (); } } @@ -1147,8 +1148,8 @@ kf_PyLong_FromLong::impl_call_post (const call_details &cd) const if (cd.get_ctxt ()) { - cd.get_ctxt ()->bifurcate (make_unique<pyobj_init_fail> (cd)); - cd.get_ctxt ()->bifurcate (make_unique<success> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<pyobj_init_fail> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<success> (cd)); cd.get_ctxt ()->terminate_path (); } } @@ -1290,14 +1291,14 @@ cpython_analyzer_init_cb (void *gcc_data, void * /*user_data */) } iface->register_known_function ("PyList_Append", - make_unique<kf_PyList_Append> ()); - iface->register_known_function ("PyList_New", make_unique<kf_PyList_New> ()); + std::make_unique<kf_PyList_Append> ()); + iface->register_known_function ("PyList_New", std::make_unique<kf_PyList_New> ()); iface->register_known_function ("PyLong_FromLong", - make_unique<kf_PyLong_FromLong> ()); + std::make_unique<kf_PyLong_FromLong> ()); iface->register_known_function ( "__analyzer_cpython_dump_refcounts", - make_unique<kf_analyzer_cpython_dump_refcounts> ()); + std::make_unique<kf_analyzer_cpython_dump_refcounts> ()); } } // namespace ana diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc index 77767c8..c101c45 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc @@ -5,19 +5,19 @@ /* { dg-options "-g" } */ #define INCLUDE_MEMORY +#define INCLUDE_STRING #define INCLUDE_VECTOR #include "gcc-plugin.h" #include "config.h" #include "system.h" #include "coretypes.h" -#include "make-unique.h" #include "diagnostic.h" #include "tree.h" #include "gimple.h" #include "gimple-iterator.h" #include "gimple-walk.h" -#include "diagnostic-event-id.h" -#include "analyzer/analyzer.h" +#include "diagnostics/event-id.h" +#include "analyzer/common.h" #include "analyzer/analyzer-logging.h" #include "json.h" #include "analyzer/sm.h" @@ -66,7 +66,7 @@ public: private: void check_for_pyobject_in_call (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, tree callee_fndecl) const; public: @@ -120,20 +120,22 @@ public: return false; } - diagnostic_event::meaning + diagnostics::paths::event::meaning get_meaning_for_state_change (const evdesc::state_change &change) const final override { + using event = diagnostics::paths::event; + 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); + return event::meaning (event::verb::release, + 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 event::meaning (event::verb::acquire, + event::noun::lock); } - return diagnostic_event::meaning (); + return event::meaning (); } protected: gil_diagnostic (const gil_state_machine &sm) : m_sm (sm) @@ -147,7 +149,7 @@ public: class double_save_thread : public gil_diagnostic { public: - double_save_thread (const gil_state_machine &sm, const gcall *call) + double_save_thread (const gil_state_machine &sm, const gcall &call) : gil_diagnostic (sm), m_call (call) {} @@ -160,7 +162,7 @@ class double_save_thread : public gil_diagnostic { const double_save_thread &sub_other = (const double_save_thread &)base_other; - return m_call == sub_other.m_call; + return &m_call == &sub_other.m_call; } bool emit (diagnostic_emission_context &ctxt) final override @@ -179,13 +181,13 @@ class double_save_thread : public gil_diagnostic } private: - const gcall *m_call; + const gcall &m_call; }; class fncall_without_gil : public gil_diagnostic { public: - fncall_without_gil (const gil_state_machine &sm, const gcall *call, + fncall_without_gil (const gil_state_machine &sm, const gcall &call, tree callee_fndecl, unsigned arg_idx) : gil_diagnostic (sm), m_call (call), m_callee_fndecl (callee_fndecl), m_arg_idx (arg_idx) @@ -200,7 +202,7 @@ class fncall_without_gil : public gil_diagnostic { const fncall_without_gil &sub_other = (const fncall_without_gil &)base_other; - return (m_call == sub_other.m_call + return (&m_call == &sub_other.m_call && m_callee_fndecl == sub_other.m_callee_fndecl && m_arg_idx == sub_other.m_arg_idx); } @@ -233,7 +235,7 @@ class fncall_without_gil : public gil_diagnostic } private: - const gcall *m_call; + const gcall &m_call; tree m_callee_fndecl; unsigned m_arg_idx; }; @@ -313,21 +315,21 @@ check_for_pyobject (gimple *, tree op, tree, void *data) void gil_state_machine::check_for_pyobject_in_call (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, tree callee_fndecl) const { - for (unsigned i = 0; i < gimple_call_num_args (call); i++) + for (unsigned i = 0; i < gimple_call_num_args (&call); i++) { - tree arg = gimple_call_arg (call, i); + tree arg = gimple_call_arg (&call, i); if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE) continue; tree type = TREE_TYPE (TREE_TYPE (arg)); if (type_based_on_pyobject_p (type)) { - sm_ctxt.warn (node, call, NULL_TREE, - make_unique<fncall_without_gil> (*this, call, - callee_fndecl, - i)); + sm_ctxt.warn (node, &call, NULL_TREE, + std::make_unique<fncall_without_gil> (*this, call, + callee_fndecl, + i)); sm_ctxt.set_global_state (m_stop); } } @@ -341,8 +343,9 @@ gil_state_machine::on_stmt (sm_context &sm_ctxt, const gimple *stmt) const { const state_t global_state = sm_ctxt.get_global_state (); - if (const gcall *call = dyn_cast <const gcall *> (stmt)) + if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt)) { + const gcall &call = *call_stmt; if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call)) { if (is_named_call_p (callee_fndecl, "PyEval_SaveThread", call, 0)) @@ -353,7 +356,7 @@ gil_state_machine::on_stmt (sm_context &sm_ctxt, if (global_state == m_released_gil) { sm_ctxt.warn (node, stmt, NULL_TREE, - make_unique<double_save_thread> (*this, call)); + std::make_unique<double_save_thread> (*this, call)); sm_ctxt.set_global_state (m_stop); } else @@ -409,7 +412,7 @@ gil_state_machine::check_for_pyobject_usage_without_gil (sm_context &sm_ctxt, if (type_based_on_pyobject_p (type)) { sm_ctxt.warn (node, stmt, NULL_TREE, - make_unique<pyobject_usage_without_gil> (*this, op)); + std::make_unique<pyobject_usage_without_gil> (*this, op)); sm_ctxt.set_global_state (m_stop); } } @@ -425,7 +428,7 @@ gil_analyzer_init_cb (void *gcc_data, void */*user_data*/) if (0) inform (input_location, "got here: gil_analyzer_init_cb"); iface->register_state_machine - (make_unique<gil_state_machine> (iface->get_logger ())); + (std::make_unique<gil_state_machine> (iface->get_logger ())); } } // namespace ana diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc index 7f2158e..fc282a7 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc @@ -2,6 +2,7 @@ /* { dg-options "-g" } */ #define INCLUDE_MEMORY +#define INCLUDE_STRING #define INCLUDE_VECTOR #include "gcc-plugin.h" #include "config.h" @@ -22,14 +23,14 @@ #include "target.h" #include "fold-const.h" #include "tree-pretty-print.h" -#include "diagnostic-color.h" -#include "diagnostic-metadata.h" +#include "diagnostics/color.h" +#include "diagnostics/metadata.h" #include "tristate.h" #include "bitmap.h" #include "selftest.h" #include "function.h" #include "json.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" #include "options.h" @@ -44,7 +45,6 @@ #include "analyzer/region-model.h" #include "analyzer/call-details.h" #include "analyzer/call-info.h" -#include "make-unique.h" int plugin_is_GPL_compatible; @@ -106,7 +106,7 @@ class copy_across_boundary_fn : public known_function if (ctxt) { /* Bifurcate state, creating a "failure" out-edge. */ - ctxt->bifurcate (make_unique<copy_failure> (cd)); + ctxt->bifurcate (std::make_unique<copy_failure> (cd)); /* The "unbifurcated" state is the "success" case. */ copy_success success (cd, @@ -238,11 +238,13 @@ kernel_analyzer_init_cb (void *gcc_data, void */*user_data*/) inform (input_location, "got here: kernel_analyzer_init_cb"); iface->register_known_function ("copy_from_user", - make_unique<known_function_copy_from_user> ()); - iface->register_known_function ("copy_to_user", - make_unique<known_function_copy_to_user> ()); - iface->register_known_function ("__check_object_size", - make_unique<known_function___check_object_size> ()); + std::make_unique<known_function_copy_from_user> ()); + iface->register_known_function + ("copy_to_user", + std::make_unique<known_function_copy_to_user> ()); + iface->register_known_function + ("__check_object_size", + std::make_unique<known_function___check_object_size> ()); } } // namespace ana diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc index c060407..44fcf37 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc @@ -2,6 +2,7 @@ /* { dg-options "-g" } */ #define INCLUDE_MEMORY +#define INCLUDE_STRING #define INCLUDE_VECTOR #include "gcc-plugin.h" #include "config.h" @@ -22,14 +23,14 @@ #include "target.h" #include "fold-const.h" #include "tree-pretty-print.h" -#include "diagnostic-color.h" -#include "diagnostic-metadata.h" +#include "diagnostics/color.h" +#include "diagnostics/metadata.h" #include "tristate.h" #include "bitmap.h" #include "selftest.h" #include "function.h" #include "json.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" #include "options.h" @@ -44,7 +45,6 @@ #include "analyzer/region-model.h" #include "analyzer/call-details.h" #include "analyzer/call-info.h" -#include "make-unique.h" int plugin_is_GPL_compatible; @@ -168,7 +168,7 @@ public: if (cd.get_ctxt ()) { /* Bifurcate state, creating a "failure" out-edge. */ - cd.get_ctxt ()->bifurcate (make_unique<copy_failure> (cd)); + cd.get_ctxt ()->bifurcate (std::make_unique<copy_failure> (cd)); /* The "unbifurcated" state is the "success" case. */ copy_success success (cd, @@ -189,11 +189,12 @@ known_fn_analyzer_init_cb (void *gcc_data, void */*user_data*/) LOG_SCOPE (iface->get_logger ()); if (0) inform (input_location, "got here: known_fn_analyzer_init_cb"); - iface->register_known_function ("returns_42", - make_unique<known_function_returns_42> ()); + iface->register_known_function + ("returns_42", + std::make_unique<known_function_returns_42> ()); iface->register_known_function ("attempt_to_copy", - make_unique<known_function_attempt_to_copy> ()); + std::make_unique<known_function_attempt_to_copy> ()); } } // namespace ana diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.c new file mode 100644 index 0000000..2256a63 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-add-output=experimental-html:javascript=no" } */ + +extern void here (void); + +void test_graphs (void) +{ + here (); /* { dg-error "this is a placeholder error, with graphs" } */ +} + +/* Use a Python script to verify various properties about the generated + HTML file: + { dg-final { run-html-pytest diagnostic-test-graphs-html.c "diagnostic-test-graphs-html.py" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.py new file mode 100644 index 0000000..9ff4645 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-html.py @@ -0,0 +1,48 @@ +# Verify that metadata works in HTML output. + +from htmltest import * + +import pytest + +@pytest.fixture(scope='function', autouse=True) +def html_tree(): + return html_tree_from_env() + +def test_result_graph(html_tree): + root = html_tree.getroot () + assert root.tag == make_tag('html') + + body = root.find('xhtml:body', ns) + assert body is not None + + diag_list = body.find('xhtml:div', ns) + assert diag_list is not None + assert diag_list.attrib['class'] == 'gcc-diagnostic-list' + + diag = diag_list.find('xhtml:div', ns) + assert diag is not None + + message = diag.find("./xhtml:div[@class='gcc-message']", ns) + assert message.attrib['id'] == 'gcc-diag-0-message' + + assert message[0].tag == make_tag('strong') + assert message[0].tail == ' this is a placeholder error, with graphs' + + graph = diag.find("./xhtml:div[@class='gcc-directed-graph']", ns) + assert graph is not None + + header = graph.find("./xhtml:h2", ns) + assert header.text == 'foo' + +def test_run_graph(html_tree): + root = html_tree.getroot () + assert root.tag == make_tag('html') + + body = root.find('xhtml:body', ns) + assert body is not None + + graph = body.find("./xhtml:div[@class='gcc-directed-graph']", ns) + assert graph is not None + + header = graph.find("./xhtml:h2", ns) + assert header.text == 'Optimization Passes' diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.c new file mode 100644 index 0000000..4170f51 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-add-output=sarif" } */ + +extern void here (void); + +void test_graphs (void) +{ + here (); /* { dg-error "this is a placeholder error, with graphs" } */ +} + +/* Verify that some JSON was written to a file with the expected name. */ +/* { dg-final { verify-sarif-file } } */ + +/* Use a Python script to verify various properties about the generated + .sarif file: + { dg-final { run-sarif-pytest diagnostic-test-graphs-sarif.c "diagnostic-test-graphs-sarif.py" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.py new file mode 100644 index 0000000..4bb7535 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs-sarif.py @@ -0,0 +1,55 @@ +from sarif import * + +import pytest + +@pytest.fixture(scope='function', autouse=True) +def sarif(): + return sarif_from_env() + +def test_basics(sarif): + schema = sarif['$schema'] + assert schema == "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json" + + version = sarif['version'] + assert version == "2.1.0" + +def test_result_graph(sarif): + runs = sarif['runs'] + run = runs[0] + results = run['results'] + + assert len(results) == 1 + + result = results[0] + assert result['level'] == 'error' + assert result['message']['text'] == "this is a placeholder error, with graphs" + + assert len(result['graphs']) == 2 + + assert result['graphs'][0]['description']['text'] == 'foo' + + assert len(result['graphs'][0]['nodes']) == 2 + assert result['graphs'][0]['nodes'][0]['id'] == 'a' + assert result['graphs'][0]['nodes'][1]['id'] == 'b' + assert result['graphs'][0]['nodes'][1]['properties']['/placeholder-prefix/color'] == 'red' + assert len(result['graphs'][0]['nodes'][1]['children']) == 1 + assert result['graphs'][0]['nodes'][1]['children'][0]['id'] == 'c' + assert result['graphs'][0]['nodes'][1]['children'][0]['label']['text'] == 'I am a node label' + + assert len(result['graphs'][0]['edges']) == 1 + result['graphs'][0]['edges'][0]['id'] == 'my-edge' + assert result['graphs'][0]['edges'][0]['label']['text'] == 'I am an edge label' + assert result['graphs'][0]['edges'][0]['sourceNodeId'] == 'a' + assert result['graphs'][0]['edges'][0]['targetNodeId'] == 'c' + + assert result['graphs'][1]['description']['text'] == 'bar' + +def test_run_graph(sarif): + runs = sarif['runs'] + run = runs[0] + + assert len(run['graphs']) == 1 + + assert run['graphs'][0]['description']['text'] == 'Optimization Passes' + assert run['graphs'][0]['nodes'][0]['id'] == 'all_lowering_passes' + assert run['graphs'][0]['edges'][0]['id'] == 'edge0' diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs.c new file mode 100644 index 0000000..7973954 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-graphs.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ + +extern void here (void); + +void test_graphs (void) +{ + here (); /* { dg-error "this is a placeholder error, with graphs" } */ +} diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-html.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-html.c new file mode 100644 index 0000000..df57b25 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-html.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-set-output=experimental-html:javascript=no" } */ +/* { dg-additional-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers" } */ + +extern char *gets (char *s); + +void test_cwe (void) +{ + char buf[1024]; + gets (buf); +} + +/* Use a Python script to verify various properties about the generated + HTML file: + { dg-final { run-html-pytest diagnostic-test-metadata-html.c "diagnostic-test-metadata-html.py" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-html.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-html.py new file mode 100644 index 0000000..67fb241 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-html.py @@ -0,0 +1,73 @@ +# Verify that metadata works in HTML output. + +from htmltest import * + +import pytest + +@pytest.fixture(scope='function', autouse=True) +def html_tree(): + return html_tree_from_env() + +def test_metadata(html_tree): + root = html_tree.getroot () + assert root.tag == make_tag('html') + + body = root.find('xhtml:body', ns) + assert body is not None + + diag_list = body.find('xhtml:div', ns) + assert diag_list is not None + assert diag_list.attrib['class'] == 'gcc-diagnostic-list' + + diag = diag_list.find('xhtml:div', ns) + assert diag is not None + assert diag.attrib['class'] == 'alert alert-warning' + + icon = diag.find('xhtml:span', ns) + assert icon.attrib['class'] == 'pficon pficon-warning-triangle-o' + + message = diag.find("./xhtml:div[@class='gcc-message']", ns) + assert message.attrib['id'] == 'gcc-diag-0-message' + + assert message[0].tag == make_tag('strong') + assert message[0].text == 'warning: ' + assert message[0].tail == " never use '" + + assert message[1].tag == make_tag('span') + assert message[1].attrib['class'] == 'gcc-quoted-text' + assert message[1].text == 'gets' + assert message[1].tail == "' " + + metadata = message[2] + assert metadata.attrib['class'] == 'gcc-metadata' + assert metadata[0].tag == make_tag('span') + assert metadata[0].attrib['class'] == 'gcc-metadata-item' + assert metadata[0].text == '[' + assert metadata[0][0].tag == make_tag('a') + assert metadata[0][0].attrib['href'] == 'https://cwe.mitre.org/data/definitions/242.html' + assert metadata[0][0].text == 'CWE-242' + assert metadata[0][0].tail == ']' + + assert metadata[1].tag == make_tag('span') + assert metadata[1].attrib['class'] == 'gcc-metadata-item' + assert metadata[1].text == '[' + assert metadata[1][0].tag == make_tag('a') + assert metadata[1][0].attrib['href'] == 'https://example.com/' + assert metadata[1][0].text == 'STR34-C' + assert metadata[1][0].tail == ']' + + src = diag.find('xhtml:table', ns) + assert src.attrib['class'] == 'locus' + + tbody = src.find('xhtml:tbody', ns) + assert tbody.attrib['class'] == 'line-span' + + rows = tbody.findall('xhtml:tr', ns) + + quoted_src_tr = rows[0] + assert_quoted_line(quoted_src_tr, + ' 10', ' gets (buf);') + + annotation_tr = rows[1] + assert_annotation_line(annotation_tr, + ' ^~~~~~~~~~') diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-html.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-html.c new file mode 100644 index 0000000..8ff7b35 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-html.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-add-output=experimental-html:javascript=no" } */ + +extern void foo (void); + +void test_nesting (void) +{ + foo (); /* { dg-error "top-level error" } */ +} + +/* Use a Python script to verify various properties about the generated + .html file: + { dg-final { run-html-pytest diagnostic-test-nesting-html.c "diagnostic-test-nesting-html.py" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-html.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-html.py new file mode 100644 index 0000000..3899ba5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-html.py @@ -0,0 +1,69 @@ +# Verify that nesting works in HTML output. + +from htmltest import * + +import pytest + +@pytest.fixture(scope='function', autouse=True) +def html_tree(): + return html_tree_from_env() + +def test_nesting(html_tree): + root = html_tree.getroot () + assert root.tag == make_tag('html') + + body = root.find('xhtml:body', ns) + assert body is not None + + diag_list = body.find('xhtml:div', ns) + assert diag_list is not None + assert diag_list.attrib['class'] == 'gcc-diagnostic-list' + + diag = diag_list.find('xhtml:div', ns) + assert diag is not None + + message = diag.find("./xhtml:div[@class='gcc-message']", ns) + assert message.attrib['id'] == 'gcc-diag-0-message' + + assert message[0].tag == make_tag('strong') + assert message[0].tail == ' top-level error' + + # We expect 12 messages, with the given IDs and text: + for i in range(12): + child = diag.find(".//xhtml:div[@id='gcc-diag-%i']" % (i + 1), + ns) + assert child is not None + + message = child.find("./xhtml:div[@class='gcc-message']", ns) + assert message.attrib['id'] == 'gcc-diag-%i-message' % (i + 1) + + if i % 4 == 0: + assert message.text == 'child %i' % (i / 4) + else: + assert message.text == 'grandchild %i %i' % ((i / 4), (i % 4) - 1) + + # We expect the messages to be organized into nested <ul> with + # "nesting-level" set, all below a <ul> + child_ul = diag.find("./xhtml:ul[@nesting-level='1']", ns) + assert child_ul is not None + msg_id = 1 + for i in range(3): + child_li = child_ul.find("./xhtml:li[@nesting-level='1'][%i]" % (i + 1), ns) + assert child_li is not None + child = child_li.find("./xhtml:div[@id='gcc-diag-%i']" % msg_id, ns) + assert child is not None + message = child.find("./xhtml:div[@class='gcc-message']", ns) + assert message.attrib['id'] == 'gcc-diag-%i-message' % msg_id + assert message.text == 'child %i' % i + msg_id += 1 + grandchild_ul = child_ul.find("./xhtml:ul[@nesting-level='2'][%i]" % (i + 1), ns) + assert grandchild_ul is not None + for j in range(3): + grandchild_li = grandchild_ul.find("./xhtml:li[@nesting-level='2'][%i]" % (j + 1), ns) + assert grandchild_li is not None + grandchild = grandchild_li.find("./xhtml:div[@id='gcc-diag-%i']" % msg_id, ns) + assert grandchild is not None + message = grandchild.find("./xhtml:div[@class='gcc-message']", ns) + assert message.attrib['id'] == 'gcc-diag-%i-message' % msg_id + assert message.text == 'grandchild %i %i' % (i, j) + msg_id += 1 diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-no-show-nesting.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-no-show-nesting.c new file mode 100644 index 0000000..3492899 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-no-show-nesting.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-fno-diagnostics-show-nesting" } */ + +extern void foo (void); + +void test_nesting (void) +{ + foo (); /* { dg-error "top-level error" } */ +} diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-show-nesting.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-show-nesting.c new file mode 100644 index 0000000..8fc2edb --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-show-nesting.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-show-nesting" } */ + +extern void foo (void); + +void test_nesting (void) +{ + foo (); /* { dg-error "top-level error" } */ +} + +/* { dg-begin-multiline-output "" } + * child 0 + * grandchild 0 0 + * grandchild 0 1 + * grandchild 0 2 + * child 1 + * grandchild 1 0 + * grandchild 1 1 + * grandchild 1 2 + * child 2 + * grandchild 2 0 + * grandchild 2 1 + * grandchild 2 2 + { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-text-indented-show-levels.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-text-indented-show-levels.c index f44c8eb..4be52fe 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-text-indented-show-levels.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-text-indented-show-levels.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-fdiagnostics-set-output=text:experimental-nesting=yes,experimental-nesting-show-levels=yes" } */ +/* { dg-options "-fdiagnostics-set-output=text:show-nesting=yes,show-nesting-levels=yes" } */ extern void foo (void); diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-text-indented-unicode.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-text-indented-unicode.c index 39e29f7..c069c3f 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-text-indented-unicode.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-text-indented-unicode.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-fdiagnostics-set-output=text:experimental-nesting=yes -fdiagnostics-text-art-charset=unicode" } */ +/* { dg-options "-fdiagnostics-set-output=text:show-nesting=yes -fdiagnostics-text-art-charset=unicode" } */ extern void foo (void); diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-text-indented.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-text-indented.c index e103429..a35254d 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-text-indented.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-nesting-text-indented.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-fdiagnostics-set-output=text:experimental-nesting=yes" } */ +/* { dg-options "-fdiagnostics-set-output=text:show-nesting=yes" } */ extern void foo (void); diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-2.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-2.c index b8134ae..dab9c38 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-2.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-2.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events" } */ +/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fdiagnostics-add-output=experimental-html:javascript=no" } */ #include <stddef.h> #include <stdlib.h> @@ -52,3 +52,7 @@ make_a_list_of_random_ints_badly(PyObject *self, | (3) when calling 'PyList_Append', passing NULL from (1) as argument 1 { dg-end-multiline-output "" } */ } + +/* Use a Python script to verify various properties about the generated + HTML file: + { dg-final { run-html-pytest diagnostic-test-paths-2.c "diagnostic-test-paths-2.py" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-2.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-2.py new file mode 100644 index 0000000..f0fed45 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-2.py @@ -0,0 +1,48 @@ +# Verify that execution paths work in HTML output. + +from htmltest import * + +import pytest + +@pytest.fixture(scope='function', autouse=True) +def html_tree(): + return html_tree_from_env() + +def test_paths(html_tree): + root = html_tree.getroot () + assert root.tag == make_tag('html') + + body = root.find('xhtml:body', ns) + assert body is not None + + diag_list = body.find('xhtml:div', ns) + assert diag_list is not None + assert diag_list.attrib['class'] == 'gcc-diagnostic-list' + + diag = diag_list.find('xhtml:div', ns) + assert diag is not None + assert diag.attrib['class'] == 'alert alert-danger' + assert diag.attrib['id'] == 'gcc-diag-0' + + exec_path = diag.find("./xhtml:div[@id='execution-path']", ns) + assert exec_path is not None + + label = exec_path.find('xhtml:label', ns) + assert label.text == 'Execution path with 3 events' + + event_ranges = exec_path.find('xhtml:div', ns) + assert_class(event_ranges, 'event-ranges') + + frame_margin = event_ranges.find('xhtml:table', ns) + assert_class(frame_margin, 'stack-frame-with-margin') + + tr = frame_margin.find('xhtml:tr', ns) + assert tr is not None + tds = tr.findall('xhtml:td', ns) + assert len(tds) == 2 + + assert_class(tds[0], 'interprocmargin') + + test_frame = tds[1] + assert_frame(test_frame, 'make_a_list_of_random_ints_badly') + assert_event_range_with_margin(test_frame[1]) diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-3.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-3.c deleted file mode 100644 index a315d20..0000000 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-3.c +++ /dev/null @@ -1,75 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-fdiagnostics-format=json" } */ - -#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-begin-multiline-output "" } -[{"kind": "error", - "message": "passing NULL as argument 1 to 'PyList_Append' which requires a non-NULL parameter", - "children": [], - "column-origin": 1, - "locations": [{"caret": {"file": " - "line": 29, - "display-column": 5, - "byte-column": 5, - "column": 5}, - "finish": {"file": " - "line": 29, - "display-column": 29, - "byte-column": 29, - "column": 29}}], - "path": [{"location": {"file": " - "line": 25, - "display-column": 10, - "byte-column": 10, - "column": 10}, - "description": "when 'PyList_New' fails, returning NULL", - "function": "make_a_list_of_random_ints_badly", - "depth": 0}, - {"location": {"file": " - "line": 27, - "display-column": 17, - "byte-column": 17, - "column": 17}, - "description": "when 'i < count'", - "function": "make_a_list_of_random_ints_badly", - "depth": 0}, - {"location": {"file": " - "line": 29, - "display-column": 5, - "byte-column": 5, - "column": 5}, - "description": "when calling 'PyList_Append', passing NULL from (1) as argument 1", - "function": "make_a_list_of_random_ints_badly", - "depth": 0}], - "escape-source": false}] -{ dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c index 847b6d4..7eb0c50 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret -fdiagnostics-show-line-numbers" } */ +/* { dg-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret -fdiagnostics-show-line-numbers -fdiagnostics-add-output=experimental-html:javascript=no" } */ /* { dg-enable-nn-line-numbers "" } */ #include <stdio.h> @@ -82,3 +82,7 @@ void test (void) | | (9) calling 'fprintf' | { dg-end-multiline-output "" } */ + +/* Use a Python script to verify various properties about the generated + HTML file: + { dg-final { run-html-pytest diagnostic-test-paths-4.c "diagnostic-test-paths-4.py" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.py new file mode 100644 index 0000000..d2bc67c --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.py @@ -0,0 +1,49 @@ +# Verify that interprocedural execution paths work in HTML output. + +from htmltest import * + +import pytest + +@pytest.fixture(scope='function', autouse=True) +def html_tree(): + return html_tree_from_env() + +def test_paths(html_tree): + diag = get_diag_by_index(html_tree, 0) + src = get_locus_within_diag (diag) + + tbody = src.find('xhtml:tbody', ns) + assert_class(tbody, 'line-span') + + rows = tbody.findall('xhtml:tr', ns) + + quoted_src_tr = rows[0] + assert_quoted_line(quoted_src_tr, + ' 13', ' fprintf(stderr, "LOG: %s", msg); /* { dg-warning "call to \'fprintf\' from within signal handler" } */') + + annotation_tr = rows[1] + assert_annotation_line(annotation_tr, + ' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~') + + exec_path = diag.find("./xhtml:div[@id='execution-path']", ns) + assert exec_path is not None + + label = exec_path.find('xhtml:label', ns) + assert label.text == 'Execution path with 9 events' + + event_ranges = exec_path.find('xhtml:div', ns) + assert_class(event_ranges, 'event-ranges') + + test_frame_margin = event_ranges.find('xhtml:table', ns) + assert_class(test_frame_margin, 'stack-frame-with-margin') + + tr = test_frame_margin.find('xhtml:tr', ns) + assert tr is not None + tds = tr.findall('xhtml:td', ns) + assert len(tds) == 2 + + assert_class(tds[0], 'interprocmargin') + + test_frame = tds[1] + assert_frame(test_frame, 'test') + assert_event_range_with_margin(test_frame[1]) diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw-line-numbers.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw-line-numbers.c index 1e8f73b..e81856a 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw-line-numbers.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw-line-numbers.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O -fdiagnostics-show-caret -fdiagnostics-show-line-numbers" } */ +/* { dg-options "-O -fdiagnostics-show-caret -fdiagnostics-show-line-numbers -fdiagnostics-add-output=experimental-html:javascript=no" } */ /* This is a collection of unittests for diagnostic_show_locus; see the overview in diagnostic_plugin_test_show_locus.c. @@ -118,3 +118,7 @@ void test_fixit_insert_newline (void) { dg-end-multiline-output "" } */ #endif } + +/* Use a Python script to verify various properties about the generated + HTML file: + { dg-final { run-html-pytest diagnostic-test-show-locus-bw-line-numbers.c "diagnostic-test-show-locus.py" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus.py new file mode 100644 index 0000000..eaca35a --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus.py @@ -0,0 +1,115 @@ +# Verify that diagnostics/source-printing.cc works with HTML output. + +from htmltest import * + +import pytest + +@pytest.fixture(scope='function', autouse=True) +def html_tree(): + return html_tree_from_env() + +#def get_tr_within_thead(thead, idx) + +def get_ruler_text(thead, idx): + trs = thead.findall('xhtml:tr', ns) + tr = trs[idx] + tds = tr.findall('xhtml:td', ns) + assert len(tds) == 3 + assert_class(tds[2], 'ruler') + return tds[2].text + +def test_very_wide_line(html_tree): + diag = get_diag_by_index(html_tree, 2) + src = get_locus_within_diag(diag) + + # Check ruler + thead = src.find('xhtml:thead', ns) + assert_class(thead, 'ruler') + trs = thead.findall('xhtml:tr', ns) + assert len(trs) == 3 + + assert get_ruler_text(thead, 0) == ' 0 0 0 0 0 1 1 ' + assert get_ruler_text(thead, 1) == ' 5 6 7 8 9 0 1 ' + assert get_ruler_text(thead, 2) == '34567890123456789012345678901234567890123456789012345678901234567890123' + + # Check quoted source + tbody = src.find('xhtml:tbody', ns) + assert_class(tbody, 'line-span') + trs = tbody.findall('xhtml:tr', ns) + assert len(trs) == 5 + assert_quoted_line(trs[0], ' 43', ' float f = foo * bar; /* { dg-warning "95: test" } */') + assert_annotation_line(trs[1], ' ~~~~^~~~~') + assert_annotation_line(trs[2], ' |') + assert_annotation_line(trs[3], ' label 0') + assert_annotation_line(trs[4], ' bar * foo') + +def test_fixit_insert(html_tree): + diag = get_diag_by_index(html_tree, 3) + msg = get_message_within_diag(diag) + assert msg[0].text == 'warning: ' + assert msg[0].tail == ' example of insertion hints' + + src = get_locus_within_diag(diag) + + # Check quoted source + tbody = src.find('xhtml:tbody', ns) + assert_class(tbody, 'line-span') + trs = tbody.findall('xhtml:tr', ns) + assert len(trs) == 3 + assert_quoted_line(trs[0], ' 63', ' int a[2][2] = { 0, 1 , 2, 3 }; /* { dg-warning "insertion hints" } */') + assert_annotation_line(trs[1], ' ^~~~') + assert_annotation_line(trs[2], ' { }') + +def test_fixit_remove(html_tree): + diag = get_diag_by_index(html_tree, 4) + msg = get_message_within_diag(diag) + assert msg[0].text == 'warning: ' + assert msg[0].tail == ' example of a removal hint' + + src = get_locus_within_diag(diag) + + # Check quoted source + tbody = src.find('xhtml:tbody', ns) + assert_class(tbody, 'line-span') + trs = tbody.findall('xhtml:tr', ns) + assert len(trs) == 3 + assert_quoted_line(trs[0], ' 77', ' int a;; /* { dg-warning "example of a removal hint" } */') + assert_annotation_line(trs[1], ' ^') + assert_annotation_line(trs[2], ' -') + +def test_fixit_replace(html_tree): + diag = get_diag_by_index(html_tree, 5) + msg = get_message_within_diag(diag) + assert msg[0].text == 'warning: ' + assert msg[0].tail == ' example of a replacement hint' + + src = get_locus_within_diag(diag) + + # Check quoted source + tbody = src.find('xhtml:tbody', ns) + assert_class(tbody, 'line-span') + trs = tbody.findall('xhtml:tr', ns) + assert len(trs) == 3 + assert_quoted_line(trs[0], ' 91', ' gtk_widget_showall (dlg); /* { dg-warning "example of a replacement hint" } */') + assert_annotation_line(trs[1], ' ^~~~~~~~~~~~~~~~~~') + assert_annotation_line(trs[2], ' gtk_widget_show_all') + +def test_fixit_insert_newline(html_tree): + diag = get_diag_by_index(html_tree, 6) + msg = get_message_within_diag(diag) + assert msg[0].text == 'warning: ' + assert msg[0].tail == ' example of newline insertion hint' + + src = get_locus_within_diag(diag) + + # Check quoted source + tbody = src.find('xhtml:tbody', ns) + assert_class(tbody, 'line-span') + trs = tbody.findall('xhtml:tr', ns) + assert len(trs) == 4 + assert_quoted_line(trs[0], ' 109', ' x = a;') + assert_annotation_line(trs[1], ' break;', + expected_line_num=' +++', + expected_left_margin='+') + assert_quoted_line(trs[2], ' 110', " case 'b': /* { dg-warning \"newline insertion\" } */") + assert_annotation_line(trs[3], ' ^~~~~~~~') diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-xhtml-1.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-xhtml-1.c deleted file mode 100644 index da069ff..0000000 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-xhtml-1.c +++ /dev/null @@ -1,19 +0,0 @@ -/* { dg-do compile } */ - -int missing_semicolon (void) -{ - return 42 -} - -/* Verify some properties of the generated HTML. */ - -/* { dg-begin-multiline-output "" } -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html - PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - { dg-end-multiline-output "" } */ - -/* { dg-excess-errors "" } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc index 7e6d7e1..48f8325 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc @@ -27,9 +27,8 @@ #include "plugin-version.h" #include "c-family/c-common.h" #include "diagnostic.h" -#include "diagnostic-format-text.h" +#include "diagnostics/text-sink.h" #include "context.h" -#include "make-unique.h" int plugin_is_GPL_compatible; @@ -166,8 +165,8 @@ pass_test_groups::execute (function *fun) expected output. */ void -test_diagnostic_text_starter (diagnostic_text_output_format &text_output, - const diagnostic_info *diagnostic) +test_diagnostic_text_starter (diagnostics::text_sink &text_output, + const diagnostics::diagnostic_info *diagnostic) { pp_set_prefix (text_output.get_printer (), xstrdup ("PREFIX: ")); } @@ -176,21 +175,22 @@ test_diagnostic_text_starter (diagnostic_text_output_format &text_output, expected output. */ void -test_diagnostic_start_span_fn (const diagnostic_location_print_policy &, - pretty_printer *pp, +test_diagnostic_start_span_fn (const diagnostics::location_print_policy &, + diagnostics::to_text &sink, expanded_location) { + pretty_printer *pp = diagnostics::get_printer (sink); pp_string (pp, "START_SPAN_FN: "); pp_newline (pp); } -/* Custom output format subclass. */ +/* Custom text_sink subclass. */ -class test_output_format : public diagnostic_text_output_format +class custom_test_sink : public diagnostics::text_sink { public: - test_output_format (diagnostic_context &context) - : diagnostic_text_output_format (context) + custom_test_sink (diagnostics::context &context) + : diagnostics::text_sink (context) {} void on_begin_group () final override @@ -228,9 +228,9 @@ plugin_init (struct plugin_name_args *plugin_info, if (!plugin_default_version_check (version, &gcc_version)) return 1; - diagnostic_text_starter (global_dc) = test_diagnostic_text_starter; - diagnostic_start_span (global_dc) = test_diagnostic_start_span_fn; - global_dc->set_output_format (::make_unique<test_output_format> (*global_dc)); + diagnostics::text_starter (global_dc) = test_diagnostic_text_starter; + diagnostics::start_span (global_dc) = test_diagnostic_start_span_fn; + global_dc->set_sink (::std::make_unique<custom_test_sink> (*global_dc)); pass_info.pass = new pass_test_groups (g); pass_info.reference_pass_name = "*warn_function_noreturn"; diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.cc index 44b94da..7e34a42 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.cc +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.cc @@ -115,7 +115,7 @@ plugin_init (struct plugin_name_args *plugin_info, if (!plugin_default_version_check (version, &gcc_version)) return 1; - global_dc->m_source_printing.max_width = 80; + global_dc->get_source_printing_options ().max_width = 80; register_callback (plugin_name, PLUGIN_PRE_GENERICIZE, diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_graphs.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_graphs.cc new file mode 100644 index 0000000..7398a29 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_graphs.cc @@ -0,0 +1,283 @@ +/* This plugin exercises diagnostic graphs. + We emit an error with a pair of digraphs associated with it, + and a global digraph showing the optimization passes. */ + +#define INCLUDE_MAP +#define INCLUDE_STRING +#define INCLUDE_VECTOR +#include "gcc-plugin.h" +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "stringpool.h" +#include "toplev.h" +#include "basic-block.h" +#include "hash-table.h" +#include "vec.h" +#include "ggc.h" +#include "basic-block.h" +#include "tree-ssa-alias.h" +#include "internal-fn.h" +#include "gimple.h" +#include "gimple-iterator.h" +#include "gimple-fold.h" +#include "tree-eh.h" +#include "gimple-expr.h" +#include "is-a.h" +#include "tree.h" +#include "tree-pass.h" +#include "intl.h" +#include "plugin-version.h" +#include "diagnostic.h" +#include "context.h" +#include "gcc-rich-location.h" +#include "diagnostics/metadata.h" +#include "diagnostics/digraphs.h" +#include "pass_manager.h" + + +int plugin_is_GPL_compatible; + +const pass_data pass_data_test_graph_emission = +{ + GIMPLE_PASS, /* type */ + "test_graph_emission", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_test_graph_emission : public gimple_opt_pass +{ +public: + pass_test_graph_emission(gcc::context *ctxt) + : gimple_opt_pass(pass_data_test_graph_emission, ctxt) + {} + + /* opt_pass methods: */ + bool gate (function *) { return true; } + virtual unsigned int execute (function *); + +}; // class pass_test_graph_emission + +/* Determine if STMT is a call with NUM_ARGS arguments to a function + named FUNCNAME. + If so, return STMT as a gcall *. Otherwise return NULL. */ + +static gcall * +check_for_named_call (gimple *stmt, + const char *funcname, unsigned int num_args) +{ + gcc_assert (funcname); + + gcall *call = dyn_cast <gcall *> (stmt); + if (!call) + return NULL; + + tree fndecl = gimple_call_fndecl (call); + if (!fndecl) + return NULL; + + if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname)) + return NULL; + + if (gimple_call_num_args (call) != num_args) + { + error_at (stmt->location, "expected number of args: %i (got %i)", + num_args, gimple_call_num_args (call)); + return NULL; + } + + return call; +} + +class lazy_passes_graph : public lazily_created<diagnostics::digraphs::digraph> +{ +public: + lazy_passes_graph (const ::gcc::pass_manager &pass_manager_) + : m_pass_manager (pass_manager_) + { + } + +private: + std::unique_ptr<diagnostics::digraphs::digraph> + create_object () const final override + { + auto g = std::make_unique<diagnostics::digraphs::digraph> (); + g->set_description ("Optimization Passes"); + +#define DEF_PASS_LIST(NAME) \ + add_top_level_pass_list (*g, #NAME, m_pass_manager.NAME); + + GCC_PASS_LISTS + +#undef DEF_PASS_LIST + + return g; + } + + void + add_top_level_pass_list (diagnostics::digraphs::digraph &g, + const char *pass_list_name, + const opt_pass *p) const + { + gcc_assert (p); + auto n = std::make_unique<diagnostics::digraphs::node> (g, pass_list_name); + n->set_label (pass_list_name); + add_child_pass (g, *n, *p); + g.add_node (std::move (n)); + } + + diagnostics::digraphs::node & + add_child_pass (diagnostics::digraphs::digraph &g, + diagnostics::digraphs::node &parent_node, + const opt_pass &p) const + { + std::string node_label; + std::string node_id; + if (p.static_pass_number > 0 ) + { + node_label = std::to_string (p.static_pass_number) + "_" + p.name; + node_id = node_label; + } + else + { + node_label = std::string (p.name); + pretty_printer pp; + pp_printf (&pp, "%s_%p", p.name, &p); + node_id = pp_formatted_text (&pp); + } + auto n + = std::make_unique<diagnostics::digraphs::node> (g, + std::move (node_id)); + n->set_label (node_label.c_str ()); + diagnostics::digraphs::node &result = *n; + parent_node.add_child (std::move (n)); + + // TODO: add attrs for things like type, properties_*, etc + + if (p.sub) + { + auto &other_node = add_child_pass (g, parent_node, *p.sub); + g.add_edge (nullptr, result, other_node, "sub"); + } + + if (p.next) + { + auto &other_node = add_child_pass (g, parent_node, *p.next); + g.add_edge (nullptr, result, other_node, "next"); + } + + return result; + } + + const ::gcc::pass_manager &m_pass_manager; +}; + +static void +report_diag_with_graphs (location_t loc) +{ + class my_lazy_digraphs : public diagnostics::metadata::lazy_digraphs + { + public: + using diagnostic_graph = diagnostics::digraphs::digraph; + using diagnostic_node = diagnostics::digraphs::node; + using diagnostic_edge = diagnostics::digraphs::edge; + + std::unique_ptr<std::vector<std::unique_ptr<diagnostic_graph>>> + create_object () const final override + { + auto graphs + = std::make_unique<std::vector<std::unique_ptr<diagnostic_graph>>> (); + + graphs->push_back (make_test_graph ("foo")); + graphs->push_back (make_test_graph ("bar")); + + return graphs; + } + + private: + std::unique_ptr<diagnostic_graph> + make_test_graph (const char *desc) const + { + auto g = std::make_unique<diagnostic_graph> (); + g->set_description (desc); + auto a = std::make_unique<diagnostic_node> (*g, "a"); + auto b = std::make_unique<diagnostic_node> (*g, "b"); +#define KEY_PREFIX "/placeholder-prefix/" + b->set_attr (KEY_PREFIX, "color", "red"); +#undef KEY_PREFIX + auto c = std::make_unique<diagnostic_node> (*g, "c"); + c->set_label ("I am a node label"); + + auto e = std::make_unique<diagnostic_edge> (*g, "my-edge", *a, *c); + e->set_label ("I am an edge label"); + g->add_edge (std::move (e)); + + g->add_node (std::move (a)); + + b->add_child (std::move (c)); + g->add_node (std::move (b)); + + return g; + } + }; + + gcc_rich_location rich_loc (loc); + diagnostics::metadata meta; + my_lazy_digraphs ldg; + meta.set_lazy_digraphs (&ldg); + error_meta (&rich_loc, meta, + "this is a placeholder error, with graphs"); +} + +/* Exercise diagnostic graph emission. */ + +unsigned int +pass_test_graph_emission::execute (function *fun) +{ + gimple_stmt_iterator gsi; + basic_block bb; + + FOR_EACH_BB_FN (bb, fun) + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + + if (gcall *call = check_for_named_call (stmt, "here", 0)) + report_diag_with_graphs (gimple_location (call)); + } + + return 0; +} + +int +plugin_init (struct plugin_name_args *plugin_info, + struct plugin_gcc_version *version) +{ + struct register_pass_info pass_info; + const char *plugin_name = plugin_info->base_name; + int argc = plugin_info->argc; + struct plugin_argument *argv = plugin_info->argv; + + if (!plugin_default_version_check (version, &gcc_version)) + return 1; + + pass_info.pass = new pass_test_graph_emission (g); + pass_info.reference_pass_name = "ssa"; + pass_info.ref_pass_instance_number = 1; + pass_info.pos_op = PASS_POS_INSERT_AFTER; + register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, + &pass_info); + + gcc_assert (::g->get_passes ()); + global_dc->report_global_digraph (lazy_passes_graph (*::g->get_passes ())); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.cc index 7edce1f..d38538d 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.cc +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.cc @@ -169,7 +169,7 @@ plugin_init (struct plugin_name_args *plugin_info, if (!plugin_default_version_check (version, &gcc_version)) return 1; - global_dc->m_source_printing.max_width = 80; + global_dc->get_source_printing_options ().max_width = 80; pass_info.pass = new pass_test_inlining (g); pass_info.reference_pass_name = "*warn_function_noreturn"; diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.cc index b86a8b3..f172258 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.cc +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.cc @@ -1,5 +1,6 @@ -/* This plugin exercises diagnostic_metadata. */ +/* This plugin exercises diagnostics::metadata. */ +#define INCLUDE_VECTOR #include "gcc-plugin.h" #include "config.h" #include "system.h" @@ -28,7 +29,7 @@ #include "diagnostic.h" #include "context.h" #include "gcc-rich-location.h" -#include "diagnostic-metadata.h" +#include "diagnostics/metadata.h" int plugin_is_GPL_compatible; @@ -89,7 +90,7 @@ check_for_named_call (gimple *stmt, return call; } -/* Exercise diagnostic_metadata. */ +/* Exercise diagnostics::metadata. */ unsigned int pass_test_metadata::execute (function *fun) @@ -106,13 +107,13 @@ pass_test_metadata::execute (function *fun) if (gcall *call = check_for_named_call (stmt, "gets", 1)) { gcc_rich_location richloc (gimple_location (call)); - diagnostic_metadata m; + diagnostics::metadata m; /* CWE-242: Use of Inherently Dangerous Function. */ m.add_cwe (242); - /* Example of a diagnostic_metadata::rule. */ - diagnostic_metadata::precanned_rule + /* Example of a diagnostics::metadata::rule. */ + diagnostics::metadata::precanned_rule test_rule ("STR34-C", "https://example.com/"); m.add_rule (test_rule); diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc index 954538f..875f4a8 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc @@ -6,6 +6,7 @@ specific tests within the compiler's IR. We can't use any real diagnostics for this, so we have to fake it, hence this plugin. */ +#define INCLUDE_VECTOR #include "gcc-plugin.h" #include "config.h" #include "system.h" @@ -32,8 +33,7 @@ #include "intl.h" #include "plugin-version.h" #include "diagnostic.h" -#include "diagnostic-path.h" -#include "diagnostic-metadata.h" +#include "diagnostics/metadata.h" #include "context.h" #include "print-tree.h" #include "gcc-rich-location.h" @@ -147,7 +147,9 @@ example_1 () { auto_diagnostic_group d; gcc_rich_location richloc (gimple_location (call_to_PyList_Append)); - simple_diagnostic_path path (global_dc->get_reference_printer ()); + tree_logical_location_manager logical_loc_mgr; + simple_diagnostic_path path (logical_loc_mgr, + global_dc->get_reference_printer ()); diagnostic_event_id_t alloc_event_id = path.add_event (gimple_location (call_to_PyList_New), example_a_fun->decl, 0, @@ -214,13 +216,14 @@ class test_diagnostic_path : public simple_diagnostic_path { public: test_diagnostic_path (pretty_printer *event_pp) - : simple_diagnostic_path (event_pp) + : simple_diagnostic_path (m_logical_loc_mgr, + event_pp) { } diagnostic_event_id_t add_event_2 (event_location_t evloc, int stack_depth, const char *desc, - diagnostic_thread_id_t thread_id = 0) + diagnostics::paths::thread_id_t thread_id = 0) { gcc_assert (evloc.m_fun); return add_thread_event (thread_id, evloc.m_loc, evloc.m_fun->decl, @@ -229,7 +232,7 @@ class test_diagnostic_path : public simple_diagnostic_path diagnostic_event_id_t add_event_2_with_event_id (event_location_t evloc, int stack_depth, const char *fmt, - diagnostic_thread_id_t thread_id, + diagnostics::paths::thread_id_t thread_id, diagnostic_event_id_t event_id) { gcc_assert (evloc.m_fun); @@ -239,7 +242,7 @@ class test_diagnostic_path : public simple_diagnostic_path } void add_entry (event_location_t evloc, int stack_depth, const char *funcname, - diagnostic_thread_id_t thread_id = 0) + diagnostics::paths::thread_id_t thread_id = 0) { gcc_assert (evloc.m_fun); add_thread_event (thread_id, evloc.m_loc, evloc.m_fun->decl, stack_depth, @@ -262,6 +265,9 @@ class test_diagnostic_path : public simple_diagnostic_path add_event (call_evloc.m_loc, call_evloc.m_fun->decl, caller_stack_depth, "calling %qs", callee); } + +private: + tree_logical_location_manager m_logical_loc_mgr; }; static void @@ -357,7 +363,7 @@ example_2 () richloc.set_path (&path); - diagnostic_metadata m; + diagnostics::metadata m; m.add_cwe (415); /* CWE-415: Double Free. */ warning_meta (&richloc, m, 0, @@ -435,7 +441,7 @@ example_3 () richloc.set_path (&path); - diagnostic_metadata m; + diagnostics::metadata m; /* CWE-479: Signal Handler Use of a Non-reentrant Function. */ m.add_cwe (479); @@ -496,8 +502,8 @@ example_4 () gcc_rich_location richloc (call_to_acquire_lock_a_in_bar.m_loc); test_diagnostic_path path (global_dc->get_reference_printer ()); - diagnostic_thread_id_t thread_1 = path.add_thread ("Thread 1"); - diagnostic_thread_id_t thread_2 = path.add_thread ("Thread 2"); + diagnostics::paths::thread_id_t thread_1 = path.add_thread ("Thread 1"); + diagnostics::paths::thread_id_t thread_2 = path.add_thread ("Thread 2"); path.add_entry (entry_to_foo, 0, "foo", thread_1); diagnostic_event_id_t event_a_acquired = path.add_event_2 (call_to_acquire_lock_a_in_foo, 1, @@ -518,7 +524,7 @@ example_4 () thread_2, event_a_acquired); richloc.set_path (&path); - diagnostic_metadata m; + diagnostics::metadata m; warning_meta (&richloc, m, 0, "deadlock due to inconsistent lock acquisition order"); } @@ -553,7 +559,7 @@ plugin_init (struct plugin_name_args *plugin_info, if (!plugin_default_version_check (version, &gcc_version)) return 1; - global_dc->m_source_printing.max_width = 80; + global_dc->get_source_printing_options ().max_width = 80; pass_info.pass = make_pass_test_show_path (g); pass_info.reference_pass_name = "whole-program"; diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc index cd3834b..92839cd 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc @@ -62,7 +62,8 @@ #include "print-tree.h" #include "gcc-rich-location.h" #include "text-range-label.h" -#include "diagnostic-format-text.h" +#include "diagnostics/text-sink.h" +#include "diagnostics/file-cache.h" int plugin_is_GPL_compatible; @@ -125,14 +126,14 @@ static bool force_show_locus_color = false; /* We want to verify the colorized output of diagnostic_show_locus, but turning on colorization for everything confuses "dg-warning" etc. Hence we special-case it within this plugin by using this modified - version of default_diagnostic_text_finalizer, which, if "color" is + version of diagnostics::default_text_finalizer, which, if "color" is passed in as a plugin argument turns on colorization, but just for diagnostic_show_locus. */ static void -custom_diagnostic_text_finalizer (diagnostic_text_output_format &text_output, - const diagnostic_info *diagnostic, - diagnostic_t) +custom_diagnostic_text_finalizer (diagnostics::text_sink &text_output, + const diagnostics::diagnostic_info *diag, + enum diagnostics::kind) { pretty_printer *const pp = text_output.get_printer (); bool old_show_color = pp_show_color (pp); @@ -143,7 +144,7 @@ custom_diagnostic_text_finalizer (diagnostic_text_output_format &text_output, pp_newline (pp); diagnostic_show_locus (&text_output.get_context (), text_output.get_source_printing_options (), - diagnostic->richloc, diagnostic->kind, pp); + diag->m_richloc, diag->m_kind, pp); pp_show_color (pp) = old_show_color; pp_set_prefix (pp, saved_prefix); pp_flush (pp); @@ -176,11 +177,11 @@ test_show_locus (function *fun) location_t fnstart = fun->function_start_locus; int fnstart_line = LOCATION_LINE (fnstart); - diagnostic_text_finalizer (global_dc) = custom_diagnostic_text_finalizer; + diagnostics::text_finalizer (global_dc) = custom_diagnostic_text_finalizer; /* Hardcode the "terminal width", to verify the behavior of very wide lines. */ - global_dc->m_source_printing.max_width = 71; + global_dc->get_source_printing_options ().max_width = 71; if (0 == strcmp (fnname, "test_simple")) { @@ -251,7 +252,7 @@ test_show_locus (function *fun) if (0 == strcmp (fnname, "test_very_wide_line")) { const int line = fnstart_line + 2; - global_dc->m_source_printing.show_ruler_p = true; + global_dc->get_source_printing_options ().show_ruler_p = true; text_range_label label0 ("label 0"); text_range_label label1 ("label 1"); rich_location richloc (line_table, @@ -263,7 +264,7 @@ test_show_locus (function *fun) &label1); richloc.add_fixit_replace ("bar * foo"); warning_at (&richloc, 0, "test"); - global_dc->m_source_printing.show_ruler_p = false; + global_dc->get_source_printing_options ().show_ruler_p = false; } /* Likewise, but with a secondary location that's immediately before @@ -271,7 +272,7 @@ test_show_locus (function *fun) if (0 == strcmp (fnname, "test_very_wide_line_2")) { const int line = fnstart_line + 2; - global_dc->m_source_printing.show_ruler_p = true; + global_dc->get_source_printing_options ().show_ruler_p = true; text_range_label label0 ("label 0"); text_range_label label1 ("label 1"); rich_location richloc (line_table, @@ -283,7 +284,7 @@ test_show_locus (function *fun) richloc.add_range (get_loc (line, 34), SHOW_RANGE_WITHOUT_CARET, &label1); warning_at (&richloc, 0, "test"); - global_dc->m_source_printing.show_ruler_p = false; + global_dc->get_source_printing_options ().show_ruler_p = false; } /* Example of multiple carets. */ @@ -294,11 +295,11 @@ test_show_locus (function *fun) location_t caret_b = get_loc (line, 11); rich_location richloc (line_table, caret_a); add_range (&richloc, caret_b, caret_b, SHOW_RANGE_WITH_CARET); - global_dc->m_source_printing.caret_chars[0] = 'A'; - global_dc->m_source_printing.caret_chars[1] = 'B'; + global_dc->get_source_printing_options ().caret_chars[0] = 'A'; + global_dc->get_source_printing_options ().caret_chars[1] = 'B'; warning_at (&richloc, 0, "test"); - global_dc->m_source_printing.caret_chars[0] = '^'; - global_dc->m_source_printing.caret_chars[1] = '^'; + global_dc->get_source_printing_options ().caret_chars[0] = '^'; + global_dc->get_source_printing_options ().caret_chars[1] = '^'; } /* Tests of rendering fixit hints. */ @@ -412,11 +413,11 @@ test_show_locus (function *fun) location_t caret_b = get_loc (line - 1, 19); rich_location richloc (line_table, caret_a); richloc.add_range (caret_b, SHOW_RANGE_WITH_CARET); - global_dc->m_source_printing.caret_chars[0] = '1'; - global_dc->m_source_printing.caret_chars[1] = '2'; + global_dc->get_source_printing_options ().caret_chars[0] = '1'; + global_dc->get_source_printing_options ().caret_chars[1] = '2'; warning_at (&richloc, 0, "test"); - global_dc->m_source_printing.caret_chars[0] = '^'; - global_dc->m_source_printing.caret_chars[1] = '^'; + global_dc->get_source_printing_options ().caret_chars[0] = '^'; + global_dc->get_source_printing_options ().caret_chars[1] = '^'; } /* Example of using the "%q+D" format code, which as well as printing @@ -443,8 +444,8 @@ test_show_locus (function *fun) rich_location richloc (line_table, loc); for (int line = start_line; line <= finish_line; line++) { - file_cache &fc = global_dc->get_file_cache (); - char_span content = fc.get_source_line (file, line); + diagnostics::file_cache &fc = global_dc->get_file_cache (); + diagnostics::char_span content = fc.get_source_line (file, line); gcc_assert (content); /* Split line up into words. */ for (int idx = 0; idx < content.length (); idx++) @@ -464,7 +465,8 @@ test_show_locus (function *fun) richloc.add_range (word, SHOW_RANGE_WITH_CARET, &label); /* Add a fixit, converting to upper case. */ - char_span word_span = content.subspan (start_idx, idx - start_idx); + diagnostics::char_span word_span + = content.subspan (start_idx, idx - start_idx); char *copy = word_span.xstrdup (); for (char *ch = copy; *ch; ch++) *ch = TOUPPER (*ch); diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.cc index 1b5fad2..b64d60f 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.cc +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.cc @@ -208,7 +208,7 @@ plugin_init (struct plugin_name_args *plugin_info, if (!plugin_default_version_check (version, &gcc_version)) return 1; - global_dc->m_source_printing.max_width = 80; + global_dc->get_source_printing_options ().max_width = 80; pass_info.pass = new pass_test_string_literals (g); pass_info.reference_pass_name = "ssa"; diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_text_art.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_text_art.cc index e28d697..ce2f1d3 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_text_art.cc +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_text_art.cc @@ -9,7 +9,7 @@ #include "coretypes.h" #include "plugin-version.h" #include "diagnostic.h" -#include "diagnostic-diagram.h" +#include "diagnostics/diagram.h" #include "text-art/canvas.h" #include "text-art/table.h" @@ -22,7 +22,7 @@ using namespace text_art; static void emit_canvas (const canvas &c, const char *alt_text) { - diagnostic_diagram diagram (c, alt_text); + diagnostics::diagram diagram (c, alt_text); global_dc->emit_diagram (diagram); } diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.cc index fbdb2f8..bbd0faa 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.cc +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.cc @@ -89,7 +89,7 @@ plugin_init (struct plugin_name_args *plugin_info, if (!plugin_default_version_check (version, &gcc_version)) return 1; - global_dc->m_source_printing.max_width = 130; + global_dc->get_source_printing_options ().max_width = 130; register_callback (plugin_name, PLUGIN_PRE_GENERICIZE, diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc deleted file mode 100644 index 2ce267c..0000000 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc +++ /dev/null @@ -1,986 +0,0 @@ -/* Verify that we can write a non-trivial diagnostic output format - as a plugin (XHTML). - Copyright (C) 2018-2024 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" -#define INCLUDE_LIST -#define INCLUDE_MAP -#define INCLUDE_MEMORY -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "diagnostic.h" -#include "diagnostic-metadata.h" -#include "diagnostic-path.h" -#include "cpplib.h" -#include "logical-location.h" -#include "diagnostic-client-data-hooks.h" -#include "diagnostic-diagram.h" -#include "text-art/canvas.h" -#include "diagnostic-format.h" -#include "diagnostic-buffer.h" -#include "ordered-hash-map.h" -#include "sbitmap.h" -#include "make-unique.h" -#include "selftest.h" -#include "selftest-diagnostic.h" -#include "selftest-diagnostic-show-locus.h" -#include "text-range-label.h" -#include "pretty-print-format-impl.h" -#include "pretty-print-urlifier.h" -#include "intl.h" -#include "gcc-plugin.h" -#include "plugin-version.h" - -namespace xml { - -/* Disable warnings about quoting issues in the pp_xxx calls below - that (intentionally) don't follow GCC diagnostic conventions. */ -#if __GNUC__ >= 10 -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wformat-diag" -#endif - -static void write_escaped_text (const char *text); - -struct node -{ - virtual ~node () {} - virtual void write_as_xml (pretty_printer *pp, - int depth, bool indent) const = 0; - void dump (FILE *out) const; - void DEBUG_FUNCTION dump () const { dump (stderr); } -}; - -struct text : public node -{ - text (label_text str) - : m_str (std::move (str)) - {} - - void write_as_xml (pretty_printer *pp, - int depth, bool indent) const final override; - - label_text m_str; -}; - -struct node_with_children : public node -{ - void add_child (std::unique_ptr<node> node); - void add_text (label_text str); - - std::vector<std::unique_ptr<node>> m_children; -}; - -struct document : public node_with_children -{ - void write_as_xml (pretty_printer *pp, - int depth, bool indent) const final override; -}; - -struct element : public node_with_children -{ - element (const char *kind, bool preserve_whitespace) - : m_kind (kind), - m_preserve_whitespace (preserve_whitespace) - {} - - void write_as_xml (pretty_printer *pp, - int depth, bool indent) const final override; - - void set_attr (const char *name, label_text value); - - const char *m_kind; - bool m_preserve_whitespace; - std::map<const char *, label_text> m_attributes; -}; - -/* Implementation. */ - -static void -write_escaped_text (pretty_printer *pp, const char *text) -{ - gcc_assert (text); - - for (const char *p = text; *p; ++p) - { - char ch = *p; - switch (ch) - { - default: - pp_character (pp, ch); - break; - case '\'': - pp_string (pp, "'"); - break; - case '"': - pp_string (pp, """); - break; - case '&': - pp_string (pp, "&"); - break; - case '<': - pp_string (pp, "<"); - break; - case '>': - pp_string (pp, ">"); - break; - } - } -} - -/* struct node. */ - -void -node::dump (FILE *out) const -{ - pretty_printer pp; - pp.set_output_stream (out); - write_as_xml (&pp, 0, true); - pp_flush (&pp); -} - -/* struct text : public node. */ - -void -text::write_as_xml (pretty_printer *pp, int /*depth*/, bool /*indent*/) const -{ - write_escaped_text (pp, m_str.get ()); -} - -/* struct node_with_children : public node. */ - -void -node_with_children::add_child (std::unique_ptr<node> node) -{ - gcc_assert (node.get ()); - m_children.push_back (std::move (node)); -} - -void -node_with_children::add_text (label_text str) -{ - gcc_assert (str.get ()); - add_child (::make_unique <text> (std::move (str))); -} - - -/* struct document : public node_with_children. */ - -void -document::write_as_xml (pretty_printer *pp, int depth, bool indent) const -{ - pp_string (pp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); - pp_string (pp, "<!DOCTYPE html\n" - " PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n" - " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"); - for (auto &iter : m_children) - iter->write_as_xml (pp, depth, indent); -} - -/* struct element : public node_with_children. */ - -void -element::write_as_xml (pretty_printer *pp, int depth, bool indent) const -{ - if (indent) - { - pp_newline (pp); - for (int i = 0; i < depth; ++i) - pp_string (pp, " "); - } - - if (m_preserve_whitespace) - indent = false; - - pp_printf (pp, "<%s", m_kind); - for (auto &attr : m_attributes) - { - pp_printf (pp, " %s=\"", attr.first); - write_escaped_text (pp, attr.second.get ()); - pp_string (pp, "\""); - } - if (m_children.empty ()) - pp_string (pp, " />"); - else - { - pp_string (pp, ">"); - for (auto &child : m_children) - child->write_as_xml (pp, depth + 1, indent); - if (indent) - { - pp_newline (pp); - for (int i = 0; i < depth; ++i) - pp_string (pp, " "); - } - pp_printf (pp, "</%s>", m_kind); - } -} - -void -element::set_attr (const char *name, label_text value) -{ - m_attributes[name] = std::move (value); -} - -#if __GNUC__ >= 10 -# pragma GCC diagnostic pop -#endif - -} // namespace xml - -class xhtml_builder; - -/* Concrete buffering implementation subclass for HTML output. */ - -class diagnostic_xhtml_format_buffer : public diagnostic_per_format_buffer -{ -public: - friend class xhtml_builder; - friend class xhtml_output_format; - - diagnostic_xhtml_format_buffer (xhtml_builder &builder) - : m_builder (builder) - {} - - void dump (FILE *out, int indent) const final override; - bool empty_p () const final override; - void move_to (diagnostic_per_format_buffer &dest) final override; - void clear () final override; - void flush () final override; - - void add_result (std::unique_ptr<xml::element> result) - { - m_results.push_back (std::move (result)); - } - -private: - xhtml_builder &m_builder; - std::vector<std::unique_ptr<xml::element>> m_results; -}; - -/* A class for managing XHTML output of diagnostics. - - Implemented: - - message text - - Known limitations/missing functionality: - - title for page - - file/line/column - - error vs warning - - CWEs - - rules - - fix-it hints - - paths -*/ - -class xhtml_builder -{ -public: - friend class diagnostic_xhtml_format_buffer; - - xhtml_builder (diagnostic_context &context, - pretty_printer &pp, - const line_maps *line_maps); - - void on_report_diagnostic (const diagnostic_info &diagnostic, - diagnostic_t orig_diag_kind, - diagnostic_xhtml_format_buffer *buffer); - void emit_diagram (const diagnostic_diagram &diagram); - void end_group (); - - std::unique_ptr<xml::element> take_current_diagnostic () - { - return std::move (m_cur_diagnostic_element); - } - - void flush_to_file (FILE *outf); - - const xml::document &get_document () const { return *m_document; } - - void set_printer (pretty_printer &pp) - { - m_printer = &pp; - } - -private: - std::unique_ptr<xml::element> - make_element_for_diagnostic (const diagnostic_info &diagnostic, - diagnostic_t orig_diag_kind); - - diagnostic_context &m_context; - pretty_printer *m_printer; - const line_maps *m_line_maps; - - std::unique_ptr<xml::document> m_document; - xml::element *m_diagnostics_element; - std::unique_ptr<xml::element> m_cur_diagnostic_element; -}; - -static std::unique_ptr<xml::element> -make_div (label_text class_) -{ - auto div = ::make_unique<xml::element> ("div", false); - div->set_attr ("class", std::move (class_)); - return div; -} - -static std::unique_ptr<xml::element> -make_span (label_text class_) -{ - auto span = ::make_unique<xml::element> ("span", true); - span->set_attr ("class", std::move (class_)); - return span; -} - -/* class diagnostic_xhtml_format_buffer : public diagnostic_per_format_buffer. */ - -void -diagnostic_xhtml_format_buffer::dump (FILE *out, int indent) const -{ - fprintf (out, "%*sdiagnostic_xhtml_format_buffer:\n", indent, ""); - int idx = 0; - for (auto &result : m_results) - { - fprintf (out, "%*sresult[%i]:\n", indent + 2, "", idx); - result->dump (out); - fprintf (out, "\n"); - ++idx; - } -} - -bool -diagnostic_xhtml_format_buffer::empty_p () const -{ - return m_results.empty (); -} - -void -diagnostic_xhtml_format_buffer::move_to (diagnostic_per_format_buffer &base) -{ - diagnostic_xhtml_format_buffer &dest - = static_cast<diagnostic_xhtml_format_buffer &> (base); - for (auto &&result : m_results) - dest.m_results.push_back (std::move (result)); - m_results.clear (); -} - -void -diagnostic_xhtml_format_buffer::clear () -{ - m_results.clear (); -} - -void -diagnostic_xhtml_format_buffer::flush () -{ - for (auto &&result : m_results) - m_builder.m_diagnostics_element->add_child (std::move (result)); - m_results.clear (); -} - -/* class xhtml_builder. */ - -/* xhtml_builder's ctor. */ - -xhtml_builder::xhtml_builder (diagnostic_context &context, - pretty_printer &pp, - const line_maps *line_maps) -: m_context (context), - m_printer (&pp), - m_line_maps (line_maps) -{ - gcc_assert (m_line_maps); - - m_document = ::make_unique<xml::document> (); - { - auto html_element = ::make_unique<xml::element> ("html", false); - html_element->set_attr - ("xmlns", - label_text::borrow ("http://www.w3.org/1999/xhtml")); - { - { - auto head_element = ::make_unique<xml::element> ("head", false); - { - auto title_element = ::make_unique<xml::element> ("title", true); - label_text title (label_text::borrow ("Title goes here")); // TODO - title_element->add_text (std::move (title)); - head_element->add_child (std::move (title_element)); - } - html_element->add_child (std::move (head_element)); - - auto body_element = ::make_unique<xml::element> ("body", false); - { - auto diagnostics_element - = make_div (label_text::borrow ("gcc-diagnostic-list")); - m_diagnostics_element = diagnostics_element.get (); - body_element->add_child (std::move (diagnostics_element)); - } - html_element->add_child (std::move (body_element)); - } - } - m_document->add_child (std::move (html_element)); - } -} - -/* Implementation of "on_report_diagnostic" for XHTML output. */ - -void -xhtml_builder::on_report_diagnostic (const diagnostic_info &diagnostic, - diagnostic_t orig_diag_kind, - diagnostic_xhtml_format_buffer *buffer) -{ - if (diagnostic.kind == DK_ICE || diagnostic.kind == DK_ICE_NOBT) - { - /* Print a header for the remaining output to stderr, and - return, attempting to print the usual ICE messages to - stderr. Hopefully this will be helpful to the user in - indicating what's gone wrong (also for DejaGnu, for pruning - those messages). */ - fnotice (stderr, "Internal compiler error:\n"); - } - - auto diag_element - = make_element_for_diagnostic (diagnostic, orig_diag_kind); - if (buffer) - { - gcc_assert (!m_cur_diagnostic_element); - buffer->m_results.push_back (std::move (diag_element)); - } - else - { - if (m_cur_diagnostic_element) - /* Nested diagnostic. */ - m_cur_diagnostic_element->add_child (std::move (diag_element)); - else - /* Top-level diagnostic. */ - m_cur_diagnostic_element = std::move (diag_element); - } -} - -std::unique_ptr<xml::element> -xhtml_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, - diagnostic_t orig_diag_kind) -{ - class xhtml_token_printer : public token_printer - { - public: - xhtml_token_printer (xhtml_builder &builder, - xml::element &parent_element) - : m_builder (builder) - { - m_open_elements.push_back (&parent_element); - } - void print_tokens (pretty_printer */*pp*/, - const pp_token_list &tokens) final override - { - /* Implement print_tokens by adding child elements to - m_parent_element. */ - for (auto iter = tokens.m_first; iter; iter = iter->m_next) - switch (iter->m_kind) - { - default: - gcc_unreachable (); - - case pp_token::kind::text: - { - pp_token_text *sub = as_a <pp_token_text *> (iter); - /* The value might be in the obstack, so we may need to - copy it. */ - insertion_element ().add_text - (label_text::take (xstrdup (sub->m_value.get ()))); - } - break; - - case pp_token::kind::begin_color: - case pp_token::kind::end_color: - /* These are no-ops. */ - break; - - case pp_token::kind::begin_quote: - { - insertion_element ().add_text (label_text::borrow (open_quote)); - push_element (make_span (label_text::borrow ("gcc-quoted-text"))); - } - break; - case pp_token::kind::end_quote: - { - pop_element (); - insertion_element ().add_text (label_text::borrow (close_quote)); - } - break; - - case pp_token::kind::begin_url: - { - pp_token_begin_url *sub = as_a <pp_token_begin_url *> (iter); - auto anchor = ::make_unique<xml::element> ("a", true); - anchor->set_attr ("href", std::move (sub->m_value)); - push_element (std::move (anchor)); - } - break; - case pp_token::kind::end_url: - pop_element (); - break; - } - } - - private: - xml::element &insertion_element () const - { - return *m_open_elements.back (); - } - void push_element (std::unique_ptr<xml::element> new_element) - { - xml::element ¤t_top = insertion_element (); - m_open_elements.push_back (new_element.get ()); - current_top.add_child (std::move (new_element)); - } - void pop_element () - { - m_open_elements.pop_back (); - } - - xhtml_builder &m_builder; - /* We maintain a stack of currently "open" elements. - Children are added to the topmost open element. */ - std::vector<xml::element *> m_open_elements; - }; - - auto diag_element = make_div (label_text::borrow ("gcc-diagnostic")); - - // TODO: might be nice to emulate the text output format, but colorize it - - auto message_span = make_span (label_text::borrow ("gcc-message")); - xhtml_token_printer tok_printer (*this, *message_span.get ()); - m_printer->set_token_printer (&tok_printer); - pp_output_formatted_text (m_printer, m_context.get_urlifier ()); - m_printer->set_token_printer (nullptr); - pp_clear_output_area (m_printer); - diag_element->add_child (std::move (message_span)); - - if (diagnostic.metadata) - { - int cwe = diagnostic.metadata->get_cwe (); - if (cwe) - { - diag_element->add_text (label_text::borrow (" ")); - auto cwe_span = make_span (label_text::borrow ("gcc-cwe-metadata")); - cwe_span->add_text (label_text::borrow ("[")); - { - auto anchor = ::make_unique<xml::element> ("a", true); - anchor->set_attr ("href", label_text::take (get_cwe_url (cwe))); - pretty_printer pp; - pp_printf (&pp, "CWE-%i", cwe); - anchor->add_text - (label_text::take (xstrdup (pp_formatted_text (&pp)))); - cwe_span->add_child (std::move (anchor)); - } - cwe_span->add_text (label_text::borrow ("]")); - diag_element->add_child (std::move (cwe_span)); - } - } - - // TODO: show any rules - - label_text option_text = label_text::take - (m_context.make_option_name (diagnostic.option_id, - orig_diag_kind, diagnostic.kind)); - if (option_text.get ()) - { - label_text option_url = label_text::take - (m_context.make_option_url (diagnostic.option_id)); - - diag_element->add_text (label_text::borrow (" ")); - auto option_span = make_span (label_text::borrow ("gcc-option")); - option_span->add_text (label_text::borrow ("[")); - { - if (option_url.get ()) - { - auto anchor = ::make_unique<xml::element> ("a", true); - anchor->set_attr ("href", std::move (option_url)); - anchor->add_text (std::move (option_text)); - option_span->add_child (std::move (anchor)); - } - else - option_span->add_text (std::move (option_text)); - option_span->add_text (label_text::borrow ("]")); - } - diag_element->add_child (std::move (option_span)); - } - - { - auto pre = ::make_unique<xml::element> ("pre", true); - pre->set_attr ("class", label_text::borrow ("gcc-annotated-source")); - // TODO: ideally we'd like to capture elements within the following: - diagnostic_show_locus (&m_context, m_context.m_source_printing, - diagnostic.richloc, diagnostic.kind, - m_printer); - pre->add_text - (label_text::take (xstrdup (pp_formatted_text (m_printer)))); - pp_clear_output_area (m_printer); - diag_element->add_child (std::move (pre)); - } - - return diag_element; -} - -/* Implementation of diagnostic_context::m_diagrams.m_emission_cb - for XHTML output. */ - -void -xhtml_builder::emit_diagram (const diagnostic_diagram &/*diagram*/) -{ - /* We must be within the emission of a top-level diagnostic. */ - gcc_assert (m_cur_diagnostic_element); - - // TODO -} - -/* Implementation of "end_group_cb" for XHTML output. */ - -void -xhtml_builder::end_group () -{ - if (m_cur_diagnostic_element) - m_diagnostics_element->add_child (std::move (m_cur_diagnostic_element)); -} - -/* Create a top-level object, and add it to all the results - (and other entities) we've seen so far. - - Flush it all to OUTF. */ - -void -xhtml_builder::flush_to_file (FILE *outf) -{ - auto top = m_document.get (); - top->dump (outf); - fprintf (outf, "\n"); -} - -class xhtml_output_format : public diagnostic_output_format -{ -public: - ~xhtml_output_format () - { - /* Any diagnostics should have been handled by now. - If not, then something's gone wrong with diagnostic - groupings. */ - std::unique_ptr<xml::element> pending_diag - = m_builder.take_current_diagnostic (); - gcc_assert (!pending_diag); - } - - void dump (FILE *out, int indent) const override - { - fprintf (out, "%*sxhtml_output_format\n", indent, ""); - diagnostic_output_format::dump (out, indent); - } - - std::unique_ptr<diagnostic_per_format_buffer> - make_per_format_buffer () final override - { - return ::make_unique<diagnostic_xhtml_format_buffer> (m_builder); - } - void set_buffer (diagnostic_per_format_buffer *base_buffer) final override - { - diagnostic_xhtml_format_buffer *buffer - = static_cast<diagnostic_xhtml_format_buffer *> (base_buffer); - m_buffer = buffer; - } - - void on_begin_group () final override - { - /* No-op, */ - } - void on_end_group () final override - { - m_builder.end_group (); - } - void - on_report_diagnostic (const diagnostic_info &diagnostic, - diagnostic_t orig_diag_kind) final override - { - m_builder.on_report_diagnostic (diagnostic, orig_diag_kind, m_buffer); - } - void on_diagram (const diagnostic_diagram &diagram) final override - { - m_builder.emit_diagram (diagram); - } - void after_diagnostic (const diagnostic_info &) - { - /* No-op, but perhaps could show paths here. */ - } - bool follows_reference_printer_p () const final override - { - return false; - } - void update_printer () final override - { - m_printer = m_context.clone_printer (); - - /* Don't colorize the text. */ - pp_show_color (m_printer.get ()) = false; - - /* No textual URLs. */ - m_printer->set_url_format (URL_FORMAT_NONE); - - /* Update the builder to use the new printer. */ - m_builder.set_printer (*get_printer ()); - } - - const xml::document &get_document () const - { - return m_builder.get_document (); - } - -protected: - xhtml_output_format (diagnostic_context &context, - const line_maps *line_maps) - : diagnostic_output_format (context), - m_builder (context, *get_printer (), line_maps), - m_buffer (nullptr) - {} - - xhtml_builder m_builder; - diagnostic_xhtml_format_buffer *m_buffer; -}; - -class xhtml_stream_output_format : public xhtml_output_format -{ -public: - xhtml_stream_output_format (diagnostic_context &context, - const line_maps *line_maps, - FILE *stream) - : xhtml_output_format (context, line_maps), - m_stream (stream) - { - } - ~xhtml_stream_output_format () - { - m_builder.flush_to_file (m_stream); - } - bool machine_readable_stderr_p () const final override - { - return m_stream == stderr; - } -private: - FILE *m_stream; -}; - -class xhtml_file_output_format : public xhtml_output_format -{ -public: - xhtml_file_output_format (diagnostic_context &context, - const line_maps *line_maps, - const char *base_file_name) - : xhtml_output_format (context, line_maps), - m_base_file_name (xstrdup (base_file_name)) - { - } - ~xhtml_file_output_format () - { - char *filename = concat (m_base_file_name, ".xhtml", nullptr); - free (m_base_file_name); - m_base_file_name = nullptr; - FILE *outf = fopen (filename, "w"); - if (!outf) - { - const char *errstr = xstrerror (errno); - fnotice (stderr, "error: unable to open '%s' for writing: %s\n", - filename, errstr); - free (filename); - return; - } - m_builder.flush_to_file (outf); - fclose (outf); - free (filename); - } - bool machine_readable_stderr_p () const final override - { - return false; - } - -private: - char *m_base_file_name; -}; - -/* Populate CONTEXT in preparation for XHTML output (either to stderr, or - to a file). */ - -static void -diagnostic_output_format_init_xhtml (diagnostic_context &context, - std::unique_ptr<xhtml_output_format> fmt) -{ - /* Don't colorize the text. */ - pp_show_color (fmt->get_printer ()) = false; - context.set_show_highlight_colors (false); - - context.set_output_format (std::move (fmt)); -} - -/* Populate CONTEXT in preparation for XHTML output to stderr. */ - -void -diagnostic_output_format_init_xhtml_stderr (diagnostic_context &context, - const line_maps *line_maps) -{ - gcc_assert (line_maps); - auto format = ::make_unique<xhtml_stream_output_format> (context, - line_maps, - stderr); - diagnostic_output_format_init_xhtml (context, std::move (format)); -} - -/* Populate CONTEXT in preparation for XHTML output to a file named - BASE_FILE_NAME.xhtml. */ - -void -diagnostic_output_format_init_xhtml_file (diagnostic_context &context, - const line_maps *line_maps, - const char *base_file_name) -{ - gcc_assert (line_maps); - auto format = ::make_unique<xhtml_file_output_format> (context, - line_maps, - base_file_name); - diagnostic_output_format_init_xhtml (context, std::move (format)); -} - -#if CHECKING_P - -namespace selftest { - -/* A subclass of xhtml_output_format for writing selftests. - The XML output is cached internally, rather than written - out to a file. */ - -class test_xhtml_diagnostic_context : public test_diagnostic_context -{ -public: - test_xhtml_diagnostic_context () - { - auto format = ::make_unique<xhtml_buffered_output_format> (*this, - line_table); - m_format = format.get (); // borrowed - diagnostic_output_format_init_xhtml (*this, std::move (format)); - } - - const xml::document &get_document () const - { - return m_format->get_document (); - } - -private: - class xhtml_buffered_output_format : public xhtml_output_format - { - public: - xhtml_buffered_output_format (diagnostic_context &context, - const line_maps *line_maps) - : xhtml_output_format (context, line_maps) - { - } - bool machine_readable_stderr_p () const final override - { - return true; - } - }; - - xhtml_output_format *m_format; // borrowed -}; - - /* Test of reporting a diagnostic at UNKNOWN_LOCATION to a - diagnostic_context and examining the generated XML document. - Verify various basic properties. */ - -static void -test_simple_log () -{ - test_xhtml_diagnostic_context dc; - - rich_location richloc (line_table, UNKNOWN_LOCATION); - dc.report (DK_ERROR, richloc, nullptr, 0, "this is a test: %i", 42); - - const xml::document &doc = dc.get_document (); - - pretty_printer pp; - doc.write_as_xml (&pp, 0, true); - ASSERT_STREQ - (pp_formatted_text (&pp), - ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" - "<!DOCTYPE html\n" - " PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n" - " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" - "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" - " <head>\n" - " <title>Title goes here</title>\n" - " </head>\n" - " <body>\n" - " <div class=\"gcc-diagnostic-list\">\n" - " <div class=\"gcc-diagnostic\">\n" - " <span class=\"gcc-message\">this is a test: 42</span>\n" - " <pre class=\"gcc-annotated-source\"></pre>\n" - " </div>\n" - " </div>\n" - " </body>\n" - "</html>")); -} - -/* Run all of the selftests within this file. */ - -static void -xhtml_format_selftests () -{ - test_simple_log (); -} - -} // namespace selftest - -#endif /* CHECKING_P */ - -/* Plugin hooks. */ - -int plugin_is_GPL_compatible; - -/* Entrypoint for the plugin. */ - -int -plugin_init (struct plugin_name_args *plugin_info, - struct plugin_gcc_version *version) -{ - const char *plugin_name = plugin_info->base_name; - int argc = plugin_info->argc; - struct plugin_argument *argv = plugin_info->argv; - - if (!plugin_default_version_check (version, &gcc_version)) - return 1; - - global_dc->set_output_format - (::make_unique<xhtml_stream_output_format> (*global_dc, - line_table, - stderr)); - -#if CHECKING_P - selftest::xhtml_format_selftests (); -#endif - - return 0; -} diff --git a/gcc/testsuite/gcc.dg/plugin/expensive_selftests_plugin.cc b/gcc/testsuite/gcc.dg/plugin/expensive_selftests_plugin.cc index 7b9b8d4..67722d4 100644 --- a/gcc/testsuite/gcc.dg/plugin/expensive_selftests_plugin.cc +++ b/gcc/testsuite/gcc.dg/plugin/expensive_selftests_plugin.cc @@ -6,9 +6,9 @@ #include "system.h" #include "coretypes.h" #include "diagnostic.h" -#include "edit-context.h" +#include "diagnostics/changes.h" #include "selftest.h" -#include "selftest-diagnostic.h" +#include "diagnostics/selftest-context.h" int plugin_is_GPL_compatible; @@ -47,14 +47,15 @@ static void test_richloc (rich_location *richloc) { /* Run the diagnostic and fix-it printing code. */ - test_diagnostic_context dc; - diagnostic_show_locus (&dc, dc.m_source_printing, - richloc, DK_ERROR, dc.get_reference_printer ()); + diagnostics::selftest::test_context dc; + diagnostic_show_locus (&dc, dc.get_source_printing_options (), + richloc, diagnostics::kind::error, + dc.get_reference_printer ()); /* Generate a diff. */ - edit_context ec (global_dc->get_file_cache ()); - ec.add_fixits (richloc); - char *diff = ec.generate_diff (true); + diagnostics::changes::change_set edit (global_dc->get_file_cache ()); + edit.add_fixits (richloc); + char *diff = edit.generate_diff (true); free (diff); } diff --git a/gcc/testsuite/gcc.dg/plugin/infoleak-net-ethtool-ioctl.c b/gcc/testsuite/gcc.dg/plugin/infoleak-net-ethtool-ioctl.c index 52846c4..afb4a57 100644 --- a/gcc/testsuite/gcc.dg/plugin/infoleak-net-ethtool-ioctl.c +++ b/gcc/testsuite/gcc.dg/plugin/infoleak-net-ethtool-ioctl.c @@ -11,8 +11,7 @@ typedef unsigned int __u32; typedef __s8 s8; typedef __u32 u32; enum { false = 0, true = 1 }; -typedef unsigned long __kernel_ulong_t; -typedef __kernel_ulong_t __kernel_size_t; +typedef __SIZE_TYPE__ __kernel_size_t; typedef _Bool bool; typedef __kernel_size_t size_t; diff --git a/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr116047-1.h b/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr116047-1.h new file mode 100644 index 0000000..3dd6434 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr116047-1.h @@ -0,0 +1,6 @@ + + + + +#include "location-overflow-test-pr116047-2.h" +static_assert (__LINE__ == 6, ""); diff --git a/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr116047-2.h b/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr116047-2.h new file mode 100644 index 0000000..048f715 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr116047-2.h @@ -0,0 +1 @@ +int i; diff --git a/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr116047.c b/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr116047.c new file mode 100644 index 0000000..75161fa --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr116047.c @@ -0,0 +1,5 @@ +/* PR preprocessor/116047 */ +/* { dg-do preprocess } */ +/* { dg-options "-nostdinc -std=c23 -fplugin-arg-location_overflow_plugin-value=0x4ffe0180" } */ +#include "location-overflow-test-pr116047-1.h" +/* { dg-final { scan-file location-overflow-test-pr116047.i "static_assert\[^\n\r]\*6\[^\n\r]\*== 6" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr120061-1.h b/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr120061-1.h new file mode 100644 index 0000000..ebf7704 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr120061-1.h @@ -0,0 +1,6 @@ + + + + +#include "location-overflow-test-pr120061-2.h" + diff --git a/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr120061-2.h b/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr120061-2.h new file mode 100644 index 0000000..048f715 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr120061-2.h @@ -0,0 +1 @@ +int i; diff --git a/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr120061.c b/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr120061.c new file mode 100644 index 0000000..e8e8038 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/location-overflow-test-pr120061.c @@ -0,0 +1,6 @@ +/* PR preprocessor/120061 */ +/* { dg-do preprocess } */ +/* { dg-options "-nostdinc -std=c23 -fplugin-arg-location_overflow_plugin-value=0x61000000" } */ +#include "location-overflow-test-pr120061-1.h" +static_assert (__LINE__ == 5, ""); +/* { dg-final { scan-file location-overflow-test-pr120061.i "static_assert\[^\n\r]\*5\[^\n\r]\*== 5" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/location_overflow_plugin.cc b/gcc/testsuite/gcc.dg/plugin/location_overflow_plugin.cc index f731b14..00ad870 100644 --- a/gcc/testsuite/gcc.dg/plugin/location_overflow_plugin.cc +++ b/gcc/testsuite/gcc.dg/plugin/location_overflow_plugin.cc @@ -7,7 +7,7 @@ #include "coretypes.h" #include "spellcheck.h" #include "diagnostic.h" -#include "diagnostic-format-text.h" +#include "diagnostics/text-sink.h" int plugin_is_GPL_compatible; @@ -39,12 +39,12 @@ on_pragma_registration (void */*gcc_data*/, void */*user_data*/) /* We add some extra testing during diagnostics by chaining up to the text finalizer. */ -static diagnostic_text_finalizer_fn original_text_finalizer = NULL; +static diagnostics::text_finalizer_fn original_text_finalizer = NULL; static void -verify_unpacked_ranges (diagnostic_text_output_format &text_output, - const diagnostic_info *diagnostic, - diagnostic_t orig_diag_kind) +verify_unpacked_ranges (diagnostics::text_sink &text_output, + const diagnostics::diagnostic_info *diagnostic, + enum diagnostics::kind orig_diag_kind) { /* Verify that the locations are ad-hoc, not packed. */ location_t loc = diagnostic_location (diagnostic); @@ -56,9 +56,9 @@ verify_unpacked_ranges (diagnostic_text_output_format &text_output, } static void -verify_no_columns (diagnostic_text_output_format &text_output, - const diagnostic_info *diagnostic, - diagnostic_t orig_diag_kind) +verify_no_columns (diagnostics::text_sink &text_output, + const diagnostics::diagnostic_info *diagnostic, + enum diagnostics::kind orig_diag_kind) { /* Verify that the locations have no columns. */ location_t loc = diagnostic_location (diagnostic); @@ -85,9 +85,18 @@ plugin_init (struct plugin_name_args *plugin_info, error_at (UNKNOWN_LOCATION, "missing plugin argument"); /* With 64-bit locations, the thresholds are larger, so shift the base - location argument accordingly. */ + location argument accordingly, basically remap the GCC 14 32-bit + location_t argument values to 64-bit location_t counterparts. There + is one exception for values slightly before the 32-bit location_t + LINE_MAP_MAX_LOCATION_WITH_PACKED_RANGES (0x50000000). In that case + remap them to the same amount before the 64-bit location_t + LINE_MAP_MAX_LOCATION_WITH_PACKED_RANGES - + ((location_t) 0x50000000) << 31. */ gcc_assert (sizeof (location_t) == sizeof (uint64_t)); - base_location = 1 + ((base_location - 1) << 31); + if (base_location >= 0x4f000000 && base_location <= 0x4fffffff) + base_location += (((location_t) 0x50000000) << 31) - 0x50000000; + else + base_location = 1 + ((base_location - 1) << 31); register_callback (plugin_info->base_name, PLUGIN_PRAGMAS, @@ -95,19 +104,19 @@ plugin_init (struct plugin_name_args *plugin_info, NULL); /* void *user_data */ /* Hack in additional testing, based on the exact value supplied. */ - original_text_finalizer = diagnostic_text_finalizer (global_dc); + original_text_finalizer = diagnostics::text_finalizer (global_dc); switch (base_location) { case LINE_MAP_MAX_LOCATION_WITH_PACKED_RANGES + 1: - diagnostic_text_finalizer (global_dc) = verify_unpacked_ranges; + diagnostics::text_finalizer (global_dc) = verify_unpacked_ranges; break; case LINE_MAP_MAX_LOCATION_WITH_COLS + 1: - diagnostic_text_finalizer (global_dc) = verify_no_columns; + diagnostics::text_finalizer (global_dc) = verify_no_columns; break; default: - error_at (UNKNOWN_LOCATION, "unrecognized value for plugin argument"); + break; } return 0; diff --git a/gcc/testsuite/gcc.dg/plugin/must-tail-call-2.c b/gcc/testsuite/gcc.dg/plugin/must-tail-call-2.c index d51d15c..6f65f4a 100644 --- a/gcc/testsuite/gcc.dg/plugin/must-tail-call-2.c +++ b/gcc/testsuite/gcc.dg/plugin/must-tail-call-2.c @@ -55,5 +55,5 @@ volatile fn_ptr_t fn_ptr; void test_5 (void) { - fn_ptr (); /* { dg-error "cannot tail-call: " } */ + fn_ptr (); } diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp index 90c9162..c7cc36c 100644 --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp @@ -76,8 +76,6 @@ set plugin_test_list [list \ crash-test-ice-in-header-sarif-2.1.c \ crash-test-ice-in-header-sarif-2.2.c \ crash-test-write-though-null-sarif.c } \ - { diagnostic_plugin_xhtml_format.cc \ - diagnostic-test-xhtml-1.c } \ { diagnostic_group_plugin.cc \ diagnostic-group-test-1.c } \ { diagnostic_plugin_test_show_locus.cc \ @@ -107,17 +105,24 @@ set plugin_test_list [list \ diagnostic-test-inlining-4.c } \ { diagnostic_plugin_test_metadata.cc diagnostic-test-metadata.c \ + diagnostic-test-metadata-html.c \ diagnostic-test-metadata-sarif.c } \ + { diagnostic_plugin_test_graphs.cc + diagnostic-test-graphs.c \ + diagnostic-test-graphs-html.c \ + diagnostic-test-graphs-sarif.c } \ { diagnostic_plugin_test_nesting.cc \ + diagnostic-test-nesting-show-nesting.c \ + diagnostic-test-nesting-no-show-nesting.c \ diagnostic-test-nesting-text-plain.c \ diagnostic-test-nesting-text-indented.c \ diagnostic-test-nesting-text-indented-show-levels.c \ diagnostic-test-nesting-text-indented-unicode.c \ + diagnostic-test-nesting-html.c \ diagnostic-test-nesting-sarif.c } \ { diagnostic_plugin_test_paths.cc \ diagnostic-test-paths-1.c \ diagnostic-test-paths-2.c \ - diagnostic-test-paths-3.c \ diagnostic-test-paths-4.c \ diagnostic-test-paths-5.c \ diagnostic-test-paths-multithreaded-inline-events.c \ @@ -138,7 +143,9 @@ set plugin_test_list [list \ { location_overflow_plugin.cc \ location-overflow-test-1.c \ location-overflow-test-2.c \ - location-overflow-test-pr83173.c } \ + location-overflow-test-pr83173.c \ + location-overflow-test-pr116047.c \ + location-overflow-test-pr120061.c } \ { must_tail_call_plugin.cc \ must-tail-call-1.c \ must-tail-call-2.c } \ |