From bbc9b6a9ca797b189f3cc768e72b776cbeb6ddbf Mon Sep 17 00:00:00 2001 From: Jakub Florek Date: Wed, 7 Aug 2024 12:10:16 +0200 Subject: [PATCH 1/6] Add switch, generic parameter and function scopes. --- .../IdentifiableSyntax.swift | 18 +++ Sources/SwiftLexicalLookup/LookupName.swift | 31 +--- ...ParameterOrAssociatedTypeScopeSyntax.swift | 92 +++++++++++ ...oducingToSequentialParentScopeSyntax.swift | 4 +- .../{ => Scopes}/ScopeImplementations.swift | 103 +++++++++---- .../{ => Scopes}/ScopeSyntax.swift | 49 +++--- .../{ => Scopes}/SequentialScopeSyntax.swift | 24 ++- .../{ => Scopes}/TypeScopeSyntax.swift | 0 ...rametersOrAssociatedTypesScopeSyntax.swift | 87 +++++++++++ Sources/SwiftSyntax/Identifier.swift | 18 +-- Tests/SwiftLexicalLookupTest/Assertions.swift | 4 +- .../SwiftLexicalLookupTest/ExpectedName.swift | 8 +- .../NameLookupTests.swift | 145 +++++++++++++++++- 13 files changed, 466 insertions(+), 117 deletions(-) create mode 100644 Sources/SwiftLexicalLookup/Scopes/GenericParameterOrAssociatedTypeScopeSyntax.swift rename Sources/SwiftLexicalLookup/{ => Scopes}/IntroducingToSequentialParentScopeSyntax.swift (92%) rename Sources/SwiftLexicalLookup/{ => Scopes}/ScopeImplementations.swift (75%) rename Sources/SwiftLexicalLookup/{ => Scopes}/ScopeSyntax.swift (73%) rename Sources/SwiftLexicalLookup/{ => Scopes}/SequentialScopeSyntax.swift (78%) rename Sources/SwiftLexicalLookup/{ => Scopes}/TypeScopeSyntax.swift (100%) create mode 100644 Sources/SwiftLexicalLookup/Scopes/WithGenericParametersOrAssociatedTypesScopeSyntax.swift diff --git a/Sources/SwiftLexicalLookup/IdentifiableSyntax.swift b/Sources/SwiftLexicalLookup/IdentifiableSyntax.swift index 033dad3244b..a5b781f13b3 100644 --- a/Sources/SwiftLexicalLookup/IdentifiableSyntax.swift +++ b/Sources/SwiftLexicalLookup/IdentifiableSyntax.swift @@ -25,6 +25,12 @@ import SwiftSyntax } } +@_spi(Experimental) extension FunctionParameterSyntax: IdentifiableSyntax { + @_spi(Experimental) public var identifier: TokenSyntax { + secondName ?? firstName + } +} + @_spi(Experimental) extension ClosureShorthandParameterSyntax: IdentifiableSyntax { @_spi(Experimental) public var identifier: TokenSyntax { name @@ -47,3 +53,15 @@ import SwiftSyntax name } } + +@_spi(Experimental) extension GenericParameterSyntax: IdentifiableSyntax { + @_spi(Experimental) public var identifier: TokenSyntax { + name + } +} + +@_spi(Experimental) extension PrimaryAssociatedTypeSyntax: IdentifiableSyntax { + @_spi(Experimental) public var identifier: TokenSyntax { + name + } +} diff --git a/Sources/SwiftLexicalLookup/LookupName.swift b/Sources/SwiftLexicalLookup/LookupName.swift index aac72f6c24f..dd96dfa3005 100644 --- a/Sources/SwiftLexicalLookup/LookupName.swift +++ b/Sources/SwiftLexicalLookup/LookupName.swift @@ -110,10 +110,6 @@ import SwiftSyntax case declaration(NamedDeclSyntax) /// Name introduced implicitly by certain syntax nodes. case implicit(ImplicitDecl) - /// Explicit `self` keyword. - case `self`(IdentifiableSyntax, accessibleAfter: AbsolutePosition?) - /// Explicit `Self` keyword. - case `Self`(IdentifiableSyntax, accessibleAfter: AbsolutePosition?) /// Syntax associated with this name. @_spi(Experimental) public var syntax: SyntaxProtocol { @@ -124,8 +120,6 @@ import SwiftSyntax return syntax case .implicit(let implicitName): return implicitName.syntax - case .self(let syntax, _), .Self(let syntax, _): - return syntax } } @@ -138,10 +132,6 @@ import SwiftSyntax return Identifier(syntax.name) case .implicit(let kind): return kind.identifier - case .self: - return Identifier("self") - case .Self: - return Identifier("Self") } } @@ -149,9 +139,7 @@ import SwiftSyntax /// If set to `nil`, the name is available at any point in scope. var accessibleAfter: AbsolutePosition? { switch self { - case .identifier(_, let absolutePosition), - .self(_, let absolutePosition), - .Self(_, let absolutePosition): + case .identifier(_, let absolutePosition): return absolutePosition default: return nil @@ -159,14 +147,13 @@ import SwiftSyntax } /// Checks if this name was introduced before the syntax used for lookup. - func isAccessible(at origin: AbsolutePosition) -> Bool { + func isAccessible(at lookUpPosition: AbsolutePosition) -> Bool { guard let accessibleAfter else { return true } - return accessibleAfter <= origin + return accessibleAfter <= lookUpPosition } /// Checks if this name refers to the looked up phrase. func refersTo(_ lookedUpIdentifier: Identifier) -> Bool { - guard let identifier else { return false } return identifier == lookedUpIdentifier } @@ -229,16 +216,10 @@ import SwiftSyntax accessibleAfter: AbsolutePosition? = nil ) -> [LookupName] { switch identifiable.identifier.tokenKind { - case .keyword(.self): - return [.self(identifiable, accessibleAfter: accessibleAfter)] - case .keyword(.Self): - return [.Self(identifiable, accessibleAfter: accessibleAfter)] + case .wildcard: + return [] default: - if identifiable.identifier.tokenKind != .wildcard { - return [.identifier(identifiable, accessibleAfter: accessibleAfter)] - } else { - return [] - } + return [.identifier(identifiable, accessibleAfter: accessibleAfter)] } } diff --git a/Sources/SwiftLexicalLookup/Scopes/GenericParameterOrAssociatedTypeScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/GenericParameterOrAssociatedTypeScopeSyntax.swift new file mode 100644 index 00000000000..3be0a541c38 --- /dev/null +++ b/Sources/SwiftLexicalLookup/Scopes/GenericParameterOrAssociatedTypeScopeSyntax.swift @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import SwiftSyntax + +/// Scope that introduces generic parameter or +/// primary associated type names and directs +/// futher lookup to it's `WithGenericParametersOrAssociatedTypesScopeSyntax` +/// parent scope's parent scope (i.e. on return, bypasses names +/// introduced by it's parent). +@_spi(Experimental) public protocol GenericParameterOrAssociatedTypeScopeSyntax: ScopeSyntax {} + +@_spi(Experimental) extension GenericParameterOrAssociatedTypeScopeSyntax { + /// Returns names matching lookup and bypasses + /// `WithGenericParametersOrAssociatedTypesScopeSyntax` parent scope in futher lookup. + /// + /// example: + /// ```swift + /// let a = 23 + /// func foo(a: A) { + /// a // <-- start lookup here + /// } + /// ``` + /// When starting lookup at the `a` reference, + /// lookup first visits the code block scope associated + /// with the function's body. Then, it's forwarded to the + /// function declaration scope and then to generic parameter + /// scope (`WithGenericParametersOrAssociatedTypesScopeSyntax`). + /// Then, to ensure there is no infinite cycle, + /// this method passes lookup to function scope's parent scope + /// (in this case: file scope). + @_spi(Experimental) public func lookup( + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, + with config: LookupConfig + ) -> [LookupResult] { + return defaultLookupImplementation( + identifier: identifier, + at: lookUpPosition, + with: config, + propagateToParent: false + ) + + lookupBypassingParentResults( + identifier: identifier, + at: lookUpPosition, + with: config + ) + } + + /// Bypasses names introduced by `WithGenericParametersOrAssociatedTypesScopeSyntax` parent scope. + /// + /// example: + /// ```swift + /// let a = 23 + /// func foo(a: A) { + /// a // <-- start lookup here + /// } + /// ``` + /// When starting lookup at the `a` reference, + /// lookup first visits the code block scope associated + /// with the function's body. Then, it's forwarded to the + /// function declaration scope and then to generic parameter + /// scope (`WithGenericParametersOrAssociatedTypesScopeSyntax`). + /// Then, to ensure there is no infinite cycle, + /// we use this method instead of the standard `lookupInParent` + /// to pass lookup to the function scope's parent scope (in this case: file scope) + /// and effectively bypass names already looked up before. + private func lookupBypassingParentResults( + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, + with config: LookupConfig + ) -> [LookupResult] { + guard let parentScope else { return [] } + + if let parentScope = Syntax(parentScope).asProtocol(SyntaxProtocol.self) + as? WithGenericParametersOrAssociatedTypesScopeSyntax + { + return parentScope.lookupInParent(identifier: identifier, at: lookUpPosition, with: config) + } else { + return lookupInParent(identifier: identifier, at: lookUpPosition, with: config) + } + } +} diff --git a/Sources/SwiftLexicalLookup/IntroducingToSequentialParentScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/IntroducingToSequentialParentScopeSyntax.swift similarity index 92% rename from Sources/SwiftLexicalLookup/IntroducingToSequentialParentScopeSyntax.swift rename to Sources/SwiftLexicalLookup/Scopes/IntroducingToSequentialParentScopeSyntax.swift index 5d58aa7a87b..e216677799d 100644 --- a/Sources/SwiftLexicalLookup/IntroducingToSequentialParentScopeSyntax.swift +++ b/Sources/SwiftLexicalLookup/Scopes/IntroducingToSequentialParentScopeSyntax.swift @@ -19,8 +19,8 @@ protocol IntroducingToSequentialParentScopeSyntax: ScopeSyntax { /// Returns results matching lookup that should be /// interleaved with results of the sequential parent. func lookupFromSequentialParent( - for identifier: Identifier?, - at origin: AbsolutePosition, + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, with config: LookupConfig ) -> [LookupResult] } diff --git a/Sources/SwiftLexicalLookup/ScopeImplementations.swift b/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift similarity index 75% rename from Sources/SwiftLexicalLookup/ScopeImplementations.swift rename to Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift index 432f99b900f..a4d3f97807b 100644 --- a/Sources/SwiftLexicalLookup/ScopeImplementations.swift +++ b/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift @@ -97,15 +97,15 @@ import SwiftSyntax /// - for `memberBlock` - a, b, c, d, e, f /// - for `codeBlock` - a @_spi(Experimental) public func lookup( - for identifier: Identifier?, - at origin: AbsolutePosition, + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, with config: LookupConfig ) -> [LookupResult] { switch config.fileScopeHandling { case .memberBlock: let names = introducedNames(using: .memberBlock) .filter { lookupName in - checkName(identifier, refersTo: lookupName, at: origin) + checkName(identifier, refersTo: lookupName, at: lookUpPosition) } return names.isEmpty ? [] : [.fromFileScope(self, withNames: names)] @@ -119,22 +119,19 @@ import SwiftSyntax if encounteredNonDeclaration { sequentialItems.append(codeBlockItem) + } else if item.is(DeclSyntax.self) { + let foundNames = LookupName.getNames(from: item) + members.append(contentsOf: foundNames.filter { checkName(identifier, refersTo: $0, at: lookUpPosition) }) } else { - if item.is(DeclSyntax.self) { - let foundNames = LookupName.getNames(from: item) - - members.append(contentsOf: foundNames.filter { checkName(identifier, refersTo: $0, at: origin) }) - } else { - encounteredNonDeclaration = true - sequentialItems.append(codeBlockItem) - } + encounteredNonDeclaration = true + sequentialItems.append(codeBlockItem) } } let sequentialNames = sequentialLookup( in: sequentialItems, - for: identifier, - at: origin, + identifier: identifier, + at: lookUpPosition, with: config, createResultsForThisScopeWith: { .fromFileScope(self, withNames: $0) } ) @@ -154,14 +151,14 @@ import SwiftSyntax } @_spi(Experimental) public func lookup( - for identifier: Identifier?, - at origin: AbsolutePosition, + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, with config: LookupConfig ) -> [LookupResult] { sequentialLookup( in: statements, - for: identifier, - at: origin, + identifier: identifier, + at: lookUpPosition, with: config, createResultsForThisScopeWith: { .fromScope(self, withNames: $0) } ) @@ -274,14 +271,14 @@ import SwiftSyntax /// } /// ``` @_spi(Experimental) public func lookup( - for identifier: Identifier?, - at origin: AbsolutePosition, + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, with config: LookupConfig ) -> [LookupResult] { - if let elseBody, elseBody.position <= origin, elseBody.endPosition >= origin { - return lookupInParent(for: identifier, at: origin, with: config) + if let elseBody, elseBody.range.contains(lookUpPosition) { + return lookupInParent(identifier: identifier, at: lookUpPosition, with: config) } else { - return defaultLookupImplementation(for: identifier, at: origin, with: config) + return defaultLookupImplementation(identifier: identifier, at: lookUpPosition, with: config) } } } @@ -319,25 +316,24 @@ import SwiftSyntax /// // a is visible here /// ``` func lookupFromSequentialParent( - for identifier: Identifier?, - at origin: AbsolutePosition, + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, with config: LookupConfig ) -> [LookupResult] { - guard body.position > origin || body.endPosition < origin - else { return [] } + guard !body.range.contains(lookUpPosition) else { return [] } let names = namesIntroducedToSequentialParent.filter { introducedName in - checkName(identifier, refersTo: introducedName, at: origin) + checkName(identifier, refersTo: introducedName, at: lookUpPosition) } return names.isEmpty ? [] : [.fromScope(self, withNames: names)] } } -@_spi(Experimental) extension ActorDeclSyntax: TypeScopeSyntax {} -@_spi(Experimental) extension ClassDeclSyntax: TypeScopeSyntax {} -@_spi(Experimental) extension StructDeclSyntax: TypeScopeSyntax {} -@_spi(Experimental) extension EnumDeclSyntax: TypeScopeSyntax {} +@_spi(Experimental) extension ActorDeclSyntax: TypeScopeSyntax, WithGenericParametersOrAssociatedTypesScopeSyntax {} +@_spi(Experimental) extension ClassDeclSyntax: TypeScopeSyntax, WithGenericParametersOrAssociatedTypesScopeSyntax {} +@_spi(Experimental) extension StructDeclSyntax: TypeScopeSyntax, WithGenericParametersOrAssociatedTypesScopeSyntax {} +@_spi(Experimental) extension EnumDeclSyntax: TypeScopeSyntax, WithGenericParametersOrAssociatedTypesScopeSyntax {} @_spi(Experimental) extension ExtensionDeclSyntax: TypeScopeSyntax {} @_spi(Experimental) extension AccessorDeclSyntax: ScopeSyntax { @@ -360,7 +356,50 @@ import SwiftSyntax @_spi(Experimental) extension CatchClauseSyntax: ScopeSyntax { /// Implicit `error` when there are no catch items. - public var introducedNames: [LookupName] { + @_spi(Experimental) public var introducedNames: [LookupName] { return catchItems.isEmpty ? [.implicit(.error(self))] : [] } } + +@_spi(Experimental) extension SwitchCaseSyntax: ScopeSyntax { + /// Names introduced within `case` items. + @_spi(Experimental) public var introducedNames: [LookupName] { + label.as(SwitchCaseLabelSyntax.self)?.caseItems.flatMap { child in + LookupName.getNames(from: child.pattern) + } ?? [] + } +} + +@_spi(Experimental) extension GenericParameterClauseSyntax: GenericParameterOrAssociatedTypeScopeSyntax { + /// Generic parameter names introduced by this clause. + @_spi(Experimental) public var introducedNames: [LookupName] { + parameters.children(viewMode: .sourceAccurate).flatMap { child in + LookupName.getNames(from: child, accessibleAfter: child.endPosition) + } + } +} + +@_spi(Experimental) extension PrimaryAssociatedTypeClauseSyntax: GenericParameterOrAssociatedTypeScopeSyntax { + /// Primary associated type names introduced by this clause. + @_spi(Experimental) public var introducedNames: [LookupName] { + primaryAssociatedTypes.children(viewMode: .sourceAccurate).flatMap { child in + LookupName.getNames(from: child, accessibleAfter: child.endPosition) + } + } +} + +@_spi(Experimental) extension ProtocolDeclSyntax: WithGenericParametersOrAssociatedTypesScopeSyntax { + /// Protocol declarations don't introduce names by themselves. + @_spi(Experimental) public var introducedNames: [LookupName] { + [] + } +} + +@_spi(Experimental) extension FunctionDeclSyntax: WithGenericParametersOrAssociatedTypesScopeSyntax { + /// Function parameters introduced by this function's signature. + @_spi(Experimental) public var introducedNames: [LookupName] { + signature.parameterClause.parameters.flatMap { parameter in + LookupName.getNames(from: parameter) + } + } +} diff --git a/Sources/SwiftLexicalLookup/ScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/ScopeSyntax.swift similarity index 73% rename from Sources/SwiftLexicalLookup/ScopeSyntax.swift rename to Sources/SwiftLexicalLookup/Scopes/ScopeSyntax.swift index af9a247a40c..bc0ec2dd674 100644 --- a/Sources/SwiftLexicalLookup/ScopeSyntax.swift +++ b/Sources/SwiftLexicalLookup/Scopes/ScopeSyntax.swift @@ -44,10 +44,10 @@ extension SyntaxProtocol { /// in this exact order. The constant declaration within the function body is omitted /// due to the ordering rules that prioritize visibility within the function body. @_spi(Experimental) public func lookup( - for identifier: Identifier?, + identifier: Identifier?, with config: LookupConfig = LookupConfig() ) -> [LookupResult] { - scope?.lookup(for: identifier, at: self.position, with: config) ?? [] + scope?.lookup(identifier: identifier, at: self.position, with: config) ?? [] } } @@ -58,10 +58,9 @@ extension SyntaxProtocol { var introducedNames: [LookupName] { get } /// Finds all declarations `identifier` refers to. `syntax` specifies the node lookup was triggered with. /// If `identifier` set to `nil`, returns all available names at the given node. - /// `state` represents lookup state passed between lookup methods. func lookup( - for identifier: Identifier?, - at origin: AbsolutePosition, + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, with config: LookupConfig ) -> [LookupResult] } @@ -74,47 +73,49 @@ extension SyntaxProtocol { /// Returns `LookupResult` of all names introduced in this scope that `identifier` /// refers to and is accessible at given syntax node then passes lookup to the parent. /// If `identifier` set to `nil`, returns all available names at the given node. - /// `state` represents lookup state passed between lookup methods. @_spi(Experimental) public func lookup( - for identifier: Identifier?, - at origin: AbsolutePosition, + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, with config: LookupConfig ) -> [LookupResult] { - defaultLookupImplementation(for: identifier, at: origin, with: config) + defaultLookupImplementation(identifier: identifier, at: lookUpPosition, with: config) } /// Returns `LookupResult` of all names introduced in this scope that `identifier` /// refers to and is accessible at given syntax node then passes lookup to the parent. /// If `identifier` set to `nil`, returns all available names at the given node. func defaultLookupImplementation( - for identifier: Identifier?, - at origin: AbsolutePosition, - with config: LookupConfig + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, + with config: LookupConfig, + propagateToParent: Bool = true ) -> [LookupResult] { let filteredNames = introducedNames .filter { introducedName in - checkName(identifier, refersTo: introducedName, at: origin) + checkName(identifier, refersTo: introducedName, at: lookUpPosition) } - if filteredNames.isEmpty { - return lookupInParent(for: identifier, at: origin, with: config) - } else { - return [.fromScope(self, withNames: filteredNames)] - + lookupInParent(for: identifier, at: origin, with: config) - } + let fromThisScope = filteredNames.isEmpty ? [] : [LookupResult.fromScope(self, withNames: filteredNames)] + + return fromThisScope + + (propagateToParent ? lookupInParent(identifier: identifier, at: lookUpPosition, with: config) : []) } /// Looks up in parent scope. func lookupInParent( - for identifier: Identifier?, - at origin: AbsolutePosition, + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, with config: LookupConfig ) -> [LookupResult] { - parentScope?.lookup(for: identifier, at: origin, with: config) ?? [] + parentScope?.lookup(identifier: identifier, at: lookUpPosition, with: config) ?? [] } - func checkName(_ name: Identifier?, refersTo introducedName: LookupName, at origin: AbsolutePosition) -> Bool { - introducedName.isAccessible(at: origin) && (name == nil || introducedName.refersTo(name!)) + func checkName( + _ name: Identifier?, + refersTo introducedName: LookupName, + at lookUpPosition: AbsolutePosition + ) -> Bool { + introducedName.isAccessible(at: lookUpPosition) && (name == nil || introducedName.refersTo(name!)) } } diff --git a/Sources/SwiftLexicalLookup/SequentialScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/SequentialScopeSyntax.swift similarity index 78% rename from Sources/SwiftLexicalLookup/SequentialScopeSyntax.swift rename to Sources/SwiftLexicalLookup/Scopes/SequentialScopeSyntax.swift index 21f6de167cd..e99878e93c0 100644 --- a/Sources/SwiftLexicalLookup/SequentialScopeSyntax.swift +++ b/Sources/SwiftLexicalLookup/Scopes/SequentialScopeSyntax.swift @@ -40,12 +40,20 @@ extension SequentialScopeSyntax { /// code block scope in this exact order. func sequentialLookup( in codeBlockItems: some Collection, - for identifier: Identifier?, - at origin: AbsolutePosition, + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, with config: LookupConfig, createResultsForThisScopeWith getResults: ([LookupName]) -> (LookupResult) ) -> [LookupResult] { + // Sequential scope needs to ensure all type declarations are + // available in the whole scope (first loop) and + // then that results from IntroducingToSequentialParentScopeSyntax + // are properly interleaved with the results produced by this scope. var results: [LookupResult] = [] + // We need to use currentChunk because we + // can't add the names directly to results + // as we need to partition them based on results + // obtained from IntroducingToSequentialParentScopeSyntax var currentChunk: [LookupName] = [] var itemsWithoutNamedDecl: [CodeBlockItemSyntax] = [] @@ -55,7 +63,7 @@ extension SequentialScopeSyntax { from: codeBlockItem.item, accessibleAfter: codeBlockItem.endPosition ).filter { introducedName in - checkName(identifier, refersTo: introducedName, at: origin) + checkName(identifier, refersTo: introducedName, at: lookUpPosition) } } else { itemsWithoutNamedDecl.append(codeBlockItem) @@ -63,15 +71,15 @@ extension SequentialScopeSyntax { } for codeBlockItem in itemsWithoutNamedDecl { - guard codeBlockItem.position < origin else { break } + guard codeBlockItem.position <= lookUpPosition else { break } if let introducingToParentScope = Syntax(codeBlockItem.item).asProtocol(SyntaxProtocol.self) as? IntroducingToSequentialParentScopeSyntax { // Get results from encountered scope. let introducedResults = introducingToParentScope.lookupFromSequentialParent( - for: identifier, - at: origin, + identifier: identifier, + at: lookUpPosition, with: config ) @@ -91,7 +99,7 @@ extension SequentialScopeSyntax { from: codeBlockItem.item, accessibleAfter: codeBlockItem.endPosition ).filter { introducedName in - checkName(identifier, refersTo: introducedName, at: origin) + checkName(identifier, refersTo: introducedName, at: lookUpPosition) } } } @@ -101,6 +109,6 @@ extension SequentialScopeSyntax { results.append(getResults(currentChunk)) } - return results.reversed() + lookupInParent(for: identifier, at: origin, with: config) + return results.reversed() + lookupInParent(identifier: identifier, at: lookUpPosition, with: config) } } diff --git a/Sources/SwiftLexicalLookup/TypeScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/TypeScopeSyntax.swift similarity index 100% rename from Sources/SwiftLexicalLookup/TypeScopeSyntax.swift rename to Sources/SwiftLexicalLookup/Scopes/TypeScopeSyntax.swift diff --git a/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersOrAssociatedTypesScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersOrAssociatedTypesScopeSyntax.swift new file mode 100644 index 00000000000..f14fb0ea6d7 --- /dev/null +++ b/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersOrAssociatedTypesScopeSyntax.swift @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import SwiftSyntax + +@_spi(Experimental) public protocol WithGenericParametersOrAssociatedTypesScopeSyntax: ScopeSyntax { + var genericParameterClause: GenericParameterClauseSyntax? { get } + var primaryAssociatedTypeClause: PrimaryAssociatedTypeClauseSyntax? { get } +} + +@_spi(Experimental) extension WithGenericParametersOrAssociatedTypesScopeSyntax { + @_spi(Experimental) public var genericParameterClause: GenericParameterClauseSyntax? { nil } + @_spi(Experimental) public var primaryAssociatedTypeClause: PrimaryAssociatedTypeClauseSyntax? { nil } + + /// Returns names matching lookup and passes lookup to + /// the generic parameter or primary associated type clause scopes. + /// + /// example: + /// ```swift + /// let a = 23 + /// func foo(a: A) { + /// a // <-- start lookup here + /// } + /// ``` + /// When starting lookup at the `a` reference, + /// lookup first visits the code block scope associated + /// with the function's body. Then, it's forwarded to the + /// function declaration scope and then to generic parameter + /// scope (`WithGenericParametersOrAssociatedTypesScopeSyntax`) + /// instead of it's actual parent scope (in this case: file scope). + @_spi(Experimental) public func lookup( + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, + with config: LookupConfig + ) -> [LookupResult] { + return defaultLookupImplementation( + identifier: identifier, + at: position, + with: config, + propagateToParent: false + ) + + lookupThroughGenericParameterScope( + identifier: identifier, + at: lookUpPosition, + with: config + ) + } + + /// Passes lookup to this scope's generic parameter or + /// primary associated type clause scope (`WithGenericParametersOrAssociatedTypesScopeSyntax`). + /// + /// example: + /// ```swift + /// let a = 23 + /// func foo(a: A) { + /// a // <-- start lookup here + /// } + /// ``` + /// When starting lookup at the `a` reference, + /// lookup first visits the code block scope associated + /// with the function's body. Then, it's forwarded to the + /// function declaration scope and then to generic parameter + /// scope (`WithGenericParametersOrAssociatedTypesScopeSyntax`) + /// with this method (instead of using standard `lookupInParent`). + private func lookupThroughGenericParameterScope( + identifier: Identifier?, + at lookUpPosition: AbsolutePosition, + with config: LookupConfig + ) -> [LookupResult] { + if let genericParameterClause { + return genericParameterClause.lookup(identifier: identifier, at: lookUpPosition, with: config) + } else if let primaryAssociatedTypeClause { + return primaryAssociatedTypeClause.lookup(identifier: identifier, at: lookUpPosition, with: config) + } else { + return lookupInParent(identifier: identifier, at: lookUpPosition, with: config) + } + } +} diff --git a/Sources/SwiftSyntax/Identifier.swift b/Sources/SwiftSyntax/Identifier.swift index 97a588395e3..e99bf61a7ae 100644 --- a/Sources/SwiftSyntax/Identifier.swift +++ b/Sources/SwiftSyntax/Identifier.swift @@ -19,15 +19,16 @@ public struct Identifier: Equatable, Hashable, Sendable { @_spi(RawSyntax) public let raw: RawIdentifier - let arena: SyntaxArenaRef? + private let arena: SyntaxArenaRef? public init?(_ token: TokenSyntax) { - guard case .identifier = token.tokenKind else { + switch token.tokenKind { + case .identifier, .keyword(.self), .keyword(.Self): + self.raw = RawIdentifier(token.tokenView) + self.arena = token.raw.arenaReference + default: return nil } - - self.raw = RawIdentifier(token.tokenView) - self.arena = token.raw.arenaReference } public init(_ staticString: StaticString) { @@ -40,13 +41,6 @@ public struct Identifier: Equatable, Hashable, Sendable { } } -extension Identifier { - @_spi(Testing) public init(anyToken token: TokenSyntax) { - self.raw = RawIdentifier(token.tokenView.rawText) - self.arena = token.raw.arenaReference - } -} - @_spi(RawSyntax) public struct RawIdentifier: Equatable, Hashable, Sendable { public let name: SyntaxText diff --git a/Tests/SwiftLexicalLookupTest/Assertions.swift b/Tests/SwiftLexicalLookupTest/Assertions.swift index eb671c5ccce..d152d80b07c 100644 --- a/Tests/SwiftLexicalLookupTest/Assertions.swift +++ b/Tests/SwiftLexicalLookupTest/Assertions.swift @@ -93,9 +93,9 @@ func assertLexicalNameLookup( assertLexicalScopeQuery( source: source, methodUnderTest: { marker, tokenAtMarker in - let lookupIdentifier = Identifier(tokenAtMarker) ?? Identifier(anyToken: tokenAtMarker) + let lookupIdentifier = Identifier(tokenAtMarker) - let result = tokenAtMarker.lookup(for: useNilAsTheParameter ? nil : lookupIdentifier, with: config) + let result = tokenAtMarker.lookup(identifier: useNilAsTheParameter ? nil : lookupIdentifier, with: config) guard let expectedValues = references[marker] else { XCTFail("For marker \(marker), couldn't find result expectation") diff --git a/Tests/SwiftLexicalLookupTest/ExpectedName.swift b/Tests/SwiftLexicalLookupTest/ExpectedName.swift index 8db81175767..4047ef90f3b 100644 --- a/Tests/SwiftLexicalLookupTest/ExpectedName.swift +++ b/Tests/SwiftLexicalLookupTest/ExpectedName.swift @@ -62,15 +62,11 @@ enum NameExpectation: ExpectedName { case identifier(String) case declaration(String) case implicit(ImplicitNameExpectation) - case `self`(String) - case `Self`(String) var marker: String { switch self { case .identifier(let marker), - .declaration(let marker), - .self(let marker), - .Self(let marker): + .declaration(let marker): return marker case .implicit(let implicitName): return implicitName.marker @@ -81,8 +77,6 @@ enum NameExpectation: ExpectedName { switch (name, self) { case (.identifier, .identifier): break case (.declaration, .declaration): break - case (.self, .self): break - case (.Self, .Self): break case (.implicit(let implicitName), .implicit(let implicitNameExpectation)): implicitNameExpectation.assertExpectation(marker: marker, for: implicitName) default: diff --git a/Tests/SwiftLexicalLookupTest/NameLookupTests.swift b/Tests/SwiftLexicalLookupTest/NameLookupTests.swift index 121610a1ed9..139645f7f7f 100644 --- a/Tests/SwiftLexicalLookupTest/NameLookupTests.swift +++ b/Tests/SwiftLexicalLookupTest/NameLookupTests.swift @@ -112,7 +112,7 @@ final class testNameLookup: XCTestCase { let 1️⃣a = 1 let 2️⃣b = 2 let 3️⃣x: (Int, Int, Int) = { 4️⃣a, _, 5️⃣c in - print(6️⃣a, 7️⃣b, 8️⃣c, 0️⃣$0) + print(6️⃣a, 7️⃣b, 8️⃣c) } 9️⃣x() } @@ -125,7 +125,6 @@ final class testNameLookup: XCTestCase { "7️⃣": [.fromScope(CodeBlockSyntax.self, expectedNames: ["2️⃣"])], "8️⃣": [.fromScope(ClosureExprSyntax.self, expectedNames: ["5️⃣"])], "9️⃣": [.fromScope(CodeBlockSyntax.self, expectedNames: ["3️⃣"])], - "0️⃣": [], ], expectedResultTypes: .all( IdentifierPatternSyntax.self, @@ -152,7 +151,7 @@ final class testNameLookup: XCTestCase { """, references: [ "5️⃣": [ - .fromScope(ClosureExprSyntax.self, expectedNames: [NameExpectation.`self`("2️⃣")]), + .fromScope(ClosureExprSyntax.self, expectedNames: [NameExpectation.identifier("2️⃣")]), .fromScope(ClassDeclSyntax.self, expectedNames: [NameExpectation.implicit(.self("7️⃣"))]), ], "6️⃣": [ @@ -179,7 +178,7 @@ final class testNameLookup: XCTestCase { let 1️⃣a = 1 let 2️⃣b = 2 let 3️⃣x = { (4️⃣a b: Int, 5️⃣c: Int) in - print(6️⃣a, 7️⃣b, 8️⃣c, 0️⃣$0) + print(6️⃣a, 7️⃣b, 8️⃣c) } 9️⃣x() } @@ -192,7 +191,6 @@ final class testNameLookup: XCTestCase { ], "8️⃣": [.fromScope(ClosureExprSyntax.self, expectedNames: ["5️⃣"])], "9️⃣": [.fromScope(CodeBlockSyntax.self, expectedNames: ["3️⃣"])], - "0️⃣": [], ], expectedResultTypes: .all( IdentifierPatternSyntax.self, @@ -659,12 +657,19 @@ final class testNameLookup: XCTestCase { 8️⃣oldValue } } + + var x: Int = 2 { + didSet(myNewValue) { + print(9️⃣newValue) + } + } """, references: [ "2️⃣": [.fromScope(AccessorDeclSyntax.self, expectedNames: [NameExpectation.implicit(.newValue("1️⃣"))])], "4️⃣": [.fromScope(AccessorDeclSyntax.self, expectedNames: [NameExpectation.identifier("3️⃣")])], "6️⃣": [.fromScope(AccessorDeclSyntax.self, expectedNames: [NameExpectation.implicit(.newValue("5️⃣"))])], "8️⃣": [.fromScope(AccessorDeclSyntax.self, expectedNames: [NameExpectation.implicit(.oldValue("7️⃣"))])], + "9️⃣": [], ] ) } @@ -830,4 +835,134 @@ final class testNameLookup: XCTestCase { ] ) } + + func testSwitchExpression() { + assertLexicalNameLookup( + source: """ + switch { + case .x(let 1️⃣a, let 2️⃣b), .y(.c(let 3️⃣c), .z): + print(4️⃣a, 5️⃣b, 6️⃣c) + case .z(let 7️⃣a), .smth(let 8️⃣a) + print(9️⃣a) + default: + print(0️⃣a) + } + """, + references: [ + "4️⃣": [.fromScope(SwitchCaseSyntax.self, expectedNames: ["1️⃣"])], + "5️⃣": [.fromScope(SwitchCaseSyntax.self, expectedNames: ["2️⃣"])], + "6️⃣": [.fromScope(SwitchCaseSyntax.self, expectedNames: ["3️⃣"])], + "9️⃣": [.fromScope(SwitchCaseSyntax.self, expectedNames: ["7️⃣", "8️⃣"])], + "0️⃣": [], + ], + expectedResultTypes: .all(IdentifierPatternSyntax.self) + ) + } + + func testSimpleGenericParameterScope() { + assertLexicalNameLookup( + source: """ + class A<1️⃣T1, 2️⃣T2> { + let 7️⃣x: 3️⃣T1 = v + let y: 4️⃣T2 = v + + class B<5️⃣T1> { + let z: 6️⃣T1 = v + + func test() { + print(8️⃣x) + } + } + } + """, + references: [ + "3️⃣": [.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["1️⃣"])], + "4️⃣": [.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["2️⃣"])], + "6️⃣": [ + .fromScope(GenericParameterClauseSyntax.self, expectedNames: ["5️⃣"]), + .fromScope(GenericParameterClauseSyntax.self, expectedNames: ["1️⃣"]), + ], + "8️⃣": [.fromScope(MemberBlockSyntax.self, expectedNames: ["7️⃣"])], + ], + expectedResultTypes: .all(GenericParameterSyntax.self, except: ["7️⃣": IdentifierPatternSyntax.self]) + ) + } + + func testGenericParameterOrdering() { + assertLexicalNameLookup( + source: """ + class Foo<1️⃣A: 2️⃣A, B: 3️⃣A, 4️⃣C: 5️⃣D, D: 6️⃣C> {} + """, + references: [ + "2️⃣": [], + "3️⃣": [.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["1️⃣"])], + "4️⃣": [], + "6️⃣": [.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["4️⃣"])], + ], + expectedResultTypes: .all(GenericParameterSyntax.self) + ) + } + + func testPrimaryAssociatedTypes() { + assertLexicalNameLookup( + source: """ + protocol Foo<1️⃣A, 2️⃣B> { + 5️⃣associatedtype 3️⃣A + 6️⃣associatedtype 4️⃣B + } + """, + references: [ + "3️⃣": [ + .fromScope(MemberBlockSyntax.self, expectedNames: ["5️⃣"]), // Conceptually, should associated type be visible at it's declaration? It's a reference and declaration at the same time and all members' names are available inside their bodies, but at the same time it doesn't seem quite right... + .fromScope(PrimaryAssociatedTypeClauseSyntax.self, expectedNames: ["1️⃣"]), + ], + "4️⃣": [ + .fromScope(MemberBlockSyntax.self, expectedNames: ["6️⃣"]), + .fromScope(PrimaryAssociatedTypeClauseSyntax.self, expectedNames: ["2️⃣"]), + ], + ], + expectedResultTypes: .all( + PrimaryAssociatedTypeSyntax.self, + except: [ + "5️⃣": AssociatedTypeDeclSyntax.self, + "6️⃣": AssociatedTypeDeclSyntax.self, + ] + ) + ) + } + + func testFunctionDeclarationScope() { + assertLexicalNameLookup( + source: """ + class X<1️⃣A> { + let 2️⃣a: A + + func foo<3️⃣A, 4️⃣B>(5️⃣a: 6️⃣A, 7️⃣b: 8️⃣B) -> 9️⃣B { + return 0️⃣a + 🔟b + } + } + """, + references: [ + "6️⃣": [ + .fromScope(GenericParameterClauseSyntax.self, expectedNames: ["3️⃣"]), + .fromScope(GenericParameterClauseSyntax.self, expectedNames: ["1️⃣"]), + ], + "8️⃣": [.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["4️⃣"])], + "9️⃣": [.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["4️⃣"])], + "0️⃣": [ + .fromScope(FunctionDeclSyntax.self, expectedNames: ["5️⃣"]), + .fromScope(MemberBlockSyntax.self, expectedNames: ["2️⃣"]), + ], + "🔟": [.fromScope(FunctionDeclSyntax.self, expectedNames: ["7️⃣"])], + ], + expectedResultTypes: .all( + GenericParameterSyntax.self, + except: [ + "2️⃣": IdentifierPatternSyntax.self, + "5️⃣": FunctionParameterSyntax.self, + "7️⃣": FunctionParameterSyntax.self, + ] + ) + ) + } } From adf11ebf01d3ce736813fad3653d1d2da6df0af7 Mon Sep 17 00:00:00 2001 From: Jakub Florek Date: Thu, 15 Aug 2024 16:33:48 +0200 Subject: [PATCH 2/6] Fix merge artifacts. --- ...nericParameterOrAssociatedTypeScopeSyntax.swift | 12 ++++++------ .../SwiftLexicalLookup/Scopes/ScopeSyntax.swift | 12 +++++------- ...ricParametersOrAssociatedTypesScopeSyntax.swift | 14 +++++++------- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Sources/SwiftLexicalLookup/Scopes/GenericParameterOrAssociatedTypeScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/GenericParameterOrAssociatedTypeScopeSyntax.swift index 3be0a541c38..cd927a0e4b1 100644 --- a/Sources/SwiftLexicalLookup/Scopes/GenericParameterOrAssociatedTypeScopeSyntax.swift +++ b/Sources/SwiftLexicalLookup/Scopes/GenericParameterOrAssociatedTypeScopeSyntax.swift @@ -39,18 +39,18 @@ import SwiftSyntax /// this method passes lookup to function scope's parent scope /// (in this case: file scope). @_spi(Experimental) public func lookup( - identifier: Identifier?, + _ identifier: Identifier?, at lookUpPosition: AbsolutePosition, with config: LookupConfig ) -> [LookupResult] { return defaultLookupImplementation( - identifier: identifier, + identifier, at: lookUpPosition, with: config, propagateToParent: false ) + lookupBypassingParentResults( - identifier: identifier, + identifier, at: lookUpPosition, with: config ) @@ -75,7 +75,7 @@ import SwiftSyntax /// to pass lookup to the function scope's parent scope (in this case: file scope) /// and effectively bypass names already looked up before. private func lookupBypassingParentResults( - identifier: Identifier?, + _ identifier: Identifier?, at lookUpPosition: AbsolutePosition, with config: LookupConfig ) -> [LookupResult] { @@ -84,9 +84,9 @@ import SwiftSyntax if let parentScope = Syntax(parentScope).asProtocol(SyntaxProtocol.self) as? WithGenericParametersOrAssociatedTypesScopeSyntax { - return parentScope.lookupInParent(identifier: identifier, at: lookUpPosition, with: config) + return parentScope.lookupInParent(identifier, at: lookUpPosition, with: config) } else { - return lookupInParent(identifier: identifier, at: lookUpPosition, with: config) + return lookupInParent(identifier, at: lookUpPosition, with: config) } } } diff --git a/Sources/SwiftLexicalLookup/Scopes/ScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/ScopeSyntax.swift index a407f8fcb0e..c1b6c43d59e 100644 --- a/Sources/SwiftLexicalLookup/Scopes/ScopeSyntax.swift +++ b/Sources/SwiftLexicalLookup/Scopes/ScopeSyntax.swift @@ -87,7 +87,8 @@ extension SyntaxProtocol { func defaultLookupImplementation( _ identifier: Identifier?, at lookUpPosition: AbsolutePosition, - with config: LookupConfig + with config: LookupConfig, + propagateToParent: Bool = true ) -> [LookupResult] { let filteredNames = introducedNames @@ -95,12 +96,9 @@ extension SyntaxProtocol { checkIdentifier(identifier, refersTo: introducedName, at: lookUpPosition) } - if filteredNames.isEmpty { - return lookupInParent(identifier, at: lookUpPosition, with: config) - } else { - return [.fromScope(self, withNames: filteredNames)] - + lookupInParent(identifier, at: lookUpPosition, with: config) - } + let fromThisScope = filteredNames.isEmpty ? [] : [LookupResult.fromScope(self, withNames: filteredNames)] + + return fromThisScope + (propagateToParent ? lookupInParent(identifier, at: lookUpPosition, with: config) : []) } /// Looks up in parent scope. diff --git a/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersOrAssociatedTypesScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersOrAssociatedTypesScopeSyntax.swift index f14fb0ea6d7..cf18be7b6b6 100644 --- a/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersOrAssociatedTypesScopeSyntax.swift +++ b/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersOrAssociatedTypesScopeSyntax.swift @@ -38,18 +38,18 @@ import SwiftSyntax /// scope (`WithGenericParametersOrAssociatedTypesScopeSyntax`) /// instead of it's actual parent scope (in this case: file scope). @_spi(Experimental) public func lookup( - identifier: Identifier?, + _ identifier: Identifier?, at lookUpPosition: AbsolutePosition, with config: LookupConfig ) -> [LookupResult] { return defaultLookupImplementation( - identifier: identifier, + identifier, at: position, with: config, propagateToParent: false ) + lookupThroughGenericParameterScope( - identifier: identifier, + identifier, at: lookUpPosition, with: config ) @@ -72,16 +72,16 @@ import SwiftSyntax /// scope (`WithGenericParametersOrAssociatedTypesScopeSyntax`) /// with this method (instead of using standard `lookupInParent`). private func lookupThroughGenericParameterScope( - identifier: Identifier?, + _ identifier: Identifier?, at lookUpPosition: AbsolutePosition, with config: LookupConfig ) -> [LookupResult] { if let genericParameterClause { - return genericParameterClause.lookup(identifier: identifier, at: lookUpPosition, with: config) + return genericParameterClause.lookup(identifier, at: lookUpPosition, with: config) } else if let primaryAssociatedTypeClause { - return primaryAssociatedTypeClause.lookup(identifier: identifier, at: lookUpPosition, with: config) + return primaryAssociatedTypeClause.lookup(identifier, at: lookUpPosition, with: config) } else { - return lookupInParent(identifier: identifier, at: lookUpPosition, with: config) + return lookupInParent(identifier, at: lookUpPosition, with: config) } } } From 4cac8a8f69e1efe7ea9172142287b3f0cf3402bc Mon Sep 17 00:00:00 2001 From: Jakub Florek Date: Thu, 15 Aug 2024 17:12:03 +0200 Subject: [PATCH 3/6] Fix primary associated type handling. --- ...wift => GenericParameterScopeSyntax.swift} | 19 ++--- .../Scopes/ScopeImplementations.swift | 85 ++++++++++++++----- ...=> WithGenericParametersScopeSyntax.swift} | 18 ++-- .../NameLookupTests.swift | 25 +++--- 4 files changed, 95 insertions(+), 52 deletions(-) rename Sources/SwiftLexicalLookup/Scopes/{GenericParameterOrAssociatedTypeScopeSyntax.swift => GenericParameterScopeSyntax.swift} (79%) rename Sources/SwiftLexicalLookup/Scopes/{WithGenericParametersOrAssociatedTypesScopeSyntax.swift => WithGenericParametersScopeSyntax.swift} (74%) diff --git a/Sources/SwiftLexicalLookup/Scopes/GenericParameterOrAssociatedTypeScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/GenericParameterScopeSyntax.swift similarity index 79% rename from Sources/SwiftLexicalLookup/Scopes/GenericParameterOrAssociatedTypeScopeSyntax.swift rename to Sources/SwiftLexicalLookup/Scopes/GenericParameterScopeSyntax.swift index cd927a0e4b1..46d0a712726 100644 --- a/Sources/SwiftLexicalLookup/Scopes/GenericParameterOrAssociatedTypeScopeSyntax.swift +++ b/Sources/SwiftLexicalLookup/Scopes/GenericParameterScopeSyntax.swift @@ -12,16 +12,15 @@ import SwiftSyntax -/// Scope that introduces generic parameter or -/// primary associated type names and directs -/// futher lookup to it's `WithGenericParametersOrAssociatedTypesScopeSyntax` +/// Scope that introduces generic parameter names and directs +/// futher lookup to it's `WithGenericParametersScopeSyntax` /// parent scope's parent scope (i.e. on return, bypasses names /// introduced by it's parent). -@_spi(Experimental) public protocol GenericParameterOrAssociatedTypeScopeSyntax: ScopeSyntax {} +@_spi(Experimental) public protocol GenericParameterScopeSyntax: ScopeSyntax {} -@_spi(Experimental) extension GenericParameterOrAssociatedTypeScopeSyntax { +@_spi(Experimental) extension GenericParameterScopeSyntax { /// Returns names matching lookup and bypasses - /// `WithGenericParametersOrAssociatedTypesScopeSyntax` parent scope in futher lookup. + /// `WithGenericParametersScopeSyntax` parent scope in futher lookup. /// /// example: /// ```swift @@ -34,7 +33,7 @@ import SwiftSyntax /// lookup first visits the code block scope associated /// with the function's body. Then, it's forwarded to the /// function declaration scope and then to generic parameter - /// scope (`WithGenericParametersOrAssociatedTypesScopeSyntax`). + /// scope (`WithGenericParametersScopeSyntax`). /// Then, to ensure there is no infinite cycle, /// this method passes lookup to function scope's parent scope /// (in this case: file scope). @@ -56,7 +55,7 @@ import SwiftSyntax ) } - /// Bypasses names introduced by `WithGenericParametersOrAssociatedTypesScopeSyntax` parent scope. + /// Bypasses names introduced by `WithGenericParametersScopeSyntax` parent scope. /// /// example: /// ```swift @@ -69,7 +68,7 @@ import SwiftSyntax /// lookup first visits the code block scope associated /// with the function's body. Then, it's forwarded to the /// function declaration scope and then to generic parameter - /// scope (`WithGenericParametersOrAssociatedTypesScopeSyntax`). + /// scope (`WithGenericParametersScopeSyntax`). /// Then, to ensure there is no infinite cycle, /// we use this method instead of the standard `lookupInParent` /// to pass lookup to the function scope's parent scope (in this case: file scope) @@ -82,7 +81,7 @@ import SwiftSyntax guard let parentScope else { return [] } if let parentScope = Syntax(parentScope).asProtocol(SyntaxProtocol.self) - as? WithGenericParametersOrAssociatedTypesScopeSyntax + as? WithGenericParametersScopeSyntax { return parentScope.lookupInParent(identifier, at: lookUpPosition, with: config) } else { diff --git a/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift b/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift index fefac614e4a..69ed2dd4a2e 100644 --- a/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift +++ b/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift @@ -290,6 +290,24 @@ import SwiftSyntax LookupName.getNames(from: member.decl) } } + + /// Creates a result from associated type declarations + /// made by it's members. + func lookupAssociatedTypeDeclarations( + _ identifier: Identifier?, + at lookUpPosition: AbsolutePosition, + with config: LookupConfig + ) -> [LookupResult] { + let filteredNames = members.flatMap { member in + guard member.decl.kind == .associatedTypeDecl else { return [LookupName]() } + + return LookupName.getNames(from: member.decl) + }.filter { name in + checkIdentifier(identifier, refersTo: name, at: lookUpPosition) + } + + return filteredNames.isEmpty ? [] : [.fromScope(self, withNames: filteredNames)] + } } @_spi(Experimental) extension GuardStmtSyntax: IntroducingToSequentialParentScopeSyntax { @@ -330,10 +348,10 @@ import SwiftSyntax } } -@_spi(Experimental) extension ActorDeclSyntax: TypeScopeSyntax, WithGenericParametersOrAssociatedTypesScopeSyntax {} -@_spi(Experimental) extension ClassDeclSyntax: TypeScopeSyntax, WithGenericParametersOrAssociatedTypesScopeSyntax {} -@_spi(Experimental) extension StructDeclSyntax: TypeScopeSyntax, WithGenericParametersOrAssociatedTypesScopeSyntax {} -@_spi(Experimental) extension EnumDeclSyntax: TypeScopeSyntax, WithGenericParametersOrAssociatedTypesScopeSyntax {} +@_spi(Experimental) extension ActorDeclSyntax: TypeScopeSyntax, WithGenericParametersScopeSyntax {} +@_spi(Experimental) extension ClassDeclSyntax: TypeScopeSyntax, WithGenericParametersScopeSyntax {} +@_spi(Experimental) extension StructDeclSyntax: TypeScopeSyntax, WithGenericParametersScopeSyntax {} +@_spi(Experimental) extension EnumDeclSyntax: TypeScopeSyntax, WithGenericParametersScopeSyntax {} @_spi(Experimental) extension ExtensionDeclSyntax: TypeScopeSyntax {} @_spi(Experimental) extension AccessorDeclSyntax: ScopeSyntax { @@ -370,32 +388,61 @@ import SwiftSyntax } } -@_spi(Experimental) extension GenericParameterClauseSyntax: GenericParameterOrAssociatedTypeScopeSyntax { - /// Generic parameter names introduced by this clause. +@_spi(Experimental) extension ProtocolDeclSyntax: ScopeSyntax { + /// Protocol declarations don't introduce names by themselves. @_spi(Experimental) public var introducedNames: [LookupName] { - parameters.children(viewMode: .sourceAccurate).flatMap { child in - LookupName.getNames(from: child, accessibleAfter: child.endPosition) - } + [] } -} -@_spi(Experimental) extension PrimaryAssociatedTypeClauseSyntax: GenericParameterOrAssociatedTypeScopeSyntax { - /// Primary associated type names introduced by this clause. - @_spi(Experimental) public var introducedNames: [LookupName] { - primaryAssociatedTypes.children(viewMode: .sourceAccurate).flatMap { child in - LookupName.getNames(from: child, accessibleAfter: child.endPosition) + /// For the lookup initiated from inside primary + /// associated type clause, this function also finds + /// all associated type declarations made inside the + /// protocol member block. + /// + /// example: + /// ```swift + /// class A {} + /// + /// protocol Foo*/> { + /// associatedtype A + /// class A {} + /// } + /// ``` + /// For the lookup started at the primary associated type `A`, + /// the function returns exactly two results. First associated with the member + /// block that consists of the `associatedtype A` declaration and + /// the latter one from the file scope and `class A` exactly in this order. + public func lookup( + _ identifier: Identifier?, + at lookUpPosition: AbsolutePosition, + with config: LookupConfig + ) -> [LookupResult] { + var results: [LookupResult] = [] + + if let primaryAssociatedTypeClause, + primaryAssociatedTypeClause.range.contains(lookUpPosition) + { + results = memberBlock.lookupAssociatedTypeDeclarations( + identifier, + at: lookUpPosition, + with: config + ) } + + return results + defaultLookupImplementation(identifier, at: lookUpPosition, with: config) } } -@_spi(Experimental) extension ProtocolDeclSyntax: WithGenericParametersOrAssociatedTypesScopeSyntax { - /// Protocol declarations don't introduce names by themselves. +@_spi(Experimental) extension GenericParameterClauseSyntax: GenericParameterScopeSyntax { + /// Generic parameter names introduced by this clause. @_spi(Experimental) public var introducedNames: [LookupName] { - [] + parameters.children(viewMode: .sourceAccurate).flatMap { child in + LookupName.getNames(from: child, accessibleAfter: child.endPosition) + } } } -@_spi(Experimental) extension FunctionDeclSyntax: WithGenericParametersOrAssociatedTypesScopeSyntax { +@_spi(Experimental) extension FunctionDeclSyntax: WithGenericParametersScopeSyntax { /// Function parameters introduced by this function's signature. @_spi(Experimental) public var introducedNames: [LookupName] { signature.parameterClause.parameters.flatMap { parameter in diff --git a/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersOrAssociatedTypesScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersScopeSyntax.swift similarity index 74% rename from Sources/SwiftLexicalLookup/Scopes/WithGenericParametersOrAssociatedTypesScopeSyntax.swift rename to Sources/SwiftLexicalLookup/Scopes/WithGenericParametersScopeSyntax.swift index cf18be7b6b6..00c9cd88e77 100644 --- a/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersOrAssociatedTypesScopeSyntax.swift +++ b/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersScopeSyntax.swift @@ -12,17 +12,13 @@ import SwiftSyntax -@_spi(Experimental) public protocol WithGenericParametersOrAssociatedTypesScopeSyntax: ScopeSyntax { +@_spi(Experimental) public protocol WithGenericParametersScopeSyntax: ScopeSyntax { var genericParameterClause: GenericParameterClauseSyntax? { get } - var primaryAssociatedTypeClause: PrimaryAssociatedTypeClauseSyntax? { get } } -@_spi(Experimental) extension WithGenericParametersOrAssociatedTypesScopeSyntax { - @_spi(Experimental) public var genericParameterClause: GenericParameterClauseSyntax? { nil } - @_spi(Experimental) public var primaryAssociatedTypeClause: PrimaryAssociatedTypeClauseSyntax? { nil } - +@_spi(Experimental) extension WithGenericParametersScopeSyntax { /// Returns names matching lookup and passes lookup to - /// the generic parameter or primary associated type clause scopes. + /// the generic parameter clause scopes. /// /// example: /// ```swift @@ -35,7 +31,7 @@ import SwiftSyntax /// lookup first visits the code block scope associated /// with the function's body. Then, it's forwarded to the /// function declaration scope and then to generic parameter - /// scope (`WithGenericParametersOrAssociatedTypesScopeSyntax`) + /// scope (`WithGenericParametersScopeSyntax`) /// instead of it's actual parent scope (in this case: file scope). @_spi(Experimental) public func lookup( _ identifier: Identifier?, @@ -56,7 +52,7 @@ import SwiftSyntax } /// Passes lookup to this scope's generic parameter or - /// primary associated type clause scope (`WithGenericParametersOrAssociatedTypesScopeSyntax`). + /// primary associated type clause scope (`WithGenericParametersScopeSyntax`). /// /// example: /// ```swift @@ -69,7 +65,7 @@ import SwiftSyntax /// lookup first visits the code block scope associated /// with the function's body. Then, it's forwarded to the /// function declaration scope and then to generic parameter - /// scope (`WithGenericParametersOrAssociatedTypesScopeSyntax`) + /// scope (`WithGenericParametersScopeSyntax`) /// with this method (instead of using standard `lookupInParent`). private func lookupThroughGenericParameterScope( _ identifier: Identifier?, @@ -78,8 +74,6 @@ import SwiftSyntax ) -> [LookupResult] { if let genericParameterClause { return genericParameterClause.lookup(identifier, at: lookUpPosition, with: config) - } else if let primaryAssociatedTypeClause { - return primaryAssociatedTypeClause.lookup(identifier, at: lookUpPosition, with: config) } else { return lookupInParent(identifier, at: lookUpPosition, with: config) } diff --git a/Tests/SwiftLexicalLookupTest/NameLookupTests.swift b/Tests/SwiftLexicalLookupTest/NameLookupTests.swift index 139645f7f7f..1e993239110 100644 --- a/Tests/SwiftLexicalLookupTest/NameLookupTests.swift +++ b/Tests/SwiftLexicalLookupTest/NameLookupTests.swift @@ -906,26 +906,29 @@ final class testNameLookup: XCTestCase { func testPrimaryAssociatedTypes() { assertLexicalNameLookup( source: """ + 0️⃣class A {} + protocol Foo<1️⃣A, 2️⃣B> { - 5️⃣associatedtype 3️⃣A - 6️⃣associatedtype 4️⃣B + 3️⃣associatedtype A + 4️⃣associatedtype B + + class A {} + class B {} } """, references: [ - "3️⃣": [ - .fromScope(MemberBlockSyntax.self, expectedNames: ["5️⃣"]), // Conceptually, should associated type be visible at it's declaration? It's a reference and declaration at the same time and all members' names are available inside their bodies, but at the same time it doesn't seem quite right... - .fromScope(PrimaryAssociatedTypeClauseSyntax.self, expectedNames: ["1️⃣"]), + "1️⃣": [ + .fromScope(MemberBlockSyntax.self, expectedNames: ["3️⃣"]), + .fromFileScope(expectedNames: ["0️⃣"]), ], - "4️⃣": [ - .fromScope(MemberBlockSyntax.self, expectedNames: ["6️⃣"]), - .fromScope(PrimaryAssociatedTypeClauseSyntax.self, expectedNames: ["2️⃣"]), + "2️⃣": [ + .fromScope(MemberBlockSyntax.self, expectedNames: ["4️⃣"]) ], ], expectedResultTypes: .all( - PrimaryAssociatedTypeSyntax.self, + AssociatedTypeDeclSyntax.self, except: [ - "5️⃣": AssociatedTypeDeclSyntax.self, - "6️⃣": AssociatedTypeDeclSyntax.self, + "0️⃣": ClassDeclSyntax.self ] ) ) From c05403ac79b1718f217ef0f39d7367a8a35ed450 Mon Sep 17 00:00:00 2001 From: Jakub Florek Date: Wed, 21 Aug 2024 13:19:20 +0200 Subject: [PATCH 4/6] Add CMakeLists to SwiftLexicalLookup. --- Sources/CMakeLists.txt | 1 + Sources/SwiftLexicalLookup/CMakeLists.txt | 29 +++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 Sources/SwiftLexicalLookup/CMakeLists.txt diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt index 5c2b0520b92..7c00da25f0e 100644 --- a/Sources/CMakeLists.txt +++ b/Sources/CMakeLists.txt @@ -11,6 +11,7 @@ add_subdirectory(_SwiftSyntaxCShims) add_subdirectory(SwiftBasicFormat) add_subdirectory(SwiftSyntax) add_subdirectory(SwiftDiagnostics) +add_subdirectory(SwiftLexicalLookup) add_subdirectory(SwiftLibraryPluginProvider) add_subdirectory(SwiftParser) add_subdirectory(SwiftParserDiagnostics) diff --git a/Sources/SwiftLexicalLookup/CMakeLists.txt b/Sources/SwiftLexicalLookup/CMakeLists.txt new file mode 100644 index 00000000000..7a5acaf57e3 --- /dev/null +++ b/Sources/SwiftLexicalLookup/CMakeLists.txt @@ -0,0 +1,29 @@ +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for Swift project authors + +add_swift_syntax_library(SwiftLexicalLookup + IdentifiableSyntax.swift + LookupName.swift + LookupResult.swift + SimpleLookupQueries.swift + + Configurations/FileScopeHandlingConfig.swift + Configurations/LookupConfig.swift + + Scopes/GenericParameterScopeSyntax.swift + Scopes/IntroducingToSequentialParentScopeSyntax.swift + Scopes/ScopeImplementations.swift + Scopes/ScopeSyntax.swift + Scopes/SequentialScopeSyntax.swift + Scopes/TypeScopeSyntax.swift + Scopes/WithGenericParametersScopeSyntax.swift +) + +target_link_swift_syntax_libraries(SwiftLexicalLookup PUBLIC +SwiftSyntax) + From 57183fc995200d6ed3a6cd8755a9c761883064fd Mon Sep 17 00:00:00 2001 From: Jakub Florek Date: Wed, 28 Aug 2024 15:29:01 +0200 Subject: [PATCH 5/6] Add suggested changes. --- Sources/SwiftLexicalLookup/CMakeLists.txt | 2 +- .../Scopes/GenericParameterScopeSyntax.swift | 8 +-- .../Scopes/ScopeImplementations.swift | 28 ++++++++--- .../Scopes/SequentialScopeSyntax.swift | 2 +- .../WithGenericParametersScopeSyntax.swift | 4 +- .../NameLookupTests.swift | 50 +++++++++++++++++++ 6 files changed, 80 insertions(+), 14 deletions(-) diff --git a/Sources/SwiftLexicalLookup/CMakeLists.txt b/Sources/SwiftLexicalLookup/CMakeLists.txt index 7a5acaf57e3..b6cd9204fc3 100644 --- a/Sources/SwiftLexicalLookup/CMakeLists.txt +++ b/Sources/SwiftLexicalLookup/CMakeLists.txt @@ -25,5 +25,5 @@ add_swift_syntax_library(SwiftLexicalLookup ) target_link_swift_syntax_libraries(SwiftLexicalLookup PUBLIC -SwiftSyntax) + SwiftSyntax) diff --git a/Sources/SwiftLexicalLookup/Scopes/GenericParameterScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/GenericParameterScopeSyntax.swift index 46d0a712726..eac1a67c824 100644 --- a/Sources/SwiftLexicalLookup/Scopes/GenericParameterScopeSyntax.swift +++ b/Sources/SwiftLexicalLookup/Scopes/GenericParameterScopeSyntax.swift @@ -13,16 +13,16 @@ import SwiftSyntax /// Scope that introduces generic parameter names and directs -/// futher lookup to it's `WithGenericParametersScopeSyntax` +/// futher lookup to its `WithGenericParametersScopeSyntax` /// parent scope's parent scope (i.e. on return, bypasses names -/// introduced by it's parent). +/// introduced by its parent). @_spi(Experimental) public protocol GenericParameterScopeSyntax: ScopeSyntax {} @_spi(Experimental) extension GenericParameterScopeSyntax { /// Returns names matching lookup and bypasses /// `WithGenericParametersScopeSyntax` parent scope in futher lookup. /// - /// example: + /// ### Example /// ```swift /// let a = 23 /// func foo(a: A) { @@ -57,7 +57,7 @@ import SwiftSyntax /// Bypasses names introduced by `WithGenericParametersScopeSyntax` parent scope. /// - /// example: + /// ### Example /// ```swift /// let a = 23 /// func foo(a: A) { diff --git a/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift b/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift index 69ed2dd4a2e..5c59f8ba66c 100644 --- a/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift +++ b/Sources/SwiftLexicalLookup/Scopes/ScopeImplementations.swift @@ -176,7 +176,7 @@ import SwiftSyntax /// All names introduced by the closure signature. /// Could be closure captures or (shorthand) parameters. /// - /// Example: + /// ### Example /// ```swift /// let x = { [weak self, a] b, _ in /// // <-- @@ -222,7 +222,7 @@ import SwiftSyntax /// Finds parent scope, omitting ancestor `if` statements if part of their `else if` clause. /// - /// Example: + /// ### Example /// ```swift /// func foo() { /// if let a = x { @@ -262,7 +262,7 @@ import SwiftSyntax /// Lookup triggered from inside of `else` /// clause is immediately forwarded to parent scope. /// - /// Example: + /// ### Example /// ```swift /// if let a = x { /// // <-- a is visible here @@ -326,7 +326,7 @@ import SwiftSyntax /// Lookup triggered from within of the `else` body /// returns no names. /// - /// Example: + /// ### Example /// ```swift /// guard let a = x else { /// return // a is not visible here @@ -399,7 +399,7 @@ import SwiftSyntax /// all associated type declarations made inside the /// protocol member block. /// - /// example: + /// ### Example /// ```swift /// class A {} /// @@ -436,7 +436,7 @@ import SwiftSyntax @_spi(Experimental) extension GenericParameterClauseSyntax: GenericParameterScopeSyntax { /// Generic parameter names introduced by this clause. @_spi(Experimental) public var introducedNames: [LookupName] { - parameters.children(viewMode: .sourceAccurate).flatMap { child in + parameters.children(viewMode: .fixedUp).flatMap { child in LookupName.getNames(from: child, accessibleAfter: child.endPosition) } } @@ -450,3 +450,19 @@ import SwiftSyntax } } } + +@_spi(Experimental) extension SubscriptDeclSyntax: WithGenericParametersScopeSyntax { + /// Parameters introduced by this subscript. + @_spi(Experimental) public var introducedNames: [LookupName] { + parameterClause.parameters.flatMap { parameter in + LookupName.getNames(from: parameter) + } + } +} + +@_spi(Experimental) extension TypeAliasDeclSyntax: WithGenericParametersScopeSyntax { + /// Type alias doesn't introduce any names to it's children. + @_spi(Experimental) public var introducedNames: [LookupName] { + [] + } +} diff --git a/Sources/SwiftLexicalLookup/Scopes/SequentialScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/SequentialScopeSyntax.swift index d8a87c3dc3d..da96821373e 100644 --- a/Sources/SwiftLexicalLookup/Scopes/SequentialScopeSyntax.swift +++ b/Sources/SwiftLexicalLookup/Scopes/SequentialScopeSyntax.swift @@ -22,7 +22,7 @@ extension SequentialScopeSyntax { /// and included `IntroducingToSequentialParentScopeSyntax` children /// scopes that match the lookup. /// - /// Example: + /// ### Example /// ```swift /// func foo() { /// let a = 1 diff --git a/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersScopeSyntax.swift b/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersScopeSyntax.swift index 00c9cd88e77..5ab700bfe4b 100644 --- a/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersScopeSyntax.swift +++ b/Sources/SwiftLexicalLookup/Scopes/WithGenericParametersScopeSyntax.swift @@ -20,7 +20,7 @@ import SwiftSyntax /// Returns names matching lookup and passes lookup to /// the generic parameter clause scopes. /// - /// example: + /// ### Example /// ```swift /// let a = 23 /// func foo(a: A) { @@ -54,7 +54,7 @@ import SwiftSyntax /// Passes lookup to this scope's generic parameter or /// primary associated type clause scope (`WithGenericParametersScopeSyntax`). /// - /// example: + /// ### Example /// ```swift /// let a = 23 /// func foo(a: A) { diff --git a/Tests/SwiftLexicalLookupTest/NameLookupTests.swift b/Tests/SwiftLexicalLookupTest/NameLookupTests.swift index 1e993239110..14c47abf483 100644 --- a/Tests/SwiftLexicalLookupTest/NameLookupTests.swift +++ b/Tests/SwiftLexicalLookupTest/NameLookupTests.swift @@ -968,4 +968,54 @@ final class testNameLookup: XCTestCase { ) ) } + + func testSubscript() { + assertLexicalNameLookup( + source: """ + class X { + let 0️⃣c = 123 + + subscript<1️⃣A, 2️⃣B>(3️⃣a: 4️⃣A, 5️⃣b: 6️⃣B) -> 7️⃣B { + return 8️⃣a + 9️⃣b + 🔟c + } + } + """, + references: [ + "4️⃣": [.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["1️⃣"])], + "6️⃣": [.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["2️⃣"])], + "7️⃣": [.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["2️⃣"])], + "8️⃣": [.fromScope(SubscriptDeclSyntax.self, expectedNames: ["3️⃣"])], + "9️⃣": [.fromScope(SubscriptDeclSyntax.self, expectedNames: ["5️⃣"])], + "🔟": [.fromScope(MemberBlockSyntax.self, expectedNames: ["0️⃣"])], + ], + expectedResultTypes: .all( + GenericParameterSyntax.self, + except: [ + "0️⃣": IdentifierPatternSyntax.self, + "3️⃣": FunctionParameterSyntax.self, + "5️⃣": FunctionParameterSyntax.self, + ] + ) + ) + } + + func testTypealias() { + assertLexicalNameLookup( + source: """ + typealias SomeType<1️⃣A> = X<2️⃣A, 3️⃣NoMatch> + + 7️⃣typealias SomeOtherType<4️⃣A> = X<5️⃣A, 6️⃣SomeOtherType> + """, + references: [ + "2️⃣": [.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["1️⃣"])], + "3️⃣": [], + "5️⃣": [.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["4️⃣"])], + "6️⃣": [.fromFileScope(expectedNames: ["7️⃣"])], + ], + expectedResultTypes: .all( + GenericParameterSyntax.self, + except: ["7️⃣": TypeAliasDeclSyntax.self] + ) + ) + } } From 5e8c6d404a44e780d26f2040d16b7dbbd7de4760 Mon Sep 17 00:00:00 2001 From: Jakub Florek Date: Wed, 28 Aug 2024 15:41:58 +0200 Subject: [PATCH 6/6] Fix typo in a test case. --- Tests/SwiftLexicalLookupTest/NameLookupTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/SwiftLexicalLookupTest/NameLookupTests.swift b/Tests/SwiftLexicalLookupTest/NameLookupTests.swift index 14c47abf483..ff96b8230d9 100644 --- a/Tests/SwiftLexicalLookupTest/NameLookupTests.swift +++ b/Tests/SwiftLexicalLookupTest/NameLookupTests.swift @@ -896,7 +896,7 @@ final class testNameLookup: XCTestCase { references: [ "2️⃣": [], "3️⃣": [.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["1️⃣"])], - "4️⃣": [], + "5️⃣": [], "6️⃣": [.fromScope(GenericParameterClauseSyntax.self, expectedNames: ["4️⃣"])], ], expectedResultTypes: .all(GenericParameterSyntax.self)