Skip to content

Commit 162729c

Browse files
committed
feat(errors): consolidate multiple sarif reports into a single report
Signed-off-by: royalpinto007 <[email protected]>
1 parent 7c8e8ec commit 162729c

File tree

3 files changed

+261
-22
lines changed

3 files changed

+261
-22
lines changed

compiler/src/dmd/errors.d

Lines changed: 177 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,23 @@ enum ErrorKind
3737
message,
3838
}
3939

40+
/**
41+
Represents a diagnostic message generated during compilation, such as errors, warnings, or other messages.
42+
43+
Params:
44+
loc = The location in the source code where the diagnostic was generated (includes file, line, and column).
45+
message = The text of the diagnostic message, describing the issue.
46+
kind = The type of diagnostic, indicating whether it is an error, warning, deprecation, etc.
47+
*/
48+
struct Diagnostic
49+
{
50+
SourceLoc loc;
51+
string message;
52+
ErrorKind kind;
53+
}
54+
55+
Diagnostic[] diagnostics; // Global array to store diagnostics
56+
4057
/***************************
4158
* Error message sink for D compiler.
4259
*/
@@ -101,6 +118,153 @@ class ErrorSinkCompiler : ErrorSink
101118
verrorReport(loc, format, ap, ErrorKind.message);
102119
va_end(ap);
103120
}
121+
122+
void plugSink()
123+
{
124+
// Only proceed if there are collected diagnostics
125+
if (diagnostics.length > 0)
126+
{
127+
OutBuffer ob;
128+
ob.doindent = true;
129+
130+
// Extract and clean the version string
131+
string toolVersion = global.versionString();
132+
// Remove 'v' prefix if it exists
133+
if (toolVersion.length > 0 && toolVersion[0] == 'v') {
134+
toolVersion = toolVersion[1 .. $];
135+
}
136+
// Find the first non-numeric character after the version number
137+
size_t length = toolVersion.length;
138+
const(char)* nonNumeric = strchr(toolVersion.ptr, '-');
139+
if (nonNumeric) {
140+
length = cast(size_t)(nonNumeric - toolVersion.ptr);
141+
}
142+
string cleanedVersion = toolVersion[0 .. length];
143+
144+
// Build SARIF report
145+
ob.writestringln("{");
146+
ob.level = 1;
147+
ob.writestringln(`"version": "2.1.0",`);
148+
ob.writestringln(`"$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0.json",`);
149+
ob.writestringln(`"runs": [{`);
150+
151+
// Tool Information
152+
ob.level += 1;
153+
ob.writestringln(`"tool": {`);
154+
ob.level += 1;
155+
ob.writestringln(`"driver": {`);
156+
ob.level += 1;
157+
158+
// Write "name" field
159+
ob.writestring(`"name": "`);
160+
ob.writestring(global.compileEnv.vendor.ptr);
161+
ob.writestringln(`",`);
162+
163+
// Write "version" field
164+
ob.writestring(`"version": "`);
165+
ob.writestring(cleanedVersion);
166+
ob.writestringln(`",`);
167+
ob.writestring(`"informationUri": "https://dlang.org/dmd.html"`);
168+
ob.writestringln("");
169+
ob.level -= 1;
170+
ob.writestringln("}");
171+
ob.level -= 1;
172+
ob.writestringln("},");
173+
174+
// Invocation Information
175+
ob.writestringln(`"invocations": [{`);
176+
ob.level += 1;
177+
ob.writestring(`"executionSuccessful": false`);
178+
ob.writestringln("");
179+
ob.level -= 1;
180+
ob.writestringln("}],");
181+
182+
// Results Array
183+
ob.writestringln(`"results": [`);
184+
ob.level += 1;
185+
186+
foreach (idx, diag; diagnostics)
187+
{
188+
ob.writestringln("{");
189+
ob.level += 1;
190+
191+
// Rule ID
192+
ob.writestring(`"ruleId": "DMD-ERROR",`);
193+
ob.writestringln("");
194+
195+
// Message Information
196+
ob.writestringln(`"message": {`);
197+
ob.level += 1;
198+
ob.writestring(`"text": "`);
199+
ob.writestring(diag.message);
200+
ob.writestringln(`"`);
201+
ob.level -= 1;
202+
ob.writestringln("},");
203+
204+
// Error Severity Level
205+
ob.writestring(`"level": "error",`);
206+
ob.writestringln("");
207+
208+
// Location Information
209+
ob.writestringln(`"locations": [{`);
210+
ob.level += 1;
211+
ob.writestringln(`"physicalLocation": {`);
212+
ob.level += 1;
213+
214+
// Artifact Location
215+
ob.writestringln(`"artifactLocation": {`);
216+
ob.level += 1;
217+
ob.writestring(`"uri": "`);
218+
ob.writestring(diag.loc.filename);
219+
ob.writestringln(`"`);
220+
ob.level -= 1;
221+
ob.writestringln("},");
222+
223+
224+
// Region Information
225+
ob.writestringln(`"region": {`);
226+
ob.level += 1;
227+
ob.writestring(`"startLine": `);
228+
ob.printf(`%d,`, diag.loc.linnum);
229+
ob.writestringln("");
230+
ob.writestring(`"startColumn": `);
231+
ob.printf(`%d`, diag.loc.charnum);
232+
ob.writestringln("");
233+
ob.level -= 1;
234+
ob.writestringln("}");
235+
236+
// Close physicalLocation and locations
237+
ob.level -= 1;
238+
ob.writestringln("}");
239+
ob.level -= 1;
240+
ob.writestringln("}]");
241+
242+
// Closing brace for each diagnostic item
243+
ob.level -= 1;
244+
if (idx < diagnostics.length - 1) {
245+
ob.writestringln("},");
246+
} else {
247+
ob.writestringln("}");
248+
}
249+
}
250+
251+
// Close results, run, and JSON document
252+
ob.level -= 1;
253+
ob.writestringln("]");
254+
ob.level -= 1;
255+
ob.writestringln("}]");
256+
ob.level -= 1;
257+
ob.writestringln("}");
258+
259+
// Print the SARIF output to stdout
260+
const(char)* sarifOutput = ob.extractChars();
261+
fputs(sarifOutput, stdout);
262+
fflush(stdout);
263+
264+
// Clear diagnostics after generating the report
265+
diagnostics.length = 0;
266+
}
267+
}
104268
}
105269

