diff --git a/compiler/src/dmd/json.d b/compiler/src/dmd/json.d index e2c3cf056b99..fcf2caf24a08 100644 --- a/compiler/src/dmd/json.d +++ b/compiler/src/dmd/json.d @@ -1048,7 +1048,7 @@ JsonFieldFlags tryParseJsonField(const(char)* fieldName) * buf = buffer to write to * str = string to escape and write as string literal */ -void writeEscapeJSONString(ref OutBuffer buf, const(char)[] str) +void writeEscapeJSONString(ref OutBuffer buf, const(char)[] str) nothrow { foreach (c; str) { diff --git a/compiler/src/dmd/sarif.d b/compiler/src/dmd/sarif.d index 095447b8b543..b19f2fcfbfd8 100644 --- a/compiler/src/dmd/sarif.d +++ b/compiler/src/dmd/sarif.d @@ -22,6 +22,7 @@ import core.stdc.string : strchr; import dmd.errors; import dmd.errorsink; import dmd.globals; +import dmd.json : writeEscapeJSONString; import dmd.location; import dmd.common.outbuffer; @@ -80,13 +81,21 @@ class ErrorSinkSarif : ErrorSinkCompiler "\t\t\t{\n" ~ "\t\t\t\t\"ruleId\": \"DMD-%s\",\n" ~ "\t\t\t\t\"message\": {\n" ~ - "\t\t\t\t\t\"text\": \"%s\"\n" ~ + "\t\t\t\t\t\"text\": \"", + kindStr.ptr); + writeEscapeJSONString(buf, msg[]); + buf.printf( + "\"\n" ~ "\t\t\t\t},\n" ~ "\t\t\t\t\"level\": \"%s\",\n" ~ "\t\t\t\t\"locations\": [{\n" ~ "\t\t\t\t\t\"physicalLocation\": {\n" ~ "\t\t\t\t\t\t\"artifactLocation\": {\n" ~ - "\t\t\t\t\t\t\t\"uri\": \"%.*s\"\n" ~ + "\t\t\t\t\t\t\t\"uri\": \"", + kindStr.ptr); + writeEscapeJSONString(buf, uri); + buf.printf( + "\"\n" ~ "\t\t\t\t\t\t},\n" ~ "\t\t\t\t\t\t\"region\": {\n" ~ "\t\t\t\t\t\t\t\"startLine\": %u,\n" ~ @@ -95,10 +104,6 @@ class ErrorSinkSarif : ErrorSinkCompiler "\t\t\t\t\t}\n" ~ "\t\t\t\t}]\n" ~ "\t\t\t}", - kindStr.ptr, - msg.peekChars(), - kindStr.ptr, - cast(int) uri.length, uri.ptr, loc.linnum, loc.charnum); } @@ -133,25 +138,31 @@ class ErrorSinkSarif : ErrorSinkCompiler cleanedVersion = cleanedVersion[0 .. $ - 1]; OutBuffer ob; - ob.printf( + ob.writestring( "{\n" ~ "\t\"version\": \"2.1.0\",\n" ~ "\t\"$schema\": \"https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0.json\",\n" ~ "\t\"runs\": [{\n" ~ "\t\t\"tool\": {\n" ~ "\t\t\t\"driver\": {\n" ~ - "\t\t\t\t\"name\": \"%s\",\n" ~ - "\t\t\t\t\"version\": \"%.*s\",\n" ~ + "\t\t\t\t\"name\": \""); + writeEscapeJSONString(ob, global.compileEnv.vendor); + ob.writestring( + "\",\n" ~ + "\t\t\t\t\"version\": \""); + writeEscapeJSONString(ob, cleanedVersion); + ob.writestring( + "\",\n" ~ "\t\t\t\t\"informationUri\": \"https://dlang.org/dmd.html\"\n" ~ "\t\t\t}\n" ~ "\t\t},\n" ~ "\t\t\"invocations\": [{\n" ~ - "\t\t\t\"executionSuccessful\": %s\n" ~ + "\t\t\t\"executionSuccessful\": "); + ob.writestring(executionSuccessful ? "true" : "false"); + ob.writestring( + "\n" ~ "\t\t}],\n" ~ - "\t\t\"results\": [", - global.compileEnv.vendor.ptr, - cast(int) cleanedVersion.length, cleanedVersion.ptr, - executionSuccessful ? "true".ptr : "false".ptr); + "\t\t\"results\": ["); if (resultCount > 0) { diff --git a/compiler/test/fail_compilation/sarif_test.d b/compiler/test/fail_compilation/sarif_test.d index 8dfc0a04b4b2..174f77994a57 100644 --- a/compiler/test/fail_compilation/sarif_test.d +++ b/compiler/test/fail_compilation/sarif_test.d @@ -1,4 +1,10 @@ // REQUIRED_ARGS: -verror-style=sarif +// DISABLED: win32 win64 +// Disabled on Windows: while the test runner transforms linux paths to Windows paths in test output, +// it's not aware that inside JSON strings that \ gets escaped as "\\" so it fails with diff: +// - "uri": "fail_compilation\sarif_test.d" +// + "uri": "fail_compilation\\sarif_test.d" + /* TEST_OUTPUT: --- @@ -29,7 +35,25 @@ TEST_OUTPUT: "uri": "fail_compilation/sarif_test.d" }, "region": { - "startLine": 45, + "startLine": 69, + "startColumn": 5 + } + } + }] + }, + { + "ruleId": "DMD-error", + "message": { + "text": "static assert: \"needs \"escaping\": back\\slash, tab\there, new\nline\"" + }, + "level": "error", + "locations": [{ + "physicalLocation": { + "artifactLocation": { + "uri": "fail_compilation/sarif_test.d" + }, + "region": { + "startLine": 71, "startColumn": 5 } } @@ -43,4 +67,6 @@ TEST_OUTPUT: void main() { x = 5; // Undefined variable to trigger the error + + static assert(0, "needs \"escaping\": back\\slash, tab\there, new\nline"); } diff --git a/compiler/test/fail_compilation/sarifmultiple_test.d b/compiler/test/fail_compilation/sarifmultiple_test.d deleted file mode 100644 index d8b79d5ef0d3..000000000000 --- a/compiler/test/fail_compilation/sarifmultiple_test.d +++ /dev/null @@ -1,65 +0,0 @@ -// REQUIRED_ARGS: -verror-style=sarif -/* -TEST_OUTPUT: ---- -{ - "version": "2.1.0", - "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0.json", - "runs": [{ - "tool": { - "driver": { - "name": "Digital Mars D", - "version": "$r:\d+\.\d+\.\d+$", - "informationUri": "https://dlang.org/dmd.html" - } - }, - "invocations": [{ - "executionSuccessful": false - }], - "results": [ - { - "ruleId": "DMD-error", - "message": { - "text": "undefined identifier `x`" - }, - "level": "error", - "locations": [{ - "physicalLocation": { - "artifactLocation": { - "uri": "fail_compilation/sarifmultiple_test.d" - }, - "region": { - "startLine": 63, - "startColumn": 5 - } - } - }] - }, - { - "ruleId": "DMD-error", - "message": { - "text": "undefined identifier `y`" - }, - "level": "error", - "locations": [{ - "physicalLocation": { - "artifactLocation": { - "uri": "fail_compilation/sarifmultiple_test.d" - }, - "region": { - "startLine": 64, - "startColumn": 5 - } - } - }] - } - ] - }] -} ---- -*/ - -void main() { - x = 5; // Undefined variable to trigger the error - y = 5; // Undefined variable to trigger the error -}