Files
sourcekit-lsp/Sources/SwiftLanguageService/InlayHintResolve.swift
2026-01-12 06:15:38 +05:30

114 lines
3.7 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2026 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
@_spi(SourceKitLSP) package import LanguageServerProtocol
import SemanticIndex
import SourceKitD
import SourceKitLSP
extension SwiftLanguageService {
/// Resolves an inlay hint by looking up the type definition location.
package func inlayHintResolve(_ req: InlayHintResolveRequest) async throws -> InlayHint {
let hint = req.inlayHint
guard hint.kind == .type,
let resolveData = InlayHintResolveData(fromLSPAny: hint.data)
else {
return hint
}
// Fail if document version has changed since the hint was created
let currentSnapshot = try await self.latestSnapshot(for: resolveData.uri)
guard currentSnapshot.version == resolveData.version else {
return hint
}
let typeLocation = try await lookupTypeDefinitionLocation(
snapshot: currentSnapshot,
position: resolveData.position
)
guard let typeLocation else {
return hint
}
if case .string(let labelText) = hint.label {
return InlayHint(
position: hint.position,
label: .parts([InlayHintLabelPart(value: labelText, location: typeLocation)]),
kind: hint.kind,
textEdits: hint.textEdits,
tooltip: hint.tooltip,
paddingLeft: hint.paddingLeft,
paddingRight: hint.paddingRight,
data: hint.data
)
}
return hint
}
/// Looks up the definition location for the type at the given position.
///
/// This is used by inlay hint resolution to enable go-to-definition on type hints.
/// For SDK types, this returns a location in the generated interface.
func lookupTypeDefinitionLocation(
snapshot: DocumentSnapshot,
position: Position
) async throws -> Location? {
let compileCommand = await self.compileCommand(for: snapshot.uri, fallbackAfterTimeout: false)
let skreq = sourcekitd.dictionary([
keys.cancelOnSubsequentRequest: 0,
keys.offset: snapshot.utf8Offset(of: position),
keys.sourceFile: snapshot.uri.sourcekitdSourceFile,
keys.primaryFile: snapshot.uri.primaryFile?.pseudoPath,
keys.compilerArgs: compileCommand?.compilerArgs as [any SKDRequestValue]?,
])
let dict = try await send(sourcekitdRequest: \.cursorInfo, skreq, snapshot: snapshot)
guard let typeUsr: String = dict[keys.typeUsr] else {
return nil
}
guard let typeInfo = try await cursorInfoFromTypeUSR(typeUsr, in: snapshot) else {
return nil
}
// For local types, return the local declaration
if let location = typeInfo.symbolInfo.bestLocalDeclaration {
return location
}
// For SDK types, fall back to generated interface
if typeInfo.symbolInfo.isSystem ?? false,
let systemModule = typeInfo.symbolInfo.systemModule
{
let interfaceDetails = try await self.openGeneratedInterface(
document: snapshot.uri,
moduleName: systemModule.moduleName,
groupName: systemModule.groupName,
symbolUSR: typeInfo.symbolInfo.usr
)
if let details = interfaceDetails {
let position = details.position ?? Position(line: 0, utf16index: 0)
return Location(uri: details.uri, range: Range(position))
}
}
return nil
}
}