Skip to content

Commit c31bf3c

Browse files
Added support for open generic params and handler interfaces.
1 parent 8e0377a commit c31bf3c

20 files changed

+1819
-206
lines changed

src/Dap.Protocol/Models/ProgressToken.cs

+7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ public record ProgressToken : IEquatable<long>, IEquatable<string>
99
private long? _long;
1010
private string? _string;
1111

12+
public ProgressToken(Guid value)
13+
{
14+
_string = value.ToString();
15+
_long = null;
16+
}
17+
1218
public ProgressToken(long value)
1319
{
1420
_long = value;
@@ -46,6 +52,7 @@ public string String
4652
public static implicit operator ProgressToken(long value) => new ProgressToken(value);
4753

4854
public static implicit operator ProgressToken(string value) => new ProgressToken(value);
55+
public static implicit operator ProgressToken(Guid value) => new ProgressToken(value);
4956

5057
public bool Equals(long other) => IsLong && Long == other;
5158
public bool Equals(string other) => IsString && String == other;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using Newtonsoft.Json;
3+
using OmniSharp.Extensions.DebugAdapter.Protocol.Models;
4+
5+
namespace OmniSharp.Extensions.DebugAdapter.Protocol.Serialization
6+
{
7+
internal class ProgressTokenConverter : JsonConverter<ProgressToken?>
8+
{
9+
public override void WriteJson(JsonWriter writer, ProgressToken? value, JsonSerializer serializer)
10+
{
11+
if (value == null) writer.WriteNull();
12+
else if (value.IsLong) serializer.Serialize(writer, value.Long);
13+
else if (value.IsString) serializer.Serialize(writer, value.String);
14+
else writer.WriteNull();
15+
}
16+
17+
public override ProgressToken? ReadJson(JsonReader reader, Type objectType, ProgressToken? existingValue, bool hasExistingValue, JsonSerializer serializer)
18+
{
19+
return reader.TokenType switch {
20+
JsonToken.Integer => new ProgressToken((long) reader.Value),
21+
JsonToken.String when reader.Value is string str && !string.IsNullOrWhiteSpace(str) => new ProgressToken(str),
22+
_ => null
23+
};
24+
}
25+
26+
public override bool CanRead => true;
27+
}
28+
}

src/Dap.Protocol/Serialization/Serializer.cs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ protected override void AddOrReplaceConverters(ICollection<JsonConverter> conver
1616
ReplaceConverter(converters, new DapClientResponseConverter(this));
1717
ReplaceConverter(converters, new DapClientRequestConverter());
1818
ReplaceConverter(converters, new DapRpcErrorConverter(this));
19+
ReplaceConverter(converters, new ProgressTokenConverter());
1920
}
2021

2122
protected override JsonSerializer CreateSerializer()

src/JsonRpc.Generators/Contexts/SyntaxSymbol.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace OmniSharp.Extensions.JsonRpc.Generators.Contexts
55
{
6-
record SyntaxSymbol(TypeSyntax Syntax, INamedTypeSymbol Symbol);
6+
record SyntaxSymbol(TypeSyntax Syntax, ITypeSymbol Symbol);
77

88
record SyntaxAttributeData(AttributeSyntax Syntax, AttributeData Data)
99
{

src/JsonRpc.Generators/GenerateHandlerMethodsGenerator.cs

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ ReportCacheDiagnostic<TypeDeclarationSyntax> cacheDiagnostic
116116
.Where(z => z.Alias == null)
117117
.Select(z => z.Name.ToFullString())
118118
)
119+
.Except(new [] { "<global namespace>" }) // I think there is a better way... but for now..
119120
.Distinct()
120121
.Select(z => UsingDirective(IdentifierName(z)))
121122
)

src/JsonRpc.Generators/Helpers.cs

+19-11
Original file line numberDiff line numberDiff line change
@@ -61,21 +61,21 @@ public static SyntaxSymbol GetResponseType(TypeDeclarationSyntax syntax, INamedT
6161
{ Identifier: { Text: "IRequest" }, Arity: 1 } => gns.TypeArgumentList.Arguments[0],
6262
_ => null
6363
},
64-
SimpleNameSyntax and { Identifier: { Text: "IRequest" } } => ParseName("MediatR.Unit"),
64+
SimpleNameSyntax and { Identifier: { Text: "IRequest" } } => ParseName("MediatR.Unit"),
6565
SimpleNameSyntax and { Identifier: { Text: "IJsonRpcRequest" } } => ParseName("MediatR.Unit"),
6666
_ => null
6767
};
6868
if (type != null) break;
6969
}
7070

