Skip to content

Commit 6dc9341

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents 2a731fb + c00cc6a commit 6dc9341

19 files changed

+1096
-151
lines changed

Contributor Documentation/Changing Swift Syntax.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Node(
6565

6666
Added syntactic elements will require corresponding changes to the included
6767
SwiftParser library. For an introduction on parsing Swift nodes, see
68-
[the article on Parsing Basics](https://github.com/swiftlang/swift-syntax/tree/main/Sources/SwiftParser/SwiftParser.docc/ParsingBasics.md).
68+
[the article on Parsing Basics](./Parsing%20Basics.md).
6969

7070
When updating nodes, certain clients of SwiftSyntax that are relying upon those
7171
nodes will need to be changed in tandem. For example, the

Examples/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Each example can be executed by navigating into this folder and running `swift r
44

55
- [AddOneToIntegerLiterals](Sources/AddOneToIntegerLiterals/AddOneToIntegerLiterals.swift): Command line tool to add 1 to every integer literal in a source file
66
- [CodeGenerationUsingSwiftSyntaxBuilder](Sources/CodeGenerationUsingSwiftSyntaxBuilder/CodeGenerationUsingSwiftSyntaxBuilder.swift): Code-generate a simple source file using SwiftSyntaxBuilder
7-
- [ExamplePlugin](Sources/ExamplePlugin): Compiler plugin executable using [`SwiftCompilerPlugin`](../Sources/SwiftCompilerPlugin)
7+
- [ExamplePlugin](Examples/Sources/MacroExamples/Implementation/Plugin.swift): Compiler plugin executable using [`SwiftCompilerPlugin`](../Sources/SwiftCompilerPlugin)
88
- [MacroExamples](Sources/MacroExamples): A collection of Swift macros
99

1010
Furthermore, SwiftSyntax uses [`SwiftSyntaxBuilder`](../Sources/SwiftSyntaxBuilder) extensively to generate its own code. That code can be found in the [CodeGeneration](../CodeGeneration) package.

Release Notes/600.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868

6969
- `DeclGroupSyntax.introducer`
7070
- Description: The `DeclGroupSyntax` trait has an extra `introducer` property, ie. the keyword that introduces the declaration.
71-
- Issue: https://github.com/swiftlang/sourcekit-lsp/issues/2535
71+
- Issue: https://github.com/swiftlang/swift-syntax/issues/2535
7272
- Pull Request: https://github.com/swiftlang/swift-syntax/pull/2539
7373

7474
- `ExprSyntax.interpretedAsVersionTuple`

Sources/SwiftLexicalLookup/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@ add_swift_syntax_library(SwiftLexicalLookup
1515
Configurations/FileScopeHandlingConfig.swift
1616
Configurations/LookupConfig.swift
1717

18+
Scopes/CanInterleaveResultsLaterScopeSyntax.swift
19+
Scopes/FunctionScopeSyntax.swift
1820
Scopes/GenericParameterScopeSyntax.swift
1921
Scopes/IntroducingToSequentialParentScopeSyntax.swift
22+
Scopes/LookInMembersScopeSyntax.swift
23+
Scopes/NominalTypeDeclSyntax.swift
2024
Scopes/ScopeImplementations.swift
2125
Scopes/ScopeSyntax.swift
2226
Scopes/SequentialScopeSyntax.swift
23-
Scopes/TypeScopeSyntax.swift
2427
Scopes/WithGenericParametersScopeSyntax.swift
2528
)
2629

Sources/SwiftLexicalLookup/Configurations/LookupConfig.swift

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,61 @@
1313
@_spi(Experimental) public struct LookupConfig {
1414
/// Specifies behavior of file scope.
1515
@_spi(Experimental) public var fileScopeHandling: FileScopeHandlingConfig
16+
/// Specifies whether lookup should finish in the closest sequential scope.
17+
///
18+
/// ### Example
19+
/// ```swift
20+
/// class X {
21+
/// let a = 42
22+
///
23+
/// func (a: Int) {
24+
/// let a = 123
25+
///
26+
/// a // <-- lookup here
27+
/// }
28+
/// }
29+
/// ```
30+
/// When looking up at the specified position with `finishInSequentialScope`
31+
/// set to `false`, lookup will return declaration from inside function body,
32+
/// function parameter and the `a` declaration from `class X` member block.
33+
/// If `finishInSequentialScope` would be set to `false`, the only name
34+
/// returned by lookup would be the `a` declaration from inside function body.
35+
@_spi(Experimental) public var finishInSequentialScope: Bool
36+
/// Specifies whether to include results generated in file and member block scopes.
37+
///
38+
/// ### Example
39+
/// ```swift
40+
/// class X {
41+
/// let a = 42
42+
///
43+
/// func (a: Int) {
44+
/// let a = 123
45+
///
46+
/// a // <-- lookup here
47+
/// }
48+
/// }
49+
/// ```
50+
/// When looking up at the specified position with `includeMembers`
51+
/// set to `true`, lookup will return declaration from inside function body,
52+
/// function parameter and the `a` declaration from `class X` member block.
53+
/// If `includeMembers` would be set to `false`, the latter name would be omitted.
54+
@_spi(Experimental) public var includeMembers: Bool
1655

1756
/// Creates a new lookup configuration.
1857
///
1958
/// - `fileScopeHandling` - specifies behavior of file scope.
2059
/// `memberBlockUpToLastDecl` by default.
60+
/// - `finishInSequentialScope` - specifies whether lookup should finish
61+
/// in the closest sequential scope. `false` by default.
62+
/// - `includeMembers` - specifies whether to include results generated
63+
/// in file and member block scopes. `true` by default.
2164
@_spi(Experimental) public init(
22-
fileScopeHandling: FileScopeHandlingConfig = .memberBlockUpToLastDecl
65+
fileScopeHandling: FileScopeHandlingConfig = .memberBlockUpToLastDecl,
66+
finishInSequentialScope: Bool = false,
67+
includeMembers: Bool = true
2368
) {
2469
self.fileScopeHandling = fileScopeHandling
70+
self.finishInSequentialScope = finishInSequentialScope
71+
self.includeMembers = includeMembers
2572
}
2673
}

Sources/SwiftLexicalLookup/LookupName.swift

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import SwiftSyntax
1616
@_spi(Experimental) public enum ImplicitDecl {
1717
/// `self` keyword representing object instance.
1818
/// Could be associated with type declaration, extension,
19-
/// or closure captures.
19+
/// or closure captures. Introduced at function edge.
2020
case `self`(DeclSyntaxProtocol)
2121
/// `Self` keyword representing object type.
2222
/// Could be associated with type declaration or extension.
@@ -135,6 +135,51 @@ import SwiftSyntax
135135
}
136136
}
137137

