diff --git a/Sources/Frontend/Scan.swift b/Sources/Frontend/Scan.swift index a5c4432f6..344c7d7d8 100644 --- a/Sources/Frontend/Scan.swift +++ b/Sources/Frontend/Scan.swift @@ -70,7 +70,7 @@ final class Scan { let indexLogger = logger.contextualized(with: "index") let plan = try driver.plan(logger: indexLogger) let syncSourceGraph = SynchronizedSourceGraph(graph: graph) - let pipeline = IndexPipeline(plan: plan, graph: syncSourceGraph, logger: indexLogger, configuration: configuration) + let pipeline = IndexPipeline(plan: plan, graph: syncSourceGraph, logger: indexLogger, configuration: configuration, swiftVersion: swiftVersion) try pipeline.perform() logger.endInterval(indexInterval) } diff --git a/Sources/Indexer/IndexPipeline.swift b/Sources/Indexer/IndexPipeline.swift index 25fabafe4..96fc8aaa6 100644 --- a/Sources/Indexer/IndexPipeline.swift +++ b/Sources/Indexer/IndexPipeline.swift @@ -1,6 +1,7 @@ import Configuration import Foundation import Logger +import Shared import SourceGraph public struct IndexPipeline { @@ -8,12 +9,14 @@ public struct IndexPipeline { private let graph: SynchronizedSourceGraph private let logger: ContextualLogger private let configuration: Configuration + private let swiftVersion: SwiftVersion - public init(plan: IndexPlan, graph: SynchronizedSourceGraph, logger: ContextualLogger, configuration: Configuration) { + public init(plan: IndexPlan, graph: SynchronizedSourceGraph, logger: ContextualLogger, configuration: Configuration, swiftVersion: SwiftVersion) { self.plan = plan self.graph = graph self.logger = logger self.configuration = configuration + self.swiftVersion = swiftVersion } public func perform() throws { @@ -21,7 +24,8 @@ public struct IndexPipeline { sourceFiles: plan.sourceFiles, graph: graph, logger: logger, - configuration: configuration + configuration: configuration, + swiftVersion: swiftVersion ).perform() if !plan.plistPaths.isEmpty { diff --git a/Sources/Indexer/SwiftIndexer.swift b/Sources/Indexer/SwiftIndexer.swift index 904213ec6..10adc79f3 100644 --- a/Sources/Indexer/SwiftIndexer.swift +++ b/Sources/Indexer/SwiftIndexer.swift @@ -17,17 +17,20 @@ final class SwiftIndexer: Indexer { private let graph: SynchronizedSourceGraph private let logger: ContextualLogger private let configuration: Configuration + private let swiftVersion: SwiftVersion required init( sourceFiles: [SourceFile: [IndexUnit]], graph: SynchronizedSourceGraph, logger: ContextualLogger, - configuration: Configuration + configuration: Configuration, + swiftVersion: SwiftVersion ) { self.sourceFiles = sourceFiles self.graph = graph self.logger = logger.contextualized(with: "swift") self.configuration = configuration + self.swiftVersion = swiftVersion super.init(configuration: configuration) } @@ -39,7 +42,8 @@ final class SwiftIndexer: Indexer { retainAllDeclarations: isRetained(file), graph: graph, logger: logger, - configuration: configuration + configuration: configuration, + swiftVersion: swiftVersion ) } @@ -88,6 +92,7 @@ final class SwiftIndexer: Indexer { private let logger: ContextualLogger private let configuration: Configuration private var retainAllDeclarations: Bool + private let swiftVersion: SwiftVersion required init( sourceFile: SourceFile, @@ -95,7 +100,8 @@ final class SwiftIndexer: Indexer { retainAllDeclarations: Bool, graph: SynchronizedSourceGraph, logger: ContextualLogger, - configuration: Configuration + configuration: Configuration, + swiftVersion: SwiftVersion ) { self.sourceFile = sourceFile self.units = units @@ -103,6 +109,7 @@ final class SwiftIndexer: Indexer { self.graph = graph self.logger = logger self.configuration = configuration + self.swiftVersion = swiftVersion } // swiftlint:disable nesting @@ -242,7 +249,7 @@ final class SwiftIndexer: Indexer { graph.addIndexedModules(sourceFile.modules) } - let multiplexingSyntaxVisitor = try MultiplexingSyntaxVisitor(file: sourceFile) + let multiplexingSyntaxVisitor = try MultiplexingSyntaxVisitor(file: sourceFile, swiftVersion: swiftVersion) let declarationSyntaxVisitor = multiplexingSyntaxVisitor.add(DeclarationSyntaxVisitor.self) let importSyntaxVisitor = multiplexingSyntaxVisitor.add(ImportSyntaxVisitor.self) diff --git a/Sources/SyntaxAnalysis/DeclarationSyntaxVisitor.swift b/Sources/SyntaxAnalysis/DeclarationSyntaxVisitor.swift index b3778af52..52a67d341 100644 --- a/Sources/SyntaxAnalysis/DeclarationSyntaxVisitor.swift +++ b/Sources/SyntaxAnalysis/DeclarationSyntaxVisitor.swift @@ -1,4 +1,5 @@ import Foundation +import Shared import SourceGraph import SwiftSyntax @@ -24,6 +25,7 @@ public final class DeclarationSyntaxVisitor: PeripherySyntaxVisitor { private let sourceLocationBuilder: SourceLocationBuilder private let typeSyntaxInspector: TypeSyntaxInspector + private let swiftVersion: SwiftVersion private(set) var results: [Result] = [] public var resultsByLocation: [Location: Result] { @@ -32,8 +34,9 @@ public final class DeclarationSyntaxVisitor: PeripherySyntaxVisitor { } } - public init(sourceLocationBuilder: SourceLocationBuilder) { + public init(sourceLocationBuilder: SourceLocationBuilder, swiftVersion: SwiftVersion) { self.sourceLocationBuilder = sourceLocationBuilder + self.swiftVersion = swiftVersion typeSyntaxInspector = .init(sourceLocationBuilder: sourceLocationBuilder) } @@ -113,11 +116,17 @@ public final class DeclarationSyntaxVisitor: PeripherySyntaxVisitor { if let memberType = node.extendedType.as(MemberTypeSyntax.self) { position = memberType.name.positionAfterSkippingLeadingTrivia - } else if let genericArgumentClause = node.extendedType.as(IdentifierTypeSyntax.self)?.genericArgumentClause { - // Generic protocol extensions in the form `extension Foo` have incorrect locations in the index store. - // This results in syntax metadata not being applied to the declaration due to the location mismatch. To - // workaround this, parse this node with the incorrect location. - position = genericArgumentClause.rightAngle.positionAfterSkippingLeadingTrivia + } else if let identifierType = node.extendedType.as(IdentifierTypeSyntax.self), + let genericArgumentClause = identifierType.genericArgumentClause + { + if swiftVersion.version.isVersion(lessThanOrEqualTo: "6.2.3") { + // Swift <= 6.2.3: Generic protocol extensions in the form `extension Foo` have incorrect locations + // in the index store. This results in syntax metadata not being applied to the declaration due to the + // location mismatch. To workaround this, parse this node with the incorrect location. + position = genericArgumentClause.rightAngle.positionAfterSkippingLeadingTrivia + } else { + position = identifierType.name.positionAfterSkippingLeadingTrivia + } } parse( diff --git a/Sources/SyntaxAnalysis/ImportSyntaxVisitor.swift b/Sources/SyntaxAnalysis/ImportSyntaxVisitor.swift index 91e1cc976..c83621c4c 100644 --- a/Sources/SyntaxAnalysis/ImportSyntaxVisitor.swift +++ b/Sources/SyntaxAnalysis/ImportSyntaxVisitor.swift @@ -1,4 +1,5 @@ import Foundation +import Shared import SourceGraph import SwiftSyntax @@ -7,8 +8,9 @@ public final class ImportSyntaxVisitor: PeripherySyntaxVisitor { private let sourceLocationBuilder: SourceLocationBuilder - public init(sourceLocationBuilder: SourceLocationBuilder) { + public init(sourceLocationBuilder: SourceLocationBuilder, swiftVersion _: SwiftVersion) { self.sourceLocationBuilder = sourceLocationBuilder + // swiftVersion is not used in this visitor but is required by the protocol } public func visit(_ node: ImportDeclSyntax) { diff --git a/Sources/SyntaxAnalysis/MultiplexingSyntaxVisitor.swift b/Sources/SyntaxAnalysis/MultiplexingSyntaxVisitor.swift index abb8bfed2..6b165767f 100644 --- a/Sources/SyntaxAnalysis/MultiplexingSyntaxVisitor.swift +++ b/Sources/SyntaxAnalysis/MultiplexingSyntaxVisitor.swift @@ -1,11 +1,12 @@ import Foundation +import Shared import SourceGraph import SwiftParser import SwiftSyntax import SystemPackage public protocol PeripherySyntaxVisitor { - init(sourceLocationBuilder: SourceLocationBuilder) + init(sourceLocationBuilder: SourceLocationBuilder, swiftVersion: SwiftVersion) func visit(_ node: ActorDeclSyntax) func visit(_ node: ClassDeclSyntax) @@ -95,20 +96,22 @@ public final class MultiplexingSyntaxVisitor: SyntaxVisitor { public let syntax: SourceFileSyntax public let locationConverter: SourceLocationConverter let sourceLocationBuilder: SourceLocationBuilder + let swiftVersion: SwiftVersion private var visitors: [PeripherySyntaxVisitor] = [] - public required init(file: SourceFile) throws { + public required init(file: SourceFile, swiftVersion: SwiftVersion) throws { sourceFile = file let source = try String(contentsOf: file.path.url) syntax = Parser.parse(source: source) locationConverter = SourceLocationConverter(fileName: file.path.string, tree: syntax) sourceLocationBuilder = SourceLocationBuilder(file: file, locationConverter: locationConverter) + self.swiftVersion = swiftVersion super.init(viewMode: .sourceAccurate) } public func add(_ visitorType: T.Type) -> T { - let visitor = visitorType.init(sourceLocationBuilder: sourceLocationBuilder) + let visitor = visitorType.init(sourceLocationBuilder: sourceLocationBuilder, swiftVersion: swiftVersion) visitors.append(visitor) return visitor } diff --git a/Tests/PeripheryTests/Syntax/FunctionVisitTest.swift b/Tests/PeripheryTests/Syntax/FunctionVisitTest.swift index ef07c9b38..8e67135de 100644 --- a/Tests/PeripheryTests/Syntax/FunctionVisitTest.swift +++ b/Tests/PeripheryTests/Syntax/FunctionVisitTest.swift @@ -1,4 +1,6 @@ import Foundation +import Logger +import Shared @testable import SourceGraph @testable import SyntaxAnalysis @testable import TestShared @@ -9,7 +11,9 @@ final class FunctionVisitTest: XCTestCase { override func setUpWithError() throws { try super.setUpWithError() - let multiplexingVisitor = try MultiplexingSyntaxVisitor(file: fixturePath) + let shell = Shell(logger: Logger(quiet: true)) + let swiftVersion = SwiftVersion(shell: shell) + let multiplexingVisitor = try MultiplexingSyntaxVisitor(file: fixturePath, swiftVersion: swiftVersion) let visitor = multiplexingVisitor.add(DeclarationSyntaxVisitor.self) multiplexingVisitor.visit() results = visitor.resultsByLocation diff --git a/Tests/PeripheryTests/Syntax/ImportVisitTest.swift b/Tests/PeripheryTests/Syntax/ImportVisitTest.swift index 1414218c5..53ae1d797 100644 --- a/Tests/PeripheryTests/Syntax/ImportVisitTest.swift +++ b/Tests/PeripheryTests/Syntax/ImportVisitTest.swift @@ -1,4 +1,6 @@ import Foundation +import Logger +import Shared @testable import SourceGraph @testable import SyntaxAnalysis @testable import TestShared @@ -9,7 +11,9 @@ final class ImportVisitTest: XCTestCase { override func setUpWithError() throws { try super.setUpWithError() - let multiplexingVisitor = try MultiplexingSyntaxVisitor(file: fixturePath) + let shell = Shell(logger: Logger(quiet: true)) + let swiftVersion = SwiftVersion(shell: shell) + let multiplexingVisitor = try MultiplexingSyntaxVisitor(file: fixturePath, swiftVersion: swiftVersion) let visitor = multiplexingVisitor.add(ImportSyntaxVisitor.self) multiplexingVisitor.visit() results = visitor.importStatements diff --git a/Tests/PeripheryTests/Syntax/PropertyVisitTest.swift b/Tests/PeripheryTests/Syntax/PropertyVisitTest.swift index fc5729c29..07b070bbe 100644 --- a/Tests/PeripheryTests/Syntax/PropertyVisitTest.swift +++ b/Tests/PeripheryTests/Syntax/PropertyVisitTest.swift @@ -1,4 +1,6 @@ import Foundation +import Logger +import Shared @testable import SourceGraph @testable import SyntaxAnalysis @testable import TestShared @@ -9,7 +11,9 @@ final class PropertyVisitTest: XCTestCase { override func setUpWithError() throws { try super.setUpWithError() - let multiplexingVisitor = try MultiplexingSyntaxVisitor(file: fixturePath) + let shell = Shell(logger: Logger(quiet: true)) + let swiftVersion = SwiftVersion(shell: shell) + let multiplexingVisitor = try MultiplexingSyntaxVisitor(file: fixturePath, swiftVersion: swiftVersion) let visitor = multiplexingVisitor.add(DeclarationSyntaxVisitor.self) multiplexingVisitor.visit() results = visitor.resultsByLocation diff --git a/Tests/Shared/SourceGraphTestCase.swift b/Tests/Shared/SourceGraphTestCase.swift index 6cceed00e..378ace760 100644 --- a/Tests/Shared/SourceGraphTestCase.swift +++ b/Tests/Shared/SourceGraphTestCase.swift @@ -55,11 +55,13 @@ open class SourceGraphTestCase: XCTestCase { } graph = SourceGraph(configuration: configuration, logger: logger) + let swiftVersion = SwiftVersion(shell: shell) let pipeline = IndexPipeline( plan: newPlan, graph: SynchronizedSourceGraph(graph: graph), logger: logger.contextualized(with: "index"), - configuration: configuration + configuration: configuration, + swiftVersion: swiftVersion ) try! pipeline.perform() @@ -68,7 +70,7 @@ open class SourceGraphTestCase: XCTestCase { graph: graph, logger: logger, configuration: configuration, - swiftVersion: SwiftVersion(shell: shell) + swiftVersion: swiftVersion ).perform() results = ScanResultBuilder.build(for: graph) }