Skip to content

Commit c23eff5

Browse files
committed
Add root_location to the incoming calls hierarchy responses
```go package main func f() (int) { return 5; } func g() (int) { return f() + f(); } func h() (int) { var x = g(); return f() + x; } ``` With incoming calls request on `g()`, the response should be something like this ```python { 'locations': [ location_of_call_to_g_inside_h ], 'root_location': location_of_h_function_name } ``` This allows clients to: 1. Jump to the actual call site, using `locations` list. 2. Switch to outgoing calls, by preparing a new hierarchy, using `root_location` object.
1 parent 26c40ff commit c23eff5

File tree

6 files changed

+94
-42
lines changed

6 files changed

+94
-42
lines changed

docs/index.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4650,6 +4650,23 @@ <h3 class="panel-title"><a name="/definitions/Hierarchy"></a>Hierarchy:
46504650
</div>
46514651
</section> </div>
46524652
</dd>
4653+
<dt data-property-name="root_location">
4654+
<span class="json-property-name">root_location:</span>
4655+
4656+
<span class="json-property-type"> <a class="json-schema-ref" href="#/definitions/Location">Location</a>
4657+
</span>
4658+
<span class="json-property-range" title="Value limits"></span>
4659+
4660+
</dt>
4661+
<dd>
4662+
<p>In call hierarchies, it is useful to differentiate between the call
4663+
site (which end up in the <code>locations</code> property) and the calling
4664+
function. This property, if present, represents the latter.</p>
4665+
4666+
<div class="json-inner-schema">
4667+
4668+
</div>
4669+
</dd>
46534670
</dl>
46544671
</section>
46554672
</div>

docs/openapi.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,13 @@ definitions:
233233
type: array
234234
items:
235235
$ref: "#/defintions/Location"
236+
root_location:
237+
type: object
238+
description: |-
239+
In call hierarchies, it is useful to differentiate between the call
240+
site (which end up in the `locations` property) and the calling
241+
function. This property, if present, represents the latter.
242+
$ref: "#/definitions/Location"
236243
# Due to the way the API combines keys at the top level, we are not able to
237244
# compose this item per-request. So this definition must be copy-pasted for
238245
# some requests.