138+
/// Position of this name.
139+
///
140+
/// For some syntax nodes, their position doesn't reflect
141+
/// the position at which a particular name was introduced at.
142+
/// Such cases are function parameters (as they can
143+
/// contain two identifiers) and function declarations (where name
144+
/// is precided by access modifiers and `func` keyword).
145+
@_spi(Experimental) public var position: AbsolutePosition {
146+
switch self {
147+
case .identifier(let syntax, _):
148+
return syntax.identifier.positionAfterSkippingLeadingTrivia
149+
case .declaration(let syntax):
150+
return syntax.name.positionAfterSkippingLeadingTrivia
151+
case .implicit(let implicitName):
152+
switch implicitName {
153+
case .self(let declSyntax):
154+
switch Syntax(declSyntax).as(SyntaxEnum.self) {
155+
case .functionDecl(let functionDecl):
156+
return functionDecl.name.positionAfterSkippingLeadingTrivia
157+
case .initializerDecl(let initializerDecl):
158+
return initializerDecl.initKeyword.positionAfterSkippingLeadingTrivia
159+
case .subscriptDecl(let subscriptDecl):
160+
return subscriptDecl.accessorBlock?.positionAfterSkippingLeadingTrivia
161+
?? subscriptDecl.endPositionBeforeTrailingTrivia
162+
case .variableDecl(let variableDecl):
163+
return variableDecl.bindings.first?.accessorBlock?.positionAfterSkippingLeadingTrivia
164+
?? variableDecl.endPosition
165+
default:
166+
return declSyntax.positionAfterSkippingLeadingTrivia
167+
}
168+
case .Self(let declSyntax):
169+
switch Syntax(declSyntax).as(SyntaxEnum.self) {
170+
case .protocolDecl(let protocolDecl):
171+
return protocolDecl.name.positionAfterSkippingLeadingTrivia
172+
default:
173+
return declSyntax.positionAfterSkippingLeadingTrivia
174+
}
175+
case .error(let catchClause):
176+
return catchClause.body.positionAfterSkippingLeadingTrivia
177+
default:
178+
return implicitName.syntax.positionAfterSkippingLeadingTrivia
179+
}
180+
}
181+
}
182+
138183
/// Point, after which the name is available in scope.
139184
/// If set to `nil`, the name is available at any point in scope.
140185
var accessibleAfter: AbsolutePosition? {
@@ -166,7 +211,7 @@ import SwiftSyntax
166211
) -> [LookupName] {
167212
switch Syntax(syntax).as(SyntaxEnum.self) {
168213
case .variableDecl(let variableDecl):
169-
return variableDecl.bindings.flatMap { binding in
214+
return variableDecl.bindings.reversed().flatMap { binding in
170215
getNames(
171216
from: binding.pattern,
172217
accessibleAfter: accessibleAfter != nil ? binding.endPositionBeforeTrailingTrivia : nil
@@ -194,6 +239,8 @@ import SwiftSyntax
194239
return functionCallExpr.arguments.flatMap { argument in
195240
getNames(from: argument.expression, accessibleAfter: accessibleAfter)
196241
}
242+
case .optionalChainingExpr(let optionalChainingExpr):
243+
return getNames(from: optionalChainingExpr.expression, accessibleAfter: accessibleAfter)
197244
default:
198245
if let namedDecl = Syntax(syntax).asProtocol(SyntaxProtocol.self) as? NamedDeclSyntax {
199246
return handle(namedDecl: namedDecl, accessibleAfter: accessibleAfter)
@@ -210,12 +257,7 @@ import SwiftSyntax
210257
identifiable: IdentifiableSyntax,
211258
accessibleAfter: AbsolutePosition? = nil
212259
) -> [LookupName] {
213-
switch identifiable.identifier.tokenKind {
214-
case .wildcard:
215-
return []
216-
default:
217-
return [.identifier(identifiable, accessibleAfter: accessibleAfter)]
218-
}
260+
[.identifier(identifiable, accessibleAfter: accessibleAfter)]
219261
}
220262

221263
/// Extracts name introduced by `NamedDeclSyntax` node.
@@ -225,4 +267,27 @@ import SwiftSyntax
225267
) -> [LookupName] {
226268
[.declaration(namedDecl)]
227269
}
270+
271+
/// Debug description of this lookup name.
272+
@_spi(Experimental) public var debugDescription: String {
273+
let sourceLocationConverter = SourceLocationConverter(fileName: "", tree: syntax.root)
274+
let location = sourceLocationConverter.location(for: position)
275+
let strName = (identifier?.name ?? "NO-NAME") + " at: \(location.line):\(location.column)"
276+
277+
switch self {
278+
case .identifier:
279+
let str = "identifier: \(strName)"
280+
281+
if let accessibleAfter {
282+
let location = sourceLocationConverter.location(for: accessibleAfter)
283+
return str + " after: \(location.line):\(location.column)"
284+
} else {
285+
return str
286+
}
287+
case .declaration:
288+
return "declaration: \(strName)"
289+
case .implicit:
290+
return "implicit: \(strName)"
291+
}
292+
}
228293
}

Sources/SwiftLexicalLookup/LookupResult.swift

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,18 @@ import SwiftSyntax
1818
case fromScope(ScopeSyntax, withNames: [LookupName])
1919
/// File scope and names that matched lookup.
2020
case fromFileScope(SourceFileSyntax, withNames: [LookupName])
21+
/// Indicates where to perform member lookup.
22+
case lookInMembers(LookInMembersScopeSyntax)
2123

2224
/// Associated scope.
23-
@_spi(Experimental) public var scope: ScopeSyntax? {
25+
@_spi(Experimental) public var scope: ScopeSyntax {
2426
switch self {
2527
case .fromScope(let scopeSyntax, _):
2628
return scopeSyntax
2729
case .fromFileScope(let fileScopeSyntax, _):
2830
return fileScopeSyntax
31+
case .lookInMembers(let lookInMemb):
32+
return lookInMemb
2933
}
3034
}
3135

@@ -34,6 +38,8 @@ import SwiftSyntax
3438
switch self {
3539
case .fromScope(_, let names), .fromFileScope(_, let names):
3640
return names
41+
case .lookInMembers(_):
42+
return []
3743
}
3844
}
3945

@@ -46,4 +52,48 @@ import SwiftSyntax
4652
return .fromScope(scope, withNames: names)
4753
}
4854
}
55+
56+
/// Debug description of this lookup name.
57+
@_spi(Experimental) public var debugDescription: String {
58+
var description =
59+
resultKindDebugName + ": " + scope.scopeDebugDescription
60+
61+
switch self {
62+
case .lookInMembers:
63+
break
64+
default:
65+
if !names.isEmpty {
66+
description += "\n"
67+
}
68+
}
69+
70+
for (index, name) in names.enumerated() {
71+
if index + 1 == names.count {
72+
description += "`-" + name.debugDescription
73+
} else {
74+
description += "|-" + name.debugDescription + "\n"
75+
}
76+
}
77+
78+
return description
79+
}
80+
81+
/// Debug name of this result kind.
82+
private var resultKindDebugName: String {
83+
switch self {
84+
case .fromScope:
85+
return "fromScope"
86+
case .fromFileScope:
87+
return "fromFileScope"
88+
case .lookInMembers:
89+
return "lookInMembers"
90+
}
91+
}
92+
}
93+
94+
@_spi(Experimental) extension [LookupResult] {
95+
/// Debug description this array of lookup results.
96+
@_spi(Experimental) public var debugDescription: String {
97+
return self.map(\.debugDescription).joined(separator: "\n")
98+
}
4999
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import SwiftSyntax
14+
15+
protocol CanInterleaveResultsLaterScopeSyntax: ScopeSyntax {
16+
/// Perform lookup in this scope and later introduce results
17+
/// passed as `resultsToInterleave`.
18+
/// The exact behavior depends on a specific scope.
19+
func lookupWithInterleavedResults(
20+
_ identifier: Identifier?,
21+
at lookUpPosition: AbsolutePosition,
22+
with config: LookupConfig,
23+
resultsToInterleave: [LookupResult]
24+
) -> [LookupResult]
25+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import SwiftSyntax
14+
15+
protocol FunctionScopeSyntax: DeclSyntaxProtocol, WithGenericParametersScopeSyntax {
16+
var signature: FunctionSignatureSyntax { get }
17+
}
18+
19+
extension FunctionScopeSyntax {
20+
/// Function parameters introduced by this function's signature.
21+
@_spi(Experimental) public var introducedNames: [LookupName] {
22+
signature.parameterClause.parameters.flatMap { parameter in
23+
LookupName.getNames(from: parameter)
24+
} + (parentScope?.is(MemberBlockSyntax.self) ?? false ? [.implicit(.self(self))] : [])
25+
}
26+
27+
/// Lookup results from this function scope.
28+
/// Routes to generic parameter clause scope if exists.
29+
@_spi(Experimental) public func lookup(
30+
_ identifier: Identifier?,
31+
at lookUpPosition: AbsolutePosition,
32+
with config: LookupConfig
33+
) -> [LookupResult] {
34+
var thisScopeResults: [LookupResult] = []
35+
36+
if !signature.range.contains(lookUpPosition) {
37+
thisScopeResults = defaultLookupImplementation(
38+
identifier,
39+
at: position,
40+
with: config,
41+
propagateToParent: false
42+
)
43+
}
44+
45+
return thisScopeResults
46+
+ lookupThroughGenericParameterScope(
47+
identifier,
48+
at: lookUpPosition,
49+
with: config
50+
)
51+
}
52+
}

0 commit comments

Comments
 (0)