71-
if (type == null) throw new ArgumentException($"Response Type {symbol.ToDisplayString()} is not a name symbol", nameof(symbol));
71+
if (type == null) throw new ArgumentException($"Response Syntax {syntax.ToString()} is not a name syntax", nameof(syntax));
7272

7373
var handlerInterface = symbol.AllInterfaces.FirstOrDefault(z => z.Name == "IRequestHandler" && z.TypeArguments.Length == 2);
74-
if (handlerInterface?.TypeArguments[1] is INamedTypeSymbol ns)
75-
return new SyntaxSymbol(type, ns);
74+
if (handlerInterface?.TypeArguments[1] is INamedTypeSymbol || handlerInterface?.TypeArguments[1] is ITypeParameterSymbol)
75+
return new SyntaxSymbol(type, handlerInterface.TypeArguments[1]);
7676
handlerInterface = symbol.AllInterfaces.FirstOrDefault(z => z.Name == "IRequest" && z.Arity == 1);
77-
if (handlerInterface?.TypeArguments[0] is INamedTypeSymbol ns2)
78-
return new SyntaxSymbol(type, ns2);
77+
if (handlerInterface?.TypeArguments[0] is INamedTypeSymbol || handlerInterface?.TypeArguments[0] is ITypeParameterSymbol)
78+
return new SyntaxSymbol(type, handlerInterface.TypeArguments[0]);
7979
throw new ArgumentException($"Response Type {symbol.ToDisplayString()} is not a name symbol", nameof(symbol));
8080
}
8181

@@ -103,11 +103,12 @@ public static SyntaxSymbol GetResponseType(TypeDeclarationSyntax syntax, INamedT
103103
{ Identifier: { Text: "IJsonRpcRequestHandler" } } => gns.TypeArgumentList.Arguments[0],
104104
{ Identifier: { Text: "IJsonRpcNotificationHandler" } } => gns.TypeArgumentList.Arguments[0],
105105
{ Identifier: { Text: "ICanBeResolvedHandler" }, Arity: 1 } => gns.TypeArgumentList.Arguments[0],
106-
{ Identifier: { Text: "IRequest" } } => ParseTypeName(syntax.Identifier.Text),
107-
{ Identifier: { Text: "IJsonRpcRequest" } } => ParseTypeName(syntax.Identifier.Text),
108-
{ Identifier: { Text: "IPartialItemRequest" }, Arity: 2 } => ParseTypeName(syntax.Identifier.Text),
109-
{ Identifier: { Text: "IPartialItemsRequest" }, Arity: 2 } => ParseTypeName(syntax.Identifier.Text),
110-
_ => null,
106+
{ Identifier: { Text: "IRequest" }, Arity: 1 } => IdentifierName(syntax.Identifier.Text),
107+
{ Identifier: { Text: "IRequest" }, Arity: 0 } => IdentifierName(syntax.Identifier.Text),
108+
{ Identifier: { Text: "IJsonRpcRequest" } } => IdentifierName(syntax.Identifier.Text),
109+
{ Identifier: { Text: "IPartialItemRequest" }, Arity: 2 } => IdentifierName(syntax.Identifier.Text),
110+
{ Identifier: { Text: "IPartialItemsRequest" }, Arity: 2 } => IdentifierName(syntax.Identifier.Text),
111+
_ => null,
111112
},
112113
_ => null,
113114
};
@@ -116,6 +117,13 @@ public static SyntaxSymbol GetResponseType(TypeDeclarationSyntax syntax, INamedT
116117
}
117118

