OmniSharp / OmniSharp/csharp-language-server-protocol

Wrong method name sent for `RequestCallHierarchyOutgoing`

Open
#1,303 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C#
Stars
638
Forks
109
Avg merge
1m
Merged PRs (30d)
2

Description

Summary

When calling the LanguageClient.RequestCallHierarchyOutgoing method, the language client uses the method name textDocument/prepareCallHierarchy instead of callHierarchy/outgoingCalls in the JSON-RPC that's sent to the language server. This (apart from just being the wrong method name) causes most language servers to emit an error, since the method's name and parameters don't match.

Workaround

As a workaround, assuming outgoingParams is the CallHierarchyOutgoingCallsParams, client is the LanguageClient, and token is a CancellationToken, one can replace

client.RequestCallHierarchyOutgoing(outgoingParams, t);

with

client.SendRequest("callHierarchy/outgoingCalls", outgoingParams).Returning<IEnumerable<CallHierarchyOutgoingCall>>(token);

Possible cause

I've tried looking into why this happens, but the implementation of this part seems pretty complex, so I'm not sure if the following is correct. What I think happens is that the KnownHandlers in LspHandlerTypeDescriptorProvider—which associate method names with LspHandlerTypeDescriptors—is set up incorrectly. Specifically, the KnownHandlers end up associating the textDocument/prepareCallHierarchy method with the DelegatingCallHierarchyHandler (or rather, its type). When this type is wrapped in the HandlerTypeDescriptor's constructor, the ParamsType is set to CallHierarchyOutgoingCallsParams, while the method is set to textDocument/prepareCallHierarchy, which is where the mismatch originates from. The issue here specifically is how the method name is retrieved: All the interfaces that the given handler implements are checked for method attributes, and then the first of these is chosen. In the case of the DelegatingCallHierarchyHandler, it implements 14 interfaces. The first relevant interface that's returned by type.GetInterfaces() is ICallHierarchyPrepareHandler, whose MethodAttribute specifies textDocument/prepareCallHierarchy as the method name to use.

Something very similar happens with textDocument/prepareTypeHierarchy and typeHierarchy/subtypes. The reason this problem does not occur here is luck: The DelegatingTypeHierarchyHandler also implements 14 analogous interfaces, but the first one returned by type.GetInterfaces() here is ITypeHierarchySubtypesHandler, which happens to match the parameter type and hence causes LanguageClient.RequestTypeHierarchySubtypes to work correctly, despite the same flaw in how the KnownHandlers (or rather the HandlerTypeDescriptors) are being constructed.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in LspHandlerTypeDescriptorProvider, focusing on KnownHandlers and how HandlerTypeDescriptor derives the method and ParamsType from DelegatingCallHierarchyHandler interfaces. Reproduce the mismatch through LanguageClient.RequestCallHierarchyOutgoing and compare it with the analogous type-hierarchy request. Done means outgoing calls are sent as callHierarchy/outgoingCalls with matching parameters, without regressing the working type-hierarchy request.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
api, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.