Skip to content

Commit d83af9c

Browse files
committed
Add astscope related fixes and lookInMembers functionality.
1 parent 51eb17a commit d83af9c

13 files changed

+614
-126
lines changed

Sources/SwiftLexicalLookup/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ add_swift_syntax_library(SwiftLexicalLookup
1717

1818
Scopes/GenericParameterScopeSyntax.swift
1919
Scopes/IntroducingToSequentialParentScopeSyntax.swift
20+
Scopes/LookInMembersScopeSyntax.swift
21+
Scopes/NominalTypeDeclSyntax.swift
2022
Scopes/ScopeImplementations.swift
2123
Scopes/ScopeSyntax.swift
2224
Scopes/SequentialScopeSyntax.swift
23-
Scopes/TypeScopeSyntax.swift
2425
Scopes/WithGenericParametersScopeSyntax.swift
2526
)
2627

Sources/SwiftLexicalLookup/Configurations/LookupConfig.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,26 @@
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+
@_spi(Experimental) public var finishInSequentialScope: Bool
18+
/// Specifies whether to include results generated in file and member block scopes.
19+
@_spi(Experimental) public var includeMembers: Bool
1620

1721
/// Creates a new lookup configuration.
1822
///
1923
/// - `fileScopeHandling` - specifies behavior of file scope.
2024
/// `memberBlockUpToLastDecl` by default.
25+
/// - `finishInSequentialScope` - specifies whether lookup should finish
26+
/// in the closest sequential scope. `false` by default.
27+
/// - `includeMembers` - specifies whether to include results generated
28+
/// in file and member block scopes. `true` by default.
2129
@_spi(Experimental) public init(
22-
fileScopeHandling: FileScopeHandlingConfig = .memberBlockUpToLastDecl
30+
fileScopeHandling: FileScopeHandlingConfig = .memberBlockUpToLastDecl,
31+
finishInSequentialScope: Bool = false,
32+
includeMembers: Bool = true
2333
) {
2434
self.fileScopeHandling = fileScopeHandling
35+
self.finishInSequentialScope = finishInSequentialScope
36+
self.includeMembers = includeMembers
2537
}
2638
}

Sources/SwiftLexicalLookup/LookupName.swift

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ 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.
20-
case `self`(DeclSyntaxProtocol)
19+
/// or closure captures. Introduced at function edge.
20+
case `self`(FunctionDeclSyntax)
2121
/// `Self` keyword representing object type.
2222
/// Could be associated with type declaration or extension.
2323
case `Self`(DeclSyntaxProtocol)
@@ -135,6 +135,35 @@ 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+
switch Syntax(syntax).as(SyntaxEnum.self) {
149+
case .functionParameter(let functionParameter):
150+
return functionParameter.secondName?.positionAfterSkippingLeadingTrivia
151+
?? functionParameter.firstName.positionAfterSkippingLeadingTrivia
152+
default:
153+
return syntax.position
154+
}
155+
case .declaration(let syntax):
156+
return syntax.name.position
157+
case .implicit(let implicitName):
158+
switch implicitName {
159+
case .self(let functionDecl):
160+
return functionDecl.name.position
161+
default:
162+
return implicitName.syntax.position
163+
}
164+
}
165+
}
166+
138167
/// Point, after which the name is available in scope.
139168
/// If set to `nil`, the name is available at any point in scope.
140169
var accessibleAfter: AbsolutePosition? {
@@ -225,4 +254,27 @@ import SwiftSyntax
225254
) -> [LookupName] {
226255
[.declaration(namedDecl)]
227256
}
257+
258+
/// Debug description of this lookup name.
259+
@_spi(Experimental) public var debugDescription: String {
260+
let sourceLocationConverter = SourceLocationConverter(fileName: "", tree: syntax.root)
261+
let location = sourceLocationConverter.location(for: position)
262+
let strName = (identifier != nil ? identifier!.name : "NO-NAME") + " at: \(location.line):\(location.column)"
263+
264+
switch self {
265+
case .identifier:
266+
let str = "identifier: \(strName)"
267+
268+
if let accessibleAfter {
269+
let location = sourceLocationConverter.location(for: accessibleAfter)
270+
return str + " after: \(location.line):\(location.column)"
271+
} else {
272+
return str
273+
}
274+
case .declaration:
275+
return "declaration: \(strName)"
276+
case .implicit:
277+
return "implicit: \(strName)"
278+
}
279+
}
228280
}

