Skip to content

Commit 6ee2296

Browse files
authored
Merge pull request #4 from xSeagullx/support-base-interfaces
Improvements to structs generation.
2 parents 8599a1b + 0fd2c62 commit 6ee2296

14 files changed

Lines changed: 677 additions & 216 deletions
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/.idea
2+
3+
!*.sln
4+
!*.csproj

SourceGenerators/PolymorphicStructsSourceGenerators/PolymorphicStructsSourceGenerators.sln

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,30 @@ Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 17
44
VisualStudioVersion = 17.0.31919.166
55
MinimumVisualStudioVersion = 10.0.40219.1
6-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PolymorphicStructsSourceGenerators", "PolymorphicStructsSourceGenerators\PolymorphicStructsSourceGenerators.csproj", "{454B6834-A6FC-432C-A3EF-702EFA899A7F}"
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PolymorphicStructsSourceGeneratorsTests", "PolymorphicStructsSourceGeneratorsTests\PolymorphicStructsSourceGeneratorsTests.csproj", "{747A1BAC-DB40-4AC7-A888-3A6BA9B37AD9}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PolymorphicStructsSourceGenerators", "PolymorphicStructsSourceGenerators\PolymorphicStructsSourceGenerators.csproj", "{C448E748-E4B8-4824-9245-CEC42CF5F6BE}"
79
EndProject
810
Global
911
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1012
Debug|Any CPU = Debug|Any CPU
1113
Release|Any CPU = Release|Any CPU
1214
EndGlobalSection
1315
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14-
{454B6834-A6FC-432C-A3EF-702EFA899A7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15-
{454B6834-A6FC-432C-A3EF-702EFA899A7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
16-
{454B6834-A6FC-432C-A3EF-702EFA899A7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
17-
{454B6834-A6FC-432C-A3EF-702EFA899A7F}.Release|Any CPU.Build.0 = Release|Any CPU
16+
{C2C9894F-E4B7-4B82-B6E9-5135577E2767}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17+
{C2C9894F-E4B7-4B82-B6E9-5135577E2767}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{C2C9894F-E4B7-4B82-B6E9-5135577E2767}.Release|Any CPU.ActiveCfg = Release|Any CPU
19+
{C2C9894F-E4B7-4B82-B6E9-5135577E2767}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{747A1BAC-DB40-4AC7-A888-3A6BA9B37AD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{747A1BAC-DB40-4AC7-A888-3A6BA9B37AD9}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{747A1BAC-DB40-4AC7-A888-3A6BA9B37AD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{747A1BAC-DB40-4AC7-A888-3A6BA9B37AD9}.Release|Any CPU.Build.0 = Release|Any CPU
24+
{C448E748-E4B8-4824-9245-CEC42CF5F6BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25+
{C448E748-E4B8-4824-9245-CEC42CF5F6BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
26+
{C448E748-E4B8-4824-9245-CEC42CF5F6BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
27+
{C448E748-E4B8-4824-9245-CEC42CF5F6BE}.Release|Any CPU.Build.0 = Release|Any CPU
1828
EndGlobalSection
1929
GlobalSection(SolutionProperties) = preSolution
2030
HideSolutionNode = FALSE
2131
EndGlobalSection
22-
GlobalSection(ExtensibilityGlobals) = postSolution
23-
SolutionGuid = {C2E19360-9CA5-4957-AB7F-28876225DC27}
24-
EndGlobalSection
2532
EndGlobal

SourceGenerators/PolymorphicStructsSourceGenerators/PolymorphicStructsSourceGenerators/PolymorphicStructsSourceGenerator.cs

Lines changed: 262 additions & 208 deletions
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<RootNamespace>PolymorphicStructsSourceGenerators</RootNamespace>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.8.0" />
10+
</ItemGroup>
11+
12+
</Project>

SourceGenerators/PolymorphicStructsSourceGenerators/PolymorphicStructsSourceGenerators/SourceGenUtils.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.IO;
77
using System.Linq;
88
using System.Text;
9+
// ReSharper disable HeapView.BoxingAllocation
910

1011
namespace PolymorphicStructsSourceGenerators
1112
{
@@ -96,5 +97,23 @@ public static string GetNamespace(BaseTypeDeclarationSyntax syntax)
9697

9798
return nameSpace;
9899
}
100+
101+
public static List<ISymbol> GetAllMemberSymbols(GeneratorExecutionContext context, InterfaceDeclarationSyntax polymorphicInterface)
102+
{
103+
var semanticModel = context.Compilation.GetSemanticModel(polymorphicInterface.SyntaxTree);
104+
var interfaceSymbol = semanticModel.GetDeclaredSymbol(polymorphicInterface, context.CancellationToken);
105+
106+
return interfaceSymbol?.GetMembers().Concat(interfaceSymbol
107+
?.AllInterfaces
108+
.SelectMany(it => it.GetMembers()))
109+
.Where(IsNotAPropertyMethod)
110+
.ToList();
111+
}
112+
113+
private static bool IsNotAPropertyMethod(ISymbol it)
114+
{
115+
return !(it is IMethodSymbol methodSymbol) || methodSymbol.MethodKind != MethodKind.PropertyGet &&
116+
methodSymbol.MethodKind != MethodKind.PropertySet;
117+
}
99118
}
100119
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
3+
namespace PolymorphicStructsSourceGeneratorsTests
4+
{
5+
/// <summary>
6+
/// We can use our own polymorphic struct argument so we don't have to reference anything else
7+
/// Generator resolves attribute by name, so as long as it matches, we don't care where it's coming from
8+
/// </summary>
9+
[AttributeUsage(AttributeTargets.Interface)]
10+
public class PolymorphicStruct : System.Attribute
11+
{
12+
public string ImplementedInterfaces;
13+
14+
public PolymorphicStruct(string implementedInterfaces = "")
15+
{
16+
ImplementedInterfaces = implementedInterfaces;
17+
}
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net5.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
9+
<PackageReference Include="NUnit" Version="3.13.3" />
10+
</ItemGroup>
11+
12+
<ItemGroup>
13+
<ProjectReference Include="..\PolymorphicStructsSourceGenerators\PolymorphicStructsSourceGenerators.csproj" OutputItemType="Analyzer" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<Folder Include="Inheritance" />
18+
</ItemGroup>
19+
20+
</Project>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using NUnit.Framework;
3+
4+
namespace PolymorphicStructsSourceGeneratorsTests.Tests
5+
{
6+
[PolymorphicStruct]
7+
public interface IFieldTestStruct
8+
{
9+
public int Foo();
10+
}
11+
12+
public partial struct FieldTestStruct {
13+
}
14+
15+
16+
public partial struct FieldTestStructA : IFieldTestStruct
17+
{
18+
public int Field;
19+
20+
public int Foo()
21+
{
22+
return Field;
23+
}
24+
}
25+
26+
public partial struct FieldTestStructB : IFieldTestStruct
27+
{
28+
public int Field;
29+
public int Field2;
30+
31+
public int Foo()
32+
{
33+
return Field + Field2;
34+
}
35+
}
36+
37+
38+
[TestFixture]
39+
[SuppressMessage("ReSharper", "HeapView.BoxingAllocation")]
40+
public partial class FieldsTest
41+
{
42+
[Test]
43+
public void PolymoprphicStructWorks()
44+
{
45+
var baseStructA = new FieldTestStructA { Field = 1 }.ToFieldTestStruct();
46+
var baseStructB = new FieldTestStructB { Field = 2, Field2 = 3 }.ToFieldTestStruct();
47+
48+
Assert.AreEqual(FieldTestStruct.TypeId.FieldTestStructA, baseStructA.CurrentTypeId);
49+
Assert.AreEqual(FieldTestStruct.TypeId.FieldTestStructB, baseStructB.CurrentTypeId);
50+
51+
Assert.AreEqual(1, baseStructA.Foo());
52+
Assert.AreEqual(5, baseStructB.Foo());
53+
}
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using NUnit.Framework;
3+
4+
namespace PolymorphicStructsSourceGeneratorsTests.Tests
5+
{
6+
public interface IParentStruct
7+
{
8+
public int Foo(int a, bool b);
9+
}
10+
11+
public interface IParentStruct2
12+
{
13+
public int Bar();
14+
}
15+
16+
[PolymorphicStruct]
17+
public interface IChildStruct : IParentStruct, IParentStruct2
18+
{ }
19+
20+
public partial struct ChildStruct : IChildStruct
21+
// an ability to explicitly define IChildStruct here is redundant, if generated ChildStruct will be always implementing IChildStruct.
22+
// But you might still want to do that and also define other interfaces, which should not affect generation
23+
// Also, if you did that by mistake, now generator won't be including it in the TypeId
24+
{
25+
}
26+
27+
public partial struct InheritedStruct : IChildStruct
28+
{
29+
public int Foo(int a, bool b)
30+
{
31+
return 42 + a * (b ? 1 : 0);
32+
}
33+
34+
public int Bar()
35+
{
36+
return 13;
37+
}
38+
}
39+
40+
[TestFixture]
41+
[SuppressMessage("ReSharper", "HeapView.BoxingAllocation")]
42+
public partial class InheritanceHierarchyTest
43+
{
44+
[Test]
45+
public void GeneratedStructureContainsMethodsFromBaseInterfaces()
46+
{
47+
var childStruct = new InheritedStruct().ToChildStruct();
48+
Assert.AreEqual(13, childStruct.Bar());
49+
Assert.AreEqual(42, childStruct.Foo(1, false));
50+
Assert.AreEqual(43, childStruct.Foo(1, true));
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)