118119
if (type == null) return null;
120+
if (type is IdentifierNameSyntax ins && ins.Identifier.Text == syntax.Identifier.Text && syntax.TypeParameterList is { Parameters: { Count: > 0 } })
121+
{
122+
type = GenericName(syntax.Identifier.Text)
123+
.WithTypeArgumentList(
124+
TypeArgumentList(SeparatedList<TypeSyntax>(syntax.TypeParameterList?.Parameters.Select(z => IdentifierName(z.Identifier.Text))))
125+
);
126+
}
119127

120128
var handlerInterface = symbol.AllInterfaces
121129
.FirstOrDefault(z => z.Name == "IRequestHandler" && z.TypeArguments.Length == 2);

src/JsonRpc.Generators/Strategies/ExtensionMethodGeneratorStrategy.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public IEnumerable<MemberDeclarationSyntax> Apply(GeneratorData item)
3838
}
3939
);
4040

41-
var className = item.JsonRpcAttributes.HandlerName + "Extensions";
41+
var className = item.JsonRpcAttributes.HandlerName + "Extensions" + ( item.TypeDeclaration.Arity == 0 ? "" : item.TypeDeclaration.Arity.ToString() );
4242

4343
var obsoleteAttribute = item.TypeDeclaration.AttributeLists
4444
.SelectMany(z => z.Attributes)

src/JsonRpc.Generators/Strategies/HandlerGeneratorStrategy.cs

+16-2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ public IEnumerable<MemberDeclarationSyntax> Apply(GeneratorData item)
3939
.WithModifiers(item.TypeDeclaration.Modifiers)
4040
.AddBaseListTypes(SimpleBaseType(GetBaseHandlerInterface(item)));
4141

42+
if (item is RequestItem { Response: { Symbol: ITypeParameterSymbol } } ri)
43+
{
44+
handlerInterface = handlerInterface.AddTypeParameterListParameters(TypeParameter(ri.Response.Symbol.Name));
45+
}
46+
4247
if (item.Request.Symbol.AllInterfaces.Any(z => z.Name == "IDoesNotParticipateInRegistration"))
4348
{
4449
handlerInterface = handlerInterface.AddBaseListTypes(SimpleBaseType(IdentifierName("IDoesNotParticipateInRegistration")));
@@ -47,7 +52,7 @@ public IEnumerable<MemberDeclarationSyntax> Apply(GeneratorData item)
4752
if (!handlerInterface.Modifiers.Any(z => z.IsKind(SyntaxKind.PartialKeyword)))
4853
{
4954
handlerInterface = handlerInterface.AddModifiers(Token(SyntaxKind.PartialKeyword));
50-
}
55+
}
5156

5257
if (item.JsonRpcAttributes.AllowDerivedRequests)
5358
{
@@ -107,6 +112,7 @@ public IEnumerable<MemberDeclarationSyntax> Apply(GeneratorData item)
107112
var baseClass = GetBaseHandlerClass(item);
108113
var handlerClass = ClassDeclaration(Identifier($"{item.JsonRpcAttributes.HandlerName}HandlerBase"))
109114
.WithAttributeLists(classAttributes)
115+
.WithTypeParameterList(handlerInterface.TypeParameterList)
110116
.AddModifiers(Token(SyntaxKind.AbstractKeyword))
111117
.AddModifiers(handlerInterface.Modifiers.ToArray());
112118
if (item.JsonRpcAttributes.AllowDerivedRequests)
@@ -170,7 +176,15 @@ public IEnumerable<MemberDeclarationSyntax> Apply(GeneratorData item)
170176
}
171177
else
172178
{
173-
handlerClass = handlerClass.AddBaseListTypes(SimpleBaseType(IdentifierName($"I{item.JsonRpcAttributes.HandlerName}Handler")));
179+
handlerClass = handlerClass.AddBaseListTypes(
180+
SimpleBaseType(
181+
item is RequestItem { Response: { Symbol: ITypeParameterSymbol s } }
182+
? GenericName($"I{item.JsonRpcAttributes.HandlerName}Handler").WithTypeArgumentList(
183+
TypeArgumentList(SingletonSeparatedList<TypeSyntax>(IdentifierName(s.Name)))
184+
)
185+
: IdentifierName($"I{item.JsonRpcAttributes.HandlerName}Handler")
186+
)
187+
);
174188
}
175189

176190
if (resolver is { })