Sources/SwiftLexicalLookup/LookupResult.swift

Lines changed: 57 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,54 @@ 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+
var str: String = ""
98+
99+
for (index, result) in self.enumerated() {
100+
str += result.debugDescription + (index + 1 == self.count ? "" : "\n")
101+
}
102+
103+
return str
104+
}
49105
}

Sources/SwiftLexicalLookup/Scopes/GenericParameterScopeSyntax.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import SwiftSyntax
1616
/// futher lookup to its `WithGenericParametersScopeSyntax`
1717
/// parent scope's parent scope (i.e. on return, bypasses names
1818
/// introduced by its parent).
19-
@_spi(Experimental) public protocol GenericParameterScopeSyntax: ScopeSyntax {}
19+
protocol GenericParameterScopeSyntax: ScopeSyntax {}
2020

2121
@_spi(Experimental) extension GenericParameterScopeSyntax {
2222
/// Returns names matching lookup and bypasses
@@ -83,7 +83,7 @@ import SwiftSyntax
8383
if let parentScope = Syntax(parentScope).asProtocol(SyntaxProtocol.self)
8484
as? WithGenericParametersScopeSyntax
8585
{
86-
return parentScope.lookupInParent(identifier, at: lookUpPosition, with: config)
86+
return parentScope.returningLookupFromGenericParameterScope(identifier, at: lookUpPosition, with: config)
8787
} else {
8888
return lookupInParent(identifier, at: lookUpPosition, with: config)
8989
}

Sources/SwiftLexicalLookup/Scopes/TypeScopeSyntax.swift renamed to Sources/SwiftLexicalLookup/Scopes/LookInMembersScopeSyntax.swift

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

1313
import SwiftSyntax
1414

15-
@_spi(Experimental) public protocol TypeScopeSyntax: ScopeSyntax, DeclSyntaxProtocol {}
16-
17-
extension TypeScopeSyntax {
18-
@_spi(Experimental) public var implicitInstanceAndTypeNames: [LookupName] {
19-
[.implicit(.self(self)), .implicit(.Self(self))]
20-
}
21-
22-
@_spi(Experimental) public var introducedNames: [LookupName] {
23-
implicitInstanceAndTypeNames
24-
}
15+
@_spi(Experimental) public protocol LookInMembersScopeSyntax: ScopeSyntax {
16+
/// Position used for member lookup.
17+
var lookupMembersPosition: AbsolutePosition { get }
2518
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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 NominalTypeDeclSyntax: LookInMembersScopeSyntax, NamedDeclSyntax, WithGenericParametersScopeSyntax {
16+
var inheritanceClause: InheritanceClauseSyntax? { get }
17+
}
18+
19+
extension NominalTypeDeclSyntax {
20+
@_spi(Experimental) public var lookupMembersPosition: AbsolutePosition {
21+
name.position
22+
}
23+
24+
/// Nominal type doesn't introduce any names by itself.
25+
@_spi(Experimental) public var introducedNames: [LookupName] {
26+
[]
27+
}
28+
29+
/// Function used by generic parameter clause
30+
/// scope on return from it's lookup.
31+
func returningLookupFromGenericParameterScope(
32+
_ identifier: Identifier?,
33+
at lookUpPosition: AbsolutePosition,
34+
with config: LookupConfig
35+
) -> [LookupResult] {
36+
if let inheritanceClause, inheritanceClause.range.contains(lookUpPosition) {
37+
return lookupInParent(identifier, at: lookUpPosition, with: config)
38+
} else {
39+
return [.lookInMembers(self)] + lookupInParent(identifier, at: lookUpPosition, with: config)
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)