Skip to content

Commit

Permalink
Added support for generating factory methods for bound generic types
Browse files Browse the repository at this point in the history
Changed test framework to xunit
Updated SPP
Replaced Nullable and IsExternalInit with Polysharp
  • Loading branch information
hugener committed Dec 4, 2023
1 parent 38511c1 commit 1359b46
Show file tree
Hide file tree
Showing 30 changed files with 249 additions and 102 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
">|symbolsApiKey={SymbolsApiKey}{NL}" ">|buildPromotion={BuildPromotion}"
--output-file $GITHUB_OUTPUT
cb match -p "^(?!^(refs/heads/main|refs/tags/release)$).*$ => test-filter-if-set= --filter TestCategory!~MainBranchBuilds" -i "${{ steps.build-setup.outputs.git-branch-name }}" -of $GITHUB_OUTPUT
cb match -p "^(?!^(refs/heads/main|refs/tags/release)$).*$ => test-filter-if-set= --filter Category!~MainBranchBuilds" -i "${{ steps.build-setup.outputs.git-branch-name }}" -of $GITHUB_OUTPUT
- name: 'Remove release tag'
if: ${{ steps.stage-build.outputs.stage == 'production' && steps.stage-build.outputs.buildPromotion != 'promoted' }}
run: git push --delete ${{ env.repository }} ${{ github.ref }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,12 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="IsExternalInit" Version="1.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
<PackageReference Include="Nullable" Version="1.3.1">
<PackageReference Include="PolySharp" Version="1.14.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Sundew.Generator.Code" Version="3.1.18" />
<PackageReference Include="Sundew.Generator.Code" Version="3.1.19" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ public async Task<Document> Fix(
}

var factoryMethods = GetCaseTypesWithMissingFactoryMethods(unionType, semanticModel.Compilation)
.Select((caseType, index) =>
.Select((@case, index) =>
{
var constructor = caseType.Constructors.OrderByDescending(x => x.Parameters.Length).SkipWhile(x =>
var constructor = @case.CaseType.Constructors.OrderByDescending(x => x.Parameters.Length).SkipWhile(x =>
x.ContainingType.IsRecord &&
SymbolEqualityComparer.Default.Equals(x.Parameters.FirstOrDefault()?.Type, x.ContainingType))
.FirstOrDefault();
Expand All @@ -80,9 +80,10 @@ public async Task<Document> Fix(
return GetFactoryMethodSyntaxNodes(
semanticModel,
unionType,
caseType.Name,
@case.CaseType.Name,
constructor,
caseType,
@case.CaseType,
@case.ReturnType,
constructor.Parameters.Select(x => x.Type).ToArray(),
parameters,
generator,
Expand Down Expand Up @@ -121,30 +122,41 @@ public async Task<Document> Fix(
return document.WithSyntaxRoot(newRoot);
}

private static IEnumerable<INamedTypeSymbol> GetCaseTypesWithMissingFactoryMethods(
private static IEnumerable<(INamedTypeSymbol CaseType, INamedTypeSymbol ReturnType)> GetCaseTypesWithMissingFactoryMethods(
INamedTypeSymbol unionType,
Compilation compilation)
{
var allCaseTypes = GetDerivedTypes(compilation, unionType);
var allCaseTypes = GetDerivedTypes(compilation, unionType).Select(x => (CaseType: x, ReturnType: GetReturnType(x, unionType)));
var knownCaseTypes = UnionHelper.GetKnownCaseTypes(unionType).ToList();

return allCaseTypes.Where(x =>
{
GetEquatableType(ref x);
GetEquatableType(ref x.CaseType);
return !knownCaseTypes.Any(knownType =>
{
GetEquatableType(ref knownType);
return SymbolEqualityComparer.Default.Equals(x, knownType);
return SymbolEqualityComparer.Default.Equals(x.CaseType, knownType);
});
});
}

private static INamedTypeSymbol GetReturnType(INamedTypeSymbol namedTypeSymbol, INamedTypeSymbol unionType)
{
return namedTypeSymbol.EnumerateBaseTypes().Concat(namedTypeSymbol.AllInterfaces)
.FirstOrDefault(x =>
{
GetEquatableType(ref x);
return SymbolEqualityComparer.Default.Equals(x, unionType);
}) ?? unionType;
}

private static SyntaxNode GetFactoryMethodSyntaxNodes(
SemanticModel semanticModel,
INamedTypeSymbol unionType,
string name,
IMethodSymbol constructor,
INamedTypeSymbol caseType,
INamedTypeSymbol returnType,
IReadOnlyCollection<ITypeSymbol> parameterTypes,
List<(SyntaxNode Parameter, string Name)> parameters,
SyntaxGenerator generator,
Expand Down Expand Up @@ -173,7 +185,7 @@ private static SyntaxNode GetFactoryMethodSyntaxNodes(
SyntaxFactory.AttributeArgument(SyntaxFactory.TypeOfExpression(SyntaxFactory.ParseTypeName(
attributeCaseType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat))))))))))),
tokenList,
SyntaxFactory.ParseTypeName(unionType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)),
SyntaxFactory.ParseTypeName(returnType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)),
null,
SyntaxFactory.Identifier(name),
null,
Expand All @@ -197,7 +209,8 @@ private static SyntaxNode GetFactoryMethodSyntaxNodes(
SyntaxFactory.SeparatedList(
parameters.Select(x =>
SyntaxFactory.Argument(SyntaxFactory.IdentifierName(x.Name))))),
null)),
null))
.WithLeadingTrivia(SyntaxFactory.Space, SyntaxFactory.Space, SyntaxFactory.Space, SyntaxFactory.Space, SyntaxFactory.Space, SyntaxFactory.Space, SyntaxFactory.Space, SyntaxFactory.Space, SyntaxFactory.CarriageReturnLineFeed, SyntaxFactory.CarriageReturnLineFeed),
SyntaxFactory.Token(SyntaxKind.SemicolonToken));

