Skip to content

Commit

Permalink
feat(errors): consolidate multiple sarif reports into a single report
Browse files Browse the repository at this point in the history
Signed-off-by: royalpinto007 <[email protected]>
  • Loading branch information
royalpinto007 committed Nov 8, 2024
1 parent 7c8e8ec commit 162729c
Show file tree
Hide file tree
Showing 3 changed files with 261 additions and 22 deletions.
182 changes: 177 additions & 5 deletions compiler/src/dmd/errors.d
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,23 @@ enum ErrorKind
message,
}

/**
Represents a diagnostic message generated during compilation, such as errors, warnings, or other messages.
Params:
loc = The location in the source code where the diagnostic was generated (includes file, line, and column).
message = The text of the diagnostic message, describing the issue.
kind = The type of diagnostic, indicating whether it is an error, warning, deprecation, etc.
*/
struct Diagnostic
{
SourceLoc loc;
string message;
ErrorKind kind;
}

Diagnostic[] diagnostics; // Global array to store diagnostics

/***************************
* Error message sink for D compiler.
*/
Expand Down Expand Up @@ -101,6 +118,153 @@ class ErrorSinkCompiler : ErrorSink
verrorReport(loc, format, ap, ErrorKind.message);
va_end(ap);
}

void plugSink()
{
// Only proceed if there are collected diagnostics
if (diagnostics.length > 0)
{
OutBuffer ob;
ob.doindent = true;

// Extract and clean the version string
string toolVersion = global.versionString();
// Remove 'v' prefix if it exists
if (toolVersion.length > 0 && toolVersion[0] == 'v') {
toolVersion = toolVersion[1 .. $];
}
// Find the first non-numeric character after the version number
size_t length = toolVersion.length;
const(char)* nonNumeric = strchr(toolVersion.ptr, '-');
if (nonNumeric) {
length = cast(size_t)(nonNumeric - toolVersion.ptr);
}
string cleanedVersion = toolVersion[0 .. length];

// Build SARIF report
ob.writestringln("{");
ob.level = 1;
ob.writestringln(`"version": "2.1.0",`);
ob.writestringln(`"$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0.json",`);
ob.writestringln(`"runs": [{`);

// Tool Information
ob.level += 1;
ob.writestringln(`"tool": {`);
ob.level += 1;
ob.writestringln(`"driver": {`);
ob.level += 1;

// Write "name" field
ob.writestring(`"name": "`);
ob.writestring(global.compileEnv.vendor.ptr);
ob.writestringln(`",`);

// Write "version" field
ob.writestring(`"version": "`);
ob.writestring(cleanedVersion);
ob.writestringln(`",`);
ob.writestring(`"informationUri": "https://dlang.org/dmd.html"`);
ob.writestringln("");
ob.level -= 1;
ob.writestringln("}");
ob.level -= 1;
ob.writestringln("},");

// Invocation Information
ob.writestringln(`"invocations": [{`);
ob.level += 1;
ob.writestring(`"executionSuccessful": false`);
ob.writestringln("");
ob.level -= 1;
ob.writestringln("}],");

// Results Array
ob.writestringln(`"results": [`);
ob.level += 1;

foreach (idx, diag; diagnostics)
{
ob.writestringln("{");
ob.level += 1;

// Rule ID
ob.writestring(`"ruleId": "DMD-ERROR",`);
ob.writestringln("");

// Message Information
ob.writestringln(`"message": {`);
ob.level += 1;
ob.writestring(`"text": "`);
ob.writestring(diag.message);
ob.writestringln(`"`);
ob.level -= 1;
ob.writestringln("},");

// Error Severity Level
ob.writestring(`"level": "error",`);
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(diag.loc.filename);
ob.writestringln(`"`);
ob.level -= 1;
ob.writestringln("},");


// Region Information
ob.writestringln(`"region": {`);
ob.level += 1;
ob.writestring(`"startLine": `);
ob.printf(`%d,`, diag.loc.linnum);
ob.writestringln("");
ob.writestring(`"startColumn": `);
ob.printf(`%d`, diag.loc.charnum);
ob.writestringln("");
ob.level -= 1;
ob.writestringln("}");

// Close physicalLocation and locations
ob.level -= 1;
ob.writestringln("}");
ob.level -= 1;
ob.writestringln("}]");

// Closing brace for each diagnostic item
ob.level -= 1;
if (idx < diagnostics.length - 1) {
ob.writestringln("},");
} else {
ob.writestringln("}");
}
}

// Close results, run, and JSON document
ob.level -= 1;
ob.writestringln("]");
ob.level -= 1;
ob.writestringln("}]");
ob.level -= 1;
ob.writestringln("}");

// Print the SARIF output to stdout
const(char)* sarifOutput = ob.extractChars();
fputs(sarifOutput, stdout);
fflush(stdout);

// Clear diagnostics after generating the report
diagnostics.length = 0;
}
}
}


Expand Down Expand Up @@ -467,6 +631,14 @@ private extern(C++) void verrorReport(const Loc loc, const(char)* format, va_lis
private extern(C++) void verrorReport(const SourceLoc loc, const(char)* format, va_list ap, ErrorKind kind, const(char)* p1 = null, const(char)* p2 = null)
{
auto info = ErrorInfo(loc, kind, p1, p2);

// Buffer to hold the fully formatted message
char[1024] buffer;
int written = vsnprintf(buffer.ptr, buffer.length, format, ap);

// Handle any truncation that may have occurred
string formattedMessage = cast(string) buffer[0 .. (written < 0 ? 0 : written)].dup;

final switch (info.kind)
{
case ErrorKind.error:
Expand All @@ -476,7 +648,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, false);
diagnostics ~= Diagnostic(loc, formattedMessage, kind);
return;
}
verrorPrint(format, ap, info);
Expand Down Expand Up @@ -510,7 +682,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, false);
diagnostics ~= Diagnostic(loc, formattedMessage, kind);
return;
}
verrorPrint(format, ap, info);
Expand All @@ -531,7 +703,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, false);
diagnostics ~= Diagnostic(loc, formattedMessage, kind);
return;
}
verrorPrint(format, ap, info);
Expand All @@ -551,7 +723,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, false);
diagnostics ~= Diagnostic(loc, formattedMessage, kind);
return;
}
verrorPrint(format, ap, info);
Expand All @@ -571,7 +743,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, false);
diagnostics ~= Diagnostic(loc, formattedMessage, kind);
return;
}
return;
Expand Down
36 changes: 19 additions & 17 deletions compiler/test/fail_compilation/sarif_test.d
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,26 @@ TEST_OUTPUT:
"invocations": [{
"executionSuccessful": false
}],
"results": [{
"ruleId": "DMD-ERROR",
"message": {
"text": "undefined identifier `x`"
},
"level": "error",
"locations": [{
"physicalLocation": {
"artifactLocation": {
"uri": "fail_compilation/sarif_test.d"
},
"region": {
"startLine": 43,
"startColumn": 5
"results": [
{
"ruleId": "DMD-ERROR",
"message": {
"text": "undefined identifier `x`"
},
"level": "error",
"locations": [{
"physicalLocation": {
"artifactLocation": {
"uri": "fail_compilation/sarif_test.d"
},
"region": {
"startLine": 45,
"startColumn": 5
}
}
}
}]
}]
}]
}
]
}]
}
---
Expand Down
65 changes: 65 additions & 0 deletions compiler/test/fail_compilation/sarifmultiple_test.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// 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
}

0 comments on commit 162729c

Please sign in to comment.