Skip to content

Commit 30b6d1d

Browse files
committed
Remove extractIndexedOccurences
`extractIndexedOccurences` mostly dealt with how to create a fallback value and we didn’t support fallback values in 3/4 cases. Remove it, simplifying the callers of `extractIndexedOccurances` along the way.
1 parent 1ccccc3 commit 30b6d1d

File tree

2 files changed

+118
-136
lines changed

2 files changed

+118
-136
lines changed

Sources/SourceKitLSP/SourceKitServer.swift

Lines changed: 110 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,46 +1654,6 @@ extension SourceKitServer {
16541654
)
16551655
}
16561656

1657-
/// Extracts the locations of an indexed symbol's occurrences,
1658-
/// e.g. for definition or reference lookups.
1659-
///
1660-
/// - Parameters:
1661-
/// - result: The symbol to look up
1662-
/// - index: The index in which the occurrences will be looked up
1663-
/// - useLocalFallback: Whether to consider the best known local declaration if no other locations are found
1664-
/// - extractOccurrences: A function fetching the occurrences by the desired roles given a usr from the index
1665-
/// - Returns: The resolved symbol locations
1666-
private func extractIndexedOccurrences(
1667-
symbols: [SymbolDetails],
1668-
index: IndexStoreDB?,
1669-
useLocalFallback: Bool = false,
1670-
extractOccurrences: (SymbolDetails, IndexStoreDB) -> [SymbolOccurrence]
1671-
) -> [(occurrence: SymbolOccurrence?, location: Location)] {
1672-
guard let symbol = symbols.first else {
1673-
return []
1674-
}
1675-
1676-
let fallback: [(occurrence: SymbolOccurrence?, location: Location)]
1677-
if useLocalFallback, let bestLocalDeclaration = symbol.bestLocalDeclaration {
1678-
fallback = [(occurrence: nil, location: bestLocalDeclaration)]
1679-
} else {
1680-
fallback = []
1681-
}
1682-
1683-
guard let index = index else {
1684-
return fallback
1685-
}
1686-
1687-
let occurs = extractOccurrences(symbol, index)
1688-
let resolved = occurs.compactMap { occur in
1689-
indexToLSPLocation(occur.location).map {
1690-
(occurrence: occur, location: $0)
1691-
}
1692-
}
1693-
1694-
return resolved.isEmpty ? fallback : resolved
1695-
}
1696-
16971657
func declaration(
16981658
_ req: DeclarationRequest,
16991659
workspace: Workspace,
@@ -1702,85 +1662,102 @@ extension SourceKitServer {
17021662
return try await languageService.declaration(req)
17031663
}
17041664

1705-
func definition(
1665+
/// Returns the result of a `DefinitionRequest` by running a `SymbolInfoRequest`, inspecting
1666+
/// its result and doing index lookups, if necessary.
1667+
///
1668+
/// In contrast to `definition`, this does not fall back to sending a `DefinitionRequest` to the
1669+
/// toolchain language server.
1670+
private func indexBasedDefinition(
17061671
_ req: DefinitionRequest,
17071672
workspace: Workspace,
17081673
languageService: ToolchainLanguageServer
1709-
) async throws -> LocationsOrLocationLinksResponse? {
1674+
) async throws -> [Location] {
17101675
let symbols = try await languageService.symbolInfo(
17111676
SymbolInfoRequest(
17121677
textDocument: req.textDocument,
17131678
position: req.position
17141679
)
17151680
)
1716-
let index = await self.workspaceForDocument(uri: req.textDocument.uri)?.index
1681+
guard let symbol = symbols.first else {
1682+
return []
1683+
}
1684+
1685+
if let symbol = symbols.first, let bestLocalDeclaration = symbol.bestLocalDeclaration, !(symbol.isDynamic ?? false)
1686+
{
1687+
// If we have a non-dynamic symbol, we don't need to do an index lookup
1688+
return [bestLocalDeclaration]
1689+
}
1690+
17171691
// If this symbol is a module then generate a textual interface
1718-
if let symbol = symbols.first, symbol.kind == .module, let name = symbol.name {
1719-
return try await self.definitionInInterface(
1692+
if symbol.kind == .module, let name = symbol.name {
1693+
let interfaceLocation = try await self.definitionInInterface(
17201694
req,
17211695
moduleName: name,
17221696
symbolUSR: nil,
17231697
languageService: languageService
17241698
)
1699+
return [interfaceLocation]
17251700
}
17261701

1727-
let resolved = self.extractIndexedOccurrences(symbols: symbols, index: index, useLocalFallback: true) {
1728-
(symbolDetails, index) in
1729-
guard symbolDetails.isDynamic ?? false else {
1730-
// If the symbol isn't dynamic, we won't get more information from the index compared to what we already have
1731-
// in the symbolDetails response. Return an empty array so that `extractIndexedOccurrences` falls back to the
1732-
// location in the symbol details response.
1733-
return []
1734-
}
1735-
guard let usr = symbolDetails.usr else { return [] }
1736-
logger.info("performing indexed jump-to-def with usr \(usr)")
1737-
var occurs = index.occurrences(ofUSR: usr, roles: [.definition])
1738-
if occurs.isEmpty {
1739-
occurs = index.occurrences(ofUSR: usr, roles: [.declaration])
1740-
}
1741-
if symbolDetails.isDynamic ?? false {
1742-
occurs += occurs.flatMap {
1743-
index.occurrences(relatedToUSR: $0.symbol.usr, roles: .overrideOf)
1744-
}
1702+
guard let index = await self.workspaceForDocument(uri: req.textDocument.uri)?.index else {
1703+
return []
1704+
}
1705+
guard let usr = symbol.usr else { return [] }
1706+
logger.info("performing indexed jump-to-def with usr \(usr)")
1707+
var occurances = index.occurrences(ofUSR: usr, roles: [.definition])
1708+
if occurances.isEmpty {
1709+
occurances = index.occurrences(ofUSR: usr, roles: [.declaration])
1710+
}
1711+
if symbol.isDynamic ?? false {
1712+
occurances += occurances.flatMap {
1713+
index.occurrences(relatedToUSR: $0.symbol.usr, roles: .overrideOf)
17451714
}
1746-
return occurs
17471715
}
17481716

1749-
// if first resolved location is in `.swiftinterface` file. Use moduleName to return
1750-
// textual interface
1751-
if let firstResolved = resolved.first,
1752-
let moduleName = firstResolved.occurrence?.location.moduleName,
1753-
firstResolved.location.uri.fileURL?.pathExtension == "swiftinterface"
1754-
{
1755-
return try await self.definitionInInterface(
1756-
req,
1757-
moduleName: moduleName,
1758-
symbolUSR: firstResolved.occurrence?.symbol.usr,
1759-
languageService: languageService
1760-
)
1717+
return try await occurances.asyncCompactMap { occurance in
1718+
if URL(fileURLWithPath: occurance.location.path).pathExtension == "swiftinterface" {
1719+
// if first resolved location is in `.swiftinterface` file. Use moduleName to return
1720+
// textual interface
1721+
return try await self.definitionInInterface(
1722+
req,
1723+
moduleName: occurance.location.moduleName,
1724+
symbolUSR: occurance.symbol.usr,
1725+
languageService: languageService
1726+
)
1727+
}
1728+
return indexToLSPLocation(occurance.location)
17611729
}
1762-
let locs = resolved.map(\.location)
1730+
}
1731+
1732+
func definition(
1733+
_ req: DefinitionRequest,
1734+
workspace: Workspace,
1735+
languageService: ToolchainLanguageServer
1736+
) async throws -> LocationsOrLocationLinksResponse? {
1737+
let indexBasedResponse = try await indexBasedDefinition(req, workspace: workspace, languageService: languageService)
17631738
// If we're unable to handle the definition request using our index, see if the
17641739
// language service can handle it (e.g. clangd can provide AST based definitions).
1765-
if locs.isEmpty {
1766-
return try await languageService.definition(req)
1740+
if indexBasedResponse.isEmpty {
1741+
do {
1742+
return try await languageService.definition(req)
1743+
} catch {}
17671744
}
1768-
return .locations(locs)
1745+
return .locations(indexBasedResponse)
17691746
}
17701747

17711748
func definitionInInterface(
17721749
_ req: DefinitionRequest,
17731750
moduleName: String,
17741751
symbolUSR: String?,
17751752
languageService: ToolchainLanguageServer
1776-
) async throws -> LocationsOrLocationLinksResponse? {
1753+
) async throws -> Location {
17771754
let openInterface = OpenInterfaceRequest(textDocument: req.textDocument, name: moduleName, symbolUSR: symbolUSR)
17781755
guard let interfaceDetails = try await languageService.openInterface(openInterface) else {
17791756
throw ResponseError.unknown("Could not generate Swift Interface for \(moduleName)")
17801757
}
17811758
let position = interfaceDetails.position ?? Position(line: 0, utf16index: 0)
17821759
let loc = Location(uri: interfaceDetails.uri, range: Range(position))
1783-
return .locations([loc])
1760+
return loc
17841761
}
17851762

17861763
func implementation(
@@ -1794,17 +1771,18 @@ extension SourceKitServer {
17941771
position: req.position
17951772
)
17961773
)
1797-
let index = await self.workspaceForDocument(uri: req.textDocument.uri)?.index
1798-
let extractedResult = self.extractIndexedOccurrences(symbols: symbols, index: index) { (symbolDetails, index) in
1799-
guard let usr = symbolDetails.usr else { return [] }
1800-
var occurs = index.occurrences(ofUSR: usr, roles: .baseOf)
1801-
if occurs.isEmpty {
1802-
occurs = index.occurrences(relatedToUSR: usr, roles: .overrideOf)
1803-
}
1804-
return occurs
1774+
guard let symbol = symbols.first,
1775+
let index = await self.workspaceForDocument(uri: req.textDocument.uri)?.index
1776+
else {
1777+
return nil
1778+
}
1779+
guard let usr = symbol.usr else { return nil }
1780+
var occurrances = index.occurrences(ofUSR: usr, roles: .baseOf)
1781+
if occurrances.isEmpty {
1782+
occurrances = index.occurrences(relatedToUSR: usr, roles: .overrideOf)
18051783
}
18061784

1807-
return .locations(extractedResult.map(\.location))
1785+
return .locations(occurrances.compactMap { indexToLSPLocation($0.location) })
18081786
}
18091787

18101788
func references(
@@ -1818,18 +1796,17 @@ extension SourceKitServer {
18181796
position: req.position
18191797
)
18201798
)
1821-
let index = await self.workspaceForDocument(uri: req.textDocument.uri)?.index
1822-
let extractedResult = self.extractIndexedOccurrences(symbols: symbols, index: index) { (symbolDetails, index) in
1823-
guard let usr = symbolDetails.usr else { return [] }
1824-
logger.info("performing indexed jump-to-def with usr \(usr)")
1825-
var roles: SymbolRole = [.reference]
1826-
if req.context.includeDeclaration {
1827-
roles.formUnion([.declaration, .definition])
1828-
}
1829-
return index.occurrences(ofUSR: usr, roles: roles)
1799+
guard let symbol = symbols.first, let index = await self.workspaceForDocument(uri: req.textDocument.uri)?.index
1800+
else {
1801+
return []
18301802
}
1831-
1832-
return extractedResult.map(\.location)
1803+
guard let usr = symbol.usr else { return [] }
1804+
logger.info("performing indexed jump-to-def with usr \(usr)")
1805+
var roles: SymbolRole = [.reference]
1806+
if req.context.includeDeclaration {
1807+
roles.formUnion([.declaration, .definition])
1808+
}
1809+
return index.occurrences(ofUSR: usr, roles: roles).compactMap { indexToLSPLocation($0.location) }
18331810
}
18341811

18351812
private func indexToLSPCallHierarchyItem(
@@ -1864,23 +1841,23 @@ extension SourceKitServer {
18641841
position: req.position
18651842
)
18661843
)
1867-
let index = await self.workspaceForDocument(uri: req.textDocument.uri)?.index
1868-
// For call hierarchy preparation we only locate the definition
1869-
let extractedResult = self.extractIndexedOccurrences(symbols: symbols, index: index) { (symbolDetails, index) in
1870-
guard let usr = symbolDetails.usr else { return [] }
1871-
return index.occurrences(ofUSR: usr, roles: [.definition, .declaration])
1844+
guard let symbol = symbols.first, let index = await self.workspaceForDocument(uri: req.textDocument.uri)?.index
1845+
else {
1846+
return nil
18721847
}
1873-
return extractedResult.compactMap { info -> CallHierarchyItem? in
1874-
guard let occurrence = info.occurrence else {
1875-
return nil
1848+
// For call hierarchy preparation we only locate the definition
1849+
guard let usr = symbol.usr else { return nil }
1850+
return index.occurrences(ofUSR: usr, roles: [.definition, .declaration])
1851+
.compactMap { info -> CallHierarchyItem? in
1852+
guard let location = indexToLSPLocation(info.location) else {
1853+
return nil
1854+
}
1855+
return self.indexToLSPCallHierarchyItem(
1856+
symbol: info.symbol,
1857+
moduleName: info.location.moduleName,
1858+
location: location
1859+
)
18761860
}
1877-
let symbol = occurrence.symbol
1878-
return self.indexToLSPCallHierarchyItem(
1879-
symbol: symbol,
1880-
moduleName: occurrence.location.moduleName,
1881-
location: info.location
1882-
)
1883-
}
18841861
}
18851862

18861863
/// Extracts our implementation-specific data about a call hierarchy
@@ -2021,25 +1998,25 @@ extension SourceKitServer {
20211998
position: req.position
20221999
)
20232000
)
2024-
guard let index = await self.workspaceForDocument(uri: req.textDocument.uri)?.index else {
2025-
return []
2001+
guard let symbol = symbols.first else {
2002+
return nil
20262003
}
2027-
let extractedResult = self.extractIndexedOccurrences(symbols: symbols, index: index) { (symbolDetails, index) in
2028-
guard let usr = symbolDetails.usr else { return [] }
2029-
return index.occurrences(ofUSR: usr, roles: [.definition, .declaration])
2004+
guard let index = await self.workspaceForDocument(uri: req.textDocument.uri)?.index else {
2005+
return nil
20302006
}
2031-
return extractedResult.compactMap { info -> TypeHierarchyItem? in
2032-
guard let occurrence = info.occurrence else {
2033-
return nil
2007+
guard let usr = symbol.usr else { return nil }
2008+
return index.occurrences(ofUSR: usr, roles: [.definition, .declaration])
2009+
.compactMap { info -> TypeHierarchyItem? in
2010+
guard let location = indexToLSPLocation(info.location) else {
2011+
return nil
2012+
}
2013+
return self.indexToLSPTypeHierarchyItem(
2014+
symbol: info.symbol,
2015+
moduleName: info.location.moduleName,
2016+
location: location,
2017+
index: index
2018+
)
20342019
}
2035-
let symbol = occurrence.symbol
2036-
return self.indexToLSPTypeHierarchyItem(
2037-
symbol: symbol,
2038-
moduleName: occurrence.location.moduleName,
2039-
location: info.location,
2040-
index: index
2041-
)
2042-
}
20432020
}
20442021

20452022
/// Extracts our implementation-specific data about a type hierarchy

Sources/SourceKitLSP/Swift/CursorInfo.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,15 @@ extension SwiftLanguageServer {
117117

118118
var location: Location? = nil
119119
if let filepath: String = dict[keys.filepath],
120-
let offset: Int = dict[keys.offset],
121-
let pos = snapshot.positionOf(utf8Offset: offset)
120+
let line: Int = dict[keys.line],
121+
let column: Int = dict[keys.column]
122122
{
123-
location = Location(uri: DocumentURI(URL(fileURLWithPath: filepath)), range: Range(pos))
123+
let position = Position(
124+
line: line - 1,
125+
// FIXME: we need to convert the utf8/utf16 column, which may require reading the file!
126+
utf16index: column - 1
127+
)
128+
location = Location(uri: DocumentURI(URL(fileURLWithPath: filepath)), range: Range(position))
124129
}
125130

126131
let refactorActionsArray: SKDResponseArray? = dict[keys.refactor_actions]

0 commit comments

Comments
 (0)