Skip to content

Commit ee387e6

Browse files
authored
Add support for generic constraints (#84)
* - Implement support for interface constraints so they carry over to generated decorator class. * Update test project from .net 7 to .net 8 so PR CI works.
1 parent f72c5b8 commit ee387e6

File tree

5 files changed

+79
-2
lines changed

5 files changed

+79
-2
lines changed

DecoratorGenerator.UnitTests/DecoratorGenerator.UnitTests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net7.0</TargetFramework>
4+
<TargetFramework>net8.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using DecoratorGenerator;
2+
3+
namespace SampleLibrary;
4+
5+
[Decorate]
6+
public interface ITigerConstraints
7+
{
8+
string Roar();
9+
10+
string Trait<T>(T trait) where T : class, ICat, new();
11+
}

DecoratorGenerator.UnitTests/Tests.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,29 @@ public async Task OneInterface_Properties() {
6262
}.RunAsync();
6363
}
6464

65+
[Test]
66+
public async Task OneInterface_Constraints() {
67+
var source = await ReadCSharpFile<ITigerConstraints>();
68+
var generated = await ReadCSharpFile<TigerConstraintsDecorator>();
69+
70+
await new VerifyCS.Test
71+
{
72+
TestState = {
73+
ReferenceAssemblies = ReferenceAssemblies.Net.Net60,
74+
AdditionalReferences =
75+
{
76+
implementationAssembly,
77+
Assembly.GetExecutingAssembly()
78+
},
79+
Sources = { source },
80+
GeneratedSources =
81+
{
82+
(typeof(Main), "TigerConstraintsDecorator.generated.cs", SourceText.From(generated, Encoding.UTF8, SourceHashAlgorithm.Sha256)),
83+
},
84+
},
85+
}.RunAsync();
86+
}
87+
6588
[Test]
6689
public async Task OneInterface_NestedNamespace() {
6790
var source = await ReadCSharpFile<INested>();
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// <auto-generated/>
2+
#nullable restore
3+
namespace SampleLibrary;
4+
5+
public abstract class TigerConstraintsDecorator : ITigerConstraints
6+
{
7+
private ITigerConstraints tigerConstraints;
8+
9+
protected TigerConstraintsDecorator(ITigerConstraints tigerConstraints) {
10+
this.tigerConstraints = tigerConstraints;
11+
}
12+
13+
14+
15+
public virtual string Roar() {
16+
return tigerConstraints.Roar();
17+
}
18+
19+
public virtual string Trait<T>(T trait) where T : class, SampleLibrary.ICat, new() {
20+
return tigerConstraints.Trait<T>(trait);
21+
}
22+
}

DecoratorGenerator/OutputGenerator.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,28 @@ public abstract class {className} : {@interface.Name}
5151
var typeParametersStrings = method.TypeParameters.Select(t => t.ToDisplayString());
5252
var parametersStrings = method.Parameters.Select(p => $@"{p.Type} {p.Name}");
5353
var formattedAccessibility = (method.ReturnType.DeclaredAccessibility != Accessibility.NotApplicable ? method.ReturnType.DeclaredAccessibility : Accessibility.Public).ToString().ToLower();
54-
var signature = $@"{formattedAccessibility} virtual {method.ReturnType} {method.Name}{(method.IsGenericMethod ? $@"<{string.Join(", ", typeParametersStrings)}>" : string.Empty)}({string.Join(", ", parametersStrings)})";
54+
var formattedGenericTypeParameters = method.IsGenericMethod ? $@"<{string.Join(", ", typeParametersStrings)}>" : string.Empty;
55+
var formattedConstraintsStrings = method.TypeParameters.Select(t => {
56+
var constraintsStrings = new List<string>();
57+
58+
if (t.HasReferenceTypeConstraint) {
59+
constraintsStrings.Add("class");
60+
}
61+
62+
if (t.HasNotNullConstraint) {
63+
constraintsStrings.Add("notnull");
64+
}
65+
constraintsStrings = constraintsStrings.Concat(t.ConstraintTypes.ToList().Select(ct => ct.ToDisplayString())).ToList();
66+
67+
if (t.HasConstructorConstraint) {
68+
constraintsStrings.Add("new()");
69+
}
70+
71+
return constraintsStrings.Any() ? $@"where {t.ToDisplayString()} : {string.Join(", ", constraintsStrings)}" : string.Empty;
72+
})
73+
.Where(cs => cs != string.Empty);
74+
var formattedConstraints = string.Join(" ", formattedConstraintsStrings);
75+
var signature = $@"{formattedAccessibility} virtual {method.ReturnType} {method.Name}{formattedGenericTypeParameters}({string.Join(", ", parametersStrings)}){(formattedConstraints != string.Empty ? $@" {formattedConstraints}" : string.Empty)}";
5576
var callParameters = $@"{string.Join(", ", method.Parameters.Select(p => p.Name))}";
5677

5778
var call = $@"{targetFieldName}.{method.Name}{(method.IsGenericMethod ? $@"<{string.Join(", ", typeParametersStrings)}>" : string.Empty)}({callParameters})";

0 commit comments

Comments
 (0)