Skip to content

Commit 67e2608

Browse files
committed
Remove superfluous code. Add an entry to the release notes. Simplify test harness. General cleanup.
1 parent b4a9b3f commit 67e2608

File tree

6 files changed

+80
-90
lines changed

6 files changed

+80
-90
lines changed

.spi.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ builder:
1212
- SwiftCompilerPlugin
1313
- SwiftDiagnostics
1414
- SwiftIDEUtils
15+
- SwiftLexicalLookup
1516
- SwiftOperators
1617
- SwiftParser
1718
- SwiftParserDiagnostics
@@ -20,6 +21,5 @@ builder:
2021
- SwiftSyntaxMacros
2122
- SwiftSyntaxMacroExpansion
2223
- SwiftSyntaxMacrosGenericTestSupport
23-
- SwiftLexicalLookup
2424
- SwiftSyntaxMacrosTestSupport
2525
custom_documentation_parameters: [--experimental-skip-synthesized-symbols]

Package.swift

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let package = Package(
1717
.library(name: "SwiftCompilerPlugin", targets: ["SwiftCompilerPlugin"]),
1818
.library(name: "SwiftDiagnostics", targets: ["SwiftDiagnostics"]),
1919
.library(name: "SwiftIDEUtils", targets: ["SwiftIDEUtils"]),
20+
.library(name: "SwiftLexicalLookup", targets: ["SwiftLexicalLookup"]),
2021
.library(name: "SwiftOperators", targets: ["SwiftOperators"]),
2122
.library(name: "SwiftParser", targets: ["SwiftParser"]),
2223
.library(name: "SwiftParserDiagnostics", targets: ["SwiftParserDiagnostics"]),
@@ -26,7 +27,6 @@ let package = Package(
2627
.library(name: "SwiftSyntaxMacros", targets: ["SwiftSyntaxMacros"]),
2728
.library(name: "SwiftSyntaxMacroExpansion", targets: ["SwiftSyntaxMacroExpansion"]),
2829
.library(name: "SwiftSyntaxMacrosTestSupport", targets: ["SwiftSyntaxMacrosTestSupport"]),
29-
.library(name: "SwiftLexicalLookup", targets: ["SwiftLexicalLookup"]),
3030
.library(name: "SwiftSyntaxMacrosGenericTestSupport", targets: ["SwiftSyntaxMacrosGenericTestSupport"]),
3131
.library(name: "_SwiftCompilerPluginMessageHandling", targets: ["SwiftCompilerPluginMessageHandling"]),
3232
.library(name: "_SwiftLibraryPluginProvider", targets: ["SwiftLibraryPluginProvider"]),
@@ -138,6 +138,18 @@ let package = Package(
138138
dependencies: ["_SwiftSyntaxTestSupport", "SwiftIDEUtils", "SwiftParser", "SwiftSyntax"]
139139
),
140140

141+
// MARK: SwiftLexicalLookup
142+
143+
.target(
144+
name: "SwiftLexicalLookup",
145+
dependencies: ["SwiftSyntax"]
146+
),
147+
148+
.testTarget(
149+
name: "SwiftLexicalLookupTest",
150+
dependencies: ["_SwiftSyntaxTestSupport", "SwiftLexicalLookup"]
151+
),
152+
141153
// MARK: SwiftLibraryPluginProvider
142154

143155
.target(
@@ -241,18 +253,6 @@ let package = Package(
241253
]
242254
),
243255

244-
// MARK: SwiftLexicalLookup
245-
246-
.target(
247-
name: "SwiftLexicalLookup",
248-
dependencies: ["SwiftSyntax"]
249-
),
250-
251-
.testTarget(
252-
name: "SwiftLexicalLookupTest",
253-
dependencies: ["_SwiftSyntaxTestSupport", "SwiftLexicalLookup"]
254-
),
255-
256256
// MARK: SwiftSyntaxMacrosGenericTestSupport
257257

258258
.target(

Release Notes/601.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
- Description: Allows retrieving the represented literal value when valid.
77
- Issue: https://github.com/apple/swift-syntax/issues/405
88
- Pull Request: https://github.com/apple/swift-syntax/pull/2605
9+
10+
- `SyntaxProtocol` now has a method `ancestorOrSelf`.
11+
- Description: Returns the node or the first ancestor that satisfies `condition`.
12+
- Pull Request: https://github.com/swiftlang/swift-syntax/pull/2696
913

1014
## API Behavior Changes
1115

Sources/SwiftLexicalLookup/SimpleLookupQueries.swift

Lines changed: 47 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import SwiftSyntax
1616
extension SyntaxProtocol {
1717
/// Returns all labeled statements available at a particular syntax node.
1818
///
19-
/// - Returns: Available labeled statements at a particular syntax node in the exact order they appear in the source code, starting with the innermost statement.
19+
/// - Returns: Available labeled statements at a particular syntax node
20+
/// in the exact order they appear in the source code, starting with the innermost statement.
2021
///
2122
/// Example usage:
2223
/// ```swift
@@ -32,15 +33,19 @@ extension SyntaxProtocol {
3233
/// break // 3
3334
/// }
3435
/// ```
35-
/// When calling this function at the first `break`, it returns `three` and `two` in this exact order. For the second `break`, it returns only `two`. The results don't include `one`, which is unavailable at both locations due to the encapsulating function body. For `break` numbered 3, the result is `one`, as it's outside the function body and within the labeled statement. The function returns an empty array when there are no available labeled statements.
36-
///
36+
/// When calling this function at the first `break`, it returns `three` and `two` in this exact order.
37+
/// For the second `break`, it returns only `two`.
38+
/// The results don't include `one`, which is unavailable at both locations due to the encapsulating function body.
39+
/// For `break` numbered 3, the result is `one`, as it's outside the function body and within the labeled statement.
40+
/// The function returns an empty array when there are no available labeled statements.
3741
@_spi(Experimental) public func lookupLabeledStmts() -> [LabeledStmtSyntax] {
38-
return lookupLabeledStmts(at: self)
42+
collectNodesOfTypeUpToFunctionBoundary(LabeledStmtSyntax.self)
3943
}
4044

4145
/// Returns the catch node responsible for handling an error thrown at a particular syntax node.
4246
///
43-
/// - Returns: The catch node responsible for handling an error thrown at the lookup source node. This could be a `do` statement, `try?`, `try!`, `init`, `deinit`, accessors, closures, or function declarations.
47+
/// - Returns: The catch node responsible for handling an error thrown at the lookup source node.
48+
/// This could be a `do` statement, `try?`, `try!`, `init`, `deinit`, accessors, closures, or function declarations.
4449
///
4550
/// Example usage:
4651
/// ```swift
@@ -53,89 +58,80 @@ extension SyntaxProtocol {
5358
/// }
5459
/// }
5560
/// ```
56-
/// When calling this function on `foo`, it returns the `do` statement. Calling the function on `bar` results in `try?`. When used on `error`, the function returns the function declaration `x`. The function returns `nil` when there's no available catch node.
57-
///
61+
/// When calling this function on `foo`, it returns the `do` statement.
62+
/// Calling the function on `bar` results in `try?`.
63+
/// When used on `error`, the function returns the function declaration `x`.
64+
/// The function returns `nil` when there's no available catch node.
5865
@_spi(Experimental) public func lookupCatchNode() -> Syntax? {
59-
return lookupCatchNodeHelper(at: Syntax(self), traversedCatchClause: false)
60-
}
61-
62-
// MARK: - lookupLabeledStmts
63-
64-
/// Given syntax node position, returns all available labeled statements.
65-
private func lookupLabeledStmts(at syntax: SyntaxProtocol) -> [LabeledStmtSyntax] {
66-
return walkParentTreeUpToFunctionBoundary(
67-
at: syntax.parent,
68-
collect: LabeledStmtSyntax.self
69-
)
66+
lookupCatchNodeHelper(traversedCatchClause: false)
7067
}
7168

7269
// MARK: - lookupCatchNode
7370

74-
/// Given syntax node location, finds where an error could be caught. If set to `true`, `traverseCatchClause`lookup will skip the next do statement.
75-
private func lookupCatchNodeHelper(at syntax: Syntax?, traversedCatchClause: Bool) -> Syntax? {
76-
guard let syntax else { return nil }
71+
/// Given syntax node location, finds where an error could be caught. If `traverseCatchClause` is set to `true` lookup will skip the next do statement.
72+
private func lookupCatchNodeHelper(traversedCatchClause: Bool) -> Syntax? {
73+
guard let parent else { return nil }
7774

78-
switch syntax.as(SyntaxEnum.self) {
75+
switch parent.as(SyntaxEnum.self) {
7976
case .doStmt:
8077
if traversedCatchClause {
81-
return lookupCatchNodeHelper(at: syntax.parent, traversedCatchClause: false)
78+
return parent.lookupCatchNodeHelper(traversedCatchClause: false)
8279
} else {
83-
return syntax
80+
return parent
8481
}
8582
case .catchClause:
86-
return lookupCatchNodeHelper(at: syntax.parent, traversedCatchClause: true)
83+
return parent.lookupCatchNodeHelper(traversedCatchClause: true)
8784
case .tryExpr(let tryExpr):
8885
if tryExpr.questionOrExclamationMark != nil {
89-
return syntax
86+
return parent
9087
} else {
91-
return lookupCatchNodeHelper(at: syntax.parent, traversedCatchClause: traversedCatchClause)
88+
return parent.lookupCatchNodeHelper(traversedCatchClause: traversedCatchClause)
9289
}
9390
case .functionDecl, .accessorDecl, .initializerDecl, .deinitializerDecl, .closureExpr:
94-
return syntax
91+
return parent
9592
case .exprList(let exprList):
9693
if let tryExpr = exprList.first?.as(TryExprSyntax.self), tryExpr.questionOrExclamationMark != nil {
9794
return Syntax(tryExpr)
9895
}
99-
return lookupCatchNodeHelper(at: syntax.parent, traversedCatchClause: traversedCatchClause)
96+
return parent.lookupCatchNodeHelper(traversedCatchClause: traversedCatchClause)
10097
default:
101-
return lookupCatchNodeHelper(at: syntax.parent, traversedCatchClause: traversedCatchClause)
98+
return parent.lookupCatchNodeHelper(traversedCatchClause: traversedCatchClause)
10299
}
103100
}
104101

105102
// MARK: - walkParentTree helper methods
106103

107-
/// Callect the first syntax node matching the collection type up to a function boundary.
108-
fileprivate func walkParentTreeUpToFunctionBoundary<T: SyntaxProtocol>(
109-
at syntax: Syntax?,
110-
collect: T.Type
104+
/// Returns the innermost node of the specified type up to a function boundary.
105+
fileprivate func innermostNodeOfTypeUpToFunctionBoundary<T: SyntaxProtocol>(
106+
_ type: T.Type
111107
) -> T? {
112-
walkParentTreeUpToFunctionBoundary(at: syntax, collect: collect, stopWithFirstMatch: true).first
108+
collectNodesOfTypeUpToFunctionBoundary(type, stopWithFirstMatch: true).first
113109
}
114110

115-
/// Callect syntax nodes matching the collection type up to a function boundary.
116-
fileprivate func walkParentTreeUpToFunctionBoundary<T: SyntaxProtocol>(
117-
at syntax: Syntax?,
118-
collect: T.Type,
111+
/// Collect syntax nodes matching the collection type up until encountering one of the specified syntax nodes. The nodes in the array are inside out, with the innermost node being the first.
112+
fileprivate func collectNodesOfTypeUpToFunctionBoundary<T: SyntaxProtocol>(
113+
_ type: T.Type,
119114
stopWithFirstMatch: Bool = false
120115
) -> [T] {
121-
walkParentTree(
116+
collectNodes(
117+
ofType: type,
122118
upTo: [
123119
MemberBlockSyntax.self,
124120
FunctionDeclSyntax.self,
125121
InitializerDeclSyntax.self,
126122
DeinitializerDeclSyntax.self,
127123
AccessorDeclSyntax.self,
128124
ClosureExprSyntax.self,
125+
SubscriptDeclSyntax.self,
129126
],
130-
collect: collect,
131127
stopWithFirstMatch: stopWithFirstMatch
132128
)
133129
}
134130

135131
/// Callect syntax nodes matching the collection type up until encountering one of the specified syntax nodes.
136-
private func walkParentTree<T: SyntaxProtocol>(
132+
private func collectNodes<T: SyntaxProtocol>(
133+
ofType type: T.Type,
137134
upTo stopAt: [SyntaxProtocol.Type],
138-
collect: T.Type,
139135
stopWithFirstMatch: Bool = false
140136
) -> [T] {
141137
var matches: [T] = []
@@ -162,7 +158,8 @@ extension SyntaxProtocol {
162158
extension FallThroughStmtSyntax {
163159
/// Returns the source and destination of a `fallthrough`.
164160
///
165-
/// - Returns: `source` as the switch case that encapsulates the `fallthrough` keyword and `destination` as the switch case that the `fallthrough` directs to.
161+
/// - Returns: `source` as the switch case that encapsulates the `fallthrough` keyword and
162+
/// `destination` as the switch case that the `fallthrough` directs to.
166163
///
167164
/// Example usage:
168165
/// ```swift
@@ -176,26 +173,15 @@ extension FallThroughStmtSyntax {
176173
/// break
177174
/// }
178175
/// ```
179-
/// When calling this function at the `fallthrough`, it returns `case 2` and `case 1` in this exact order. The `nil` results handle ill-formed code: there's no `source` if the `fallthrough` is outside of a case. There's no `destination` if there is no case or `default` after the source case.
180-
///
181-
@_spi(Experimental) public func lookupFallthroughSourceAndDest()
176+
/// When calling this function at the `fallthrough`, it returns `case 2` and `case 1` in this exact order.
177+
/// The `nil` results handle ill-formed code: there's no `source` if the `fallthrough` is outside of a case.
178+
/// There's no `destination` if there is no case or `default` after the source case.
179+
@_spi(Experimental) public func lookupFallthroughSourceAndDestintation()
182180
-> (source: SwitchCaseSyntax?, destination: SwitchCaseSyntax?)
183-
{
184-
return lookupFallthroughSourceAndDestination(at: self)
185-
}
186-
187-
// MARK: - lookupFallthroughSourceAndDest
188-
189-
/// Given syntax node position, returns the current switch case and it's fallthrough destination.
190-
private func lookupFallthroughSourceAndDestination(
191-
at syntax: SyntaxProtocol
192-
)
193-
-> (SwitchCaseSyntax?, SwitchCaseSyntax?)
194181
{
195182
guard
196-
let originalSwitchCase = walkParentTreeUpToFunctionBoundary(
197-
at: Syntax(syntax),
198-
collect: SwitchCaseSyntax.self
183+
let originalSwitchCase = innermostNodeOfTypeUpToFunctionBoundary(
184+
SwitchCaseSyntax.self
199185
)
200186
else {
201187
return (nil, nil)

Tests/SwiftLexicalLookupTest/Assertions.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,10 @@ import SwiftSyntax
1717
import XCTest
1818
import _SwiftSyntaxTestSupport
1919

20-
/// Parse `source` and check if the method passed as `methodUnderTest` produces the same results as indicated in `expected`.
21-
///
22-
/// The `methodUnderTest` provides test inputs taken from the `expected` dictionary. The closure should return result produced by the tested method as an array with the same ordering.
23-
///
24-
/// - Parameters:
25-
/// - methodUnderTest: Closure with the tested method. Provides test argument from `expected` to the tested function. Should return method result as an array.
26-
/// - expected: A dictionary with parameter markers as keys and expected results as marker arrays ordered as returned by the test method.
20+
/// `methodUnderTest` is called with the token at every position marker in the keys of `expected`. It then asserts that the positions of the syntax nodes returned by `methodUnderTest` are the values in `expected`.
2721
func assertLexicalScopeQuery(
2822
source: String,
29-
methodUnderTest: (SyntaxProtocol) -> ([SyntaxProtocol?]),
23+
methodUnderTest: (TokenSyntax) -> ([SyntaxProtocol?]),
3024
expected: [String: [String?]]
3125
) {
3226
// Extract markers
@@ -50,17 +44,16 @@ func assertLexicalScopeQuery(
5044
let result = methodUnderTest(testArgument)
5145

5246
// Extract the expected results for the test argument
53-
let expectedValues: [SyntaxProtocol?] = expectedMarkers.map { expectedMarker in
47+
let expectedValues: [AbsolutePosition?] = expectedMarkers.map { expectedMarker in
5448
guard let expectedMarker else { return nil }
5549

56-
guard let expectedPosition = markerDict[expectedMarker],
57-
let expectedToken = sourceFileSyntax.token(at: AbsolutePosition(utf8Offset: expectedPosition))
50+
guard let expectedPosition = markerDict[expectedMarker]
5851
else {
5952
XCTFail("Could not find token at location \(marker)")
6053
return nil
6154
}
6255

63-
return expectedToken
56+
return AbsolutePosition(utf8Offset: expectedPosition)
6457
}
6558

6659
// Compare number of actual results to the number of expected results
@@ -74,9 +67,16 @@ func assertLexicalScopeQuery(
7467
for (actual, expected) in zip(result, expectedValues) {
7568
if actual == nil && expected == nil { continue }
7669

70+
guard let actual, let expected else {
71+
XCTFail(
72+
"For marker \(marker), actual result: \(actual?.description ?? "nil"), expected position: \(expected.debugDescription)"
73+
)
74+
continue
75+
}
76+
7777
XCTAssert(
78-
actual?.firstToken(viewMode: .sourceAccurate)?.id == expected?.id,
79-
"For marker \(marker), actual result: \(actual?.firstToken(viewMode: .sourceAccurate) ?? "nil") doesn't match expected value: \(expected?.firstToken(viewMode: .sourceAccurate) ?? "nil")"
78+
actual.positionAfterSkippingLeadingTrivia == expected,
79+
"For marker \(marker), actual result: \(actual.description) doesn't match expected value: \(sourceFileSyntax.token(at: expected) ?? "nil")"
8080
)
8181
}
8282
}

Tests/SwiftLexicalLookupTest/SimpleQueryTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ final class testSimpleQueries: XCTestCase {
128128
guard let fallthroughStmt = argument.ancestorOrSelf(mapping: { $0.as(FallThroughStmtSyntax.self) }) else {
129129
return []
130130
}
131-
let result = fallthroughStmt.lookupFallthroughSourceAndDest()
131+
let result = fallthroughStmt.lookupFallthroughSourceAndDestintation()
132132
return [result.source, result.destination]
133133
},
134134
expected: ["2️⃣": ["1️⃣", "3️⃣"], "4️⃣": ["3️⃣", "5️⃣"], "6️⃣": ["5️⃣", nil], "7️⃣": [nil, nil]]

0 commit comments

Comments
 (0)