lookup_rule_by_id_in_component (const char *rule_id,
const json::object &tool_component_obj);
+ // "fix" object (§3.55)
+ enum status
+ handle_fix_object (libgdiagnostics::diagnostic &diag,
+ const json::object &fix_obj);
+
+ // "artifactChange" object (§3.56)
+ enum status
+ handle_artifact_change_object (libgdiagnostics::diagnostic &diag,
+ const json::object &change_obj);
+
/* Support functions. */
/* Report an error to m_control_mgr about JV violating REF,
- doesn't yet handle "taxa" property (§3.27.8)
- handling of "level" property (§3.27.10) doesn't yet support the
full logic for when "level" is absent.
- - doesn't yet handle "fixes" property (§3.27.30)
- doesn't yet support multithreaded flows (§3.36.3)
*/
}
}
+ // §3.27.30 "fixes" property
+ const property_spec_ref prop_fixes ("result", "fixes", "3.27.30");
+ if (auto fixes_arr
+ = get_optional_property<json::array> (result_obj, prop_fixes))
+ {
+ // We only support a single fix
+ if (fixes_arr->length () == 1)
+ if (auto fix_obj = require_object (*fixes_arr->get (0), prop_fixes))
+ handle_fix_object (err, *fix_obj);
+ }
+
err.finish ("%s", text.get ());
// Flush any notes
}
return status::ok;
-
}
/* If ITER_SRC starts with a placeholder as per §3.11.5, advance ITER_SRC
return nullptr;
}
+// "fix" object (§3.55)
+
+enum status
+sarif_replayer::handle_fix_object (libgdiagnostics::diagnostic &diag,
+ const json::object &fix_obj)
+{
+ const property_spec_ref changes ("fix", "artifactChanges", "3.55.3");
+ auto changes_arr = get_required_property<json::array> (fix_obj, changes);
+ if (!changes_arr)
+ return status::err_invalid_sarif;
+
+ for (auto element : *changes_arr)
+ {
+ const json::object *change_obj
+ = require_object_for_element (*element, changes);
+ if (!change_obj)
+ return status::err_invalid_sarif;
+ enum status s = handle_artifact_change_object (diag, *change_obj);
+ if (s != status::ok)
+ return s;
+ }
+ return status::ok;
+}
+
+// "artifactChange" object (§3.56)
+
+enum status
+sarif_replayer::
+handle_artifact_change_object (libgdiagnostics::diagnostic &diag,
+ const json::object &change_obj)
+{
+ const property_spec_ref location
+ ("artifactChange", "artifactLocation", "3.56.2");
+ auto artifact_loc_obj
+ = get_required_property<json::object> (change_obj, location);
+ if (!artifact_loc_obj)
+ return status::err_invalid_sarif;
+
+ libgdiagnostics::file file;
+ enum status s = handle_artifact_location_object (*artifact_loc_obj, file);
+ if (s != status::ok)
+ return s;
+
+ const property_spec_ref replacements
+ ("artifactChange", "replacements", "3.56.3");
+ auto replacements_arr
+ = get_required_property<json::array> (change_obj, replacements);
+ if (!replacements_arr)
+ return status::err_invalid_sarif;
+ for (auto element : *replacements_arr)
+ {
+ // 3.57 replacement object
+ const json::object *replacement_obj
+ = require_object_for_element (*element, replacements);
+ if (!replacement_obj)
+ return status::err_invalid_sarif;
+
+ // 3.57.3 deletedRegion property
+ const property_spec_ref deleted_region
+ ("replacement", "deletedRegion", "3.57.3");
+ auto deleted_region_obj
+ = get_required_property<json::object> (*replacement_obj,
+ deleted_region);
+ if (!deleted_region_obj)
+ return status::err_invalid_sarif;
+
+ libgdiagnostics::physical_location phys_loc;
+ enum status s = handle_region_object (*deleted_region_obj,
+ file,
+ phys_loc);
+ if (s != status::ok)
+ return s;
+
+ // 3.57.4 insertedContent property
+ const property_spec_ref inserted_content
+ ("replacement", "insertedContent", "3.57.4");
+ const char *inserted_text = "";
+ if (auto inserted_content_obj
+ = get_optional_property<json::object> (*replacement_obj,
+ inserted_content))
+ {
+ const property_spec_ref prop_text
+ ("artifactContent", "text", "3.3.2");
+ if (auto text_jstr
+ = get_optional_property<json::string> (*inserted_content_obj,
+ prop_text))
+ inserted_text = text_jstr->get_string ();
+ }
+
+ diag.add_fix_it_hint_replace (phys_loc, inserted_text);
+ }
+ return status::ok;
+}
+
} // anonymous namespace
/* Error-checking at the API boundary. */
--- /dev/null
+/* Example of GCC SARIF output for a replacement fix-it hint. */
+
+{"$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json",
+ "version": "2.1.0",
+ "runs": [{"tool": {"driver": {"name": "GNU C23",
+ "fullName": "GNU C23 (GCC) version 15.0.1 20250203 (experimental) (x86_64-pc-linux-gnu)",
+ "version": "15.0.1 20250203 (experimental)",
+ "informationUri": "https://gcc.gnu.org/gcc-15/",
+ "rules": [{"id": "-Wformat=",
+ "helpUri": "https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wformat"}]}},
+ "invocations": [{"executionSuccessful": true,
+ "toolExecutionNotifications": []}],
+ "originalUriBaseIds": {"PWD": {"uri": "file:///this/path/does/not/exist/"}},
+ "artifacts": [{"location": {"uri": "/this/path/does/not/exist/diagnostic-ranges.c",
+ "uriBaseId": "PWD"},
+ "sourceLanguage": "c",
+ "contents": {"text": "#include <stdio.h>\n\nvoid test_mismatching_types (const char *msg)\n{\n printf(\"hello %i\", msg);\n}\n"},
+ "roles": ["analysisTarget"]}],
+ "results": [{"ruleId": "-Wformat=",
+ "level": "warning",
+ "message": {"text": "format '%i' expects argument of type 'int', but argument 2 has type 'const char *'"},
+ "locations": [{"physicalLocation": {"artifactLocation": {"uri": "/this/path/does/not/exist/diagnostic-ranges.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 5,
+ "startColumn": 17,
+ "endColumn": 19},
+ "contextRegion": {"startLine": 5,
+ "snippet": {"text": " printf(\"hello %i\", msg);\n"}}},
+ "logicalLocations": [{"name": "test_mismatching_types",
+ "fullyQualifiedName": "test_mismatching_types",
+ "decoratedName": "test_mismatching_types",
+ "kind": "function"}],
+ "annotations": [{"startLine": 5,
+ "startColumn": 17,
+ "endColumn": 19,
+ "message": {"text": "int"}},
+ {"startLine": 5,
+ "startColumn": 22,
+ "endColumn": 25,
+ "message": {"text": "const char *"}}]}],
+ "fixes": [{"artifactChanges": [{"artifactLocation": {"uri": "/this/path/does/not/exist/diagnostic-ranges.c",
+ "uriBaseId": "PWD"},
+ "replacements": [{"deletedRegion": {"startLine": 5,
+ "startColumn": 17,
+ "endColumn": 19},
+ "insertedContent": {"text": "%s"}}]}]}]}]}]}
+
+/* { dg-begin-multiline-output "" }
+/this/path/does/not/exist/diagnostic-ranges.c:5:17: warning: format '%i' expects argument of type 'int', but argument 2 has type 'const char *' [-Wformat=]
+ 5 | printf("hello %i", msg);
+ | ^~ ~~~
+ | | |
+ | int const char *
+ | %s
+ { dg-end-multiline-output "" } */
--- /dev/null
+/* Example of GCC SARIF output for a deletion fix-it hint. */
+
+{"$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json",
+ "version": "2.1.0",
+ "runs": [{"tool": {"driver": {"name": "GNU C++17",
+ "fullName": "GNU C++17 (GCC) version 15.0.1 20250203 (experimental) (x86_64-pc-linux-gnu)",
+ "version": "15.0.1 20250203 (experimental)",
+ "informationUri": "https://gcc.gnu.org/gcc-15/",
+ "rules": []}},
+ "invocations": [{"executionSuccessful": false,
+ "toolExecutionNotifications": []}],
+ "artifacts": [{"location": {"uri": "t.cc",
+ "uriBaseId": "PWD"},
+ "sourceLanguage": "cplusplus",
+ "contents": {"text": "unsigned unsigned int i;\n"},
+ "roles": ["analysisTarget"]}],
+ "results": [{"ruleId": "error",
+ "level": "error",
+ "message": {"text": "duplicate 'unsigned'"},
+ "locations": [{"physicalLocation": {"artifactLocation": {"uri": "t.cc",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 1,
+ "startColumn": 10,
+ "endColumn": 18},
+ "contextRegion": {"startLine": 1,
+ "snippet": {"text": "unsigned unsigned int i;\n"}}}}],
+ "fixes": [{"artifactChanges": [{"artifactLocation": {"uri": "t.cc",
+ "uriBaseId": "PWD"},
+ "replacements": [{"deletedRegion": {"startLine": 1,
+ "startColumn": 10,
+ "endColumn": 18},
+ "insertedContent": {"text": ""}}]}]}]}]}]}
+
+/* { dg-begin-multiline-output "" }
+t.cc:1:10: error: duplicate 'unsigned'
+ 1 | unsigned unsigned int i;
+ | ^~~~~~~~
+ | --------
+ { dg-end-multiline-output "" } */
--- /dev/null
+/* Example of GCC SARIF output for an insertion fix-it hint. */
+
+{"$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json",
+ "version": "2.1.0",
+ "runs": [{"tool": {"driver": {"name": "GNU C23",
+ "fullName": "GNU C23 (GCC) version 15.0.1 20250203 (experimental) (x86_64-pc-linux-gnu)",
+ "version": "15.0.1 20250203 (experimental)",
+ "informationUri": "https://gcc.gnu.org/gcc-15/",
+ "rules": []}},
+ "invocations": [{"executionSuccessful": false,
+ "toolExecutionNotifications": []}],
+ "artifacts": [{"location": {"uri": "t.c",
+ "uriBaseId": "PWD"},
+ "sourceLanguage": "c",
+ "contents": {"text": "struct foo {};\n\nfoo *ptr;\n"},
+ "roles": ["analysisTarget"]}],
+ "results": [{"ruleId": "error",
+ "level": "error",
+ "message": {"text": "unknown type name 'foo'; use 'struct' keyword to refer to the type"},
+ "locations": [{"physicalLocation": {"artifactLocation": {"uri": "t.c",
+ "uriBaseId": "PWD"},
+ "region": {"startLine": 3,
+ "startColumn": 1,
+ "endColumn": 4},
+ "contextRegion": {"startLine": 3,
+ "snippet": {"text": "foo *ptr;\n"}}}}],
+ "fixes": [{"artifactChanges": [{"artifactLocation": {"uri": "t.c",
+ "uriBaseId": "PWD"},
+ "replacements": [{"deletedRegion": {"startLine": 3,
+ "startColumn": 1,
+ "endColumn": 1},
+ "insertedContent": {"text": "struct "}}]}]}]}]}]}
+
+/* { dg-begin-multiline-output "" }
+t.c:3:1: error: unknown type name 'foo'; use 'struct' keyword to refer to the type
+ 3 | foo *ptr;
+ | ^~~
+ | struct
+ { dg-end-multiline-output "" } */