update and format

This commit is contained in:
Adam Hathcock
2024-05-17 11:58:54 +01:00
parent c0c79ef240
commit 6945bae955
21 changed files with 305 additions and 228 deletions
+12
View File
@@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"csharpier": {
"version": "0.28.2",
"commands": [
"dotnet-csharpier"
]
}
}
}
@@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using FluentAssertions; using FluentAssertions;
using FluentAssertions.Common; using FluentAssertions.Common;
@@ -18,7 +19,11 @@ public class AccessorsGenerationTests
[Fact] [Fact]
public void GetSetIndexer_IsImplemented() public void GetSetIndexer_IsImplemented()
{ {
var indexer = typeof(IAccessorsTestsService).GetIndexerByParameterTypes(new[] { typeof(string) }); var indexer = typeof(IAccessorsTestsService)
.GetProperties()
.First(x =>
x.GetIndexParameters().Select(x => x.ParameterType).Contains(typeof(string))
);
indexer.Should().NotBeNull(); indexer.Should().NotBeNull();
@@ -32,8 +37,10 @@ public class AccessorsGenerationTests
[Fact] [Fact]
public void PublicProperty_IsImplemented() public void PublicProperty_IsImplemented()
{ {
var prop = typeof(IAccessorsTestsService) var prop =
.GetProperty(nameof(IAccessorsTestsService.PublicProperty)) ?? throw new InvalidOperationException(); typeof(IAccessorsTestsService).GetProperty(
nameof(IAccessorsTestsService.PublicProperty)
) ?? throw new InvalidOperationException();
prop.Should().NotBeNull(); prop.Should().NotBeNull();
@@ -47,15 +54,19 @@ public class AccessorsGenerationTests
[Fact] [Fact]
public void InitProperty_IsImplemented() public void InitProperty_IsImplemented()
{ {
var prop = typeof(IAccessorsTestsService) var prop =
.GetProperty(nameof(IAccessorsTestsService.InitOnlyProperty)) ?? throw new InvalidOperationException(); typeof(IAccessorsTestsService).GetProperty(
nameof(IAccessorsTestsService.InitOnlyProperty)
) ?? throw new InvalidOperationException();
prop.Should().NotBeNull(); prop.Should().NotBeNull();
prop.GetMethod.Should().NotBeNull(); prop.GetMethod.Should().NotBeNull();
prop.SetMethod.Should().NotBeNull(); prop.SetMethod.Should().NotBeNull();
prop.SetMethod?.ReturnParameter?.GetRequiredCustomModifiers().Should().Contain(typeof(IsExternalInit)); prop.SetMethod?.ReturnParameter?.GetRequiredCustomModifiers()
.Should()
.Contain(typeof(IsExternalInit));
var _ = _sut.InitOnlyProperty; var _ = _sut.InitOnlyProperty;
} }
@@ -63,8 +74,10 @@ public class AccessorsGenerationTests
[Fact] [Fact]
public void PrivateSetter_IsOmitted() public void PrivateSetter_IsOmitted()
{ {
var prop = typeof(IAccessorsTestsService) var prop =
.GetProperty(nameof(IAccessorsTestsService.PropertyWithPrivateSetter)) ?? throw new InvalidOperationException(); typeof(IAccessorsTestsService).GetProperty(
nameof(IAccessorsTestsService.PropertyWithPrivateSetter)
) ?? throw new InvalidOperationException();
prop.Should().NotBeNull(); prop.Should().NotBeNull();
@@ -77,8 +90,10 @@ public class AccessorsGenerationTests
[Fact] [Fact]
public void PrivateGetter_IsOmitted() public void PrivateGetter_IsOmitted()
{ {
var prop = typeof(IAccessorsTestsService) var prop =
.GetProperty(nameof(IAccessorsTestsService.PropertyWithPrivateGetter)) ?? throw new InvalidOperationException(); typeof(IAccessorsTestsService).GetProperty(
nameof(IAccessorsTestsService.PropertyWithPrivateGetter)
) ?? throw new InvalidOperationException();
prop.Should().NotBeNull(); prop.Should().NotBeNull();
@@ -91,8 +106,10 @@ public class AccessorsGenerationTests
[Fact] [Fact]
public void ProtectedSetter_IsOmitted() public void ProtectedSetter_IsOmitted()
{ {
var prop = typeof(IAccessorsTestsService) var prop =
.GetProperty(nameof(IAccessorsTestsService.PropertyWithProtectedSetter)) ?? throw new InvalidOperationException(); typeof(IAccessorsTestsService).GetProperty(
nameof(IAccessorsTestsService.PropertyWithProtectedSetter)
) ?? throw new InvalidOperationException();
prop.Should().NotBeNull(); prop.Should().NotBeNull();
@@ -105,8 +122,10 @@ public class AccessorsGenerationTests
[Fact] [Fact]
public void ProtectedGetter_IsOmitted() public void ProtectedGetter_IsOmitted()
{ {
var prop = typeof(IAccessorsTestsService) var prop =
.GetProperty(nameof(IAccessorsTestsService.PropertyWithProtectedGetter)) ?? throw new InvalidOperationException(); typeof(IAccessorsTestsService).GetProperty(
nameof(IAccessorsTestsService.PropertyWithProtectedGetter)
) ?? throw new InvalidOperationException();
prop.Should().NotBeNull(); prop.Should().NotBeNull();
@@ -119,8 +138,9 @@ public class AccessorsGenerationTests
[Fact] [Fact]
public void IgnoredProperty_IsOmitted() public void IgnoredProperty_IsOmitted()
{ {
var prop = typeof(IAccessorsTestsService) var prop = typeof(IAccessorsTestsService).GetProperty(
.GetProperty(nameof(AccessorsTestsService.IgnoredProperty)); nameof(AccessorsTestsService.IgnoredProperty)
);
prop.Should().BeNull(); prop.Should().BeNull();
} }
@@ -128,8 +148,9 @@ public class AccessorsGenerationTests
[Fact] [Fact]
public void StaticProperty_IsOmitted() public void StaticProperty_IsOmitted()
{ {
var prop = typeof(IAccessorsTestsService) var prop = typeof(IAccessorsTestsService).GetProperty(
.GetProperty(nameof(AccessorsTestsService.StaticProperty)); nameof(AccessorsTestsService.StaticProperty)
);
prop.Should().BeNull(); prop.Should().BeNull();
} }
@@ -142,9 +163,7 @@ internal class AccessorsTestsService : IAccessorsTestsService
public int this[string x] public int this[string x]
{ {
get => 0; get => 0;
set set { }
{
}
} }
public string PublicProperty { get; set; } public string PublicProperty { get; set; }
@@ -159,8 +178,9 @@ internal class AccessorsTestsService : IAccessorsTestsService
public string PropertyWithProtectedGetter { protected get; set; } public string PropertyWithProtectedGetter { protected get; set; }
[AutoInterfaceIgnore] public string IgnoredProperty { get; set; } [AutoInterfaceIgnore]
public string IgnoredProperty { get; set; }
public static string StaticProperty { get; set; } public static string StaticProperty { get; set; }
} }
// ReSharper enable UnusedMember.Local, ValueParameterNotUsed // ReSharper enable UnusedMember.Local, ValueParameterNotUsed
@@ -18,12 +18,15 @@ public class GenericInterfaceTests
genericArgs[0].IsClass.Should().BeTrue(); genericArgs[0].IsClass.Should().BeTrue();
genericArgs[0] genericArgs[0]
.GenericParameterAttributes .GenericParameterAttributes.Should()
.Should()
.HaveFlag(GenericParameterAttributes.DefaultConstructorConstraint); .HaveFlag(GenericParameterAttributes.DefaultConstructorConstraint);
var iEquatableOfTx = typeof(IEquatable<>).MakeGenericType(genericArgs[0]); var iEquatableOfTx = typeof(IEquatable<>).MakeGenericType(genericArgs[0]);
genericArgs[0].GetGenericParameterConstraints().Should().HaveCount(1).And.Contain(iEquatableOfTx); genericArgs[0]
.GetGenericParameterConstraints()
.Should()
.HaveCount(1)
.And.Contain(iEquatableOfTx);
genericArgs[1].IsValueType.Should().BeTrue(); genericArgs[1].IsValueType.Should().BeTrue();
} }
@@ -33,6 +36,4 @@ public class GenericInterfaceTests
// ReSharper disable once UnusedType.Global // ReSharper disable once UnusedType.Global
internal class GenericInterfaceTestsService<TX, TY> : IGenericInterfaceTestsService<TX, TY> internal class GenericInterfaceTestsService<TX, TY> : IGenericInterfaceTestsService<TX, TY>
where TX : class, IEquatable<TX>, new() where TX : class, IEquatable<TX>, new()
where TY : struct where TY : struct { }
{
}
@@ -19,8 +19,9 @@ public class MethodGenerationTests
[Fact] [Fact]
public void VoidMethod_IsImplemented() public void VoidMethod_IsImplemented()
{ {
var method = typeof(IMethodsTestService).GetMethod( var method =
nameof(MethodsTestService.VoidMethod)) ?? throw new InvalidOperationException(); typeof(IMethodsTestService).GetMethod(nameof(MethodsTestService.VoidMethod))
?? throw new InvalidOperationException();
method.Should().NotBeNull(); method.Should().NotBeNull();
method.ReturnType.Should().Be(typeof(void)); method.ReturnType.Should().Be(typeof(void));
@@ -34,8 +35,10 @@ public class MethodGenerationTests
[Fact] [Fact]
public void VoidMethodWithKeywordParam_IsImplemented() public void VoidMethodWithKeywordParam_IsImplemented()
{ {
var method = typeof(IMethodsTestService).GetMethod( var method =
nameof(MethodsTestService.VoidMethodWithKeywordParam)) ?? throw new InvalidOperationException(); typeof(IMethodsTestService).GetMethod(
nameof(MethodsTestService.VoidMethodWithKeywordParam)
) ?? throw new InvalidOperationException();
method.Should().NotBeNull(); method.Should().NotBeNull();
method.ReturnType.Should().Be(typeof(void)); method.ReturnType.Should().Be(typeof(void));
@@ -52,9 +55,11 @@ public class MethodGenerationTests
[Fact] [Fact]
public void VoidMethodWithParams_IsImplemented() public void VoidMethodWithParams_IsImplemented()
{ {
var method = typeof(IMethodsTestService).GetMethod( var method =
nameof(MethodsTestService.VoidMethodWithParams), typeof(IMethodsTestService).GetMethod(
[typeof(string), typeof(string)]) ?? throw new InvalidOperationException(); nameof(MethodsTestService.VoidMethodWithParams),
[typeof(string), typeof(string)]
) ?? throw new InvalidOperationException();
method.Should().NotBeNull(); method.Should().NotBeNull();
method.ReturnType.Should().Be(typeof(void)); method.ReturnType.Should().Be(typeof(void));
@@ -69,15 +74,20 @@ public class MethodGenerationTests
[Fact] [Fact]
public void VoidMethodWithOutParam_IsImplemented() public void VoidMethodWithOutParam_IsImplemented()
{ {
var method = typeof(IMethodsTestService).GetMethod( var method =
nameof(MethodsTestService.VoidMethodWithOutParam), typeof(IMethodsTestService).GetMethod(
[typeof(string).MakeByRefType()]) ?? throw new InvalidOperationException(); nameof(MethodsTestService.VoidMethodWithOutParam),
[typeof(string).MakeByRefType()]
) ?? throw new InvalidOperationException();
method.Should().NotBeNull(); method.Should().NotBeNull();
method.ReturnType.Should().Be(typeof(void)); method.ReturnType.Should().Be(typeof(void));
var parameters = method.GetParameters(); var parameters = method.GetParameters();
parameters.Select(x => x.ParameterType).Should().AllBeEquivalentTo(typeof(string).MakeByRefType()); parameters
.Select(x => x.ParameterType)
.Should()
.AllBeEquivalentTo(typeof(string).MakeByRefType());
parameters.Should().HaveCount(1); parameters.Should().HaveCount(1);
parameters[0].IsOut.Should().BeTrue(); parameters[0].IsOut.Should().BeTrue();
@@ -87,15 +97,20 @@ public class MethodGenerationTests
[Fact] [Fact]
public void VoidMethodWithInParam_IsImplemented() public void VoidMethodWithInParam_IsImplemented()
{ {
var method = typeof(IMethodsTestService).GetMethod( var method =
nameof(MethodsTestService.VoidMethodWithInParam), typeof(IMethodsTestService).GetMethod(
[typeof(string).MakeByRefType()]) ?? throw new InvalidOperationException(); nameof(MethodsTestService.VoidMethodWithInParam),
[typeof(string).MakeByRefType()]
) ?? throw new InvalidOperationException();
method.Should().NotBeNull(); method.Should().NotBeNull();
method.ReturnType.Should().Be(typeof(void)); method.ReturnType.Should().Be(typeof(void));
var parameters = method.GetParameters(); var parameters = method.GetParameters();
parameters.Select(x => x.ParameterType).Should().AllBeEquivalentTo(typeof(string).MakeByRefType()); parameters
.Select(x => x.ParameterType)
.Should()
.AllBeEquivalentTo(typeof(string).MakeByRefType());
parameters.Should().HaveCount(1); parameters.Should().HaveCount(1);
parameters[0].IsIn.Should().BeTrue(); parameters[0].IsIn.Should().BeTrue();
@@ -106,15 +121,20 @@ public class MethodGenerationTests
[Fact] [Fact]
public void VoidMethodWithRefParam_IsImplemented() public void VoidMethodWithRefParam_IsImplemented()
{ {
var method = typeof(IMethodsTestService).GetMethod( var method =
nameof(MethodsTestService.VoidMethodWithRefParam), typeof(IMethodsTestService).GetMethod(
[typeof(string).MakeByRefType()]) ?? throw new InvalidOperationException(); nameof(MethodsTestService.VoidMethodWithRefParam),
[typeof(string).MakeByRefType()]
) ?? throw new InvalidOperationException();
method.Should().NotBeNull(); method.Should().NotBeNull();
method.ReturnType.Should().Be(typeof(void)); method.ReturnType.Should().Be(typeof(void));
var parameters = method.GetParameters(); var parameters = method.GetParameters();
parameters.Select(x => x.ParameterType).Should().AllBeEquivalentTo(typeof(string).MakeByRefType()); parameters
.Select(x => x.ParameterType)
.Should()
.AllBeEquivalentTo(typeof(string).MakeByRefType());
parameters.Should().HaveCount(1); parameters.Should().HaveCount(1);
parameters[0].IsIn.Should().BeFalse(); parameters[0].IsIn.Should().BeFalse();
parameters[0].IsOut.Should().BeFalse(); parameters[0].IsOut.Should().BeFalse();
@@ -126,8 +146,9 @@ public class MethodGenerationTests
[Fact] [Fact]
public void StringMethod_IsImplemented() public void StringMethod_IsImplemented()
{ {
var method = typeof(IMethodsTestService).GetMethod( var method =
nameof(MethodsTestService.StringMethod)) ?? throw new InvalidOperationException(); typeof(IMethodsTestService).GetMethod(nameof(MethodsTestService.StringMethod))
?? throw new InvalidOperationException();
method.Should().NotBeNull(); method.Should().NotBeNull();
method.ReturnType.Should().Be(typeof(string)); method.ReturnType.Should().Be(typeof(string));
@@ -142,8 +163,8 @@ public class MethodGenerationTests
public void GenericVoidMethod_IsImplemented() public void GenericVoidMethod_IsImplemented()
{ {
var method = typeof(IMethodsTestService) var method = typeof(IMethodsTestService)
.GetMethods() .GetMethods()
.First(x => x.Name == nameof(MethodsTestService.GenericVoidMethod)); .First(x => x.Name == nameof(MethodsTestService.GenericVoidMethod));
method.Should().NotBeNull(); method.Should().NotBeNull();
method.ReturnType.Should().Be(typeof(void)); method.ReturnType.Should().Be(typeof(void));
@@ -160,8 +181,8 @@ public class MethodGenerationTests
public void GenericVoidMethodWithGenericParam_IsImplemented() public void GenericVoidMethodWithGenericParam_IsImplemented()
{ {
var method = typeof(IMethodsTestService) var method = typeof(IMethodsTestService)
.GetMethods() .GetMethods()
.First(x => x.Name == nameof(MethodsTestService.GenericVoidMethodWithGenericParam)); .First(x => x.Name == nameof(MethodsTestService.GenericVoidMethodWithGenericParam));
method.Should().NotBeNull(); method.Should().NotBeNull();
method.ReturnType.Should().Be(typeof(void)); method.ReturnType.Should().Be(typeof(void));
@@ -180,8 +201,8 @@ public class MethodGenerationTests
public void GenericVoidMethodWithConstraints_IsImplemented() public void GenericVoidMethodWithConstraints_IsImplemented()
{ {
var method = typeof(IMethodsTestService) var method = typeof(IMethodsTestService)
.GetMethods() .GetMethods()
.First(x => x.Name == nameof(MethodsTestService.GenericVoidMethodWithConstraints)); .First(x => x.Name == nameof(MethodsTestService.GenericVoidMethodWithConstraints));
method.Should().NotBeNull(); method.Should().NotBeNull();
method.ReturnType.Should().Be(typeof(void)); method.ReturnType.Should().Be(typeof(void));
@@ -206,8 +227,8 @@ public class MethodGenerationTests
public void VoidMethodWithOptionalParams_IsImplemented() public void VoidMethodWithOptionalParams_IsImplemented()
{ {
var method = typeof(IMethodsTestService) var method = typeof(IMethodsTestService)
.GetMethods() .GetMethods()
.First(x => x.Name == nameof(MethodsTestService.VoidMethodWithOptionalParams)); .First(x => x.Name == nameof(MethodsTestService.VoidMethodWithOptionalParams));
method.Should().NotBeNull(); method.Should().NotBeNull();
method.ReturnType.Should().Be(typeof(void)); method.ReturnType.Should().Be(typeof(void));
@@ -226,7 +247,7 @@ public class MethodGenerationTests
parameters[7].DefaultValue.Should().Be(true); parameters[7].DefaultValue.Should().Be(true);
parameters[8].DefaultValue.Should().Be(false); parameters[8].DefaultValue.Should().Be(false);
parameters[9].DefaultValue.Should().Be(null); parameters[9].DefaultValue.Should().Be(null);
_sut.VoidMethodWithOptionalParams(); _sut.VoidMethodWithOptionalParams();
} }
@@ -234,8 +255,8 @@ public class MethodGenerationTests
public void VoidMethodWithExpandingParam_IsImplemented() public void VoidMethodWithExpandingParam_IsImplemented()
{ {
var method = typeof(IMethodsTestService) var method = typeof(IMethodsTestService)
.GetMethods() .GetMethods()
.First(x => x.Name == nameof(MethodsTestService.VoidMethodWithExpandingParam)); .First(x => x.Name == nameof(MethodsTestService.VoidMethodWithExpandingParam));
method.ReturnType.Should().Be(typeof(void)); method.ReturnType.Should().Be(typeof(void));
@@ -249,8 +270,8 @@ public class MethodGenerationTests
public void IgnoreMethod_IsOmitted() public void IgnoreMethod_IsOmitted()
{ {
var method = typeof(IMethodsTestService) var method = typeof(IMethodsTestService)
.GetMethods() .GetMethods()
.FirstOrDefault(x => x.Name == nameof(MethodsTestService.IgnoredMethod)); .FirstOrDefault(x => x.Name == nameof(MethodsTestService.IgnoredMethod));
method.Should().BeNull(); method.Should().BeNull();
} }
@@ -259,8 +280,8 @@ public class MethodGenerationTests
public void StaticMethod_IsOmitted() public void StaticMethod_IsOmitted()
{ {
var method = typeof(IMethodsTestService) var method = typeof(IMethodsTestService)
.GetMethods() .GetMethods()
.FirstOrDefault(x => x.Name == nameof(MethodsTestService.StaticMethod)); .FirstOrDefault(x => x.Name == nameof(MethodsTestService.StaticMethod));
method.Should().BeNull(); method.Should().BeNull();
} }
@@ -271,49 +292,33 @@ internal class MethodsTestService : IMethodsTestService
{ {
public const string StringConstant = "Const"; public const string StringConstant = "Const";
public void VoidMethod() public void VoidMethod() { }
{
}
public void VoidMethodWithParams(string a, string b) public void VoidMethodWithParams(string a, string b) { }
{
}
public void VoidMethodWithKeywordParam(string @void) public void VoidMethodWithKeywordParam(string @void) { }
{
}
public void VoidMethodWithOutParam(out string a) public void VoidMethodWithOutParam(out string a)
{ {
a = default; a = default;
} }
public void VoidMethodWithRefParam(ref string a) public void VoidMethodWithRefParam(ref string a) { }
{
}
public void VoidMethodWithInParam(in string a) public void VoidMethodWithInParam(in string a) { }
{
}
public string StringMethod() public string StringMethod()
{ {
return string.Empty; return string.Empty;
} }
public void GenericVoidMethod<TX, TY>() public void GenericVoidMethod<TX, TY>() { }
{
}
public void GenericVoidMethodWithGenericParam<TX, TY>(TX a) public void GenericVoidMethodWithGenericParam<TX, TY>(TX a) { }
{
}
public void GenericVoidMethodWithConstraints<TX, TY>() public void GenericVoidMethodWithConstraints<TX, TY>()
where TX : class where TX : class
where TY : class, TX, new() where TY : class, TX, new() { }
{
}
public void VoidMethodWithOptionalParams( public void VoidMethodWithOptionalParams(
string stringLiteral = "cGFyYW0=", string stringLiteral = "cGFyYW0=",
@@ -325,25 +330,17 @@ internal class MethodsTestService : IMethodsTestService
bool falseLiteral = false, bool falseLiteral = false,
bool? nullableTrueLiteral = true, bool? nullableTrueLiteral = true,
bool? nullableFalseLiteral = false, bool? nullableFalseLiteral = false,
bool? nullableNullBoolLiteral = null) bool? nullableNullBoolLiteral = null
{ ) { }
}
public void VoidMethodWithExpandingParam(params string[] strings) public void VoidMethodWithExpandingParam(params string[] strings) { }
{
}
[AutoInterfaceIgnore] [AutoInterfaceIgnore]
public void IgnoredMethod() public void IgnoredMethod() { }
{
}
public static void StaticMethod() public static void StaticMethod() { }
{
}
} }
[GenerateAutoInterface] [GenerateAutoInterface]
internal class MethodsTestServiceGeneric<T> : IMethodsTestServiceGeneric<T> where T : class internal class MethodsTestServiceGeneric<T> : IMethodsTestServiceGeneric<T>
{ where T : class { }
}
@@ -1,7 +1,4 @@
namespace Speckle.InterfaceGenerator.Tests.Partial; namespace Speckle.InterfaceGenerator.Tests.Partial;
[GenerateAutoInterface] [GenerateAutoInterface]
internal partial class PartialClass : IPartialClass internal partial class PartialClass : IPartialClass { }
{
}
@@ -2,7 +2,5 @@ namespace Speckle.InterfaceGenerator.Tests.Partial;
internal partial class PartialClass internal partial class PartialClass
{ {
public void SomeMethodThatShouldGenerate() public void SomeMethodThatShouldGenerate() { }
{ }
}
}
@@ -10,6 +10,9 @@ public class PartialClassTests
public void GeneratesMethodFromOtherParts() public void GeneratesMethodFromOtherParts()
{ {
var tInterface = typeof(IPartialClass); var tInterface = typeof(IPartialClass);
tInterface.GetMethods().Should().Contain(x => x.Name == nameof(PartialClass.SomeMethodThatShouldGenerate)); tInterface
.GetMethods()
.Should()
.Contain(x => x.Name == nameof(PartialClass.SomeMethodThatShouldGenerate));
} }
} }
@@ -17,14 +17,17 @@ public class RecordInterfaceGenerationTests
[Fact] [Fact]
public void RecordProperty_IsGenerated() public void RecordProperty_IsGenerated()
{ {
var prop = typeof(ITestRecord) var prop =
.GetProperty(nameof(TestRecord.RecordProperty)) ?? throw new InvalidOperationException(); typeof(ITestRecord).GetProperty(nameof(TestRecord.RecordProperty))
?? throw new InvalidOperationException();
prop.Should().NotBeNull(); prop.Should().NotBeNull();
prop.GetMethod.Should().NotBeNull(); prop.GetMethod.Should().NotBeNull();
prop.SetMethod.Should().NotBeNull(); prop.SetMethod.Should().NotBeNull();
prop.SetMethod?.ReturnParameter?.GetRequiredCustomModifiers().Should().Contain(typeof(IsExternalInit)); prop.SetMethod?.ReturnParameter?.GetRequiredCustomModifiers()
.Should()
.Contain(typeof(IsExternalInit));
_sut.RecordProperty.Should().Be(420); _sut.RecordProperty.Should().Be(420);
} }
@@ -32,8 +35,7 @@ public class RecordInterfaceGenerationTests
[Fact] [Fact]
public void RecordMethod_IsGenerated() public void RecordMethod_IsGenerated()
{ {
var method = typeof(ITestRecord).GetMethod( var method = typeof(ITestRecord).GetMethod(nameof(TestRecord.RecordMethod));
nameof(TestRecord.RecordMethod));
method.Should().NotBeNull(); method.Should().NotBeNull();
method?.ReturnType.Should().Be(typeof(void)); method?.ReturnType.Should().Be(typeof(void));
@@ -47,13 +49,12 @@ public class RecordInterfaceGenerationTests
[Fact] [Fact]
public void Deconstruct_IsGenerated() public void Deconstruct_IsGenerated()
{ {
var method = typeof(ITestRecord).GetMethod( var method = typeof(ITestRecord).GetMethod(nameof(TestRecord.Deconstruct));
nameof(TestRecord.Deconstruct));
method.Should().NotBeNull(); method.Should().NotBeNull();
method?.ReturnType.Should().Be(typeof(void)); method?.ReturnType.Should().Be(typeof(void));
var parameters = method?.GetParameters() ?? throw new InvalidOperationException(); var parameters = method?.GetParameters() ?? throw new InvalidOperationException();
parameters.Length.Should().Be(1); parameters.Length.Should().Be(1);
var parameter = parameters[0]; var parameter = parameters[0];
@@ -65,7 +66,5 @@ public class RecordInterfaceGenerationTests
[GenerateAutoInterface] [GenerateAutoInterface]
internal record TestRecord(int RecordProperty) : ITestRecord internal record TestRecord(int RecordProperty) : ITestRecord
{ {
public void RecordMethod() public void RecordMethod() { }
{ }
}
}
@@ -9,7 +9,4 @@ namespace InterfaceGenerator.Tests.SameName_1;
/// qualified names. /// qualified names.
/// </summary> /// </summary>
[GenerateAutoInterface] [GenerateAutoInterface]
internal class SameNameClass : ISameNameClass internal class SameNameClass : ISameNameClass { }
{
}
@@ -5,7 +5,4 @@ using Speckle.InterfaceGenerator;
namespace InterfaceGenerator.Tests.SameName_2; namespace InterfaceGenerator.Tests.SameName_2;
[GenerateAutoInterface] [GenerateAutoInterface]
internal class SameNameClass : ISameNameClass internal class SameNameClass : ISameNameClass { }
{
}
@@ -7,14 +7,14 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.10.3" /> <PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.8.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.8.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\InterfaceGenerator\Speckle.InterfaceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" /> <ProjectReference Include="..\Speckle.InterfaceGenerator\Speckle.InterfaceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -36,21 +36,13 @@ public class VisibilityModifierTests
} }
[GenerateAutoInterface(VisibilityModifier = "public")] [GenerateAutoInterface(VisibilityModifier = "public")]
internal class ExplicitlyPublicService : IExplicitlyPublicService internal class ExplicitlyPublicService : IExplicitlyPublicService { }
{
}
[GenerateAutoInterface(VisibilityModifier = "internal")] [GenerateAutoInterface(VisibilityModifier = "internal")]
public class ExplicitlyInternalService : IExplicitlyInternalService public class ExplicitlyInternalService : IExplicitlyInternalService { }
{
}
[GenerateAutoInterface] [GenerateAutoInterface]
public class ImplicitlyPublicService : IImplicitlyPublicService public class ImplicitlyPublicService : IImplicitlyPublicService { }
{
}
[GenerateAutoInterface] [GenerateAutoInterface]
internal class ImplicitlyInternalService : IImplicitlyInternalService internal class ImplicitlyInternalService : IImplicitlyInternalService { }
{
}
@@ -10,4 +10,4 @@ internal static class AttributeDataExtensions
var pair = attributeData.NamedArguments.FirstOrDefault(x => x.Key == paramName); var pair = attributeData.NamedArguments.FirstOrDefault(x => x.Key == paramName);
return pair.Value.Value?.ToString(); return pair.Value.Value?.ToString();
} }
} }
+4 -3
View File
@@ -9,8 +9,9 @@ internal class Attributes
public const string VisibilityModifierPropName = "VisibilityModifier"; public const string VisibilityModifierPropName = "VisibilityModifier";
public const string InterfaceNamePropName = "Name"; public const string InterfaceNamePropName = "Name";
public static readonly string AttributesSourceCode = $@" public static readonly string AttributesSourceCode =
$@"
using System; using System;
using System.Diagnostics; using System.Diagnostics;
@@ -38,4 +39,4 @@ namespace {AttributesNamespace}
}} }}
}} }}
"; ";
} }
@@ -44,7 +44,10 @@ public class AutoInterfaceGenerator : ISourceGenerator
} }
} }
private static void RaiseExceptionDiagnostic(GeneratorExecutionContext context, Exception exception) private static void RaiseExceptionDiagnostic(
GeneratorExecutionContext context,
Exception exception
)
{ {
var descriptor = new DiagnosticDescriptor( var descriptor = new DiagnosticDescriptor(
"Speckle.InterfaceGenerator.CriticalError", "Speckle.InterfaceGenerator.CriticalError",
@@ -53,13 +56,14 @@ public class AutoInterfaceGenerator : ISourceGenerator
"Speckle.InterfaceGenerator", "Speckle.InterfaceGenerator",
DiagnosticSeverity.Error, DiagnosticSeverity.Error,
true, true,
customTags: WellKnownDiagnosticTags.AnalyzerException); customTags: WellKnownDiagnosticTags.AnalyzerException
);
var diagnostic = Diagnostic.Create(descriptor, null); var diagnostic = Diagnostic.Create(descriptor, null);
context.ReportDiagnostic(diagnostic); context.ReportDiagnostic(diagnostic);
} }
private void ExecuteCore(GeneratorExecutionContext context) private void ExecuteCore(GeneratorExecutionContext context)
{ {
// setting the culture to invariant prevents errors such as emitting a decimal comma (0,1) instead of // setting the culture to invariant prevents errors such as emitting a decimal comma (0,1) instead of
@@ -77,7 +81,8 @@ public class AutoInterfaceGenerator : ISourceGenerator
{ {
context.AddSource( context.AddSource(
Attributes.GenerateAutoInterfaceClassname, Attributes.GenerateAutoInterfaceClassname,
SourceText.From(Attributes.AttributesSourceCode, Encoding.UTF8)); SourceText.From(Attributes.AttributesSourceCode, Encoding.UTF8)
);
} }
private void GenerateInterfaces(GeneratorExecutionContext context) private void GenerateInterfaces(GeneratorExecutionContext context)
@@ -96,26 +101,47 @@ public class AutoInterfaceGenerator : ISourceGenerator
foreach (var implTypeSymbol in classSymbols) foreach (var implTypeSymbol in classSymbols)
{ {
if (!implTypeSymbol.TryGetAttribute(_generateAutoInterfaceAttribute ?? throw new NullReferenceException("_generateAutoInterfaceAttribute is null"), out var attributes)) if (
!implTypeSymbol.TryGetAttribute(
_generateAutoInterfaceAttribute
?? throw new NullReferenceException(
"_generateAutoInterfaceAttribute is null"
),
out var attributes
)
)
{ {
continue; continue;
} }
if(classSymbolNames.Contains(implTypeSymbol.GetFullMetadataName(useNameWhenNotFound: true))) if (
classSymbolNames.Contains(
implTypeSymbol.GetFullMetadataName(useNameWhenNotFound: true)
)
)
{ {
continue; // partial class, already added continue; // partial class, already added
} }
classSymbolNames.Add(implTypeSymbol.GetFullMetadataName(useNameWhenNotFound: true)); classSymbolNames.Add(implTypeSymbol.GetFullMetadataName(useNameWhenNotFound: true));
var attribute = attributes.Single(); var attribute = attributes.Single();
var source = SourceText.From(GenerateInterfaceCode(implTypeSymbol, attribute), Encoding.UTF8); var source = SourceText.From(
GenerateInterfaceCode(implTypeSymbol, attribute),
Encoding.UTF8
);
context.AddSource($"{implTypeSymbol.GetFullMetadataName(useNameWhenNotFound: true)}_AutoInterface.g.cs", source); context.AddSource(
$"{implTypeSymbol.GetFullMetadataName(useNameWhenNotFound: true)}_AutoInterface.g.cs",
source
);
} }
} }
private static string InferVisibilityModifier(ISymbol implTypeSymbol, AttributeData attributeData) private static string InferVisibilityModifier(
ISymbol implTypeSymbol,
AttributeData attributeData
)
{ {
string? result = attributeData.GetNamedParamValue(Attributes.VisibilityModifierPropName); string? result = attributeData.GetNamedParamValue(Attributes.VisibilityModifierPropName);
if (!string.IsNullOrEmpty(result)) if (!string.IsNullOrEmpty(result))
@@ -126,16 +152,20 @@ public class AutoInterfaceGenerator : ISourceGenerator
return implTypeSymbol.DeclaredAccessibility switch return implTypeSymbol.DeclaredAccessibility switch
{ {
Accessibility.Public => "public", Accessibility.Public => "public",
_ => "internal", _ => "internal",
}; };
} }
private static string InferInterfaceName(ISymbol implTypeSymbol, AttributeData attributeData) private static string InferInterfaceName(ISymbol implTypeSymbol, AttributeData attributeData)
{ {
return attributeData.GetNamedParamValue(Attributes.InterfaceNamePropName) ?? $"I{implTypeSymbol.Name}"; return attributeData.GetNamedParamValue(Attributes.InterfaceNamePropName)
?? $"I{implTypeSymbol.Name}";
} }
private string GenerateInterfaceCode(INamedTypeSymbol implTypeSymbol, AttributeData attributeData) private string GenerateInterfaceCode(
INamedTypeSymbol implTypeSymbol,
AttributeData attributeData
)
{ {
using var stream = new MemoryStream(); using var stream = new MemoryStream();
var streamWriter = new StreamWriter(stream, Encoding.UTF8); var streamWriter = new StreamWriter(stream, Encoding.UTF8);
@@ -179,7 +209,10 @@ public class AutoInterfaceGenerator : ISourceGenerator
return reader.ReadToEnd(); return reader.ReadToEnd();
} }
private static void WriteTypeGenericsIfNeeded(TextWriter writer, INamedTypeSymbol implTypeSymbol) private static void WriteTypeGenericsIfNeeded(
TextWriter writer,
INamedTypeSymbol implTypeSymbol
)
{ {
if (!implTypeSymbol.IsGenericType) if (!implTypeSymbol.IsGenericType)
{ {
@@ -193,16 +226,23 @@ public class AutoInterfaceGenerator : ISourceGenerator
WriteTypeParameterConstraints(writer, implTypeSymbol.TypeParameters); WriteTypeParameterConstraints(writer, implTypeSymbol.TypeParameters);
} }
private void GenerateInterfaceMemberDefinitions(TextWriter writer, INamespaceOrTypeSymbol implTypeSymbol) private void GenerateInterfaceMemberDefinitions(
TextWriter writer,
INamespaceOrTypeSymbol implTypeSymbol
)
{ {
foreach (var member in implTypeSymbol.GetMembers()) foreach (var member in implTypeSymbol.GetMembers())
{ {
if (member.DeclaredAccessibility != Accessibility.Public || if (
member.HasAttribute(_ignoreAttribute ?? throw new NullReferenceException("_ignoreAttribute is null"))) member.DeclaredAccessibility != Accessibility.Public
|| member.HasAttribute(
_ignoreAttribute ?? throw new NullReferenceException("_ignoreAttribute is null")
)
)
{ {
continue; continue;
} }
GenerateInterfaceMemberDefinition(writer, member); GenerateInterfaceMemberDefinition(writer, member);
} }
} }
@@ -229,10 +269,10 @@ public class AutoInterfaceGenerator : ISourceGenerator
} }
// omit the fist and last lines to skip the <member> tag // omit the fist and last lines to skip the <member> tag
var reader = new StringReader(xml); var reader = new StringReader(xml);
var lines = new List<string>(); var lines = new List<string>();
while (true) while (true)
{ {
var line = reader.ReadLine(); var line = reader.ReadLine();
@@ -240,7 +280,7 @@ public class AutoInterfaceGenerator : ISourceGenerator
{ {
break; break;
} }
lines.Add(line); lines.Add(line);
} }
@@ -256,18 +296,21 @@ public class AutoInterfaceGenerator : ISourceGenerator
return symbol.DeclaredAccessibility is Accessibility.Public or Accessibility.Internal; return symbol.DeclaredAccessibility is Accessibility.Public or Accessibility.Internal;
} }
private static void GeneratePropertyDefinition(TextWriter writer, IPropertySymbol propertySymbol) private static void GeneratePropertyDefinition(
TextWriter writer,
IPropertySymbol propertySymbol
)
{ {
if (propertySymbol.IsStatic) if (propertySymbol.IsStatic)
{ {
return; return;
} }
bool hasPublicGetter = propertySymbol.GetMethod is not null && bool hasPublicGetter =
IsPublicOrInternal(propertySymbol.GetMethod); propertySymbol.GetMethod is not null && IsPublicOrInternal(propertySymbol.GetMethod);
bool hasPublicSetter = propertySymbol.SetMethod is not null && bool hasPublicSetter =
IsPublicOrInternal(propertySymbol.SetMethod); propertySymbol.SetMethod is not null && IsPublicOrInternal(propertySymbol.SetMethod);
if (!hasPublicGetter && !hasPublicSetter) if (!hasPublicGetter && !hasPublicSetter)
{ {
@@ -275,7 +318,7 @@ public class AutoInterfaceGenerator : ISourceGenerator
} }
WriteSymbolDocsIfPresent(writer, propertySymbol); WriteSymbolDocsIfPresent(writer, propertySymbol);
if (propertySymbol.IsIndexer) if (propertySymbol.IsIndexer)
{ {
writer.Write("{0} this[", propertySymbol.Type); writer.Write("{0} this[", propertySymbol.Type);
@@ -316,13 +359,13 @@ public class AutoInterfaceGenerator : ISourceGenerator
return; return;
} }
if (methodSymbol.IsImplicitlyDeclared && methodSymbol.Name != "Deconstruct") if (methodSymbol.IsImplicitlyDeclared && methodSymbol.Name != "Deconstruct")
{ {
// omit methods that are auto generated by the compiler (eg. record's methods), // omit methods that are auto generated by the compiler (eg. record's methods),
// except for the record Deconstruct method // except for the record Deconstruct method
return; return;
} }
WriteSymbolDocsIfPresent(writer, methodSymbol); WriteSymbolDocsIfPresent(writer, methodSymbol);
writer.Write("{0} {1}", methodSymbol.ReturnType, methodSymbol.Name); // ex. int Foo writer.Write("{0} {1}", methodSymbol.ReturnType, methodSymbol.Name); // ex. int Foo
@@ -366,7 +409,7 @@ public class AutoInterfaceGenerator : ISourceGenerator
writer.Write("in "); writer.Write("in ");
break; break;
} }
writer.Write(param.Type); writer.Write(param.Type);
writer.Write(" "); writer.Write(" ");
@@ -374,7 +417,7 @@ public class AutoInterfaceGenerator : ISourceGenerator
{ {
writer.Write("@"); writer.Write("@");
} }
writer.Write(param.Name); writer.Write(param.Name);
if (param.HasExplicitDefaultValue) if (param.HasExplicitDefaultValue)
@@ -420,7 +463,8 @@ public class AutoInterfaceGenerator : ISourceGenerator
private static void WriteTypeParameterConstraints( private static void WriteTypeParameterConstraints(
TextWriter writer, TextWriter writer,
IEnumerable<ITypeParameterSymbol> typeParameters) IEnumerable<ITypeParameterSymbol> typeParameters
)
{ {
foreach (var typeParameter in typeParameters) foreach (var typeParameter in typeParameters)
{ {
@@ -438,15 +482,23 @@ public class AutoInterfaceGenerator : ISourceGenerator
private void InitAttributes(Compilation compilation) private void InitAttributes(Compilation compilation)
{ {
_generateAutoInterfaceAttribute = compilation.GetTypeByMetadataName( _generateAutoInterfaceAttribute = compilation.GetTypeByMetadataName(
$"{Attributes.AttributesNamespace}.{Attributes.GenerateAutoInterfaceClassname}"); $"{Attributes.AttributesNamespace}.{Attributes.GenerateAutoInterfaceClassname}"
);
_ignoreAttribute = compilation.GetTypeByMetadataName( _ignoreAttribute = compilation.GetTypeByMetadataName(
$"{Attributes.AttributesNamespace}.{Attributes.AutoInterfaceIgnoreAttributeClassname}"); $"{Attributes.AttributesNamespace}.{Attributes.AutoInterfaceIgnoreAttributeClassname}"
);
} }
private static IEnumerable<INamedTypeSymbol> GetImplTypeSymbols(Compilation compilation, SyntaxReceiver receiver) private static IEnumerable<INamedTypeSymbol> GetImplTypeSymbols(
Compilation compilation,
SyntaxReceiver receiver
)
{ {
return receiver.CandidateTypes.Select(candidate => GetTypeSymbol(compilation, candidate)).Where(x => x != null).Cast<INamedTypeSymbol>(); return receiver
.CandidateTypes.Select(candidate => GetTypeSymbol(compilation, candidate))
.Where(x => x != null)
.Cast<INamedTypeSymbol>();
} }
private static INamedTypeSymbol? GetTypeSymbol(Compilation compilation, SyntaxNode type) private static INamedTypeSymbol? GetTypeSymbol(Compilation compilation, SyntaxNode type)
@@ -462,8 +514,11 @@ public class AutoInterfaceGenerator : ISourceGenerator
var compilation = context.Compilation.AddSyntaxTrees( var compilation = context.Compilation.AddSyntaxTrees(
CSharpSyntaxTree.ParseText( CSharpSyntaxTree.ParseText(
SourceText.From(Attributes.AttributesSourceCode, Encoding.UTF8), options)); SourceText.From(Attributes.AttributesSourceCode, Encoding.UTF8),
options
)
);
return compilation; return compilation;
} }
} }
@@ -10,6 +10,7 @@
<IncludeBuildOutput>false</IncludeBuildOutput> <IncludeBuildOutput>false</IncludeBuildOutput>
<NoPackageAnalysis>true</NoPackageAnalysis> <NoPackageAnalysis>true</NoPackageAnalysis>
<RootNamespace>Speckle.InterfaceGenerator</RootNamespace> <RootNamespace>Speckle.InterfaceGenerator</RootNamespace>
<EnforoceExtendedAnalyzerRules>true</EnforoceExtendedAnalyzerRules>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
@@ -22,9 +23,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.2.0" PrivateAssets="all" /> <PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.9.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.2.0" PrivateAssets="all" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" > <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
@@ -121,4 +121,4 @@ internal static class StringExtensions
return false; return false;
} }
} }
} }
+13 -5
View File
@@ -10,16 +10,19 @@ internal static class SymbolExtensions
public static bool TryGetAttribute( public static bool TryGetAttribute(
this ISymbol symbol, this ISymbol symbol,
INamedTypeSymbol attributeType, INamedTypeSymbol attributeType,
out IEnumerable<AttributeData> attributes) out IEnumerable<AttributeData> attributes
)
{ {
attributes = symbol.GetAttributes() attributes = symbol
.GetAttributes()
.Where(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attributeType)); .Where(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attributeType));
return attributes.Any(); return attributes.Any();
} }
public static bool HasAttribute(this ISymbol symbol, INamedTypeSymbol attributeType) public static bool HasAttribute(this ISymbol symbol, INamedTypeSymbol attributeType)
{ {
return symbol.GetAttributes() return symbol
.GetAttributes()
.Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attributeType)); .Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attributeType));
} }
@@ -47,7 +50,12 @@ internal static class SymbolExtensions
stringBuilder.Insert(0, '.'); stringBuilder.Insert(0, '.');
} }
stringBuilder.Insert(0, symbol.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)); stringBuilder.Insert(
0,
symbol.OriginalDefinition.ToDisplayString(
SymbolDisplayFormat.MinimallyQualifiedFormat
)
);
symbol = symbol.ContainingSymbol; symbol = symbol.ContainingSymbol;
} }
@@ -64,4 +72,4 @@ internal static class SymbolExtensions
{ {
return symbol is INamespaceSymbol { IsGlobalNamespace: true }; return symbol is INamespaceSymbol { IsGlobalNamespace: true };
} }
} }
+9 -6
View File
@@ -7,12 +7,14 @@ namespace Speckle.InterfaceGenerator;
internal class SyntaxReceiver : ISyntaxReceiver internal class SyntaxReceiver : ISyntaxReceiver
{ {
public IList<TypeDeclarationSyntax> CandidateTypes { get; } = new List<TypeDeclarationSyntax>(); public IList<TypeDeclarationSyntax> CandidateTypes { get; } = new List<TypeDeclarationSyntax>();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode) public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{ {
if (syntaxNode is TypeDeclarationSyntax typeDeclarationSyntax && if (
IsClassOrRecord(typeDeclarationSyntax) && syntaxNode is TypeDeclarationSyntax typeDeclarationSyntax
typeDeclarationSyntax.AttributeLists.Count > 0) && IsClassOrRecord(typeDeclarationSyntax)
&& typeDeclarationSyntax.AttributeLists.Count > 0
)
{ {
CandidateTypes.Add(typeDeclarationSyntax); CandidateTypes.Add(typeDeclarationSyntax);
} }
@@ -20,6 +22,7 @@ internal class SyntaxReceiver : ISyntaxReceiver
private static bool IsClassOrRecord(TypeDeclarationSyntax typeDeclarationSyntax) private static bool IsClassOrRecord(TypeDeclarationSyntax typeDeclarationSyntax)
{ {
return typeDeclarationSyntax is ClassDeclarationSyntax || typeDeclarationSyntax is RecordDeclarationSyntax; return typeDeclarationSyntax is ClassDeclarationSyntax
|| typeDeclarationSyntax is RecordDeclarationSyntax;
} }
} }
@@ -6,20 +6,17 @@ namespace Speckle.InterfaceGenerator;
internal static class TextWriterExtensions internal static class TextWriterExtensions
{ {
public static void WriteJoin<T>(this TextWriter writer, string separator, IEnumerable<T> values)
public static void WriteJoin<T>(
this TextWriter writer,
string separator,
IEnumerable<T> values)
{ {
writer.WriteJoin(separator, values, (w, x) => w.Write(x)); writer.WriteJoin(separator, values, (w, x) => w.Write(x));
} }
public static void WriteJoin<T>( public static void WriteJoin<T>(
this TextWriter writer, this TextWriter writer,
string separator, string separator,
IEnumerable<T> values, IEnumerable<T> values,
Action<TextWriter, T> writeAction) Action<TextWriter, T> writeAction
)
{ {
using var enumerator = values.GetEnumerator(); using var enumerator = values.GetEnumerator();
@@ -41,4 +38,4 @@ internal static class TextWriterExtensions
writeAction(writer, enumerator.Current); writeAction(writer, enumerator.Current);
} while (enumerator.MoveNext()); } while (enumerator.MoveNext());
} }
} }
@@ -12,36 +12,35 @@ internal static class TypeParameterSymbolExtensions
{ {
yield return "notnull"; yield return "notnull";
} }
if (symbol.HasValueTypeConstraint) if (symbol.HasValueTypeConstraint)
{ {
yield return "struct"; yield return "struct";
} }
if (symbol.HasUnmanagedTypeConstraint) if (symbol.HasUnmanagedTypeConstraint)
{ {
yield return "unmanaged"; yield return "unmanaged";
} }
if (symbol.HasReferenceTypeConstraint) if (symbol.HasReferenceTypeConstraint)
{ {
yield return symbol.ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated yield return symbol.ReferenceTypeConstraintNullableAnnotation
== NullableAnnotation.Annotated
? "class?" ? "class?"
: "class"; : "class";
} }
// types go in the middle // types go in the middle
foreach (var constraintType in symbol.ConstraintTypes) foreach (var constraintType in symbol.ConstraintTypes)
{ {
yield return constraintType.ToDisplayString(); yield return constraintType.ToDisplayString();
} }
// the new() constraint has to be the last // the new() constraint has to be the last
if (symbol.HasConstructorConstraint) if (symbol.HasConstructorConstraint)
{ {
yield return "new()"; yield return "new()";
} }
} }
} }