106270

@@ -467,6 +631,14 @@ private extern(C++) void verrorReport(const Loc loc, const(char)* format, va_lis
467631
private extern(C++) void verrorReport(const SourceLoc loc, const(char)* format, va_list ap, ErrorKind kind, const(char)* p1 = null, const(char)* p2 = null)
468632
{
469633
auto info = ErrorInfo(loc, kind, p1, p2);
634+
635+
// Buffer to hold the fully formatted message
636+
char[1024] buffer;
637+
int written = vsnprintf(buffer.ptr, buffer.length, format, ap);
638+
639+
// Handle any truncation that may have occurred
640+
string formattedMessage = cast(string) buffer[0 .. (written < 0 ? 0 : written)].dup;
641+
470642
final switch (info.kind)
471643
{
472644
case ErrorKind.error:
@@ -476,7 +648,7 @@ private extern(C++) void verrorReport(const SourceLoc loc, const(char)* format,
476648
info.headerColor = Classification.error;
477649
if (global.params.v.messageStyle == MessageStyle.sarif)
478650
{
479-
generateSarifReport(loc, format, ap, info.kind, false);
651+
diagnostics ~= Diagnostic(loc, formattedMessage, kind);
480652
return;
481653
}
482654
verrorPrint(format, ap, info);
@@ -510,7 +682,7 @@ private extern(C++) void verrorReport(const SourceLoc loc, const(char)* format,
510682
info.headerColor = Classification.deprecation;
511683
if (global.params.v.messageStyle == MessageStyle.sarif)
512684
{
513-
generateSarifReport(loc, format, ap, info.kind, false);
685+
diagnostics ~= Diagnostic(loc, formattedMessage, kind);
514686
return;
515687
}
516688
verrorPrint(format, ap, info);
@@ -531,7 +703,7 @@ private extern(C++) void verrorReport(const SourceLoc loc, const(char)* format,
531703
info.headerColor = Classification.warning;
532704
if (global.params.v.messageStyle == MessageStyle.sarif)
533705
{
534-
generateSarifReport(loc, format, ap, info.kind, false);
706+
diagnostics ~= Diagnostic(loc, formattedMessage, kind);
535707
return;
536708
}
537709
verrorPrint(format, ap, info);
@@ -551,7 +723,7 @@ private extern(C++) void verrorReport(const SourceLoc loc, const(char)* format,
551723
info.headerColor = Classification.tip;
552724
if (global.params.v.messageStyle == MessageStyle.sarif)
553725
{
554-
generateSarifReport(loc, format, ap, info.kind, false);
726+
diagnostics ~= Diagnostic(loc, formattedMessage, kind);
555727
return;
556728
}
557729
verrorPrint(format, ap, info);
@@ -571,7 +743,7 @@ private extern(C++) void verrorReport(const SourceLoc loc, const(char)* format,
571743
fflush(stdout); // ensure it gets written out in case of compiler aborts
572744
if (global.params.v.messageStyle == MessageStyle.sarif)
573745
{
574-
generateSarifReport(loc, format, ap, info.kind, false);
746+
diagnostics ~= Diagnostic(loc, formattedMessage, kind);
575747
return;
576748
}
577749
return;

compiler/test/fail_compilation/sarif_test.d

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,26 @@ TEST_OUTPUT:
1616
"invocations": [{
1717
"executionSuccessful": false
1818
}],
19-
"results": [{
20-
"ruleId": "DMD-ERROR",
21-
"message": {
22-
"text": "undefined identifier `x`"
23-
},
24-
"level": "error",
25-
"locations": [{
26-
"physicalLocation": {
27-
"artifactLocation": {
28-
"uri": "fail_compilation/sarif_test.d"
29-
},
30-
"region": {
31-
"startLine": 43,
32-
"startColumn": 5
19+
"results": [
20+
{
21+
"ruleId": "DMD-ERROR",
22+
"message": {
23+
"text": "undefined identifier `x`"
24+
},
25+
"level": "error",
26+
"locations": [{
27+
"physicalLocation": {
28+
"artifactLocation": {
29+
"uri": "fail_compilation/sarif_test.d"
30+
},
31+
"region": {
32+
"startLine": 45,
33+
"startColumn": 5
34+
}
3335
}
34-
}
35-
}]
36-
}]
36+
}]
37+
}
38+
]
3739
}]
3840
}
3941
---
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// REQUIRED_ARGS: -verror-style=sarif
2+
/*
3+
TEST_OUTPUT:
4+
---
5+
{
6+
"version": "2.1.0",
7+
"$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0.json",
8+
"runs": [{
9+
"tool": {
10+
"driver": {
11+
"name": "Digital Mars D",
12+
"version": "$r:\d+\.\d+\.\d+$",
13+
"informationUri": "https://dlang.org/dmd.html"
14+
}
15+
},
16+
"invocations": [{
17+
"executionSuccessful": false
18+
}],
19+
"results": [
20+
{
21+
"ruleId": "DMD-ERROR",
22+
"message": {
23+
"text": "undefined identifier `x`"
24+
},
25+
"level": "error",
26+
"locations": [{
27+
"physicalLocation": {
28+
"artifactLocation": {
29+
"uri": "fail_compilation/sarifmultiple_test.d"
30+
},
31+
"region": {
32+
"startLine": 63,
33+
"startColumn": 5
34+
}
35+
}
36+
}]
37+
},
38+
{
39+
"ruleId": "DMD-ERROR",
40+
"message": {
41+
"text": "undefined identifier `y`"
42+
},
43+
"level": "error",
44+
"locations": [{
45+
"physicalLocation": {
46+
"artifactLocation": {
47+
"uri": "fail_compilation/sarifmultiple_test.d"
48+
},
49+
"region": {
50+
"startLine": 64,
51+
"startColumn": 5
52+
}
53+
}
54+
}]
55+
}
56+
]
57+
}]
58+
}
59+
---
60+
*/
61+
62+
void main() {
63+
x = 5; // Undefined variable to trigger the error
64+
y = 5; // Undefined variable to trigger the error
65+
}

0 commit comments

Comments
 (0)