if (addAdditionalNewLine)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="IsExternalInit" Version="1.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,14 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="IsExternalInit" Version="1.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
<PackageReference Include="Nullable" Version="1.3.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PackageReference Include="PolySharp" Version="1.14.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435">
<PrivateAssets>all</PrivateAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ namespace Sundew.DiscriminatedUnions.Generator.IntegrationTests;
using NUnit.Framework;
using Sundew.Testing.CodeAnalysis;
using Sundew.Testing.IO;
using Xunit;

[TestFixture(Category = "MainBranchBuilds")]
[Trait("Category", "MainBranchBuilds")]
public class BaselineValidationFixture
{
[Test]
[Fact]
public void VerifyWorkingCopyAndBaselineProjectsAreTheSame()
{
var workingCopyProject = new CSharpProject(Paths.FindPathUpwards("Sundew.DiscriminatedUnions.Generator"), new Paths(), new Paths("bin", "obj"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@
namespace Sundew.DiscriminatedUnions.Generator.IntegrationTests;

using FluentAssertions;
using Microsoft.CodeAnalysis;
using NUnit.Framework;
using Sundew.DiscriminatedUnions.Generator.DeclarationStage;
using Sundew.Testing.CodeAnalysis;
using Sundew.Testing.IO;
using VerifyXunit;
using Xunit;

[TestFixture]
[UsesVerify]
public class DiscriminatedUnionCaseDeclarationEqualityFixture
{
[Test]
[Fact]
public void TryGetDiscriminatedUnionCaseDeclaration_Then_ResultShouldNotBeNull()
{
var compilation = TestProjects.SundewDiscriminatedUnionsTester.Compilation;
Expand All @@ -28,7 +26,7 @@ public void TryGetDiscriminatedUnionCaseDeclaration_Then_ResultShouldNotBeNull()
result.Should().NotBeNull();
}

[Test]
[Fact]
public void Equals_Then_ResultShouldBeTrue()
{
var compilation = TestProjects.SundewDiscriminatedUnionsTester.Compilation;
Expand All @@ -40,7 +38,7 @@ public void Equals_Then_ResultShouldBeTrue()
lhs.Should().Be(rhs);
}

[Test]
[Fact]
public void Equals_When_ValuesDiffer_Then_ResultShouldBeFalse()
{
var compilation = TestProjects.SundewDiscriminatedUnionsTester.Compilation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@
namespace Sundew.DiscriminatedUnions.Generator.IntegrationTests;

using FluentAssertions;
using NUnit.Framework;
using Sundew.DiscriminatedUnions.Generator.DeclarationStage;
using Xunit;

[TestFixture]
public class DiscriminatedUnionDeclarationEqualityFixture
{
[Test]
[Fact]
public void TryGetDiscriminatedUnionDeclaration_Then_ResultShouldNotBeEmpty()
{
var compilation = TestProjects.SundewDiscriminatedUnionsTester.Compilation;
Expand All @@ -25,7 +24,7 @@ public void TryGetDiscriminatedUnionDeclaration_Then_ResultShouldNotBeEmpty()
result.Should().NotBeNull();
}

[Test]
[Fact]
public void Equals_Then_ResultShouldBeTrue()
{
var compilation = TestProjects.SundewDiscriminatedUnionsTester.Compilation;
Expand All @@ -37,7 +36,7 @@ public void Equals_Then_ResultShouldBeTrue()
lhs.Should().Be(rhs);
}

[Test]
[Fact]
public void Equals_When_ValuesDiffer_Then_ResultShouldBeFalse()
{
var compilation = TestProjects.SundewDiscriminatedUnionsTester.Compilation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@ namespace Sundew.DiscriminatedUnions.Generator.IntegrationTests;
using System.Linq;
using System.Threading;
using FluentAssertions;
using NUnit.Framework;
using Sundew.Base.Collections.Immutable;
using Sundew.DiscriminatedUnions.Generator.DeclarationStage;
using Sundew.DiscriminatedUnions.Generator.ModelStage;
using Xunit;
using Accessibility = Sundew.DiscriminatedUnions.Generator.Model.Accessibility;

[TestFixture]
public class DiscriminatedUnionEqualityFixture
{
[Test]
[Fact]
public void GetDiscriminatedUnionResults_Then_ResultShouldNotBeEmpty()
{
var compilation = TestProjects.SundewDiscriminatedUnionsTester.Compilation;
Expand All @@ -36,7 +35,7 @@ public void GetDiscriminatedUnionResults_Then_ResultShouldNotBeEmpty()
result.Should().NotBeEmpty();
}

[Test]
[Fact]
public void Equals_Then_ResultShouldBeTrue()
{
var compilation = TestProjects.SundewDiscriminatedUnionsTester.Compilation;
Expand All @@ -53,7 +52,7 @@ public void Equals_Then_ResultShouldBeTrue()
((object)lhs).Should().Be(rhs);
}

[Test]
[Fact]
public void Equals_When_ValuesDiffer_Then_ResultShouldBeFalse()
{
var compilation = TestProjects.SundewDiscriminatedUnionsTester.Compilation;
Expand All @@ -71,7 +70,7 @@ public void Equals_When_ValuesDiffer_Then_ResultShouldBeFalse()
((object)lhs).Should().NotBe(rhs);
}

[Test]
[Fact]
public void GetDiscriminatedUnionResults_When__Then_ResultShouldNotBeEmpty()
{
var compilation = TestProjects.SundewDiscriminatedUnionsTester.Compilation;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//HintName: Sundew.DiscriminatedUnions.Tester.DoubleError.generated.cs
#nullable enable

namespace Sundew.DiscriminatedUnions.Tester
{
#pragma warning disable SA1601
[global::System.Diagnostics.DebuggerNonUserCode]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Sundew.DiscriminateUnions.Generator", "5.1.0.0")]
public partial record DoubleError
#pragma warning restore SA1601
{
/// <summary>
/// Gets the OutOfRangeError case.
/// </summary>
/// <returns>The OutOfRangeError.</returns>
[Sundew.DiscriminatedUnions.CaseType(typeof(global::Sundew.DiscriminatedUnions.Tester.DoubleError.OutOfRangeError))]
public static global::Sundew.DiscriminatedUnions.Tester.DoubleError _OutOfRangeError { get; }
= new global::Sundew.DiscriminatedUnions.Tester.DoubleError.OutOfRangeError();

/// <summary>
/// Gets the RoundingError case.
/// </summary>
/// <returns>The RoundingError.</returns>
[Sundew.DiscriminatedUnions.CaseType(typeof(global::Sundew.DiscriminatedUnions.Tester.DoubleError.RoundingError))]
public static global::Sundew.DiscriminatedUnions.Tester.DoubleError _RoundingError { get; }
= new global::Sundew.DiscriminatedUnions.Tester.DoubleError.RoundingError();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//HintName: Sundew.DiscriminatedUnions.Tester.Input{TError}.generated.cs
#nullable enable

namespace Sundew.DiscriminatedUnions.Tester
{
#pragma warning disable SA1601
[global::System.Diagnostics.DebuggerNonUserCode]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Sundew.DiscriminateUnions.Generator", "5.1.0.0")]
public partial record Input<TError>
#pragma warning restore SA1601
{
/// <summary>
/// Factory method for the DoubleInput case.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>A new DoubleInput.</returns>
[Sundew.DiscriminatedUnions.CaseType(typeof(global::Sundew.DiscriminatedUnions.Tester.DoubleInput))]
public static global::Sundew.DiscriminatedUnions.Tester.Input<global::Sundew.DiscriminatedUnions.Tester.DoubleError> DoubleInput(double value)
=> new global::Sundew.DiscriminatedUnions.Tester.DoubleInput(value);

/// <summary>
/// Factory method for the IntInput case.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>A new IntInput.</returns>
[Sundew.DiscriminatedUnions.CaseType(typeof(global::Sundew.DiscriminatedUnions.Tester.IntInput))]
public static global::Sundew.DiscriminatedUnions.Tester.Input<global::Sundew.DiscriminatedUnions.Tester.IntError> IntInput(int value)
=> new global::Sundew.DiscriminatedUnions.Tester.IntInput(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//HintName: Sundew.DiscriminatedUnions.Tester.IntError.generated.cs
#nullable enable

namespace Sundew.DiscriminatedUnions.Tester
{
#pragma warning disable SA1601
[global::System.Diagnostics.DebuggerNonUserCode]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Sundew.DiscriminateUnions.Generator", "5.1.0.0")]
public partial record IntError
#pragma warning restore SA1601
{
/// <summary>
/// Gets the OutOfRangeError case.
/// </summary>
/// <returns>The OutOfRangeError.</returns>
[Sundew.DiscriminatedUnions.CaseType(typeof(global::Sundew.DiscriminatedUnions.Tester.IntError.OutOfRangeError))]
public static global::Sundew.DiscriminatedUnions.Tester.IntError _OutOfRangeError { get; }
= new global::Sundew.DiscriminatedUnions.Tester.IntError.OutOfRangeError();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ namespace Sundew.DiscriminatedUnions.Generator.IntegrationTests;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using NUnit.Framework;
using Sundew.Testing.CodeAnalysis;
using Sundew.Testing.IO;
using VerifyNUnit;
using VerifyTests;
using VerifyXunit;
using Xunit;

[TestFixture]
[UsesVerify]
public class DiscriminatedUnionGeneratorFixture
{
[Test]
[Fact]
public Task VerifyGeneratedSources()
{
var project = new CSharpProject(Paths.FindPathUpwards("Sundew.DiscriminatedUnions.Tester"), new Paths(), new Paths("bin", "obj"));
Expand Down
Loading

0 comments on commit 1359b46

Please sign in to comment.