Skip to content

Several improvements to diagnostics in the new parser #623

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

Merged
merged 9 commits into from
Aug 24, 2022

Conversation

ahoppen
Copy link
Member

@ahoppen ahoppen commented Aug 23, 2022

The goal of this PR is to provide the mentioned functionality above. At this point, the goal is not to review ParseDiagnosticsGenerator.swift. I know that the generator has super rough edges at the moment but before optimizing it for better ergonomics, I would like to implement a few more diagnostics to see what the common patterns are.

@ahoppen
Copy link
Member Author

ahoppen commented Aug 23, 2022

@swift-ci Please test

Package.swift Outdated
@@ -58,6 +58,10 @@ let package = Package(
"README.md"
]
),
.target(
name: "Diagnostics",
Copy link
Member

Choose a reason for hiding this comment

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

This is a very general name. How about SwiftDiagnostics, since Swift-based tooling will use it?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good idea. I changed it.

}
if let unexpectedCondition = node.body.unexpectedBeforeLeftBrace,
unexpectedCondition.tokens(withKind: .semicolon).count == 2 {
// FIXME: This is aweful. We should have a way to either get all children between two cursors in a syntax node or highlight a range from one node to another.
Copy link
Member

Choose a reason for hiding this comment

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

Ouch. Can we define a range as being all of the source between two Syntax nodes?

Copy link
Member Author

Choose a reason for hiding this comment

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

I totally agree that this is awful. The reason why I didn’t want to use a range was that that might now become a runtime error if the end node is not after the start node (or even in a different syntax tree).

As I mentioned in the PR description, I would like to implement a few more diagnostics first to find common patterns that we use in diagnostic generation before designing the entire diagnostic system. E.g. if it turns out that this is the only diagnostic that needs to highlight >3 syntax nodes, I would maybe be fine with it. Or it would certainly influence our design.

Copy link
Member Author

Choose a reason for hiding this comment

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

Basically, I would like to get this merged so I can start implementing new diagnostics on top of it.

Copy link
Member

Choose a reason for hiding this comment

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

Oh yes, let's merge and we can iterate in the tree.

@ahoppen
Copy link
Member Author

ahoppen commented Aug 24, 2022

@swift-ci Please test

@allevato
Copy link
Member

Are there plans to make the SwiftDiagnostics module its own lightweight standalone package/repository? Fundamentally, it's not really related to parsing. As the compiler is factored out into different libraries, it would be great to have a single canonical implementation of diagnostics that has all the expected support for different kinds of consumers/printers, serialization, and so forth, and everyone (including tools built on top of these libraries, like swift-format) could get those capabilities for free.

There's also the one in swift-tools-support-core, but that package is something of a grab bag that brings in a lot of other things that aren't needed for just diagnostics.

@DougGregor
Copy link
Member

Are there plans to make the SwiftDiagnostics module its own lightweight standalone package/repository? Fundamentally, it's not really related to parsing.

We do need to figure out the layering strategy here. This SwiftDiagnostics is a bit tied to Syntax nodes, so it cannot sink below SwiftSyntax unless we abstract that away.

There's also the one in swift-tools-support-core, but that package is something of a grab bag that brings in a lot of other things that aren't needed for just diagnostics.

Right, and I think we'd like to avoid a dependency on swift-tools-support-core here, because it also brings in a dependency on Foundation, which complicates the compiler build.

I suspect this does mean we need a common layer underlying these tools, which knows how to render diagnostics with varying levels of source information (file/line/column, syntax nodes, etc.), emission to the Clang diagnostic file format, etc. I'd like to understand what else might live at that layer, or whether diagnostics is enough to form its own package.

@ahoppen ahoppen merged commit 8c76dc3 into swiftlang:main Aug 24, 2022
@ahoppen ahoppen deleted the pr/diag-changes branch August 24, 2022 21:24
//===----------------------------------------------------------------------===//

import SwiftSyntax

Copy link
Contributor

Choose a reason for hiding this comment

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

IMO we want a Note (but not with that name because it's the same as severity). Notes can have messages and a possibly-empty list of changes. Diagnostics can have any numbers of notes. Ie. it's just additional information on a diagnostic.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree. Let’s add them when the need comes up.

var message: String { get }

/// See ``MessageID``.
var fixItID: MessageID { get }
Copy link
Contributor

Choose a reason for hiding this comment

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

Do these (or notes in my scheme) need IDs? Seems like clients would only ever care about the ID of the diagnostic itself.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it might be useful if clients want to hide certain fix-its or otherwise transform them. Adding IDs to things never hurts IMO.

public struct FixIt {
public enum Change {
/// Replace `oldNode` by `newNode`.
case replace(oldNode: Syntax, newNode: Syntax)
Copy link
Contributor

Choose a reason for hiding this comment

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

I suspect we'll end up needing more than this but no harm in starting with this.

Copy link
Member Author

Choose a reason for hiding this comment

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

Absolutely, that’s why I made it an enum. I’ll add more cases as uses come up.

}

public enum StaticParserFixIt: String, FixItMessage {
case moveThrowBeforeArrow = "Move 'throws' in before of '->'"
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
case moveThrowBeforeArrow = "Move 'throws' in before of '->'"
case moveThrowBeforeArrow = "Move 'throws' before '->'"

XCTAssertSingleDiagnostic(in: signature, line: 1, column: 7, message: "'throws' may only occur before '->'")
XCTAssertSingleDiagnostic(
in: signature,
line: 1, column: 7,
Copy link
Contributor

Choose a reason for hiding this comment

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

It'd be nice to add a marker equivalent to the structure tests. Maybe not as important here, I just highly dislike referencing line/col in tests in general 😅

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree. Filed #638 to track it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants