-
Notifications
You must be signed in to change notification settings - Fork 271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add -diagnosticsFormat
command-line flag
#2363
Conversation
5d8b142
to
c9b8564
Compare
6147c97
to
6f0b6e9
Compare
Design notes: - Many compilers have this option, but it's not named consistently. Other tools use `-fdiagnostics-format=json`, `--json`, `--outputjson`, `--formatter=json`, `--format=json`, `--error-format=json`, `--output-format=json`, `--message-format=json`, etc. - Output format is one message per line. This makes it easy to parse output even if it's mixed with other non-JSON output. This is a common approach (e.g. `rustc` does this), but it's not universal (GCC groups all messages into an array). Streaming results allows clients to consume them as they come. Implementation: * `Source/Dafny/DafnyOptions.cs` (`DiagnosticsFormats`): New enum. (`DiagnosticsFormat`): Default to `PlainText`. (`ParseOption`): Recognize new `-diagnosticsFormat` flag. (`HelpBody`): Document it. * `Source/DafnyDriver/DafnyDriver.cs` (`ThreadMain`): Delay initialization of `ErrorReporter`. * `Source/Dafny/JsonDiagnostics.cs`: New file. Capture Dafny and boogie message and print them as single-line JSON objects. * `Test/cli/diagnosticsFormats.dfy`: New test. * `docs/DafnyRef/UserGuide.md`: Document `-diagnosticsFormat`.
6f0b6e9
to
1bed89b
Compare
This is a great addition to the Dafny ecosystem which will surely make Dafny more modular.
|
Done, can you give me an example of code with a RangeToken so I can test the code?
I don't think we should deviate from LSP here, but I can do it if you want.
Yep, good catch. Done.
I will look into that. |
7ba16a1
to
2ddb4a7
Compare
Done. |
Can you update the PR description? |
I changed my mind. I'd love to do that, but we don't have the data. Tokens have a UTF-16 offset, which is not very usable by clients. Until we move away from that, I don't think we should include that info in the output. |
With the example output? I can! It's also in the diff of the PR (there's a test) |
Ready for review, I think |
An UTF-16 offset? I don't think so. I have been consistently using |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few items, otherwise, great start to make Dafny become more library-friendly.
diagnosticsFormats.dfy(11,35): Related location: This is the precondition that might not hold. | ||
|
||
Dafny program verifier finished with 1 verified, 2 errors | ||
{"range":{"filename":"diagnosticsFormats.dfy","range":{"start":{"line":8,"character":0}}},"severity":2,"message":"module-level const declarations are always non-instance, so the \u0027static\u0027 keyword is not allowed here","source":"Parser","relatedInformation":[]} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To test for the "end", you have to provide the argument name /showSnippets:1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand: /showSnippets
is for showing the error in context, and we don't want to do that in JSON mode, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/showSnippets
enables Dafny to create RangeTokens instead of just Tokens.
For the JSON mode, if /showSnippets
is activated, it would be reasonable to me that we don't add the snippet as part of the error message (but we could... that could be useful), but that way we can report error using ranges.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, I understand now :) Is there a strong reason to not create RangeTokens all the time? This way we could report ranges on the command line even when /showSnippets
isn't specified, not just line-column pairs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well the only reason was that I'm too lazy (or don't think it's worth it?) to change the 1200+ files of our integration tests And it could be a breaking change (however, I don't think this would be a big deal)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, good point regarding the test files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added -showSnippets:1
to the test and documented it in UserGuide.md
diagnosticsFormats.dfy(11,35): Related location: This is the precondition that might not hold. | ||
|
||
Dafny program verifier finished with 1 verified, 2 errors | ||
{"range":{"filename":"diagnosticsFormats.dfy","range":{"start":{"line":8,"character":0}}},"severity":2,"message":"module-level const declarations are always non-instance, so the \u0027static\u0027 keyword is not allowed here","source":"Parser","relatedInformation":[]} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{"range":{"filename":"diagnosticsFormats.dfy","range":{"start":{"line":8,"character":0}}},"severity":2,"message":"module-level const declarations are always non-instance, so the \u0027static\u0027 keyword is not allowed here","source":"Parser","relatedInformation":[]} | |
{"location":{"filename":"diagnosticsFormats.dfy","range":{"start":{"line":8,"character":0}}},"severity":2,"message":"module-level const declarations are always non-instance, so the \u0027static\u0027 keyword is not allowed here","source":"Parser","relatedInformation":[]} |
I suggest we use "range" only for the start and the end, and "location" for something that holds a file name and a range, like LSP is doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, will fix, that was the intended thing and I got it wrong :'(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
Yep, strings are UTF-16 in C#, so if you use these offsets into strings in C# it will work, but it wouldn't work in other languages that use bytes or utf-8. It would be weird to leak that. |
Co-authored-by: Mikaël Mayer <[email protected]>
Co-authored-by: Mikaël Mayer <[email protected]>
But isn't "col" already leaking this information? |
😱 you're right :'( |
Done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, almost there.
@@ -74,7 +75,7 @@ record DiagnosticMessageData(MessageSource source, ErrorLevel level, IToken tok, | |||
var auxRelated = related?.SelectMany(SerializeAuxInfo) ?? Enumerable.Empty<JsonNode>(); | |||
var innerRelated = SerializeInnerTokens(tok); | |||
return new JsonObject { | |||
["range"] = SerializeToken(tok), | |||
["location"] = SerializeToken(tok), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few CI failures line 93?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job
This PR adds
-diagnosticsFormat:json
to the CLI. The output looks like this:This format is consistent with a bunch of other tools (see below). The intent is that client can look for
{
in column 0 and parse one object per such line.Design notes:
use
-fdiagnostics-format=json
,--json
,--outputjson
,--formatter=json
,--format=json
,--error-format=json
,--output-format=json
,--message-format=json
, etc.even if it's mixed with other non-JSON output. This is a common
approach (e.g.
rustc
does this), but it's not universal (GCC groups allmessages into an array). Streaming results allows clients to consume them as
they come.
Implementation:
Source/Dafny/DafnyOptions.cs
(
DiagnosticsFormats
): New enum.(
DiagnosticsFormat
): Default toPlainText
.(
ParseOption
): Recognize new-diagnosticsFormat
flag.(
HelpBody
): Document it.Source/DafnyDriver/DafnyDriver.cs
(ThreadMain): Delay initialization of
ErrorReporter
.Source/Dafny/JsonDiagnostics.cs
: New file. Capture Dafny and boogie messageand print them as single-line JSON objects.
Test/cli/diagnosticsFormats.dfy
: New test.docs/DafnyRef/UserGuide.md
: Document-diagnosticsFormat
.Closes #2084 (by adressing the underlying use case), closes #2229 (by superseding it). CC @mschlaipfer