Skip to content

Commit 6c897fe

Browse files
committed
ASTScope related unqualified lookup fixes. Dollar identifier, extended type generic parameters and where clause handling.
1 parent 6dc9341 commit 6c897fe

14 files changed

+377
-476
lines changed

Sources/SwiftLexicalLookup/CMakeLists.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ add_swift_syntax_library(SwiftLexicalLookup
1111
LookupName.swift
1212
LookupResult.swift
1313
SimpleLookupQueries.swift
14-
15-
Configurations/FileScopeHandlingConfig.swift
16-
Configurations/LookupConfig.swift
14+
LookupConfig.swift
1715

1816
Scopes/CanInterleaveResultsLaterScopeSyntax.swift
1917
Scopes/FunctionScopeSyntax.swift

Sources/SwiftLexicalLookup/Configurations/FileScopeHandlingConfig.swift

Lines changed: 0 additions & 23 deletions
This file was deleted.

Sources/SwiftLexicalLookup/Configurations/LookupConfig.swift renamed to Sources/SwiftLexicalLookup/LookupConfig.swift

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
@_spi(Experimental) public struct LookupConfig {
14-
/// Specifies behavior of file scope.
15-
@_spi(Experimental) public var fileScopeHandling: FileScopeHandlingConfig
1614
/// Specifies whether lookup should finish in the closest sequential scope.
1715
///
1816
/// ### Example
@@ -33,41 +31,14 @@
3331
/// If `finishInSequentialScope` would be set to `false`, the only name
3432
/// returned by lookup would be the `a` declaration from inside function body.
3533
@_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
5534

5635
/// Creates a new lookup configuration.
5736
///
58-
/// - `fileScopeHandling` - specifies behavior of file scope.
59-
/// `memberBlockUpToLastDecl` by default.
6037
/// - `finishInSequentialScope` - specifies whether lookup should finish
6138
/// 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.
6439
@_spi(Experimental) public init(
65-
fileScopeHandling: FileScopeHandlingConfig = .memberBlockUpToLastDecl,
66-
finishInSequentialScope: Bool = false,
67-
includeMembers: Bool = true
40+
finishInSequentialScope: Bool = false
6841
) {
69-
self.fileScopeHandling = fileScopeHandling
7042
self.finishInSequentialScope = finishInSequentialScope
71-
self.includeMembers = includeMembers
7243
}
7344
}

Sources/SwiftLexicalLookup/LookupName.swift

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ import SwiftSyntax
4646
}
4747

4848
/// The name of the implicit declaration.
49-
private var name: String {
49+
private var name: StaticString {
5050
switch self {
5151
case .self:
5252
return "self"
@@ -86,17 +86,38 @@ import SwiftSyntax
8686
/// `self` and `Self` identifers override implicit `self` and `Self` introduced by
8787
/// the `Foo` class declaration.
8888
var identifier: Identifier {
89+
Identifier(name)
90+
}
91+
92+
/// Position of this implicit name.
93+
@_spi(Experimental) public var position: AbsolutePosition {
8994
switch self {
90-
case .self:
91-
return Identifier("self")
92-
case .Self:
93-
return Identifier("Self")
94-
case .error:
95-
return Identifier("error")
96-
case .newValue:
97-
return Identifier("newValue")
98-
case .oldValue:
99-
return Identifier("oldValue")
95+
case .self(let declSyntax):
96+
switch Syntax(declSyntax).as(SyntaxEnum.self) {
97+
case .functionDecl(let functionDecl):
98+
return functionDecl.name.positionAfterSkippingLeadingTrivia
99+
case .initializerDecl(let initializerDecl):
100+
return initializerDecl.initKeyword.positionAfterSkippingLeadingTrivia
101+
case .subscriptDecl(let subscriptDecl):
102+
return subscriptDecl.accessorBlock?.positionAfterSkippingLeadingTrivia
103+
?? subscriptDecl.endPositionBeforeTrailingTrivia
104+
case .variableDecl(let variableDecl):
105+
return variableDecl.bindings.first?.accessorBlock?.positionAfterSkippingLeadingTrivia
106+
?? variableDecl.endPosition
107+
default:
108+
return declSyntax.positionAfterSkippingLeadingTrivia
109+
}
110+
case .Self(let declSyntax):
111+
switch Syntax(declSyntax).as(SyntaxEnum.self) {
112+
case .protocolDecl(let protocolDecl):
113+
return protocolDecl.name.positionAfterSkippingLeadingTrivia
114+
default:
115+
return declSyntax.positionAfterSkippingLeadingTrivia
116+
}
117+
case .error(let catchClause):
118+
return catchClause.catchItems.positionAfterSkippingLeadingTrivia
119+
default:
120+
return syntax.positionAfterSkippingLeadingTrivia
100121
}
101122
}
102123
}
@@ -110,6 +131,8 @@ import SwiftSyntax
110131
case declaration(NamedDeclSyntax)
111132
/// Name introduced implicitly by certain syntax nodes.
112133
case implicit(ImplicitDecl)
134+
/// Dollar identifier introduced by a closure without parameters.
135+
case dollarIdentifier(ClosureExprSyntax, strRepresentation: String)
113136

114137
/// Syntax associated with this name.
115138
@_spi(Experimental) public var syntax: SyntaxProtocol {
@@ -120,6 +143,8 @@ import SwiftSyntax
120143
return syntax
121144
case .implicit(let implicitName):
122145
return implicitName.syntax
146+
case .dollarIdentifier(let closureExpr, _):
147+
return closureExpr
123148
}
124149
}
125150

@@ -132,6 +157,8 @@ import SwiftSyntax
132157
return Identifier(syntax.name)
133158
case .implicit(let kind):
134159
return kind.identifier
160+
case .dollarIdentifier(_, strRepresentation: _):
161+
return nil
135162
}
136163
}
137164

