Skip to content

Commit ce40438

Browse files
committed
Improve resolve handling
- Also set DocumentSelector when preprocessing in order to support same handler type instances supporting different languages.
1 parent fae86e0 commit ce40438

File tree

3 files changed

+35
-6
lines changed

3 files changed

+35
-6
lines changed

src/Server/HandlerCollection.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,13 @@ private HandlerDescriptor GetDescriptor(string method, Type implementedType, IJs
8282

8383
var key = "default";
8484
// This protects against the case where class implements many, possibly conflicting, interfaces.
85-
if (registration != null &&
86-
typeof(TextDocumentRegistrationOptions).GetTypeInfo().IsAssignableFrom(registration) &&
85+
if ((registration != null && typeof(TextDocumentRegistrationOptions).GetTypeInfo().IsAssignableFrom(registration) ||
86+
registration == null && implementedType.GetTypeInfo().ImplementedInterfaces.Any(x => x.GetTypeInfo().IsGenericType && x.GetTypeInfo().GetGenericTypeDefinition() == typeof(ICanBeResolvedHandler<>))) &&
8787
handler is IRegistration<TextDocumentRegistrationOptions> handlerRegistration)
8888
{
89-
key = handlerRegistration.GetRegistrationOptions()?.DocumentSelector ?? key;
89+
key = string.IsNullOrEmpty(handlerRegistration?.GetRegistrationOptions()?.DocumentSelector)
90+
? key
91+
: handlerRegistration?.GetRegistrationOptions()?.DocumentSelector;
9092
}
9193

9294
return new HandlerDescriptor(

src/Server/Matchers/ResolveCommandMatcher.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public class ResolveCommandMatcher : IHandlerMatcher, IHandlerPreProcessorMatche
1313
{
1414
private readonly ILogger _logger;
1515
internal static string PrivateHandlerTypeName = "$$___handlerType___$$";
16+
internal static string PrivateHandlerKey = "$$___handlerKey___$$";
1617

1718
public ResolveCommandMatcher(ILogger logger)
1819
{
@@ -30,10 +31,15 @@ public IEnumerable<ILspHandlerDescriptor> FindHandler(object parameters, IEnumer
3031
if (parameters is ICanBeResolved canBeResolved)
3132
{
3233
string handlerType = null;
34+
string handlerKey = null;
3335
if (canBeResolved.Data != null && canBeResolved.Data.Type == JTokenType.Object)
36+
{
3437
handlerType = canBeResolved.Data?[PrivateHandlerTypeName]?.ToString();
38+
handlerKey = canBeResolved.Data?[PrivateHandlerKey]?.ToString();
39+
}
3540

36-
if (string.IsNullOrWhiteSpace(handlerType))
41+
if (string.IsNullOrWhiteSpace(handlerType) &&
42+
string.IsNullOrWhiteSpace(handlerKey))
3743
{
3844
foreach (var descriptor in descriptors)
3945
{
@@ -65,7 +71,8 @@ public IEnumerable<ILspHandlerDescriptor> FindHandler(object parameters, IEnumer
6571
_logger.LogTrace("Checking handler {Method}:{Handler}",
6672
descriptor.Method,
6773
descriptor.Handler.GetType().FullName);
68-
if (descriptor.Handler.GetType().FullName == handlerType || descriptor.HandlerType.FullName == handlerType)
74+
if ((descriptor.Handler.GetType().FullName == handlerType || descriptor.HandlerType.FullName == handlerType) &&
75+
((descriptor is HandlerDescriptor handlerDescriptor) && handlerDescriptor.Key == handlerKey))
6976
{
7077
yield return descriptor;
7178
}
@@ -120,8 +127,11 @@ public object Process(ILspHandlerDescriptor descriptor, object parameters)
120127

121128
public object Process(ILspHandlerDescriptor descriptor, object parameters, object response)
122129
{
130+
var registrationOptions = descriptor.Registration.RegisterOptions as TextDocumentRegistrationOptions;
131+
123132
// Only pin the handler type, if we know the source handler (codelens) is also the resolver.
124-
if (response is IEnumerable<ICanBeResolved> canBeResolveds &&
133+
if (registrationOptions?.DocumentSelector != null &&
134+
response is IEnumerable<ICanBeResolved> canBeResolveds &&
125135
descriptor?.CanBeResolvedHandlerType?.GetTypeInfo().IsAssignableFrom(descriptor.Handler.GetType()) == true)
126136
{
127137
_logger.LogTrace("Updating Resolve items with wrapped data for {Method}:{Handler}",
@@ -135,6 +145,7 @@ public object Process(ILspHandlerDescriptor descriptor, object parameters, objec
135145
var data = new JObject();
136146
data["data"] = item.Data;
137147
data[PrivateHandlerTypeName] = descriptor.Handler.GetType().FullName;
148+
data[PrivateHandlerKey] = registrationOptions.DocumentSelector.ToString();
138149
item.Data = data;
139150
}
140151
}

test/Lsp.Tests/HandlerResolverTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,22 @@ public void Should_DealWithClassesThatImplementMultipleHandlers_WithoutConflicti
192192
descriptor.Key.Should().Be("default");
193193
}
194194

195+
[Fact]
196+
public void Should_DealWithClassesThatImplementMultipleHandlers_BySettingKeyAccordingly()
197+
{
198+
var codeLensHandler = Substitute.For(new Type[] { typeof(ICodeLensHandler), typeof(ICodeLensResolveHandler) }, new object[0]);
199+
((ICodeLensHandler)codeLensHandler).GetRegistrationOptions()
200+
.Returns(new CodeLensRegistrationOptions() {
201+
DocumentSelector = new DocumentSelector(DocumentFilter.ForLanguage("foo"))
202+
});
203+
204+
var handler = new HandlerCollection();
205+
handler.Add(codeLensHandler as IJsonRpcHandler);
206+
207+
var descriptor = handler._handlers.Select(x => x.Key);
208+
descriptor.ShouldAllBeEquivalentTo(new [] { "[foo]", "[foo]" });
209+
}
210+
195211
public static IEnumerable<object[]> Should_DealWithClassesThatImplementMultipleHandlers_WithoutConflictingRegistrations_Data()
196212
{
197213
var codeLensHandler = Substitute.For(new Type[] { typeof(ICodeLensHandler), typeof(ICodeLensResolveHandler) }, new object[0]);

0 commit comments

Comments
 (0)