ycmd/completers/language_server/language_server_completer.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2721,17 +2721,26 @@ def Hierarchy( self, request_data, args ):
27212721
for item in result:
27222722
if kind == 'call':
27232723
name_and_kind_key = 'to' if direction == 'outgoingCalls' else 'from'
2724-
kind_string = lsp.SYMBOL_KIND[ item[ name_and_kind_key ][ 'kind' ] ]
2724+
hierarchy_item = item[ name_and_kind_key ]
2725+
kind_string = lsp.SYMBOL_KIND[ hierarchy_item[ 'kind' ] ]
27252726
item[ 'kind' ] = kind_string
2726-
item[ 'name' ] = item[ name_and_kind_key ][ 'name' ]
2727+
item[ 'name' ] = hierarchy_item[ 'name' ]
27272728
lsp_locations = [ {
2728-
'uri': item[ name_and_kind_key ][ 'uri' ],
2729+
'uri': hierarchy_item[ 'uri' ],
27292730
'range': r }
27302731
for r in item[ 'fromRanges' ] ]
27312732
item[ 'locations' ] = [
27322733
responses.BuildGoToResponseFromLocation(
27332734
*_LspLocationToLocationAndDescription( request_data, location ) )
27342735
for location in lsp_locations ]
2736+
2737+
if direction == 'incomingCalls':
2738+
loc = {
2739+
'uri': hierarchy_item[ 'uri' ],
2740+
'range': hierarchy_item[ 'range' ]
2741+
}
2742+
item[ 'root_location' ] = responses.BuildGoToResponseFromLocation(
2743+
*_LspLocationToLocationAndDescription( request_data, loc ) )
27352744
else:
27362745
item[ 'kind' ] = lsp.SYMBOL_KIND[ item[ 'kind' ] ]
27372746
item[ 'locations' ] = [

ycmd/tests/clangd/subcommands_test.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,22 +1395,25 @@ def test_Subcommands_IncomingCallHierarchy( self, app ):
13951395
for location, response, code in [
13961396
[ ( filepath, 1, 5 ),
13971397
contains_inanyorder(
1398-
has_entry( 'locations',
1399-
contains_exactly(
1400-
LocationMatcher( filepath, 4, 12 ),
1401-
LocationMatcher( filepath, 4, 18 )
1402-
) ),
1403-
has_entry( 'locations',
1404-
contains_exactly(
1405-
LocationMatcher( filepath, 9, 12 )
1406-
) ) ),
1398+
has_entries( {
1399+
'locations': contains_exactly(
1400+
LocationMatcher( filepath, 4, 12 ),
1401+
LocationMatcher( filepath, 4, 18 ) ),
1402+
'root_location': LocationMatcher( filepath, 3, 5 )
1403+
} ),
1404+
has_entries( {
1405+
'locations': contains_exactly( LocationMatcher( filepath, 9, 12 ) ),
1406+
'root_location': LocationMatcher( filepath, 7, 5 )
1407+
} )
1408+
),
14071409
requests.codes.ok ],
14081410
[ ( filepath, 3, 5 ),
14091411
contains_inanyorder(
1410-
has_entry( 'locations',
1411-
contains_exactly(
1412-
LocationMatcher( filepath, 8, 13 )
1413-
) ) ),
1412+
has_entries( {
1413+
'locations': contains_exactly( LocationMatcher( filepath, 8, 13 ) ),
1414+
'root_location': LocationMatcher( filepath, 7, 5 )
1415+
} )
1416+
),
14141417
requests.codes.ok ],
14151418
[ ( filepath, 7, 5 ),
14161419
ErrorMatcher( RuntimeError, 'No incoming calls found.' ),

ycmd/tests/go/subcommands_test.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -598,22 +598,27 @@ def test_Subcommands_IncomingCallHierarchy( self, app ):
598598
for location, response, code in [
599599
[ ( filepath, 3, 6 ),
600600
contains_inanyorder(
601-
has_entry( 'locations',
602-
contains_exactly(
603-
LocationMatcher( filepath, 7, 12 ),
604-
LocationMatcher( filepath, 7, 18 )
605-
) ),
606-
has_entry( 'locations',
607-
contains_exactly(
608-
LocationMatcher( filepath, 11, 12 )
609-
) ) ),
601+
has_entries( {
602+
'locations': contains_exactly(
603+
LocationMatcher( filepath, 7, 12 ),
604+
LocationMatcher( filepath, 7, 18 ) ),
605+
'root_location': LocationMatcher( filepath, 6, 6 )
606+
} ),
607+
has_entries( {
608+
'locations': contains_exactly(
609+
LocationMatcher( filepath, 11, 12 ) ),
610+
'root_location': LocationMatcher( filepath, 9, 6 )
611+
} )
612+
),
610613
requests.codes.ok ],
611614
[ ( filepath, 6, 6 ),
612615
contains_inanyorder(
613-
has_entry( 'locations',
614-
contains_exactly(
615-
LocationMatcher( filepath, 10, 13 )
616-
) ) ),
616+
has_entries( {
617+
'locations': contains_exactly(
618+
LocationMatcher( filepath, 10, 13 ) ),
619+
'root_location': LocationMatcher( filepath, 9, 6 )
620+
} )
621+
),
617622
requests.codes.ok ],
618623
[ ( filepath, 9, 6 ),
619624
ErrorMatcher( RuntimeError, 'No incoming calls found.' ),

ycmd/tests/rust/subcommands_test.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -629,22 +629,33 @@ def test_Subcommands_IncomingCallHierarchy( self, app ):
629629
for location, response, code in [
630630
[ ( filepath, 1, 4 ),
631631
contains_inanyorder(
632-
has_entry( 'locations',
633-
contains_exactly(
634-
LocationMatcher( filepath, 6, 5 ),
635-
LocationMatcher( filepath, 6, 11 )
636-
) ),
637-
has_entry( 'locations',
638-
contains_exactly(
639-
LocationMatcher( filepath, 11, 5 )
640-
) ) ),
632+
has_entries( {
633+
'locations': contains_exactly(
634+
LocationMatcher( filepath, 6, 5 ),
635+
LocationMatcher( filepath, 6, 11 ) ),
636+
# rust-analyzer always returns column 1 for root_location,
637+
# which is useless for us... unfortunately.
638+
'root_location': LocationMatcher( filepath, 5, 1 )
639+
} ),
640+
has_entries( {
641+
'locations': contains_exactly(
642+
LocationMatcher( filepath, 11, 5 ) ),
643+
# rust-analyzer always returns column 1 for root_location,
644+
# which is useless for us... unfortunately.
645+
'root_location': LocationMatcher( filepath, 9, 1 )
646+
} )
647+
),
641648
requests.codes.ok ],
642649
[ ( filepath, 5, 4 ),
643650
contains_inanyorder(
644-
has_entry( 'locations',
645-
contains_exactly(
646-
LocationMatcher( filepath, 10, 13 )
647-
) ) ),
651+
has_entries( {
652+
'locations': contains_exactly(
653+
LocationMatcher( filepath, 10, 13 ) ),
654+
# rust-analyzer always returns column 1 for root_location,
655+
# which is useless for us... unfortunately.
656+
'root_location': LocationMatcher( filepath, 9, 1 )
657+
} )
658+
),
648659
requests.codes.ok ],
649660
[ ( filepath, 9, 4 ),
650661
ErrorMatcher( RuntimeError, 'No incoming calls found.' ),

0 commit comments

Comments
 (0)