Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a5dad01
Created errorsink implementation of JSON output messages
Iskaban10 Oct 6, 2025
eb20136
Merge branch 'dlang:master' into lsp
Iskaban10 Oct 6, 2025
4740d3e
minor change
Iskaban10 Oct 6, 2025
82be54f
Merge branch 'lsp' of https://github.com/Iskaban10/dmd into lsp
Iskaban10 Oct 6, 2025
2512d7f
Modified errorsinkjson.d
Iskaban10 Oct 12, 2025
3967911
Shifter errrosinkjson inside errorsink class and deleted errorsinkjso…
Iskaban10 Oct 15, 2025
d58c5c4
Merge branch 'lsp' of https://github.com/Iskaban10/dmd into lsp
Iskaban10 Oct 15, 2025
8253a7a
Removed errorsinkjson.d from build
Iskaban10 Oct 15, 2025
5017f40
Merge branch 'dlang:master' into lsp
Iskaban10 Oct 18, 2025
aa22e17
Updation of cli flag and errorsinklsp functions
Iskaban10 Oct 18, 2025
410200b
Merge branch 'dlang:master' into lsp
Iskaban10 Oct 18, 2025
85f5049
Rectification of params.v.messagestyle to params.v.messageStyle
Iskaban10 Oct 18, 2025
cbd064a
Removed ErrorsinkLSP and implemented custom printLSPDiagnostic in err…
Iskaban10 Oct 20, 2025
1801323
Merge branch 'dlang:master' into lsp
Iskaban10 Oct 20, 2025
dc00590
removed commented out portions in printSLPDiagnostic()
Iskaban10 Oct 20, 2025
ac8b366
Merge branch 'lsp' of https://github.com/Iskaban10/dmd into lsp
Iskaban10 Oct 20, 2025
4f77eb2
added lsp in frontend.h and removed printing of supplemental messages…
Iskaban10 Oct 21, 2025
f259384
Deletion of lines 824-826 in errors.d
Iskaban10 Oct 26, 2025
e730e1d
Deletion of 824-826 in errors.d and creation of diag_lsp.d fail-compi…
Iskaban10 Oct 26, 2025
1fb5bec
removed newline at end of diag_lsp.d in fail_compilation
Iskaban10 Oct 26, 2025
6ea6488
Merge branch 'dlang:master' into lsp
Iskaban10 Oct 27, 2025
08bf99f
added addLSPDiagnostic and gnenerateLSPReport functions in dmd
Iskaban10 Oct 27, 2025
fbb850b
Merge branch 'lsp' of https://github.com/Iskaban10/dmd into lsp
Iskaban10 Oct 27, 2025
2efad74
range parameter added to lsp
Iskaban10 Nov 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/src/dmd/cli.d
Original file line number Diff line number Diff line change
Expand Up @@ -904,14 +904,15 @@ dmd -cov -unittest myprog.d
Option("vcolumns",
"print character (column) numbers in diagnostics"
),
Option("verror-style=[digitalmars|gnu|sarif]",
Option("verror-style=[digitalmars|gnu|sarif|lsp]",
"set the style for file/line number annotations on compiler messages",
`Set the style for file/line number annotations on compiler messages,
where:
$(DL
$(DT digitalmars)$(DD 'file(line[,column]): message'. This is the default.)
$(DT gnu)$(DD 'file:line[:column]: message', conforming to the GNU standard used by gcc and clang.)
$(DT sarif)$(DD 'Generates JSON output conforming to the SARIF (Static Analysis Results Interchange Format) standard, useful for integration with tools like GitHub and other SARIF readers.')
$(DT lsp)$(DD 'Generates JSON output conforming to Language Server Protocol(LSP) standard.')
)`,
),
Option("verror-supplements=<num>",
Expand Down
158 changes: 154 additions & 4 deletions compiler/src/dmd/errors.d
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct Diagnostic
SourceLoc loc; // The location in the source code where the diagnostic was generated (includes file, line, and column).
string message; // The text of the diagnostic message, describing the issue.
ErrorKind kind; // The type of diagnostic, indicating whether it is an error, warning, deprecation, etc.
bool supplemental; // true if supplemental message
}

__gshared Diagnostic[] diagnostics = [];
Expand Down Expand Up @@ -98,11 +99,12 @@ class ErrorSinkCompiler : ErrorSink
void plugSink()
{
// Exit if there are no collected diagnostics
if (!diagnostics.length) return;

if (!diagnostics.length) return;
// Generate the SARIF report with the current diagnostics
generateSarifReport(false);

if(global.params.v.messageStyle == MessageStyle.lsp)
generateLSPArray();
else
generateSarifReport(false);
// Clear diagnostics after generating the report
diagnostics.length = 0;
}
Expand Down Expand Up @@ -562,6 +564,11 @@ private extern(C++) void vreportDiagnostic(const SourceLoc loc, const(char)* for

case ErrorKind.message:
OutBuffer tmp;
if (global.params.v.messageStyle == MessageStyle.lsp)
{
addLSPDiagnostic(info.loc,format,ap,ErrorKind.message,info.supplemental);
return;
}
writeSourceLoc(tmp, info.loc, Loc.showColumns, Loc.messageStyle);
if (tmp.length)
fprintf(stdout, "%s: ", tmp.extractChars());
Expand Down Expand Up @@ -611,7 +618,9 @@ private extern(C++) void vsupplementalDiagnostic(const SourceLoc loc, const(char
info.headerColor = Classification.gagged;
}
else
{
info.headerColor = Classification.error;
}
printDiagnostic(format, ap, info);
return;

Expand Down Expand Up @@ -651,6 +660,11 @@ private extern(C++) void vsupplementalDiagnostic(const SourceLoc loc, const(char
*/
private void printDiagnostic(const(char)* format, va_list ap, ref DiagnosticContext info)
{
if(global.params.v.messageStyle == MessageStyle.lsp)
{
addLSPDiagnostic(info.loc,format,ap,info.kind,info.supplemental);
return;
}
const(char)* header; // title of error message
if (info.supplemental)
header = " ";
Expand Down Expand Up @@ -799,6 +813,142 @@ unittest
);
}

/**
Adds a LSP diagnostic entry to the diagnostics list.

Formats a diagnostic message and appends it to the global diagnostics array, allowing errors, warnings, or other diagnostics to be captured in LSP format.

Params:
loc = The location in the source code where the diagnostic was generated (includes file, line, and column).
format = The printf-style format string for the diagnostic message.
ap = The variadic argument list containing values to format into the diagnostic message.
kind = The type of diagnostic, indicating whether it is an error, warning, deprecation, etc.
*/
private void addLSPDiagnostic(const SourceLoc loc, const(char)* format, va_list ap, ErrorKind kind, bool isSupplemental) nothrow
{
char[2048] buffer;
int written = vsnprintf(buffer.ptr, buffer.length, format, ap);

// Handle any truncation
string formattedMessage = cast(string) buffer[0 .. (written < 0 || written > buffer.length ? buffer.length : written)].dup;

// Add the Diagnostic to the global diagnostics array
diagnostics ~= Diagnostic(loc, formattedMessage, kind, isSupplemental);
}

/**
* Just print to stdout in LSP format, doesn't care about gagging.
* (format,ap) text within backticks gets syntax highlighted.
* Params:
* format = printf-style format specification
* ap = printf-style variadic arguments
* info = context of error
*/

private void printLSPDiagnostic(ref OutBuffer tmp, Diagnostic diag)
{
const(char)* severity = ""; // title of error message
if (diag.supplemental)
{
tmp.writestring("\"supplemental\":\"");
tmp.writestring(diag.message);
tmp.writestring("\"");
}
else
{
final switch (diag.kind)
{
case ErrorKind.error: severity = "Error"; break;
case ErrorKind.deprecation: severity = "Deprecation"; break;
case ErrorKind.warning: severity = "Warning"; break;
case ErrorKind.tip: severity = "Tip"; break;
case ErrorKind.message: assert(0);
}

/// Print line number
tmp.writestringln("\"range\":{");
++tmp.level;
tmp.writestring("\"start\":{\"line\":");
tmp.printf(`'%d',`,diag.loc.linnum);
tmp.writestring("\"character:\"");
tmp.printf(`'%d'`,diag.loc.charnum);
tmp.writestringln("},");
tmp.writestring("\"end\":{\"line\":");
tmp.printf(`'%d',`,diag.loc.linnum+1);
tmp.writestring("\"character:'0'\"");
tmp.writestringln("}");
--tmp.level;
tmp.writestringln("}");

/// Print diagnostic severity (i.e. errors, warnings etc.)
tmp.writestring("\"severity\":\"");
tmp.writestring(severity);
tmp.writestringln("\",");

/// Print filename
tmp.writestring("\"uri\":\"");
tmp.writestring(diag.loc.filename);
tmp.writestringln("\",");

/// Print error message
tmp.writestring("\"description\":\"");
tmp.writestring(diag.message);
tmp.writestring("\"");
}
}

/**
* Generate LSP report containing LSP objects in a diagnostic array
*/

void generateLSPArray(bool flag = false) nothrow
{
if(flag)
{
fputs("Diagnostics {}",stdout);
return;
}
OutBuffer tmp;
tmp.doindent = true;
tmp.spaces = true;
tmp.writestringln("Diagnostics [");
++tmp.level;
foreach(idx, diag; diagnostics)
{
if(!diag.supplemental)
{
tmp.writestringln("{");
++tmp.level;
}
printLSPDiagnostic(tmp,diag);
if(idx < diagnostics.length-1)
{
if(diagnostics[idx+1].supplemental)
{
tmp.writestringln(",");
}
else
{
tmp.writestringln("");
--tmp.level;
tmp.writestringln("},");
}
}
else
{
tmp.writestringln("");
--tmp.level;
tmp.writestringln("}");
}
}
--tmp.level;
tmp.writestring("]");
const(char)* LSPOutput = tmp.extractChars();
fputs(LSPOutput,stdout);
fflush(stdout); // ensure it gets written out in case of compiler aborts
}


/**
* The type of the fatal error handler
* Returns: true if error handling is done, false to do exit(EXIT_FAILURE)
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dmd/errorsink.d
Original file line number Diff line number Diff line change
Expand Up @@ -208,4 +208,5 @@ class ErrorSinkStderr : ErrorSink
}

void vdeprecationSupplemental(Loc loc, const(char)* format, va_list ap) { }
}

}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leave to newline at EOF in place

1 change: 1 addition & 0 deletions compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ enum class MessageStyle : uint8_t
digitalmars = 0u,
gnu = 1u,
sarif = 2u,
lsp = 3u,
};

struct SourceLoc final
Expand Down
3 changes: 2 additions & 1 deletion compiler/src/dmd/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ enum class MessageStyle : unsigned char
{
digitalmars, // file(line,column): message
gnu, // file:line:column: message
sarif // JSON SARIF output, see https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
sarif, // JSON SARIF output, see https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
lsp // Output errors in JSON LSP format
};

// The state of array bounds checking
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dmd/location.d
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ enum MessageStyle : ubyte
{
digitalmars, /// filename.d(line): message
gnu, /// filename.d:line: message, see https://www.gnu.org/prep/standards/html_node/Errors.html
sarif /// JSON SARIF output, see https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
sarif, /// JSON SARIF output, see https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
lsp /// JSON output in Language Server protocol format
Comment on lines +26 to +27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also you will probably have to update frontend.h with this change, see the CircleCI failure

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like this in frontend.h?

enum class MessageStyle : uint8_t
{
    digitalmars = 0u,
    gnu = 1u,
    sarif = 2u,
    lsp = 3u,
};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

}
/**
A source code location
Expand Down Expand Up @@ -228,6 +229,8 @@ void writeSourceLoc(ref OutBuffer buf,
case MessageStyle.sarif: // https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
// No formatting needed here for SARIF
break;
case MessageStyle.lsp: // lsp-style error messages
break;
}
}

Expand Down
5 changes: 5 additions & 0 deletions compiler/src/dmd/main.d
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ private int tryMain(const(char)[][] argv, out Param params)
{
generateSarifReport(true);
}

if (global.errors == 0 && global.params.v.messageStyle == MessageStyle.lsp)
{
generateLSPArray(true);
}
}

target.setTargetBuildDefaults();
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dmd/mars.d
Original file line number Diff line number Diff line change
Expand Up @@ -1114,8 +1114,11 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, out Param
case "sarif":
params.v.messageStyle = MessageStyle.sarif;
break;
case "lsp":
params.v.messageStyle = MessageStyle.lsp;
break;
default:
error("unknown error style '%.*s', must be 'digitalmars', 'gnu', or 'sarif'", cast(int) style.length, style.ptr);
error("unknown error style '%.*s', must be 'digitalmars', 'gnu', 'sarif' or 'lsp'", cast(int) style.length, style.ptr);
}
}
else if (startsWith(p + 1, "target"))
Expand Down
23 changes: 23 additions & 0 deletions compiler/test/fail_compilation/diag_lsp.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
REQUIRED_ARGS: -verror-style=lsp
TEST_OUTPUT:
---
{
"severity":"Error",
"uri":"fail_compilation/diag21979.d",
"line:":27,
"column":12,
"description":"return value `"hi"` of type `string` does not match return type `int`, and cannot be implicitly converted",
}
---
*/

int num(int a)
{
return "hi";
}
void main()
{
int ch = num(5);
writeln(ch);
}
Loading