@@ -2128,27 +2128,44 @@ extension SourceKitLSPServer {
2128
2128
callableUsrs += index. occurrences ( ofUSR: data. usr, roles: . overrideOf) . flatMap { occurrence in
2129
2129
occurrence. relations. filter { $0. roles. contains ( . overrideOf) } . map ( \. symbol. usr)
2130
2130
}
2131
+ // callOccurrences are all the places that any of the USRs in callableUsrs is called.
2132
+ // We also load the `calledBy` roles to get the method that contains the reference to this call.
2131
2133
let callOccurrences = callableUsrs. flatMap { index. occurrences ( ofUSR: $0, roles: . calledBy) }
2132
- let calls = callOccurrences. flatMap { occurrence -> [ CallHierarchyIncomingCall ] in
2133
- guard let location = indexToLSPLocation ( occurrence. location) else {
2134
- return [ ]
2134
+
2135
+ // Maps functions that call a USR in `callableUSRs` to all the called occurrences of `callableUSRs` within the
2136
+ // function. If a function `foo` calls `bar` multiple times, `callersToCalls[foo]` will contain two call
2137
+ // `SymbolOccurrence`s.
2138
+ // This way, we can group multiple calls to `bar` within `foo` to a single item with multiple `fromRanges`.
2139
+ var callersToCalls : [ Symbol : [ SymbolOccurrence ] ] = [ : ]
2140
+
2141
+ for call in callOccurrences {
2142
+ // Callers are all `calledBy` relations of a call to a USR in `callableUsrs`, ie. all the functions that contain a
2143
+ // call to a USR in callableUSRs. In practice, this should always be a single item.
2144
+ let callers = call. relations. filter { $0. symbol. kind. isCallable } . map ( \. symbol)
2145
+ for caller in callers {
2146
+ callersToCalls [ caller, default: [ ] ] . append ( call)
2135
2147
}
2136
- return occurrence. relations. filter { $0. symbol. kind. isCallable }
2137
- . map { related in
2138
- // Resolve the caller's definition to find its location
2139
- let definition = index. primaryDefinitionOrDeclarationOccurrence ( ofUSR: related. symbol. usr)
2140
- let definitionSymbolLocation = definition? . location
2141
- let definitionLocation = definitionSymbolLocation. flatMap ( indexToLSPLocation)
2142
-
2143
- return CallHierarchyIncomingCall (
2144
- from: indexToLSPCallHierarchyItem (
2145
- symbol: related. symbol,
2146
- containerName: definition? . containerName,
2147
- location: definitionLocation ?? location // Use occurrence location as fallback
2148
- ) ,
2149
- fromRanges: [ location. range]
2150
- )
2151
- }
2148
+ }
2149
+
2150
+ let calls = callersToCalls. compactMap { ( caller: Symbol , calls: [ SymbolOccurrence ] ) -> CallHierarchyIncomingCall ? in
2151
+ // Resolve the caller's definition to find its location
2152
+ let definition = index. primaryDefinitionOrDeclarationOccurrence ( ofUSR: caller. usr)
2153
+ let definitionSymbolLocation = definition? . location
2154
+ let definitionLocation = definitionSymbolLocation. flatMap ( indexToLSPLocation)
2155
+
2156
+ let locations = calls. compactMap { indexToLSPLocation ( $0. location) } . sorted ( )
2157
+ guard !locations. isEmpty else {
2158
+ return nil
2159
+ }
2160
+
2161
+ return CallHierarchyIncomingCall (
2162
+ from: indexToLSPCallHierarchyItem (
2163
+ symbol: caller,
2164
+ containerName: definition? . containerName,
2165
+ location: definitionLocation ?? locations. first!
2166
+ ) ,
2167
+ fromRanges: locations. map ( \. range)
2168
+ )
2152
2169
}
2153
2170
return calls. sorted ( by: { $0. from. name < $1. from. name } )
2154
2171
}
0 commit comments