@@ -2126,27 +2126,44 @@ extension SourceKitLSPServer {
2126
2126
callableUsrs += index. occurrences ( ofUSR: data. usr, roles: . overrideOf) . flatMap { occurrence in
2127
2127
occurrence. relations. filter { $0. roles. contains ( . overrideOf) } . map ( \. symbol. usr)
2128
2128
}
2129
+ // callOccurrences are all the places that any of the USRs in callableUsrs is called.
2130
+ // We also load the `calledBy` roles to get the method that contains the reference to this call.
2129
2131
let callOccurrences = callableUsrs. flatMap { index. occurrences ( ofUSR: $0, roles: . calledBy) }
2130
- let calls = callOccurrences. flatMap { occurrence -> [ CallHierarchyIncomingCall ] in
2131
- guard let location = indexToLSPLocation ( occurrence. location) else {
2132
- return [ ]
2132
+
2133
+ // Maps functions that call a USR in `callableUSRs` to all the called occurrences of `callableUSRs` within the
2134
+ // function. If a function `foo` calls `bar` multiple times, `callersToCalls[foo]` will contain two call
2135
+ // `SymbolOccurrence`s.
2136
+ // This way, we can group multiple calls to `bar` within `foo` to a single item with multiple `fromRanges`.
2137
+ var callersToCalls : [ Symbol : [ SymbolOccurrence ] ] = [ : ]
2138
+
2139
+ for call in callOccurrences {
2140
+ // Callers are all `calledBy` relations of a call to a USR in `callableUsrs`, ie. all the functions that contain a
2141
+ // call to a USR in callableUSRs. In practice, this should always be a single item.
2142
+ let callers = call. relations. filter { $0. roles. contains ( . calledBy) } . map ( \. symbol)
2143
+ for caller in callers {
2144
+ callersToCalls [ caller, default: [ ] ] . append ( call)
2133
2145
}
2134
- return occurrence. relations. filter { $0. symbol. kind. isCallable }
2135
- . map { related in
2136
- // Resolve the caller's definition to find its location
2137
- let definition = index. primaryDefinitionOrDeclarationOccurrence ( ofUSR: related. symbol. usr)
2138
- let definitionSymbolLocation = definition? . location
2139
- let definitionLocation = definitionSymbolLocation. flatMap ( indexToLSPLocation)
2140
-
2141
- return CallHierarchyIncomingCall (
2142
- from: indexToLSPCallHierarchyItem (
2143
- symbol: related. symbol,
2144
- containerName: definition? . containerName,
2145
- location: definitionLocation ?? location // Use occurrence location as fallback
2146
- ) ,
2147
- fromRanges: [ location. range]
2148
- )
2149
- }
2146
+ }
2147
+
2148
+ let calls = callersToCalls. compactMap { ( caller: Symbol , calls: [ SymbolOccurrence ] ) -> CallHierarchyIncomingCall ? in
2149
+ // Resolve the caller's definition to find its location
2150
+ let definition = index. primaryDefinitionOrDeclarationOccurrence ( ofUSR: caller. usr)
2151
+ let definitionSymbolLocation = definition? . location
2152
+ let definitionLocation = definitionSymbolLocation. flatMap ( indexToLSPLocation)
2153
+
2154
+ let locations = calls. compactMap { indexToLSPLocation ( $0. location) } . sorted ( )
2155
+ guard !locations. isEmpty else {
2156
+ return nil
2157
+ }
2158
+
2159
+ return CallHierarchyIncomingCall (
2160
+ from: indexToLSPCallHierarchyItem (
2161
+ symbol: caller,
2162
+ containerName: definition? . containerName,
2163
+ location: definitionLocation ?? locations. first!
2164
+ ) ,
2165
+ fromRanges: locations. map ( \. range)
2166
+ )
2150
2167
}
2151
2168
return calls. sorted ( by: { $0. from. name < $1. from. name } )
2152
2169
}
@@ -2455,17 +2472,6 @@ extension IndexSymbolKind {
2455
2472
return . null
2456
2473
}
2457
2474
}
2458
-
2459
- var isCallable : Bool {
2460
- switch self {
2461
- case . function, . instanceMethod, . classMethod, . staticMethod, . constructor, . destructor, . conversionFunction:
2462
- return true
2463
- case . unknown, . module, . namespace, . namespaceAlias, . macro, . enum, . struct, . protocol, . extension, . union,
2464
- . typealias, . field, . enumConstant, . parameter, . using, . concept, . commentTag, . variable, . instanceProperty,
2465
- . class, . staticProperty, . classProperty:
2466
- return false
2467
- }
2468
- }
2469
2475
}
2470
2476
2471
2477
extension SymbolOccurrence {
0 commit comments