@@ -149,34 +176,9 @@ import SwiftSyntax
149176
case .declaration(let syntax):
150177
return syntax.name.positionAfterSkippingLeadingTrivia
151178
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-
}
179+
return implicitName.position
180+
case .dollarIdentifier(let closureExpr, _):
181+
return closureExpr.positionAfterSkippingLeadingTrivia
180182
}
181183
}
182184

@@ -197,6 +199,17 @@ import SwiftSyntax
197199
return accessibleAfter <= lookUpPosition
198200
}
199201

202+
func refersTo(_ otherIdentifier: Identifier?) -> Bool {
203+
guard let otherIdentifier else { return true }
204+
205+
switch self {
206+
case .dollarIdentifier(_, let strRepresentation):
207+
return strRepresentation == otherIdentifier.name
208+
default:
209+
return identifier == otherIdentifier
210+
}
211+
}
212+
200213
/// Extracts names introduced by the given `syntax` structure.
201214
///
202215
/// When e.g. looking up a variable declaration like `let a = a`,
@@ -221,6 +234,12 @@ import SwiftSyntax
221234
return tuplePattern.elements.flatMap { tupleElement in
222235
getNames(from: tupleElement.pattern, accessibleAfter: accessibleAfter)
223236
}
237+
case .tupleExpr(let tupleExpr):
238+
return tupleExpr.elements.flatMap { tupleElement in
239+
getNames(from: tupleElement, accessibleAfter: accessibleAfter)
240+
}
241+
case .labeledExpr(let labeledExpr):
242+
return getNames(from: labeledExpr.expression, accessibleAfter: accessibleAfter)
224243
case .valueBindingPattern(let valueBindingPattern):
225244
return getNames(from: valueBindingPattern.pattern, accessibleAfter: accessibleAfter)
226245
case .expressionPattern(let expressionPattern):
@@ -288,6 +307,8 @@ import SwiftSyntax
288307
return "declaration: \(strName)"
289308
case .implicit:
290309
return "implicit: \(strName)"
310+
case .dollarIdentifier(_, strRepresentation: let str):
311+
return "dollarIdentifier: \(str)"
291312
}
292313
}
293314
}

Sources/SwiftLexicalLookup/LookupResult.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ import SwiftSyntax
2020
case fromFileScope(SourceFileSyntax, withNames: [LookupName])
2121
/// Indicates where to perform member lookup.
2222
case lookInMembers(LookInMembersScopeSyntax)
23+
/// Indicates to lookup generic parameters of extended type.
24+
case lookInGenericParametersOfExtendedType(ExtensionDeclSyntax)
25+
/// Indicates this closure expression could introduce dollar identifiers.
26+
case mightIntroduceDollarIdentifiers(ClosureExprSyntax)
2327

2428
/// Associated scope.
2529
@_spi(Experimental) public var scope: ScopeSyntax {
@@ -30,6 +34,10 @@ import SwiftSyntax
3034
return fileScopeSyntax
3135
case .lookInMembers(let lookInMemb):
3236
return lookInMemb
37+
case .lookInGenericParametersOfExtendedType(let extensionDecl):
38+
return extensionDecl
39+
case .mightIntroduceDollarIdentifiers(let closureExpr):
40+
return closureExpr
3341
}
3442
}
3543

@@ -38,7 +46,9 @@ import SwiftSyntax
3846
switch self {
3947
case .fromScope(_, let names), .fromFileScope(_, let names):
4048
return names
41-
case .lookInMembers(_):
49+
case .lookInMembers(_),
50+
.lookInGenericParametersOfExtendedType(_),
51+
.mightIntroduceDollarIdentifiers(_):
4252
return []
4353
}
4454
}
@@ -53,6 +63,14 @@ import SwiftSyntax
5363
}
5464
}
5565

