diff --git a/Package.swift b/Package.swift index 0fc3ed7c..cc7a6ebc 100644 --- a/Package.swift +++ b/Package.swift @@ -227,6 +227,7 @@ var targets: [Target] = [ "SwiftExtensions", .product(name: "IndexStoreDB", package: "indexstore-db"), .product(name: "SwiftDocC", package: "swift-docc"), + .product(name: "SymbolKit", package: "swift-docc-symbolkit"), ], exclude: ["CMakeLists.txt"], swiftSettings: globalSwiftSettings diff --git a/Sources/DocCDocumentation/DocCCatalogIndexManager.swift b/Sources/DocCDocumentation/DocCCatalogIndexManager.swift index b8a6de58..9ab7573f 100644 --- a/Sources/DocCDocumentation/DocCCatalogIndexManager.swift +++ b/Sources/DocCDocumentation/DocCCatalogIndexManager.swift @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// package import Foundation -@preconcurrency import SwiftDocC +@_spi(LinkCompletion) @preconcurrency import SwiftDocC final actor DocCCatalogIndexManager { private let server: DocCServer @@ -74,63 +74,74 @@ package enum DocCIndexError: LocalizedError { } package struct DocCCatalogIndex: Sendable { - private let assetReferenceToDataAsset: [String: DataAsset] - private let documentationExtensionToSourceURL: [DocCSymbolLink: URL] - let articlePathToSourceURLAndReference: [String: (URL, TopicRenderReference)] - let tutorialPathToSourceURLAndReference: [String: (URL, TopicRenderReference)] - let tutorialOverviewPathToSourceURLAndReference: [String: (URL, TopicRenderReference)] + /// A map from an asset name to its DataAsset contents. + let assets: [String: DataAsset] - func asset(for assetReference: AssetReference) -> DataAsset? { - assetReferenceToDataAsset[assetReference.assetName] - } + /// An array of DocCSymbolLink and their associated document URLs. + let documentationExtensions: [(link: DocCSymbolLink, documentURL: URL?)] - package func documentationExtension(for symbolLink: DocCSymbolLink) -> URL? { - return documentationExtensionToSourceURL[symbolLink] + /// A map from article name to its TopicRenderReference. + let articles: [String: TopicRenderReference] + + /// A map from tutorial name to its TopicRenderReference. + let tutorials: [String: TopicRenderReference] + + // A map from tutorial overview name to its TopicRenderReference. + let tutorialOverviews: [String: TopicRenderReference] + + /// Retrieves the documentation extension URL for the given symbol if one exists. + /// + /// - Parameter symbolInformation: The `DocCSymbolInformation` representing the symbol to search for. + package func documentationExtension(for symbolInformation: DocCSymbolInformation) -> URL? { + documentationExtensions.filter { symbolInformation.matches($0.link) }.first?.documentURL } init(from renderReferenceStore: RenderReferenceStore) { // Assets - var assetReferenceToDataAsset: [String: DataAsset] = [:] + var assets: [String: DataAsset] = [:] for (reference, asset) in renderReferenceStore.assets { var asset = asset asset.variants = asset.variants.compactMapValues { $0.withScheme("doc-asset") } - assetReferenceToDataAsset[reference.assetName] = asset + assets[reference.assetName] = asset } - self.assetReferenceToDataAsset = assetReferenceToDataAsset + self.assets = assets // Markdown and Tutorial content - var documentationExtensionToSourceURL: [DocCSymbolLink: URL] = [:] - var articlePathToSourceURLAndReference = [String: (URL, TopicRenderReference)]() - var tutorialPathToSourceURLAndReference = [String: (URL, TopicRenderReference)]() - var tutorialOverviewPathToSourceURLAndReference = [String: (URL, TopicRenderReference)]() + var documentationExtensionToSourceURL: [(link: DocCSymbolLink, documentURL: URL?)] = [] + var articles: [String: TopicRenderReference] = [:] + var tutorials: [String: TopicRenderReference] = [:] + var tutorialOverviews: [String: TopicRenderReference] = [:] for (renderReferenceKey, topicContentValue) in renderReferenceStore.topics { - guard let topicRenderReference = topicContentValue.renderReference as? TopicRenderReference, - let topicContentSource = topicContentValue.source - else { + guard let topicRenderReference = topicContentValue.renderReference as? TopicRenderReference else { continue } + // Article and Tutorial URLs in SwiftDocC are always of the form `doc://///`. + // Therefore, we only really need to store the filename in these cases which will always be the last path component. let lastPathComponent = renderReferenceKey.url.lastPathComponent switch topicRenderReference.kind { case .article: - articlePathToSourceURLAndReference[lastPathComponent] = (topicContentSource, topicRenderReference) + articles[lastPathComponent] = topicRenderReference case .tutorial: - tutorialPathToSourceURLAndReference[lastPathComponent] = (topicContentSource, topicRenderReference) + tutorials[lastPathComponent] = topicRenderReference case .overview: - tutorialOverviewPathToSourceURLAndReference[lastPathComponent] = (topicContentSource, topicRenderReference) + tutorialOverviews[lastPathComponent] = topicRenderReference default: - guard topicContentValue.isDocumentationExtensionContent, - let absoluteSymbolLink = AbsoluteSymbolLink(string: topicContentValue.renderReference.identifier.identifier) - else { + guard topicContentValue.isDocumentationExtensionContent else { continue } - let doccSymbolLink = DocCSymbolLink(absoluteSymbolLink: absoluteSymbolLink) - documentationExtensionToSourceURL[doccSymbolLink] = topicContentValue.source + // Documentation extensions are always of the form `doc:///documentation/`. + // We want to parse the `SymbolPath` in this case and store it in the index for lookups later. + let linkString = renderReferenceKey.url.pathComponents[2...].joined(separator: "/") + guard let doccSymbolLink = DocCSymbolLink(linkString: linkString) else { + continue + } + documentationExtensionToSourceURL.append((link: doccSymbolLink, documentURL: topicContentValue.source)) } } - self.documentationExtensionToSourceURL = documentationExtensionToSourceURL - self.articlePathToSourceURLAndReference = articlePathToSourceURLAndReference - self.tutorialPathToSourceURLAndReference = tutorialPathToSourceURLAndReference - self.tutorialOverviewPathToSourceURLAndReference = tutorialOverviewPathToSourceURLAndReference + self.documentationExtensions = documentationExtensionToSourceURL + self.articles = articles + self.tutorials = tutorials + self.tutorialOverviews = tutorialOverviews } } diff --git a/Sources/DocCDocumentation/DocCDocumentationManager.swift b/Sources/DocCDocumentation/DocCDocumentationManager.swift index b9dc1849..18999971 100644 --- a/Sources/DocCDocumentation/DocCDocumentationManager.swift +++ b/Sources/DocCDocumentation/DocCDocumentationManager.swift @@ -13,10 +13,8 @@ import BuildServerProtocol package import BuildSystemIntegration package import Foundation -package import IndexStoreDB package import LanguageServerProtocol import SKLogging -package import SemanticIndex import SwiftDocC package struct DocCDocumentationManager: Sendable { @@ -53,90 +51,6 @@ package struct DocCDocumentationManager: Sendable { try await catalogIndexManager.index(for: catalogURL) } - package func symbolLink(string: String) -> DocCSymbolLink? { - DocCSymbolLink(string: string) - } - - private func parentSymbol(of symbol: SymbolOccurrence, in index: CheckedIndex) -> SymbolOccurrence? { - let allParentRelations = symbol.relations - .filter { $0.roles.contains(.childOf) } - .sorted() - if allParentRelations.count > 1 { - logger.debug("Symbol \(symbol.symbol.usr) has multiple parent symbols") - } - guard let parentRelation = allParentRelations.first else { - return nil - } - if parentRelation.symbol.kind == .extension { - let allSymbolOccurrences = index.occurrences(relatedToUSR: parentRelation.symbol.usr, roles: .extendedBy) - .sorted() - if allSymbolOccurrences.count > 1 { - logger.debug("Extension \(parentRelation.symbol.usr) extends multiple symbols") - } - return allSymbolOccurrences.first - } - return index.primaryDefinitionOrDeclarationOccurrence(ofUSR: parentRelation.symbol.usr) - } - - package func symbolLink(forUSR usr: String, in index: CheckedIndex) -> DocCSymbolLink? { - guard let topLevelSymbolOccurrence = index.primaryDefinitionOrDeclarationOccurrence(ofUSR: usr) else { - return nil - } - let module = topLevelSymbolOccurrence.location.moduleName - var components = [topLevelSymbolOccurrence.symbol.name] - // Find any parent symbols - var symbolOccurrence: SymbolOccurrence = topLevelSymbolOccurrence - while let parentSymbolOccurrence = parentSymbol(of: symbolOccurrence, in: index) { - components.insert(parentSymbolOccurrence.symbol.name, at: 0) - symbolOccurrence = parentSymbolOccurrence - } - return DocCSymbolLink(string: module)?.appending(components: components) - } - - /// Find a `SymbolOccurrence` that is considered the primary definition of the symbol with the given `DocCSymbolLink`. - /// - /// If the `DocCSymbolLink` has an ambiguous definition, the most important role of this function is to deterministically return - /// the same result every time. - package func primaryDefinitionOrDeclarationOccurrence( - ofDocCSymbolLink symbolLink: DocCSymbolLink, - in index: CheckedIndex - ) -> SymbolOccurrence? { - var components = symbolLink.components - guard components.count > 0 else { - return nil - } - // Do a lookup to find the top level symbol - let topLevelSymbolName = components.removeLast().name - var topLevelSymbolOccurrences: [SymbolOccurrence] = [] - index.forEachCanonicalSymbolOccurrence(byName: topLevelSymbolName) { symbolOccurrence in - guard symbolOccurrence.location.moduleName == symbolLink.moduleName else { - return true // continue - } - topLevelSymbolOccurrences.append(symbolOccurrence) - return true // continue - } - // Search each potential symbol's parents to find an exact match - let symbolOccurences = topLevelSymbolOccurrences.filter { topLevelSymbolOccurrence in - var components = components - var symbolOccurrence = topLevelSymbolOccurrence - while let parentSymbolOccurrence = parentSymbol(of: symbolOccurrence, in: index), !components.isEmpty { - let nextComponent = components.removeLast() - guard parentSymbolOccurrence.symbol.name == nextComponent.name else { - return false - } - symbolOccurrence = parentSymbolOccurrence - } - guard components.isEmpty else { - return false - } - return true - }.sorted() - if symbolOccurences.count > 1 { - logger.debug("Multiple symbols found for DocC symbol link '\(symbolLink.absoluteString)'") - } - return symbolOccurences.first - } - /// Generates the SwiftDocC RenderNode for a given symbol, tutorial, or markdown file. /// /// - Parameters: diff --git a/Sources/DocCDocumentation/DocCReferenceResolutionService.swift b/Sources/DocCDocumentation/DocCReferenceResolutionService.swift index 165a736f..2b63813a 100644 --- a/Sources/DocCDocumentation/DocCReferenceResolutionService.swift +++ b/Sources/DocCDocumentation/DocCReferenceResolutionService.swift @@ -14,7 +14,7 @@ import Foundation import IndexStoreDB import LanguageServerProtocol import SemanticIndex -@preconcurrency import SwiftDocC +@_spi(Linkcompletion) @preconcurrency import SwiftDocC import SwiftExtensions final class DocCReferenceResolutionService: DocumentationService, Sendable { @@ -85,7 +85,7 @@ final class DocCReferenceResolutionService: DocumentationService, Sendable { guard let catalog = context.catalogIndex else { throw .indexNotAvailable } - guard let dataAsset = catalog.asset(for: assetReference) else { + guard let dataAsset = catalog.assets[assetReference.assetName] else { throw .assetNotFound } return .asset(dataAsset) @@ -95,9 +95,9 @@ final class DocCReferenceResolutionService: DocumentationService, Sendable { let resolvedReference: TopicRenderReference? = switch relevantPathComponents.first { case NodeURLGenerator.Path.documentationFolderName: - context.catalogIndex?.articlePathToSourceURLAndReference[topicURL.lastPathComponent]?.1 + context.catalogIndex?.articles[topicURL.lastPathComponent] case NodeURLGenerator.Path.tutorialsFolderName: - context.catalogIndex?.tutorialPathToSourceURLAndReference[topicURL.lastPathComponent]?.1 + context.catalogIndex?.tutorials[topicURL.lastPathComponent] default: nil } @@ -106,7 +106,7 @@ final class DocCReferenceResolutionService: DocumentationService, Sendable { } // Otherwise this must be a link to a symbol let urlString = topicURL.absoluteString - guard let absoluteSymbolLink = AbsoluteSymbolLink(string: urlString) else { + guard let doccSymbolLink = DocCSymbolLink(linkString: urlString) else { throw .invalidURLInRequest } // Don't bother checking to see if the symbol actually exists in the index. This can be time consuming and @@ -114,7 +114,7 @@ final class DocCReferenceResolutionService: DocumentationService, Sendable { return .resolvedInformation( OutOfProcessReferenceResolver.ResolvedInformation( symbolURL: topicURL, - symbolName: absoluteSymbolLink.symbolName + symbolName: doccSymbolLink.symbolName ) ) } @@ -159,18 +159,6 @@ struct DocCReferenceResolutionContext { let catalogIndex: DocCCatalogIndex? } -fileprivate extension AbsoluteSymbolLink { - var symbolName: String { - guard !representsModule else { - return module - } - guard let lastComponent = basePathComponents.last else { - return topLevelSymbol.name - } - return lastComponent.name - } -} - fileprivate extension OutOfProcessReferenceResolver.ResolvedInformation { init(symbolURL: URL, symbolName: String) { self = OutOfProcessReferenceResolver.ResolvedInformation( diff --git a/Sources/DocCDocumentation/DocCSymbolInformation.swift b/Sources/DocCDocumentation/DocCSymbolInformation.swift new file mode 100644 index 00000000..1b69a731 --- /dev/null +++ b/Sources/DocCDocumentation/DocCSymbolInformation.swift @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 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 Foundation +import IndexStoreDB +package import SemanticIndex +@_spi(LinkCompletion) @preconcurrency import SwiftDocC +import SymbolKit + +package struct DocCSymbolInformation { + let components: [(name: String, information: LinkCompletionTools.SymbolInformation)] + + /// Find the DocCSymbolLink for a given symbol USR. + /// + /// - Parameters: + /// - usr: The symbol USR to find in the index. + /// - index: The CheckedIndex to search within. + package init?(fromUSR usr: String, in index: CheckedIndex) { + guard let topLevelSymbolOccurrence = index.primaryDefinitionOrDeclarationOccurrence(ofUSR: usr) else { + return nil + } + let moduleName = topLevelSymbolOccurrence.location.moduleName + var components = [topLevelSymbolOccurrence] + // Find any parent symbols + var symbolOccurrence: SymbolOccurrence = topLevelSymbolOccurrence + while let parentSymbolOccurrence = symbolOccurrence.parent(index) { + components.insert(parentSymbolOccurrence, at: 0) + symbolOccurrence = parentSymbolOccurrence + } + self.components = + [(name: moduleName, LinkCompletionTools.SymbolInformation(fromModuleName: moduleName))] + + components.map { + (name: $0.symbol.name, information: LinkCompletionTools.SymbolInformation(fromSymbolOccurrence: $0)) + } + } + + package func matches(_ link: DocCSymbolLink) -> Bool { + var linkComponents = link.components + var symbolComponents = components + while !linkComponents.isEmpty, !symbolComponents.isEmpty { + let nextLinkComponent = linkComponents.removeLast() + let nextSymbolComponent = symbolComponents.removeLast() + guard nextLinkComponent.name == nextSymbolComponent.name, + nextSymbolComponent.information.matches(nextLinkComponent.disambiguation) + else { + return false + } + } + return true + } +} + +fileprivate typealias KindIdentifier = SymbolGraph.Symbol.KindIdentifier + +extension SymbolOccurrence { + var doccSymbolKind: String { + switch symbol.kind { + case .module: + KindIdentifier.module.identifier + case .namespace, .namespaceAlias: + KindIdentifier.namespace.identifier + case .macro: + KindIdentifier.macro.identifier + case .enum: + KindIdentifier.enum.identifier + case .struct: + KindIdentifier.struct.identifier + case .class: + KindIdentifier.class.identifier + case .protocol: + KindIdentifier.protocol.identifier + case .extension: + KindIdentifier.extension.identifier + case .union: + KindIdentifier.union.identifier + case .typealias: + KindIdentifier.typealias.identifier + case .function: + KindIdentifier.func.identifier + case .variable: + KindIdentifier.var.identifier + case .field: + KindIdentifier.property.identifier + case .enumConstant: + KindIdentifier.case.identifier + case .instanceMethod: + KindIdentifier.func.identifier + case .classMethod: + KindIdentifier.func.identifier + case .staticMethod: + KindIdentifier.func.identifier + case .instanceProperty: + KindIdentifier.property.identifier + case .classProperty, .staticProperty: + KindIdentifier.typeProperty.identifier + case .constructor: + KindIdentifier.`init`.identifier + case .destructor: + KindIdentifier.deinit.identifier + case .conversionFunction: + KindIdentifier.func.identifier + case .unknown, .using, .concept, .commentTag, .parameter: + "unknown" + } + } +} + +extension LinkCompletionTools.SymbolInformation { + init(fromModuleName moduleName: String) { + self.init( + kind: KindIdentifier.module.identifier, + symbolIDHash: Self.hash(uniqueSymbolID: moduleName) + ) + } + + init(fromSymbolOccurrence occurrence: SymbolOccurrence) { + self.init( + kind: occurrence.doccSymbolKind, + symbolIDHash: Self.hash(uniqueSymbolID: occurrence.symbol.usr), + parameterTypes: nil, + returnTypes: nil + ) + } +} diff --git a/Sources/DocCDocumentation/DocCSymbolLink.swift b/Sources/DocCDocumentation/DocCSymbolLink.swift index 9210a7bd..6d8e37c1 100644 --- a/Sources/DocCDocumentation/DocCSymbolLink.swift +++ b/Sources/DocCDocumentation/DocCSymbolLink.swift @@ -11,98 +11,25 @@ //===----------------------------------------------------------------------===// import Foundation -@preconcurrency import SwiftDocC +import IndexStoreDB +import SemanticIndex +@_spi(LinkCompletion) @preconcurrency import SwiftDocC +import SymbolKit -/// Represents the link to a symbol in DocC documentation. -/// -/// Symbol links are always of the form `/` or simply `` -/// if they refer to the module itself. package struct DocCSymbolLink: Sendable { - let moduleName: String - let components: [AbsoluteSymbolLink.LinkComponent] + let linkString: String + let components: [(name: String, disambiguation: LinkCompletionTools.ParsedDisambiguation)] - var absoluteString: String { - return components.map { $0.asLinkComponentString }.joined(separator: "/") + var symbolName: String { + components.last!.name } - var representsModule: Bool { - return components.count == 1 - } - - init(absoluteSymbolLink: AbsoluteSymbolLink) { - self.moduleName = absoluteSymbolLink.module - guard !absoluteSymbolLink.representsModule else { - self.components = [] - return - } - self.components = [absoluteSymbolLink.topLevelSymbol] + absoluteSymbolLink.basePathComponents - } - - init?(string: String) { - var rawComponents = string.split(separator: "/") - guard rawComponents.count > 0 else { + package init?(linkString: String) { + let components = LinkCompletionTools.parse(linkString: linkString) + guard !components.isEmpty else { return nil } - let moduleName = String(rawComponents.removeFirst()) - var components = [AbsoluteSymbolLink.LinkComponent]() - for rawComponent in rawComponents { - guard let component = AbsoluteSymbolLink.LinkComponent(string: String(rawComponent)) else { - return nil - } - components.append(component) - } - self = DocCSymbolLink(moduleName: moduleName, components: components) - } - - private init(moduleName: String, components: [AbsoluteSymbolLink.LinkComponent]) { - self.moduleName = moduleName + self.linkString = linkString self.components = components } - - func appending(string componentString: String) -> DocCSymbolLink? { - guard let component = AbsoluteSymbolLink.LinkComponent(string: componentString) else { - return nil - } - return DocCSymbolLink(moduleName: moduleName, components: components + [component]) - } - - func appending(components rawComponents: [String]) -> DocCSymbolLink? { - var result = self - for rawComponent in rawComponents { - guard let nextSymbolLink = result.appending(string: rawComponent) else { - return nil - } - result = nextSymbolLink - } - return result - } -} - -extension DocCSymbolLink: Equatable { - package static func == (lhs: DocCSymbolLink, rhs: DocCSymbolLink) -> Bool { - guard lhs.components.count == rhs.components.count else { - return false - } - for i in 0.. SymbolOccurrence? { + var components = symbolLink.components + guard components.count > 0 else { + return nil + } + // Do a lookup to find the top level symbol + let topLevelSymbol = components.removeLast() + var topLevelSymbolOccurrences: [SymbolOccurrence] = [] + forEachCanonicalSymbolOccurrence(byName: topLevelSymbol.name) { symbolOccurrence in + topLevelSymbolOccurrences.append(symbolOccurrence) + return true // continue + } + topLevelSymbolOccurrences = topLevelSymbolOccurrences.filter { + let symbolInformation = LinkCompletionTools.SymbolInformation(fromSymbolOccurrence: $0) + return symbolInformation.matches(topLevelSymbol.disambiguation) + } + // Search each potential symbol's parents to find an exact match + let symbolOccurences = topLevelSymbolOccurrences.filter { topLevelSymbolOccurrence in + var components = components + var symbolOccurrence = topLevelSymbolOccurrence + while let parentSymbolOccurrence = symbolOccurrence.parent(self), !components.isEmpty { + let nextComponent = components.removeLast() + let parentSymbolInformation = LinkCompletionTools.SymbolInformation( + fromSymbolOccurrence: parentSymbolOccurrence + ) + guard parentSymbolOccurrence.symbol.name == nextComponent.name, + parentSymbolInformation.matches(nextComponent.disambiguation) + else { + return false + } + symbolOccurrence = parentSymbolOccurrence + } + // If we have exactly one component left, check to see if it's the module name + if components.count == 1 { + let lastComponent = components.removeLast() + guard lastComponent.name == topLevelSymbolOccurrence.location.moduleName else { + return false + } + } + guard components.isEmpty else { + return false + } + return true + }.sorted() + if symbolOccurences.count > 1 { + logger.debug("Multiple symbols found for DocC symbol link '\(symbolLink.linkString)'") + } + return symbolOccurences.first + } +} + +extension SymbolOccurrence { + func parent(_ index: CheckedIndex) -> SymbolOccurrence? { + let allParentRelations = + relations + .filter { $0.roles.contains(.childOf) } + .sorted() + if allParentRelations.count > 1 { + logger.debug("Symbol \(symbol.usr) has multiple parent symbols") + } + guard let parentRelation = allParentRelations.first else { + return nil + } + if parentRelation.symbol.kind == .extension { + let allSymbolOccurrences = index.occurrences(relatedToUSR: parentRelation.symbol.usr, roles: .extendedBy) + .sorted() + if allSymbolOccurrences.count > 1 { + logger.debug("Extension \(parentRelation.symbol.usr) extends multiple symbols") + } + return allSymbolOccurrences.first + } + return index.primaryDefinitionOrDeclarationOccurrence(ofUSR: parentRelation.symbol.usr) + } +} diff --git a/Sources/SourceKitLSP/Documentation/DoccDocumentationHandler.swift b/Sources/SourceKitLSP/Documentation/DoccDocumentationHandler.swift index 5fba4910..df2291b0 100644 --- a/Sources/SourceKitLSP/Documentation/DoccDocumentationHandler.swift +++ b/Sources/SourceKitLSP/Documentation/DoccDocumentationHandler.swift @@ -76,11 +76,8 @@ extension DocumentationLanguageService { guard let index = workspace.index(checkedFor: .deletedFiles) else { throw ResponseError.requestFailed(doccDocumentationError: .indexNotAvailable) } - guard let symbolLink = documentationManager.symbolLink(string: symbolName), - let symbolOccurrence = documentationManager.primaryDefinitionOrDeclarationOccurrence( - ofDocCSymbolLink: symbolLink, - in: index - ) + guard let symbolLink = DocCSymbolLink(linkString: symbolName), + let symbolOccurrence = index.primaryDefinitionOrDeclarationOccurrence(ofDocCSymbolLink: symbolLink) else { throw ResponseError.requestFailed(doccDocumentationError: .symbolNotFound(symbolName)) } diff --git a/Sources/SourceKitLSP/Swift/DoccDocumentation.swift b/Sources/SourceKitLSP/Swift/DoccDocumentation.swift index a6cf6500..74d0e337 100644 --- a/Sources/SourceKitLSP/Swift/DoccDocumentation.swift +++ b/Sources/SourceKitLSP/Swift/DoccDocumentation.swift @@ -94,8 +94,8 @@ extension SwiftLanguageService { } let catalogIndex = try await documentationManager.catalogIndex(for: catalogURL) guard let index = workspace.index(checkedFor: .deletedFiles), - let symbolLink = documentationManager.symbolLink(forUSR: symbolUSR, in: index), - let markupExtensionFileURL = catalogIndex.documentationExtension(for: symbolLink) + let symbolInformation = DocCSymbolInformation(fromUSR: symbolUSR, in: index), + let markupExtensionFileURL = catalogIndex.documentationExtension(for: symbolInformation) else { return nil }