-
Notifications
You must be signed in to change notification settings - Fork 440
[SwiftLexicalLookup] Add ASTScope related fixes and lookInMembers result kind. #2852
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
d83af9c
7521e4e
fae4d0e
3de7208
433f14b
0f9b2bc
baf6a2f
fc1ab88
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,7 @@ import SwiftSyntax | |
@_spi(Experimental) public enum ImplicitDecl { | ||
/// `self` keyword representing object instance. | ||
/// Could be associated with type declaration, extension, | ||
/// or closure captures. | ||
/// or closure captures. Introduced at function edge. | ||
case `self`(DeclSyntaxProtocol) | ||
/// `Self` keyword representing object type. | ||
/// Could be associated with type declaration or extension. | ||
|
@@ -135,6 +135,51 @@ import SwiftSyntax | |
} | ||
} | ||
|
||
/// Position of this name. | ||
/// | ||
/// For some syntax nodes, their position doesn't reflect | ||
/// the position at which a particular name was introduced at. | ||
/// Such cases are function parameters (as they can | ||
/// contain two identifiers) and function declarations (where name | ||
/// is precided by access modifiers and `func` keyword). | ||
@_spi(Experimental) public var position: AbsolutePosition { | ||
switch self { | ||
case .identifier(let syntax, _): | ||
return syntax.identifier.positionAfterSkippingLeadingTrivia | ||
case .declaration(let syntax): | ||
return syntax.name.positionAfterSkippingLeadingTrivia | ||
case .implicit(let implicitName): | ||
switch implicitName { | ||
case .self(let declSyntax): | ||
switch Syntax(declSyntax).as(SyntaxEnum.self) { | ||
case .functionDecl(let functionDecl): | ||
return functionDecl.name.positionAfterSkippingLeadingTrivia | ||
case .initializerDecl(let initializerDecl): | ||
return initializerDecl.initKeyword.positionAfterSkippingLeadingTrivia | ||
case .subscriptDecl(let subscriptDecl): | ||
return subscriptDecl.accessorBlock?.positionAfterSkippingLeadingTrivia | ||
?? subscriptDecl.endPositionBeforeTrailingTrivia | ||
case .variableDecl(let variableDecl): | ||
return variableDecl.bindings.first?.accessorBlock?.positionAfterSkippingLeadingTrivia | ||
?? variableDecl.endPosition | ||
default: | ||
return declSyntax.positionAfterSkippingLeadingTrivia | ||
} | ||
case .Self(let declSyntax): | ||
switch Syntax(declSyntax).as(SyntaxEnum.self) { | ||
case .protocolDecl(let protocolDecl): | ||
return protocolDecl.name.positionAfterSkippingLeadingTrivia | ||
Comment on lines
+170
to
+171
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we only need this for protocols and not other type declarations? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this PR, protocol declarations are the only places we are introducing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, you’re not handling class Foo {
func bar() -> Self { fatalError() }
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interestingly, it seems to me like
Nevertheless, there certainly are more places protocol Foo {}
extension Foo {
func bar() -> Self { fatalError() }
}
|
||
default: | ||
return declSyntax.positionAfterSkippingLeadingTrivia | ||
} | ||
case .error(let catchClause): | ||
return catchClause.body.positionAfterSkippingLeadingTrivia | ||
default: | ||
return implicitName.syntax.positionAfterSkippingLeadingTrivia | ||
} | ||
} | ||
} | ||
|
||
/// Point, after which the name is available in scope. | ||
/// If set to `nil`, the name is available at any point in scope. | ||
var accessibleAfter: AbsolutePosition? { | ||
|
@@ -166,7 +211,7 @@ import SwiftSyntax | |
) -> [LookupName] { | ||
switch Syntax(syntax).as(SyntaxEnum.self) { | ||
case .variableDecl(let variableDecl): | ||
return variableDecl.bindings.flatMap { binding in | ||
return variableDecl.bindings.reversed().flatMap { binding in | ||
getNames( | ||
from: binding.pattern, | ||
accessibleAfter: accessibleAfter != nil ? binding.endPositionBeforeTrailingTrivia : nil | ||
|
@@ -194,6 +239,8 @@ import SwiftSyntax | |
return functionCallExpr.arguments.flatMap { argument in | ||
getNames(from: argument.expression, accessibleAfter: accessibleAfter) | ||
} | ||
case .optionalChainingExpr(let optionalChainingExpr): | ||
return getNames(from: optionalChainingExpr.expression, accessibleAfter: accessibleAfter) | ||
default: | ||
if let namedDecl = Syntax(syntax).asProtocol(SyntaxProtocol.self) as? NamedDeclSyntax { | ||
return handle(namedDecl: namedDecl, accessibleAfter: accessibleAfter) | ||
|
@@ -210,12 +257,7 @@ import SwiftSyntax | |
identifiable: IdentifiableSyntax, | ||
accessibleAfter: AbsolutePosition? = nil | ||
) -> [LookupName] { | ||
switch identifiable.identifier.tokenKind { | ||
case .wildcard: | ||
return [] | ||
default: | ||
return [.identifier(identifiable, accessibleAfter: accessibleAfter)] | ||
} | ||
[.identifier(identifiable, accessibleAfter: accessibleAfter)] | ||
} | ||
|
||
/// Extracts name introduced by `NamedDeclSyntax` node. | ||
|
@@ -225,4 +267,27 @@ import SwiftSyntax | |
) -> [LookupName] { | ||
[.declaration(namedDecl)] | ||
} | ||
|
||
/// Debug description of this lookup name. | ||
@_spi(Experimental) public var debugDescription: String { | ||
let sourceLocationConverter = SourceLocationConverter(fileName: "", tree: syntax.root) | ||
let location = sourceLocationConverter.location(for: position) | ||
let strName = (identifier?.name ?? "NO-NAME") + " at: \(location.line):\(location.column)" | ||
|
||
switch self { | ||
case .identifier: | ||
let str = "identifier: \(strName)" | ||
|
||
if let accessibleAfter { | ||
let location = sourceLocationConverter.location(for: accessibleAfter) | ||
return str + " after: \(location.line):\(location.column)" | ||
} else { | ||
return str | ||
} | ||
case .declaration: | ||
return "declaration: \(strName)" | ||
case .implicit: | ||
return "implicit: \(strName)" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// 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 | ||
|
||
protocol CanInterleaveResultsLaterScopeSyntax: ScopeSyntax { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add a comment explaining what it means to interleave results later? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for pointing this out! I added documentation comments to the definition of |
||
/// Perform lookup in this scope and later introduce results | ||
/// passed as `resultsToInterleave`. | ||
/// The exact behavior depends on a specific scope. | ||
func lookupWithInterleavedResults( | ||
_ identifier: Identifier?, | ||
at lookUpPosition: AbsolutePosition, | ||
with config: LookupConfig, | ||
resultsToInterleave: [LookupResult] | ||
) -> [LookupResult] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// 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 | ||
|
||
protocol FunctionScopeSyntax: DeclSyntaxProtocol, WithGenericParametersScopeSyntax { | ||
var signature: FunctionSignatureSyntax { get } | ||
} | ||
|
||
extension FunctionScopeSyntax { | ||
/// Function parameters introduced by this function's signature. | ||
@_spi(Experimental) public var introducedNames: [LookupName] { | ||
signature.parameterClause.parameters.flatMap { parameter in | ||
LookupName.getNames(from: parameter) | ||
} + (parentScope?.is(MemberBlockSyntax.self) ?? false ? [.implicit(.self(self))] : []) | ||
} | ||
|
||
/// Lookup results from this function scope. | ||
/// Routes to generic parameter clause scope if exists. | ||
@_spi(Experimental) public func lookup( | ||
_ identifier: Identifier?, | ||
at lookUpPosition: AbsolutePosition, | ||
with config: LookupConfig | ||
) -> [LookupResult] { | ||
var thisScopeResults: [LookupResult] = [] | ||
|
||
if !signature.range.contains(lookUpPosition) { | ||
thisScopeResults = defaultLookupImplementation( | ||
identifier, | ||
at: position, | ||
with: config, | ||
propagateToParent: false | ||
) | ||
} | ||
|
||
return thisScopeResults | ||
+ lookupThroughGenericParameterScope( | ||
identifier, | ||
at: lookUpPosition, | ||
with: config | ||
) | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.