From 796cf5fb9273c464528eda4418412b762ff9157c Mon Sep 17 00:00:00 2001 From: royalpinto007 Date: Wed, 6 Nov 2024 23:36:23 +0530 Subject: [PATCH] feat(errors): generate sarif report on successful execution Signed-off-by: royalpinto007 fix(errors): tests dDoc, implicit conversion Signed-off-by: royalpinto007 fix(errors): implicit conversion Signed-off-by: royalpinto007 fix(errors): brace, default parameters, invert if-else Signed-off-by: royalpinto007 fix(errors): pre commit checks Signed-off-by: royalpinto007 fix(errors): arguments Signed-off-by: royalpinto007 fix(errors): va_list Signed-off-by: royalpinto007 fix(errors): imports Signed-off-by: royalpinto007 fix(errors): imports Signed-off-by: royalpinto007 fix(errors): va_list Signed-off-by: royalpinto007 fix(errors): va_list Signed-off-by: royalpinto007 --- compiler/src/dmd/errors.d | 10 +- compiler/src/dmd/main.d | 9 + compiler/src/dmd/sarif.d | 186 ++++++++++-------- compiler/test/compilable/sarif_success_test.d | 27 +++ 4 files changed, 140 insertions(+), 92 deletions(-) create mode 100644 compiler/test/compilable/sarif_success_test.d diff --git a/compiler/src/dmd/errors.d b/compiler/src/dmd/errors.d index d280331f6a6e..3c3f5e6733ae 100644 --- a/compiler/src/dmd/errors.d +++ b/compiler/src/dmd/errors.d @@ -476,7 +476,7 @@ private extern(C++) void verrorReport(const SourceLoc loc, const(char)* format, info.headerColor = Classification.error; if (global.params.v.messageStyle == MessageStyle.sarif) { - generateSarifReport(loc, format, ap, info.kind); + generateSarifReport(loc, format, ap, info.kind, false); return; } verrorPrint(format, ap, info); @@ -510,7 +510,7 @@ private extern(C++) void verrorReport(const SourceLoc loc, const(char)* format, info.headerColor = Classification.deprecation; if (global.params.v.messageStyle == MessageStyle.sarif) { - generateSarifReport(loc, format, ap, info.kind); + generateSarifReport(loc, format, ap, info.kind, false); return; } verrorPrint(format, ap, info); @@ -531,7 +531,7 @@ private extern(C++) void verrorReport(const SourceLoc loc, const(char)* format, info.headerColor = Classification.warning; if (global.params.v.messageStyle == MessageStyle.sarif) { - generateSarifReport(loc, format, ap, info.kind); + generateSarifReport(loc, format, ap, info.kind, false); return; } verrorPrint(format, ap, info); @@ -551,7 +551,7 @@ private extern(C++) void verrorReport(const SourceLoc loc, const(char)* format, info.headerColor = Classification.tip; if (global.params.v.messageStyle == MessageStyle.sarif) { - generateSarifReport(loc, format, ap, info.kind); + generateSarifReport(loc, format, ap, info.kind, false); return; } verrorPrint(format, ap, info); @@ -571,7 +571,7 @@ private extern(C++) void verrorReport(const SourceLoc loc, const(char)* format, fflush(stdout); // ensure it gets written out in case of compiler aborts if (global.params.v.messageStyle == MessageStyle.sarif) { - generateSarifReport(loc, format, ap, info.kind); + generateSarifReport(loc, format, ap, info.kind, false); return; } return; diff --git a/compiler/src/dmd/main.d b/compiler/src/dmd/main.d index 2207917b92bc..752ece66d744 100644 --- a/compiler/src/dmd/main.d +++ b/compiler/src/dmd/main.d @@ -162,6 +162,8 @@ private: private int tryMain(size_t argc, const(char)** argv, ref Param params) { import dmd.common.charactertables; + import dmd.sarif; + import core.stdc.stdarg; Strings files; Strings libmodules; @@ -172,6 +174,13 @@ private int tryMain(size_t argc, const(char)** argv, ref Param params) // If we are here then compilation has ended // gracefully as opposed to with `fatal` global.plugErrorSinks(); + + if (global.errors == 0 && global.params.v.messageStyle == MessageStyle.sarif) + { + SourceLoc defaultLoc = SourceLoc(null, 0u, 0u); + va_list[1] ap; + generateSarifReport(defaultLoc, "", &ap[0], ErrorKind.message, true); + } } target.setTargetBuildDefaults(); diff --git a/compiler/src/dmd/sarif.d b/compiler/src/dmd/sarif.d index 148ac5a3e264..61c7cfa56568 100644 --- a/compiler/src/dmd/sarif.d +++ b/compiler/src/dmd/sarif.d @@ -165,6 +165,7 @@ Params: format = A format string for constructing the error message. ap = A variable argument list used with the format string. kind = The kind of error (error, warning, deprecation, note, or message). + executionSuccessful = `true` if execution succeeded; includes an empty `results` array in the SARIF report. Throws: This function is marked as `nothrow` and does not throw exceptions. @@ -172,37 +173,8 @@ Throws: See_Also: $(LINK2 https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0.json, SARIF 2.1.0 schema) */ -void generateSarifReport(const ref SourceLoc loc, const(char)* format, va_list ap, ErrorKind kind) nothrow +void generateSarifReport(const ref SourceLoc loc, const(char)* format, va_list ap, ErrorKind kind, bool executionSuccessful) nothrow { - // Format the error message - string formattedMessage = formatErrorMessage(format, ap); - - // Map ErrorKind to SARIF levels - const(char)* level; - string ruleId; - final switch (kind) { - case ErrorKind.error: - level = "error"; - ruleId = "DMD-ERROR"; - break; - case ErrorKind.warning: - level = "warning"; - ruleId = "DMD-WARNING"; - break; - case ErrorKind.deprecation: - level = "deprecation"; - ruleId = "DMD-DEPRECATION"; - break; - case ErrorKind.tip: - level = "note"; - ruleId = "DMD-NOTE"; - break; - case ErrorKind.message: - level = "none"; - ruleId = "DMD-MESSAGE"; - break; - } - // Create an OutBuffer to store the SARIF report OutBuffer ob; ob.doindent = true; @@ -257,67 +229,107 @@ void generateSarifReport(const ref SourceLoc loc, const(char)* format, va_list a // Invocation Information ob.writestringln(`"invocations": [{`); ob.level += 1; - ob.writestringln(`"executionSuccessful": false`); + ob.writestring(`"executionSuccessful": `); + ob.writestring(executionSuccessful ? "true" : "false"); + ob.writestringln(""); ob.level -= 1; ob.writestringln("}],"); - // Results Array - ob.writestringln(`"results": [{`); - ob.level += 1; - - // Rule ID - ob.writestring(`"ruleId": "`); - ob.writestring(ruleId); - ob.writestringln(`",`); - - // Message Information - ob.writestringln(`"message": {`); - ob.level += 1; - ob.writestring(`"text": "`); - ob.writestring(formattedMessage.ptr); - ob.writestringln(`"`); - ob.level -= 1; - ob.writestringln(`},`); - - // Error Severity Level - ob.writestring(`"level": "`); - ob.writestring(level); - ob.writestringln(`",`); - - // Location Information - ob.writestringln(`"locations": [{`); - ob.level += 1; - ob.writestringln(`"physicalLocation": {`); - ob.level += 1; - - // Artifact Location - ob.writestringln(`"artifactLocation": {`); - ob.level += 1; - ob.writestring(`"uri": "`); - ob.writestring(loc.filename); - ob.writestringln(`"`); - ob.level -= 1; - ob.writestringln(`},`); - - // Region Information - ob.writestringln(`"region": {`); - ob.level += 1; - ob.writestring(`"startLine": `); - ob.printf(`%d,`, loc.linnum); - ob.writestringln(``); - ob.writestring(`"startColumn": `); - ob.printf(`%d`, loc.charnum); - ob.writestringln(``); - ob.level -= 1; - ob.writestringln(`}`); + // Empty results array for successful execution + if (executionSuccessful) + { + ob.writestringln(`"results": []`); + } + // Error information if execution was unsuccessful + else + { + // Format the error message + string formattedMessage = formatErrorMessage(format, ap); + + // Map ErrorKind to SARIF levels + const(char)* level; + string ruleId; + final switch (kind) { + case ErrorKind.error: + level = "error"; + ruleId = "DMD-ERROR"; + break; + case ErrorKind.warning: + level = "warning"; + ruleId = "DMD-WARNING"; + break; + case ErrorKind.deprecation: + level = "deprecation"; + ruleId = "DMD-DEPRECATION"; + break; + case ErrorKind.tip: + level = "note"; + ruleId = "DMD-NOTE"; + break; + case ErrorKind.message: + level = "none"; + ruleId = "DMD-MESSAGE"; + break; + } - // Close physicalLocation and locations - ob.level -= 1; - ob.writestringln(`}`); - ob.level -= 1; - ob.writestringln(`}]`); - ob.level -= 1; - ob.writestringln("}]"); + // Results Array for errors + ob.writestringln(`"results": [{`); + ob.level += 1; + + // Rule ID + ob.writestring(`"ruleId": "`); + ob.writestring(ruleId); + ob.writestringln(`",`); + + // Message Information + ob.writestringln(`"message": {`); + ob.level += 1; + ob.writestring(`"text": "`); + ob.writestring(formattedMessage.ptr); + ob.writestringln(`"`); + ob.level -= 1; + ob.writestringln("},"); + + // Error Severity Level + ob.writestring(`"level": "`); + ob.writestring(level); + ob.writestringln(`",`); + + // Location Information + ob.writestringln(`"locations": [{`); + ob.level += 1; + ob.writestringln(`"physicalLocation": {`); + ob.level += 1; + + // Artifact Location + ob.writestringln(`"artifactLocation": {`); + ob.level += 1; + ob.writestring(`"uri": "`); + ob.writestring(loc.filename); + ob.writestringln(`"`); + ob.level -= 1; + ob.writestringln("},"); + + // Region Information + ob.writestringln(`"region": {`); + ob.level += 1; + ob.writestring(`"startLine": `); + ob.printf(`%d,`, loc.linnum); + ob.writestringln(""); + ob.writestring(`"startColumn": `); + ob.printf(`%d`, loc.charnum); + ob.writestringln(""); + ob.level -= 1; + ob.writestringln("}"); + + // Close physicalLocation and locations + ob.level -= 1; + ob.writestringln("}"); + ob.level -= 1; + ob.writestringln("}]"); + ob.level -= 1; + ob.writestringln("}]"); + } // Close the run and SARIF JSON ob.level -= 1; diff --git a/compiler/test/compilable/sarif_success_test.d b/compiler/test/compilable/sarif_success_test.d new file mode 100644 index 000000000000..c3f79184e9c4 --- /dev/null +++ b/compiler/test/compilable/sarif_success_test.d @@ -0,0 +1,27 @@ +/* +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": "2.110.0", + "informationUri": "https://dlang.org/dmd.html" + } + }, + "invocations": [{ + "executionSuccessful": true + }], + "results": [] + }] +} +--- +*/ +// REQUIRED_ARGS: -verror-style=sarif + +void main() { + int x = 5; +}