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 LspHandlerTypeDescriptor
s—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 HandlerTypeDescriptor
s) are being constructed.