-
Notifications
You must be signed in to change notification settings - Fork 439
Fix trivia handling in AttributeRemover
of MacroSystem
#2215
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
Fix trivia handling in AttributeRemover
of MacroSystem
#2215
Conversation
@ahoppen I think I see a simple fix that will get all these tests passing. But first, do these test cases and expected outputs look good to you? |
The tests I added exercise I did a cursory search and turned up these tests that seem to test
|
Getting a little ahead, I sketched out the fix I have in mind. With the following change, the test suite passes: diff --git a/Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift b/Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift
index f97f02b5..1198c292 100644
--- a/Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift
+++ b/Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift
@@ -397,11 +397,12 @@ private class AttributeRemover: SyntaxRewriter {
var filteredAttributes: [AttributeListSyntax.Element] = []
for case .attribute(let attribute) in node {
if attributesToRemove.contains(attribute) {
- var leadingTrivia = node.leadingTrivia
+ var leadingTrivia = attribute.leadingTrivia
if let lastNewline = leadingTrivia.pieces.lastIndex(where: { $0.isNewline }),
leadingTrivia.pieces[lastNewline...].allSatisfy(\.isWhitespace),
- node.trailingTrivia.isEmpty,
- node.nextToken(viewMode: .sourceAccurate)?.leadingTrivia.first?.isNewline ?? false
+ attribute.trailingTrivia.isEmpty//,
+ // Both before this PR and in this PR, removing `node.nextToken`/`attribute.nextToken` condition has no effect on the test suite
+// attribute.nextToken(viewMode: .sourceAccurate)?.leadingTrivia.first?.isNewline ?? false
{
// If the attribute is on its own line based on the following conditions,
// remove the newline from it so we don’t end up with an empty line
@@ -414,22 +415,25 @@ private class AttributeRemover: SyntaxRewriter {
let trailingTrivia = Trivia(pieces: attribute.trailingTrivia.drop(while: { $0.isSpaceOrTab }))
triviaToAttachToNextToken += leadingTrivia + trailingTrivia
} else {
- filteredAttributes.append(.attribute(attribute))
+ filteredAttributes.append(.attribute(prependAccumulatedTrivia(attribute)))
}
}
return AttributeListSyntax(filteredAttributes)
}
override func visit(_ token: TokenSyntax) -> TokenSyntax {
- if !triviaToAttachToNextToken.isEmpty {
- defer { triviaToAttachToNextToken = Trivia() }
- return token.with(\.leadingTrivia, triviaToAttachToNextToken + token.leadingTrivia)
- } else {
- return token
- }
+ return prependAccumulatedTrivia(token)
+ }
+
+ private func prependAccumulatedTrivia<T: SyntaxProtocol>(_ node: T) -> T {
+ guard !triviaToAttachToNextToken.isEmpty else { return node }
+
+ defer { triviaToAttachToNextToken = Trivia() }
+ return node.with(\.leadingTrivia, triviaToAttachToNextToken + node.leadingTrivia)
}
}
let diagnosticDomain: String = "SwiftSyntaxMacroExpansion"
private enum MacroApplicationError: DiagnosticMessage, Error { |
The tests look good to me and the source changes also make sense on first sight. Can you push them and then we can work from there. |
PeerMacroTests
, with failing test outputs inlineMacroSystem
Pushed! All the tests are passing, but note the caveat — I'll address that caveat Thursday evening. |
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.
Thanks. Your removal of the newline check made me realize that attributes don’t need to be separated by spaces to be valid and that we have a bug surrounding that as well. I added a suggestion of how to fix that one as well, since you’re at it.
@ahoppen Pending your feedback, I think this PR is in a pretty good spot. There are a few improvements I'd like to make/discuss:
|
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.
Fantastic job on the unit tests you've added! 🎉 It's really refreshing to see such comprehensive testing, especially in a codebase as complex as ours.
That said, I noticed there's a hefty chunk of tests focused specifically on attribute removal. Have you considered breaking these out into a separate test file? It might make it easier to navigate and maintain down the line.
On another note, free thought here: what do you think about running those attribute removal test cases directly against AttributeRemover
instead of going through the PeerMacro
? It could make the tests a bit more targeted, and might even expose some edge cases we haven't thought of.
Looking forward to your thoughts! Keep up the awesome work. 👏👏
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.
Ah, I see you've already been thinking along the same lines:
- Most tests in
PeerMacroTests
are actually focused onMacroSystem.AttributeRemover
. Should we move these to a new test file, perhaps calledAttributeRemoverTests
?MacroSystem.AttributeRemover
has become quite complex with lots of conditional logic. It might be a good idea to refactor it for better readability and to eliminate any unnecessary logic.
I'm in full agreement with moving these tests. What is more, I don't see a compelling reason to keep MacroSystem.AttributeRemover
as private
. Making it visible for testing could allow us to cover it more directly, don't you think?
As for the refactoring, it's definitely a good idea but probably in follow-up PR?
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 personally fine with either direction here - targeted testing or testing just on MacroSystem
itself. But if we go for the former, AttributeRemover
should be SPI as it shouldn't be part of the public API. We should also still keep one or two tests on MacroSystem
to ensure it's using AttributeRemover
correctly.
I disagree here. For example when reviewing code on GitHub, I don’t have the option of uncommenting the line and re-running the tests. Also, while reading the code, IMO it’s good practice to capture the intended purpose of these lines since it explains the Why in addition to the What. The purpose of the test cases is, IMO, to verify that the code works on specific examples, which is yet another level of specifying what the code does and why it does it.
Sounds good to me. Do you want to create a follow-up PR once this one is merged?
Splitting seems like a good idea to me. Like @bnbarham I don’t have a strong opinion of whether we should test
I’m always in favor of refactorings that make code easier to read. I personally don’t think there’s to be much/any unnecessary code that can be deleted in |
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.
Who would have guessed that removing an attribute could be this difficult? Thanks for your work on fixing it. I have one more functional comment. Otherwise it looks good to me.
@ahoppen I believe I've addressed your feedback. Care to take a (perhaps!) final look? Now that we're close, would you like me to squash this PR into a single commit, and annotate it with references to the GitHub and rdar issues? |
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.
Yes, this looks great. If you could squash the commits, that would be great and I’ll trigger CI.
Also, add `AttributeRemoverTests` covering a variety of attribute removal cases involving surrounding trivia. Fixes swiftlang#2203 rdar://115585919
080033a
to
c6ceed4
Compare
MacroSystem
AttributeRemover
of MacroSystem
@ahoppen Squashed. Let me know if there's anything else! |
@swift-ci Please test |
Let’s get this in 🚢 |
@swift-ci Please test Windowss |
@ahoppen Is there something in this PR that needs to be done to satisfy the Windows CI, or perhaps Windows CI is/was generally broken? |
Nothing on your side. I'll run again, though could be there's a failure that needs fixing. |
@swift-ci please test Windows platform |
@ahoppen Quick question: Do you know the release plan for this PR's changes? |
This was merged into |
Initially opened for discussion of #2203, and now a fix for it.
Also, adds
AttributeRemoverTests
covering a variety of attribute removal cases involving surrounding trivia.Fixes #2203
rdar://115585919