Skip to content

Commit 7521e4e

Browse files
committed
Add sequential handling of subscript and switch case scopes. Remove wild card filtering.
1 parent d83af9c commit 7521e4e

File tree

4 files changed

+167
-42
lines changed

4 files changed

+167
-42
lines changed

Sources/SwiftLexicalLookup/LookupName.swift

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import SwiftSyntax
1717
/// `self` keyword representing object instance.
1818
/// Could be associated with type declaration, extension,
1919
/// or closure captures. Introduced at function edge.
20-
case `self`(FunctionDeclSyntax)
20+
case `self`(DeclSyntaxProtocol)
2121
/// `Self` keyword representing object type.
2222
/// Could be associated with type declaration or extension.
2323
case `Self`(DeclSyntaxProtocol)
@@ -136,7 +136,7 @@ import SwiftSyntax
136136
}
137137

138138
/// Position of this name.
139-
///
139+
///
140140
/// For some syntax nodes, their position doesn't reflect
141141
/// the position at which a particular name was introduced at.
142142
/// Such cases are function parameters (as they can
@@ -145,21 +145,24 @@ import SwiftSyntax
145145
@_spi(Experimental) public var position: AbsolutePosition {
146146
switch self {
147147
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-
}
148+
return syntax.identifier.positionAfterSkippingLeadingTrivia
155149
case .declaration(let syntax):
156150
return syntax.name.position
157151
case .implicit(let implicitName):
158152
switch implicitName {
159-
case .self(let functionDecl):
160-
return functionDecl.name.position
153+
case .self(let declSyntax):
154+
switch Syntax(declSyntax).as(SyntaxEnum.self) {
155+
case .functionDecl(let functionDecl):
156+
return functionDecl.name.position
157+
case .subscriptDecl(let subscriptDecl):
158+
return subscriptDecl.accessorBlock?.position ?? subscriptDecl.endPosition
159+
default:
160+
return declSyntax.positionAfterSkippingLeadingTrivia
161+
}
162+
case .error(let catchClause):
163+
return catchClause.body.position
161164
default:
162-
return implicitName.syntax.position
165+
return implicitName.syntax.positionAfterSkippingLeadingTrivia
163166
}
164167
}
165168
}
@@ -195,7 +198,7 @@ import SwiftSyntax
195198
) -> [LookupName] {
196199
switch Syntax(syntax).as(SyntaxEnum.self) {
197200
case .variableDecl(let variableDecl):
198-
return variableDecl.bindings.flatMap { binding in
201+
return variableDecl.bindings.reversed().flatMap { binding in
199202
getNames(
200203
from: binding.pattern,
201204
accessibleAfter: accessibleAfter != nil ? binding.endPositionBeforeTrailingTrivia : nil
@@ -239,12 +242,7 @@ import SwiftSyntax
239242
identifiable: IdentifiableSyntax,
240243
accessibleAfter: AbsolutePosition? = nil
241244
) -> [LookupName] {
242-
switch identifiable.identifier.tokenKind {
243-
case .wildcard:
244-
return []
245-
default:
246-
return [.identifier(identifiable, accessibleAfter: accessibleAfter)]
247-
}
245+
[.identifier(identifiable, accessibleAfter: accessibleAfter)]
248246
}
249247

250248
/// Extracts name introduced by `NamedDeclSyntax` node.

Sources/SwiftLexicalLookup/Scopes/NominalTypeDeclSyntax.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import SwiftSyntax
1414

1515
protocol NominalTypeDeclSyntax: LookInMembersScopeSyntax, NamedDeclSyntax, WithGenericParametersScopeSyntax {
16+
var genericParameterClause: GenericParameterClauseSyntax? { get }
1617
var inheritanceClause: InheritanceClauseSyntax? { get }
1718
}
1819

@@ -35,6 +36,10 @@ extension NominalTypeDeclSyntax {
3536
) -> [LookupResult] {
3637
if let inheritanceClause, inheritanceClause.range.contains(lookUpPosition) {
3738
return lookupInParent(identifier, at: lookUpPosition, with: config)
39+
} else if let genericParameterClause, genericParameterClause.range.contains(lookUpPosition) {
40+
return lookupInParent(identifier, at: lookUpPosition, with: config)
41+
} else if name.range.contains(lookUpPosition) {
42+
return lookupInParent(identifier, at: lookUpPosition, with: config)
3843
} else {
3944
return [.lookInMembers(self)] + lookupInParent(identifier, at: lookUpPosition, with: config)
4045
}

Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift

Lines changed: 138 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,21 @@ import SwiftSyntax
191191
@_spi(Experimental) public var scopeDebugName: String {
192192
"ForStmtScope"
193193
}
194+
195+
/// Returns results with names matching lookup.
196+
/// Doesn't include names introduced at this scope
197+
/// if lookup started inside it's `pattern` or `sequence`.
198+
@_spi(Experimental) public func lookup(
199+
_ identifier: Identifier?,
200+
at lookUpPosition: AbsolutePosition,
201+
with config: LookupConfig
202+
) -> [LookupResult] {
203+
if pattern.range.contains(lookUpPosition) || sequence.range.contains(lookUpPosition) {
204+
return lookupInParent(identifier, at: lookUpPosition, with: config)
205+
} else {
206+
return defaultLookupImplementation(identifier, at: lookUpPosition, with: config)
207+
}
208+
}
194209
}
195210

196211
@_spi(Experimental) extension ClosureExprSyntax: SequentialScopeSyntax {
@@ -249,8 +264,14 @@ import SwiftSyntax
249264
at lookUpPosition: AbsolutePosition,
250265
with config: LookupConfig
251266
) -> [LookupResult] {
252-
let filteredSignatureNames = introducedNamesInSignature.filter { name in
253-
checkIdentifier(identifier, refersTo: name, at: lookUpPosition)
267+
let filteredSignatureNames: [LookupName]
268+
269+
if let signature, signature.range.contains(lookUpPosition) {
270+
filteredSignatureNames = []
271+
} else {
272+
filteredSignatureNames = introducedNamesInSignature.filter { name in
273+
checkIdentifier(identifier, refersTo: name, at: lookUpPosition)
274+
}
254275
}
255276

256277
return sequentialLookup(
@@ -267,8 +288,8 @@ import SwiftSyntax
267288
@_spi(Experimental) extension WhileStmtSyntax: ScopeSyntax {
268289
/// Names introduced by the `while` loop by its conditions.
269290
@_spi(Experimental) public var introducedNames: [LookupName] {
270-
conditions.flatMap { element in
271-
LookupName.getNames(from: element.condition)
291+
conditions.reversed().flatMap { element in
292+
LookupName.getNames(from: element.condition, accessibleAfter: element.endPositionBeforeTrailingTrivia)
272293
}
273294
}
274295

@@ -486,18 +507,26 @@ import SwiftSyntax
486507
@_spi(Experimental) extension AccessorDeclSyntax: ScopeSyntax {
487508
/// Implicit and/or explicit names introduced within the accessor.
488509
@_spi(Experimental) public var introducedNames: [LookupName] {
510+
let names: [LookupName]
511+
489512
if let parameters {
490-
return LookupName.getNames(from: parameters)
513+
names = LookupName.getNames(from: parameters)
491514
} else {
492515
switch accessorSpecifier.tokenKind {
493516
case .keyword(.set), .keyword(.willSet):
494-
return [.implicit(.newValue(self))]
517+
names = [.implicit(.newValue(self))]
495518
case .keyword(.didSet):
496-
return [.implicit(.oldValue(self))]
519+
names = [.implicit(.oldValue(self))]
497520
default:
498-
return []
521+
names = []
499522
}
500523
}
524+
525+
if let parentScope, parentScope.is(AccessorBlockSyntax.self) {
526+
return names + [.implicit(.self(self))]
527+
} else {
528+
return names
529+
}
501530
}
502531

503532
@_spi(Experimental) public var scopeDebugName: String {
@@ -516,17 +545,47 @@ import SwiftSyntax
516545
}
517546
}
518547

519-
@_spi(Experimental) extension SwitchCaseSyntax: ScopeSyntax {
548+
@_spi(Experimental) extension SwitchCaseSyntax: SequentialScopeSyntax {
520549
/// Names introduced within `case` items.
521-
@_spi(Experimental) public var introducedNames: [LookupName] {
550+
var namesFromLabel: [LookupName] {
522551
label.as(SwitchCaseLabelSyntax.self)?.caseItems.flatMap { child in
523552
LookupName.getNames(from: child.pattern)
524553
} ?? []
525554
}
526555

556+
/// Names introduced within `case` items
557+
/// as well as sequential names from inside this case.
558+
@_spi(Experimental) public var introducedNames: [LookupName] {
559+
statements.flatMap { codeBlockItem in
560+
LookupName.getNames(from: codeBlockItem.item, accessibleAfter: codeBlockItem.endPosition)
561+
} + namesFromLabel
562+
}
563+
527564
@_spi(Experimental) public var scopeDebugName: String {
528565
"SwitchCaseScope"
529566
}
567+
568+
/// Returns results with names matching lookup.
569+
/// Includes names introduced in it's label and sequentially
570+
/// introduced names from inside this case.
571+
@_spi(Experimental) public func lookup(
572+
_ identifier: Identifier?,
573+
at lookUpPosition: AbsolutePosition,
574+
with config: LookupConfig
575+
) -> [LookupResult] {
576+
let filteredNamesFromLabel = namesFromLabel.filter { name in
577+
checkIdentifier(identifier, refersTo: name, at: lookUpPosition)
578+
}
579+
580+
return sequentialLookup(
581+
in: statements,
582+
identifier,
583+
at: lookUpPosition,
584+
with: config,
585+
propagateToParent: false
586+
) + (filteredNamesFromLabel.isEmpty ? [] : [.fromScope(self, withNames: filteredNamesFromLabel)])
587+
+ lookupInParent(identifier, at: lookUpPosition, with: config)
588+
}
530589
}
531590

532591
@_spi(Experimental) extension ProtocolDeclSyntax: ScopeSyntax {
@@ -631,16 +690,83 @@ import SwiftSyntax
631690
}
632691

633692
@_spi(Experimental) extension SubscriptDeclSyntax: WithGenericParametersScopeSyntax {
634-
/// Parameters introduced by this subscript.
693+
/// Parameters introduced by this subscript and possibly `self` keyword.
635694
@_spi(Experimental) public var introducedNames: [LookupName] {
636-
parameterClause.parameters.flatMap { parameter in
695+
let parameters = parameterClause.parameters.flatMap { parameter in
637696
LookupName.getNames(from: parameter)
638697
}
698+
699+
if let accessorBlock, case .getter = accessorBlock.accessors {
700+
return parameters + [.implicit(.self(self))]
701+
} else {
702+
return parameters
703+
}
639704
}
640705

641706
@_spi(Experimental) public var scopeDebugName: String {
642707
"SubscriptDeclScope"
643708
}
709+
710+
/// Lookup results from this subscript scope.
711+
/// Routes to generic parameter clause scope if exists.
712+
@_spi(Experimental) public func lookup(
713+
_ identifier: Identifier?,
714+
at lookUpPosition: AbsolutePosition,
715+
with config: LookupConfig
716+
) -> [LookupResult] {
717+
var thisScopeResults: [LookupResult] = []
718+
719+
if !parameterClause.range.contains(lookUpPosition) && !returnClause.range.contains(lookUpPosition) {
720+
thisScopeResults = defaultLookupImplementation(
721+
identifier,
722+
at: position,
723+
with: config,
724+
propagateToParent: false
725+
)
726+
}
727+
728+
return thisScopeResults
729+
+ lookupThroughGenericParameterScope(
730+
identifier,
731+
at: lookUpPosition,
732+
with: config
733+
)
734+
}
735+
}
736+
737+
@_spi(Experimental) extension AccessorBlockSyntax: SequentialScopeSyntax {
738+
/// Names from the accessors or
739+
/// getters of this accessor block scope.
740+
@_spi(Experimental) public var introducedNames: [LookupName] {
741+
switch accessors {
742+
case .getter(let codeBlockItems):
743+
return codeBlockItems.flatMap { codeBlockItem in
744+
LookupName.getNames(from: codeBlockItem.item)
745+
}
746+
case .accessors:
747+
return []
748+
}
749+
}
750+
751+
@_spi(Experimental) public var scopeDebugName: String {
752+
"AccessorBlockScope"
753+
}
754+
755+
/// Names introduced in this accessir block scope.
756+
/// If `accessor` is of `.getter` kind, introduced
757+
/// it's items sequentially. Otherwise, propagate to parent.
758+
@_spi(Experimental) public func lookup(
759+
_ identifier: Identifier?,
760+
at lookUpPosition: AbsolutePosition,
761+
with config: LookupConfig
762+
) -> [LookupResult] {
763+
switch accessors {
764+
case .getter(let codeBlockItems):
765+
return sequentialLookup(in: codeBlockItems, identifier, at: lookUpPosition, with: config)
766+
case .accessors:
767+
return lookupInParent(identifier, at: lookUpPosition, with: config)
768+
}
769+
}
644770
}
645771

646772
@_spi(Experimental) extension TypeAliasDeclSyntax: WithGenericParametersScopeSyntax {

Tests/SwiftLexicalLookupTest/NameLookupTests.swift

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ final class testNameLookup: XCTestCase {
633633
)
634634
}
635635

636-
func testGuardOnFileScope() {
636+
func testGuardOnFileScope() { // TODO: Fix this according to ASTScope (ommiting class a)
637637
assertLexicalNameLookup(
638638
source: """
639639
let 1️⃣a = 0
@@ -902,7 +902,7 @@ final class testNameLookup: XCTestCase {
902902
)
903903
}
904904

905-
func testSwitchExpression() {
905+
func testSwitchExpression() { // TODO: For some reason ASTScope doesn't introduce any results besides first function call expr.
906906
assertLexicalNameLookup(
907907
source: """
908908
switch {
@@ -973,20 +973,16 @@ final class testNameLookup: XCTestCase {
973973
""",
974974
references: [
975975
"2️⃣": [
976-
.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["1️⃣"]),
977-
.lookInMembers(ClassDeclSyntax.self),
976+
.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["1️⃣"])
978977
],
979978
"3️⃣": [
980-
.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["1️⃣"]),
981-
.lookInMembers(ClassDeclSyntax.self),
979+
.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["1️⃣"])
982980
],
983981
"5️⃣": [
984-
.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["7️⃣"]),
985-
.lookInMembers(ClassDeclSyntax.self),
982+
.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["7️⃣"])
986983
],
987984
"6️⃣": [
988-
.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["4️⃣"]),
989-
.lookInMembers(ClassDeclSyntax.self),
985+
.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["4️⃣"])
990986
],
991987
],
992988
expectedResultTypes: .all(GenericParameterSyntax.self)
@@ -1070,7 +1066,7 @@ final class testNameLookup: XCTestCase {
10701066
)
10711067
}
10721068

1073-
func testSubscript() {
1069+
func testSubscript() { // TODO: Fix behavior of self keyword in subscript with accessors.
10741070
assertLexicalNameLookup(
10751071
source: """
10761072
class X {

0 commit comments

Comments
 (0)