66+
/// Returns result specific for the particular `scope` kind with provided `names`
67+
/// as an array with one element. If names are empty, returns an empty array.
68+
static func getResultArray(for scope: ScopeSyntax, withNames names: [LookupName]) -> [LookupResult] {
69+
guard !names.isEmpty else { return [] }
70+
71+
return [getResult(for: scope, withNames: names)]
72+
}
73+
5674
/// Debug description of this lookup name.
5775
@_spi(Experimental) public var debugDescription: String {
5876
var description =
@@ -87,6 +105,10 @@ import SwiftSyntax
87105
return "fromFileScope"
88106
case .lookInMembers:
89107
return "lookInMembers"
108+
case .lookInGenericParametersOfExtendedType(_):
109+
return "lookInGenericParametersOfExtendedType"
110+
case .mightIntroduceDollarIdentifiers(_):
111+
return "mightIntroduceDollarIdentifiers"
90112
}
91113
}
92114
}

Sources/SwiftLexicalLookup/Scopes/FunctionScopeSyntax.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@
1212

1313
import SwiftSyntax
1414

15-
protocol FunctionScopeSyntax: DeclSyntaxProtocol, WithGenericParametersScopeSyntax {
15+
@_spi(Experimental) public protocol FunctionScopeSyntax: DeclSyntaxProtocol, WithGenericParametersScopeSyntax {
1616
var signature: FunctionSignatureSyntax { get }
17+
var body: CodeBlockSyntax? { get }
1718
}
1819

1920
extension FunctionScopeSyntax {
2021
/// Function parameters introduced by this function's signature.
21-
@_spi(Experimental) public var introducedNames: [LookupName] {
22+
@_spi(Experimental) public var defaultIntroducedNames: [LookupName] {
2223
signature.parameterClause.parameters.flatMap { parameter in
2324
LookupName.getNames(from: parameter)
2425
} + (parentScope?.is(MemberBlockSyntax.self) ?? false ? [.implicit(.self(self))] : [])
@@ -33,7 +34,7 @@ extension FunctionScopeSyntax {
3334
) -> [LookupResult] {
3435
var thisScopeResults: [LookupResult] = []
3536

36-
if !signature.range.contains(lookUpPosition) {
37+
if body?.range.contains(lookUpPosition) ?? false {
3738
thisScopeResults = defaultLookupImplementation(
3839
identifier,
3940
at: position,

Sources/SwiftLexicalLookup/Scopes/NominalTypeDeclSyntax.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,26 @@
1212

1313
import SwiftSyntax
1414

15-
protocol NominalTypeDeclSyntax: LookInMembersScopeSyntax, NamedDeclSyntax, WithGenericParametersScopeSyntax {
15+
@_spi(Experimental)
16+
public protocol NominalTypeDeclSyntax: LookInMembersScopeSyntax, NamedDeclSyntax, WithGenericParametersScopeSyntax {
1617
var genericParameterClause: GenericParameterClauseSyntax? { get }
18+
var genericWhereClause: GenericWhereClauseSyntax? { get }
1719
var inheritanceClause: InheritanceClauseSyntax? { get }
1820
}
1921

2022
extension NominalTypeDeclSyntax {
2123
@_spi(Experimental) public var lookupMembersPosition: AbsolutePosition {
22-
name.position
24+
name.positionAfterSkippingLeadingTrivia
2325
}
2426

2527
/// Nominal type doesn't introduce any names by itself.
26-
@_spi(Experimental) public var introducedNames: [LookupName] {
28+
@_spi(Experimental) public var defaultIntroducedNames: [LookupName] {
2729
[]
2830
}
2931

3032
/// Function used by generic parameter clause
3133
/// scope on return from it's lookup.
32-
func returningLookupFromGenericParameterScope(
34+
@_spi(Experimental) public func returningLookupFromGenericParameterScope(
3335
_ identifier: Identifier?,
3436
at lookUpPosition: AbsolutePosition,
3537
with config: LookupConfig
@@ -38,7 +40,7 @@ extension NominalTypeDeclSyntax {
3840
return lookupInParent(identifier, at: lookUpPosition, with: config)
3941
} else if let genericParameterClause, genericParameterClause.range.contains(lookUpPosition) {
4042
return lookupInParent(identifier, at: lookUpPosition, with: config)
41-
} else if name.range.contains(lookUpPosition) {
43+
} else if name.range.contains(lookUpPosition) || genericWhereClause?.range.contains(lookUpPosition) ?? false {
4244
return lookupInParent(identifier, at: lookUpPosition, with: config)
4345
} else {
4446
return [.lookInMembers(self)] + lookupInParent(identifier, at: lookUpPosition, with: config)

0 commit comments

Comments
 (0)