-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Emit compiler diagnostics #3867
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
base: main
Are you sure you want to change the base?
Emit compiler diagnostics #3867
Conversation
Check for error,warning,note and remark in a format compatible with clang and swiftc, see: https://github.com/apple/swift/blob/main/docs/Diagnostics.md
411c1c6
to
4fbbeef
Compare
@swift-ci please smoke test |
Could you please add a test for this? |
for match in regex.matchGroups(in: output) { | ||
self.errorMessagesByTarget[parser.targetName] = (self.errorMessagesByTarget[parser.targetName] ?? []) + [match[0]] | ||
|
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.
remove deal line
} | ||
} | ||
|
||
let regex = try! RegEx(pattern: #"(error:[^\n]*)\n.*"#, options: .dotMatchesLineSeparators) |
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.
try!
safe?
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.
safe. not my line though, I just moved it
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.
Agreed, with a literal string to a RegEx, try!
is fine — it's unfortunate but if we get support for compiler-checked RegEx literals in Swift some day, it will go away.
do { | ||
let regex = try! RegEx(pattern: #"^(.*):(\d+):(\d+):\s*(error|warning|note|remark)\S?\s*(.*)$"#, options: .anchorsMatchLines) | ||
for match in regex.matchGroups(in: output) { | ||
if let filePath = try? AbsolutePath(validating: match[0]) { |
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.
should we guard for length of match? seems safer?
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'm not sure it's necessary in this case, since it comes from a RegEx created from a string literal. There will always be five matches unless there's a bug in matchGroups(in:)
. Perhaps we can assert that, but it doesn't seem as if there is any runtime condition here that could cause this to fail.
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.
Hopefully at some point Swift will have support for regular expressions where the matches can be returned as tuples so the type system knows how many there are.
desc += ":\(line)" | ||
} | ||
|
||
if let column = column { |
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.
if let column = self.column
reads better
} | ||
|
||
public var description: String { | ||
"\(self.file)\(self.line?.description.appending(" ") ?? "")" | ||
var desc = self.file.description | ||
if let line = line { |
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.
if let line = self.line
reads better
this is a nice improvement, thanks for putting the PR together @krzyzanowskim. we need a couple of tests, and one thing to confirm is this won't print errors/warnings multiple times now since I think we are printing the compiler output in L609? cc @abertelrud |
@@ -859,13 +859,24 @@ extension ObservabilityMetadata { | |||
public struct FileLocation: Equatable, CustomStringConvertible { | |||
public let file: AbsolutePath | |||
public let line: Int? | |||
public let column: Int? |
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.
Eventually I think we will want line/column ranges here (as the .dia format supports) for that's for a later PR. Just a note about the direction I think we'll end up going here.
That's a really good point — I hadn't noticed that. It does look as if the message would be emitted twice. For other IDEs I've worked on the pattern is usually to try to recognize it as a diagnostics and if that fails to just print it. Either way, a unit test would show for sure whether it's printed once or twice now. |
writing to output is parallel to diagnostics. emitting diagnostics is derived from the output as we parse the output. I use it as library and it's handy to have it in diagnostics and in the output stream. Does the SPM CLI print diagnostics too? |
Yes, it looks like the |
An alternative is to either emit diagnostic or write to the output stream, but not both? while it would work for |
Right, that doesn't seem like a great solution. Another option would be to use the new ability to associate metadata with diagnostics (this is a new feature of ObservabilityScope) to indicate that it was derived by parsing the output text. Then an observer who is printing text anyway can ignore those diagnostics, while an observer who isn't printing the text can emit them. |
It would be clearer in this case if it were the observer that printed regular output text too — I guess in this case the SwiftTool observer will have to rely no line 609 to have already emitted the output, and just not print diagnostics that are tagged as having been parsed from output text. |
lets take a step back here. @krzyzanowskim I assume in your use case are setting a |
@tomerd I use |
thanks for the additional info @krzyzanowskim, so in your case it sounds the console output is treated as optional and the diagnostics are the critical part. @abertelrud @neonichu iiuc the delegate here was designed to pipe the build-system output to the provided stream, to give users information about the build status, etc. is there any important information expected to be included in this beyond what we consider diagnostics? iow, should the entire thing be parsed(*) into diagnostics instead of being printed to the stream as-is? * with some failure mode protection in which we fall back to dumping it into the stream |
Yes, it looks to me as if it would be better to just use a single sequence of delegate calls here (and no text stream). Each line of text could really be broken into an I think the key would be to get rid of the parallel streams, either by making non-issues become info diagnostics or having separate |
I guess I didn't really answer the key question there. Yes, I think the delegate calls about starting and ending certain steps are important because it affects what clients show in terms of status. We can also model those as debug or info diagnostics (perhaps carrying specific metadata) but it seems cleaner to keep a delegate for such build events. |
So the other approach would then be to have a delegate call to handle the diagnostic in-order with the other calls, but that seems at odds with using ObservabilityScope.emit for diagnostics. |
Having looked at this a bit more, my specific suggestion for this PR is to:
That keeps all the output in order, and everything only gets reported once. I think the only change compared with what you have here would be to send each line of non-matching output as @krzyzanowskim is that something you'd be willing to take on as part of this? |
thank you for that. I wasn't sure what's the output of the discussion here was.
yes. I put it on my todo |
Yes, sorry about that — I was exploring ideas out loud, but of course that's not very helpful for the PR author.
Great, thanks! Please do ping me here if there are problems or ambiguities and I'll try to be more specific with any recommendations. |
Check for error,warning,note and remark in a format compatible with clang and swiftc, see: https://github.com/apple/swift/blob/main/docs/Diagnostics.md
Motivation:
Emit compiler diagnostics, normally redirected to output, now consumable by libSwiftPM users. https://bugs.swift.org/browse/SR-15479