src/JsonRpc.Generators/Strategies/OnRequestMethodGeneratorWithRegistrationOptionsStrategy.cs

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Collections.Immutable;
44
using System.Linq;
5+
using Microsoft.CodeAnalysis;
56
using Microsoft.CodeAnalysis.CSharp;
67
using Microsoft.CodeAnalysis.CSharp.Syntax;
78
using OmniSharp.Extensions.JsonRpc.Generators.Contexts;
@@ -42,6 +43,12 @@ public IEnumerable<MemberDeclarationSyntax> Apply(ExtensionMethodContext extensi
4243
resolve
4344
)
4445
);
46+
47+
if (item is RequestItem { Response: { Symbol: ITypeParameterSymbol } } ri)
48+
{
49+
method = method.AddTypeParameterListParameters(TypeParameter(ri.Response.Symbol.Name));
50+
}
51+
4552
if (request.IsUnit)
4653
{
4754
method = method

src/JsonRpc.Generators/Strategies/OnRequestMethodGeneratorWithoutRegistrationOptionsStrategy.cs

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using Microsoft.CodeAnalysis;
34
using Microsoft.CodeAnalysis.CSharp;
45
using Microsoft.CodeAnalysis.CSharp.Syntax;
56
using OmniSharp.Extensions.JsonRpc.Generators.Contexts;
@@ -40,6 +41,11 @@ public IEnumerable<MemberDeclarationSyntax> Apply(ExtensionMethodContext extensi
4041
.WithExpressionBody(GetRequestHandlerExpression(request, GetJsonRpcMethodName(extensionMethodContext.TypeDeclaration)))
4142
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
4243

44+
if (item is RequestItem { Response: { Symbol: ITypeParameterSymbol } } ri)
45+
{
46+
method = method.AddTypeParameterListParameters(TypeParameter(ri.Response.Symbol.Name));
47+
}
48+
4349
var methodFactory = MakeFactory(extensionMethodContext.GetRegistryParameterList());
4450

4551
var factory = methodFactory(method);

src/JsonRpc.Generators/Strategies/OnRequestTypedResolveMethodGeneratorWithRegistrationOptionsStrategy.cs

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Collections.Immutable;
44
using System.Linq;
5+
using Microsoft.CodeAnalysis;
56
using Microsoft.CodeAnalysis.CSharp;
67
using Microsoft.CodeAnalysis.CSharp.Syntax;
78
using OmniSharp.Extensions.JsonRpc.Generators.Contexts;
@@ -57,6 +58,11 @@ public IEnumerable<MemberDeclarationSyntax> Apply(ExtensionMethodContext extensi
5758
)
5859
);
5960

61+
if (item is RequestItem { Response: { Symbol: ITypeParameterSymbol } } ri)
62+
{
63+
method = method.AddTypeParameterListParameters(TypeParameter(ri.Response.Symbol.Name));
64+
}
65+
6066
var methodFactory = MakeFactory(
6167
extensionMethodContext.GetRegistryParameterList(),
6268
registrationOptions.Syntax,

src/JsonRpc.Generators/Strategies/OnRequestTypedResolveMethodGeneratorWithoutRegistrationOptionsStrategy.cs

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using Microsoft.CodeAnalysis;
34
using Microsoft.CodeAnalysis.CSharp;
45
using Microsoft.CodeAnalysis.CSharp.Syntax;
56
using OmniSharp.Extensions.JsonRpc.Generators.Contexts;
@@ -52,6 +53,11 @@ public IEnumerable<MemberDeclarationSyntax> Apply(ExtensionMethodContext extensi
5253
.WithExpressionBody(GetRequestHandlerExpression(request, GetJsonRpcMethodName(extensionMethodContext.TypeDeclaration)))
5354
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
5455

56+
if (item is RequestItem { Response: { Symbol: ITypeParameterSymbol } } ri)
57+
{
58+
method = method.AddTypeParameterListParameters(TypeParameter(ri.Response.Symbol.Name));
59+
}
60+
5561
var methodFactory = MakeFactory(extensionMethodContext.GetRegistryParameterList());
5662

5763
var factory = methodFactory(method);

0 commit comments

Comments
 (0)