-
Notifications
You must be signed in to change notification settings - Fork 439
Add methods from RangeReplaceableCollection
to SyntaxCollection
and remove add*
methods on syntax nodes that have a collection as child
#1958
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
Conversation
@swift-ci Please test |
With swiftlang/swift-syntax#1958, `node.filter` will return a new `SyntaxCollection` that has the filtered elements removed (instead of the array it’s currently returning). Since that node has elements removed, it will have a new parent and thus all the nodes inside of it have new IDs. Use `where` after `for` to get the elements with the same IDs and just don’t iterate the elements that don’t satisfy the condition. This is also more performant because it doesn’t create an intermediate array.
@swift-ci Please test |
4635597
to
b690ece
Compare
@swift-ci Please test |
@swift-ci Please test Windows |
With swiftlang/swift-syntax#1958, `node.filter` will return a new `SyntaxCollection` that has the filtered elements removed (instead of the array it’s currently returning). Since that node has elements removed, it will have a new parent and thus all the nodes inside of it have new IDs. Use `where` after `for` to get the elements with the same IDs and just don’t iterate the elements that don’t satisfy the condition. This is also more performant because it doesn’t create an intermediate array.
b690ece
to
d069a9f
Compare
@swift-ci Please test |
@swift-ci Please test Windows |
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.
My main concern here is that many of the methods list a Big O that isn't true for our implementation. Eg. even something like append
ends up doing much more work than you'd otherwise expect (since it is constructing all parents + has to copy the elements into a new raw syntax node).
That's what all the add*
are doing today though, so while I don't think this is blocking, perhaps we should add some extra documentation in. There's also the filter
case, which we should probably make a custom implementation for.
@@ -33,6 +33,11 @@ extension SyntaxCollection { | |||
self.init(Syntax(data))! | |||
} | |||
|
|||
/// Create an empty ``SyntaCollection`` with no children. |
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.
/// Create an empty ``SyntaCollection`` with no children. | |
/// Create an empty ``SyntaxCollection`` with no children. |
d069a9f
to
fc54536
Compare
I added an overload of |
@swift-ci Please test |
@@ -33,6 +33,11 @@ extension SyntaxCollection { | |||
self.init(Syntax(data))! | |||
} | |||
|
|||
/// Create an empty ``SyntaxCollection`` with no children. | |||
public init() { | |||
self.init([]) |
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 guess this is the other downside of using RangeReplaceableCollection
. This constructor should really never be used and makes it super easy to drop the parent accidentally.
@swift-ci Please test Windows |
fc54536
to
e07c1bf
Compare
RangeReplaceableCollection
and remove add*
methods on syntax nodes that have a collection as childRangeReplaceableCollection
to SyntaxCollection
and remove add*
methods on syntax nodes that have a collection as child
e07c1bf
to
c827d90
Compare
@swift-ci Please test |
let addedElements: ArrayElementListSyntax = Array([integerLiteralElement(4)]) + array.elements | ||
XCTAssertEqual(addedElements.count, 4) | ||
// If the first collection of + doesn’t have a parent, it doesn’t really | ||
// make sense to inherit the parent from the second collection. | ||
XCTAssert(addedElements.parent?.is(ArrayExprSyntax.self) ?? false) |
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 wouldn't expect this. This is basically prepending and I think I'd want to keep the parent in that case?
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.
testPrependingElement
tests this case FWIW
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.
But that’s what it’s testing. after adding the elements, the parent should still be an ArrayExprSyntax
. Or am I misunderstanding you?
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.
That's... true 🤔 The comment seems to be suggesting the opposite doesn't it? And then I read the assert as an XCTAssertFalse
.
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, the comment was outdated…
// If the first collection of + doesn’t have a parent, it doesn’t really | ||
// make sense to inherit the parent from the second collection. | ||
XCTAssert(addedElements.parent?.is(ArrayExprSyntax.self) ?? false) | ||
} |
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.
Would be good to test the added functions too (append, insert, replace). Or update the existing ones - they all manipulate the underlying list for the most part.
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.
Added tests
Especially the `+` operators make manipulation of `SyntaxCollection` a lot easier. `SyntaxCollection` doesn’t conform to `RangeReplaceableCollection` because of two reasons: - `RangeReplaceableCollection` assumes that creating a new colleciton and adding all elements from another collection to it results in the same collection. This is not true for `SyntaxCollection` because the new collection wouldn’t have a parent. This causes eg. the default implementation of `filter` to misbehave. - It can’t make the complexity guarantees that `RangeReplaceableCollection` requires, e.g. `append` is `O(tree depth)` instead of `O(1)`. For the same reason, also remove the conformance to `MutableCollection`.
c827d90
to
744275d
Compare
@swift-ci Please test |
@swift-ci Please test Windows |
XCTAssertNotNil(newArrayElementList.child(at: 1)) | ||
XCTAssert(!newArrayElementList.child(at: 1)!.kind.isSyntaxCollection) | ||
XCTAssertEqual("\(newArrayElementList.child(at: 1)!)", "1") | ||
fileprivate func assertSyntaxCollectionManipulation( |
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.
Would it be worth adding a parent in here and then checking we still have a parent in the transformed? Or are there cases where that's not always true?
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.
That’s why I am performing all the transformations on an ArrayExprSyntax
instead of the actual collection type ArrayElementListSyntax
. That way the substructure test checks that we still have the collection anchored in a parent.
With swiftlang/swift-syntax#1958, `node.filter` will return a new `SyntaxCollection` that has the filtered elements removed (instead of the array it’s currently returning). Since that node has elements removed, it will have a new parent and thus all the nodes inside of it have new IDs. Use `where` after `for` to get the elements with the same IDs and just don’t iterate the elements that don’t satisfy the condition. This is also more performant because it doesn’t create an intermediate array.
Especially the
+
operators make manipulation ofSyntaxCollection
a lot easier.SyntaxCollection
doesn’t conform toRangeReplaceableCollection
because of two reasons:RangeReplaceableCollection
assumes that creating a new colleciton and adding all elements from another collection to it results in the same collection. This is not true forSyntaxCollection
because the new collection wouldn’t have a parent. This causes eg. the default implementation offilter
to misbehave.RangeReplaceableCollection
requires, e.g.append
isO(tree depth)
instead ofO(1)
.For the same reason, also remove the conformance to
MutableCollection
.With those operators and methods, we no longer need the
add*
methods on syntax nodes that have a syntax collection as their child.