From 9a4e8f2bc0ed8a4c729280c5c31456861c8004b0 Mon Sep 17 00:00:00 2001 From: Oleh Formaniuk Date: Thu, 19 Sep 2024 10:04:29 -0700 Subject: [PATCH 01/15] Inheritance implementation for Fluent API --- src/ExampleProject/OrderInheritance.cs | 68 +++++++++++++++++++ src/ExampleProject/Program.cs | 16 +++++ .../SourceGenerators/ClassInfoFactory.cs | 20 +++++- 3 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 src/ExampleProject/OrderInheritance.cs diff --git a/src/ExampleProject/OrderInheritance.cs b/src/ExampleProject/OrderInheritance.cs new file mode 100644 index 0000000..b6785d8 --- /dev/null +++ b/src/ExampleProject/OrderInheritance.cs @@ -0,0 +1,68 @@ +// Non-nullable member is uninitialized +#pragma warning disable CS8618 +// ReSharper disable All + +// Example from https://youtu.be/qCIr30WxJQw?si=FRALafrpA1zWACA8. +// Implementation with arbitrary steps. + +using M31.FluentApi.Attributes; + +namespace ExampleProject; + +public class BaseOrder +{ + [FluentMember(0, "{Name}")] + [FluentContinueWith(0)] + public virtual DateTime? CreatedOn { get; protected set; } +} + +[FluentApi] +public class Order3 : BaseOrder +{ + [FluentMember(0)] + [FluentContinueWith(0)] + public int? Number { get; private set; } + + [FluentMember(0, "ShippedTo")] + [FluentContinueWith(0)] + public Address3? ShippingAddress { get; private set; } + + [FluentMethod(0)] + private void Build() + { + } +} + +[FluentApi] +public class Address3 +{ + [FluentMember(0, "{Name}")] + [FluentContinueWith(0)] + public string Street { get; private set; } + + [FluentMember(0, "{Name}")] + [FluentContinueWith(0)] + public string City { get; private set; } + + [FluentMember(0, "{Name}")] + [FluentContinueWith(0)] + public string Zip { get; private set; } + + [FluentMember(0, "{Name}")] + [FluentContinueWith(0)] + public string State { get; private set; } + + [FluentMember(0, "{Name}")] + [FluentContinueWith(0)] + public string Country { get; private set; } + + [FluentMethod(0)] + private void Build() + { + Street ??= "N/A"; + City ??= "N/A"; + Zip ??= "N/A"; + State ??= "N/A"; + Country ??= "N/A"; + } +} \ No newline at end of file diff --git a/src/ExampleProject/Program.cs b/src/ExampleProject/Program.cs index 645728c..d996368 100644 --- a/src/ExampleProject/Program.cs +++ b/src/ExampleProject/Program.cs @@ -59,6 +59,22 @@ Console.WriteLine(JsonSerializer.Serialize(order2)); +// Order (with inheritance) +// + +Order3 order3 = CreateOrder3 + .CreatedOn(DateTime.UtcNow) + .ShippedTo(a => a + .Country("country") + .Street("street") + .Zip("zip") + .City("city") + .Build()) + .WithNumber(10) + .Build(); + +Console.WriteLine(JsonSerializer.Serialize(order3)); + // HashCode // diff --git a/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs b/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs index 7cd340e..8b1baab 100644 --- a/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs +++ b/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs @@ -90,9 +90,9 @@ private ClassInfoResult CreateFluentApiClassInfoInternal( FluentApiAttributeInfo fluentApiAttributeInfo = FluentApiAttributeInfo.Create(attributeDataExtended.AttributeData, className); - List infos = new List(); + HashSet infos = new HashSet(); - foreach (var member in type.GetMembers().Where(m => m.CanBeReferencedByName && m.Name != string.Empty)) + foreach (var member in GetMembers(type)) { if (cancellationToken.IsCancellationRequested) { @@ -121,6 +121,22 @@ private ClassInfoResult CreateFluentApiClassInfoInternal( infos, usingStatements, new FluentApiClassAdditionalInfo(groups)); + + static IEnumerable GetMembers(ITypeSymbol? typeSymbol) + { + if (typeSymbol != null && typeSymbol.Name != nameof(Object)) + { + foreach (var member in typeSymbol.GetMembers().Where(m => m.CanBeReferencedByName && m.Name != string.Empty)) + { + yield return member; + } + + foreach (var member in GetMembers(typeSymbol.BaseType)) + { + yield return member; + } + } + } } private ConstructorInfo? TryGetConstructorInfo(INamedTypeSymbol type) From 4515b48368406b44981eefc99de18cdce56a5350 Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Mon, 23 Sep 2024 21:06:52 +0200 Subject: [PATCH 02/15] refactor(ClassInfoFactory): minor changes --- .../SourceGenerators/ClassInfoFactory.cs | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs b/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs index 8b1baab..f45835a 100644 --- a/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs +++ b/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs @@ -91,8 +91,9 @@ private ClassInfoResult CreateFluentApiClassInfoInternal( FluentApiAttributeInfo.Create(attributeDataExtended.AttributeData, className); HashSet infos = new HashSet(); + ISymbol[] members = GetMembers(type).ToArray(); - foreach (var member in GetMembers(type)) + foreach (ISymbol member in members) { if (cancellationToken.IsCancellationRequested) { @@ -121,21 +122,24 @@ private ClassInfoResult CreateFluentApiClassInfoInternal( infos, usingStatements, new FluentApiClassAdditionalInfo(groups)); + } - static IEnumerable GetMembers(ITypeSymbol? typeSymbol) + private static IEnumerable GetMembers(ITypeSymbol typeSymbol) + { + foreach (ISymbol member in typeSymbol.GetMembers() + .Where(m => m.CanBeReferencedByName && m.Name != string.Empty)) { - if (typeSymbol != null && typeSymbol.Name != nameof(Object)) - { - foreach (var member in typeSymbol.GetMembers().Where(m => m.CanBeReferencedByName && m.Name != string.Empty)) - { - yield return member; - } - - foreach (var member in GetMembers(typeSymbol.BaseType)) - { - yield return member; - } - } + yield return member; + } + + if (typeSymbol.BaseType == null || typeSymbol.BaseType.Name == nameof(Object)) + { + yield break; + } + + foreach (ISymbol member in GetMembers(typeSymbol.BaseType)) + { + yield return member; } } From 5f80cd14dca6462d1c48a28a847a46e28334a964 Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Mon, 23 Sep 2024 22:41:25 +0200 Subject: [PATCH 03/15] test: InheritedClass --- .../Abstract/InheritedClass/CreatePerson.g.cs | 50 +++++++++++++ .../InheritedClass/CreateStudent.expected.txt | 74 +++++++++++++++++++ .../InheritedClass/CreateStudent.g.cs | 74 +++++++++++++++++++ .../Abstract/InheritedClass/Person.cs | 15 ++++ .../Abstract/InheritedClass/Student.cs | 18 +++++ .../CodeGeneration/TestDataProvider.cs | 1 + 6 files changed, 232 insertions(+) create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreatePerson.g.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreateStudent.expected.txt create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreateStudent.g.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Person.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Student.cs diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreatePerson.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreatePerson.g.cs new file mode 100644 index 0000000..53c656b --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreatePerson.g.cs @@ -0,0 +1,50 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass; + +public class CreatePerson : + CreatePerson.ICreatePerson, + CreatePerson.IInSemester +{ + private readonly Person person; + + private CreatePerson() + { + person = new Person(); + } + + public static ICreatePerson InitialStep() + { + return new CreatePerson(); + } + + public static Person InSemester(int semester) + { + CreatePerson createPerson = new CreatePerson(); + createPerson.person.Semester = semester; + return createPerson.person; + } + + Person IInSemester.InSemester(int semester) + { + person.Semester = semester; + return person; + } + + public interface ICreatePerson : IInSemester + { + } + + public interface IInSemester + { + Person InSemester(int semester); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreateStudent.expected.txt new file mode 100644 index 0000000..bccf1b4 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreateStudent.expected.txt @@ -0,0 +1,74 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass; + +public class CreateStudent : + CreateStudent.ICreateStudent, + CreateStudent.IWithName, + CreateStudent.IBornOn, + CreateStudent.IInSemester +{ + private readonly Student student; + + private CreateStudent() + { + student = new Student(); + } + + public static ICreateStudent InitialStep() + { + return new CreateStudent(); + } + + public static IBornOn WithName(string name) + { + CreateStudent createStudent = new CreateStudent(); + createStudent.student.Name = name; + return createStudent; + } + + IBornOn IWithName.WithName(string name) + { + student.Name = name; + return this; + } + + IInSemester IBornOn.BornOn(System.DateOnly dateOfBirth) + { + student.DateOfBirth = dateOfBirth; + return this; + } + + Student IInSemester.InSemester(int semester) + { + student.Semester = semester; + return student; + } + + public interface ICreateStudent : IWithName + { + } + + public interface IWithName + { + IBornOn WithName(string name); + } + + public interface IBornOn + { + IInSemester BornOn(System.DateOnly dateOfBirth); + } + + public interface IInSemester + { + Student InSemester(int semester); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreateStudent.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreateStudent.g.cs new file mode 100644 index 0000000..bccf1b4 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreateStudent.g.cs @@ -0,0 +1,74 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass; + +public class CreateStudent : + CreateStudent.ICreateStudent, + CreateStudent.IWithName, + CreateStudent.IBornOn, + CreateStudent.IInSemester +{ + private readonly Student student; + + private CreateStudent() + { + student = new Student(); + } + + public static ICreateStudent InitialStep() + { + return new CreateStudent(); + } + + public static IBornOn WithName(string name) + { + CreateStudent createStudent = new CreateStudent(); + createStudent.student.Name = name; + return createStudent; + } + + IBornOn IWithName.WithName(string name) + { + student.Name = name; + return this; + } + + IInSemester IBornOn.BornOn(System.DateOnly dateOfBirth) + { + student.DateOfBirth = dateOfBirth; + return this; + } + + Student IInSemester.InSemester(int semester) + { + student.Semester = semester; + return student; + } + + public interface ICreateStudent : IWithName + { + } + + public interface IWithName + { + IBornOn WithName(string name); + } + + public interface IBornOn + { + IInSemester BornOn(System.DateOnly dateOfBirth); + } + + public interface IInSemester + { + Student InSemester(int semester); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Person.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Person.cs new file mode 100644 index 0000000..b9c96b2 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Person.cs @@ -0,0 +1,15 @@ +// Non-nullable member is uninitialized +#pragma warning disable CS8618 +// ReSharper disable All + +using System; +using M31.FluentApi.Attributes; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass; + +[FluentApi] +public class Person +{ + [FluentMember(2, "InSemester")] + public int Semester { get; set; } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Student.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Student.cs new file mode 100644 index 0000000..529b6e4 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Student.cs @@ -0,0 +1,18 @@ +// Non-nullable member is uninitialized +#pragma warning disable CS8618 +// ReSharper disable All + +using System; +using M31.FluentApi.Attributes; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass; + +[FluentApi] +public class Student : Person +{ + [FluentMember(0, "WithName")] + public string Name { get; set; } + + [FluentMember(1, "BornOn")] + public DateOnly DateOfBirth{ get; set; } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs index cba4ff3..7aecebb 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs @@ -57,6 +57,7 @@ internal class TestDataProvider : IEnumerable new object[] { "Abstract", "GetPrivateInitPropertyClass", "Student" }, new object[] { "Abstract", "GetPrivateSetPropertyClass", "Student" }, new object[] { "Abstract", "InternalPropertyClass", "Student" }, + new object[] { "Abstract", "InheritedClass", "Student|Person"}, new object[] { "Abstract", "InternalClass", "Student" }, new object[] { "Abstract", "NonGenericCollectionMemberClass", "Student" }, new object[] { "Abstract", "NullablePredicateAndCollectionClass", "Student" }, From 8972f2a28a432a00386962bb237b7d347fbe6a7d Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Mon, 23 Sep 2024 22:44:42 +0200 Subject: [PATCH 04/15] fix(ClassInfoFactory): compare to SpecialType in GetMembers --- .../SourceGenerators/ClassInfoFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs b/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs index f45835a..e31629e 100644 --- a/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs +++ b/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs @@ -132,7 +132,7 @@ private static IEnumerable GetMembers(ITypeSymbol typeSymbol) yield return member; } - if (typeSymbol.BaseType == null || typeSymbol.BaseType.Name == nameof(Object)) + if (typeSymbol.BaseType == null || typeSymbol.BaseType.SpecialType == SpecialType.System_Object) { yield break; } From 4c03d1d816ba9b0f5028caef6822e80ac419e95f Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Mon, 23 Sep 2024 22:58:43 +0200 Subject: [PATCH 05/15] test: InheritedClassProtectedMembers and InheritedClassProtectedSetters --- .../CodeGenerationExecutionTests.cs | 50 +++++++++++ .../CreatePerson.g.cs | 57 +++++++++++++ .../CreateStudent.expected.txt | 85 +++++++++++++++++++ .../CreateStudent.g.cs | 85 +++++++++++++++++++ .../InheritedClassProtectedMembers/Person.cs | 15 ++++ .../InheritedClassProtectedMembers/Student.cs | 18 ++++ .../CreatePerson.g.cs | 57 +++++++++++++ .../CreateStudent.expected.txt | 85 +++++++++++++++++++ .../CreateStudent.g.cs | 85 +++++++++++++++++++ .../InheritedClassProtectedSetters/Person.cs | 15 ++++ .../InheritedClassProtectedSetters/Student.cs | 18 ++++ .../CodeGeneration/TestDataProvider.cs | 4 +- 12 files changed, 573 insertions(+), 1 deletion(-) create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreatePerson.g.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.expected.txt create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.g.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Person.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Student.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreatePerson.g.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.expected.txt create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.g.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Person.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Student.cs diff --git a/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs b/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs index 04770f8..3ecdcb0 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Reflection; using M31.FluentApi.Tests.CodeGeneration.Helpers; using Xunit; using Xunit.Priority; @@ -448,6 +449,55 @@ public void CanExecuteGenericOverloadedPrivateMethodClass() } } + [Fact, Priority(1)] + public void CanExecuteInheritedClass() + { + var student = TestClasses.Abstract.InheritedClass + .CreateStudent + .WithName("Alice") + .BornOn(new DateOnly(2002, 8, 3)) + .InSemester(2); + + Assert.Equal("Alice", student.Name); + Assert.Equal(new DateOnly(2002, 8, 3), student.DateOfBirth); + Assert.Equal(2, student.Semester); + } + + [Fact, Priority(1)] + public void CanExecuteInheritedClassProtectedMembers() + { + var student = TestClasses.Abstract.InheritedClassProtectedMembers + .CreateStudent + .WithName("Alice") + .BornOn(new DateOnly(2002, 8, 3)) + .InSemester(2); + + Assert.Equal("Alice", GetProperty("Name")); + Assert.Equal(new DateOnly(2002, 8, 3), GetProperty("DateOfBirth")); + Assert.Equal(2, GetProperty("Semester")); + + object GetProperty(string propertyName) + { + return typeof(TestClasses.Abstract.InheritedClassProtectedMembers.Student) + .GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic)? + .GetValue(student)!; + } + } + + [Fact, Priority(1)] + public void CanExecuteInheritedClassProtectedSetters() + { + var student = TestClasses.Abstract.InheritedClassProtectedSetters + .CreateStudent + .WithName("Alice") + .BornOn(new DateOnly(2002, 8, 3)) + .InSemester(2); + + Assert.Equal("Alice", student.Name); + Assert.Equal(new DateOnly(2002, 8, 3), student.DateOfBirth); + Assert.Equal(2, student.Semester); + } + [Fact, Priority(1)] public void CanExecutePartialClass() { diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreatePerson.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreatePerson.g.cs new file mode 100644 index 0000000..269bcae --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreatePerson.g.cs @@ -0,0 +1,57 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; +using System.Reflection; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassProtectedMembers; + +public class CreatePerson : + CreatePerson.ICreatePerson, + CreatePerson.IInSemester +{ + private readonly Person person; + private static readonly PropertyInfo semesterPropertyInfo; + + static CreatePerson() + { + semesterPropertyInfo = typeof(Person).GetProperty("Semester", BindingFlags.Instance | BindingFlags.NonPublic)!; + } + + private CreatePerson() + { + person = new Person(); + } + + public static ICreatePerson InitialStep() + { + return new CreatePerson(); + } + + public static Person InSemester(int semester) + { + CreatePerson createPerson = new CreatePerson(); + CreatePerson.semesterPropertyInfo.SetValue(createPerson.person, semester); + return createPerson.person; + } + + Person IInSemester.InSemester(int semester) + { + CreatePerson.semesterPropertyInfo.SetValue(person, semester); + return person; + } + + public interface ICreatePerson : IInSemester + { + } + + public interface IInSemester + { + Person InSemester(int semester); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.expected.txt new file mode 100644 index 0000000..c747dc2 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.expected.txt @@ -0,0 +1,85 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; +using System.Reflection; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassProtectedMembers; + +public class CreateStudent : + CreateStudent.ICreateStudent, + CreateStudent.IWithName, + CreateStudent.IBornOn, + CreateStudent.IInSemester +{ + private readonly Student student; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + private static readonly PropertyInfo semesterPropertyInfo; + + static CreateStudent() + { + namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic)!; + dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.NonPublic)!; + semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.NonPublic)!; + } + + private CreateStudent() + { + student = new Student(); + } + + public static ICreateStudent InitialStep() + { + return new CreateStudent(); + } + + public static IBornOn WithName(string name) + { + CreateStudent createStudent = new CreateStudent(); + CreateStudent.namePropertyInfo.SetValue(createStudent.student, name); + return createStudent; + } + + IBornOn IWithName.WithName(string name) + { + CreateStudent.namePropertyInfo.SetValue(student, name); + return this; + } + + IInSemester IBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreateStudent.dateOfBirthPropertyInfo.SetValue(student, dateOfBirth); + return this; + } + + Student IInSemester.InSemester(int semester) + { + CreateStudent.semesterPropertyInfo.SetValue(student, semester); + return student; + } + + public interface ICreateStudent : IWithName + { + } + + public interface IWithName + { + IBornOn WithName(string name); + } + + public interface IBornOn + { + IInSemester BornOn(System.DateOnly dateOfBirth); + } + + public interface IInSemester + { + Student InSemester(int semester); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.g.cs new file mode 100644 index 0000000..c747dc2 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.g.cs @@ -0,0 +1,85 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; +using System.Reflection; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassProtectedMembers; + +public class CreateStudent : + CreateStudent.ICreateStudent, + CreateStudent.IWithName, + CreateStudent.IBornOn, + CreateStudent.IInSemester +{ + private readonly Student student; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + private static readonly PropertyInfo semesterPropertyInfo; + + static CreateStudent() + { + namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic)!; + dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.NonPublic)!; + semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.NonPublic)!; + } + + private CreateStudent() + { + student = new Student(); + } + + public static ICreateStudent InitialStep() + { + return new CreateStudent(); + } + + public static IBornOn WithName(string name) + { + CreateStudent createStudent = new CreateStudent(); + CreateStudent.namePropertyInfo.SetValue(createStudent.student, name); + return createStudent; + } + + IBornOn IWithName.WithName(string name) + { + CreateStudent.namePropertyInfo.SetValue(student, name); + return this; + } + + IInSemester IBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreateStudent.dateOfBirthPropertyInfo.SetValue(student, dateOfBirth); + return this; + } + + Student IInSemester.InSemester(int semester) + { + CreateStudent.semesterPropertyInfo.SetValue(student, semester); + return student; + } + + public interface ICreateStudent : IWithName + { + } + + public interface IWithName + { + IBornOn WithName(string name); + } + + public interface IBornOn + { + IInSemester BornOn(System.DateOnly dateOfBirth); + } + + public interface IInSemester + { + Student InSemester(int semester); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Person.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Person.cs new file mode 100644 index 0000000..19a727c --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Person.cs @@ -0,0 +1,15 @@ +// Non-nullable member is uninitialized +#pragma warning disable CS8618 +// ReSharper disable All + +using System; +using M31.FluentApi.Attributes; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassProtectedMembers; + +[FluentApi] +public class Person +{ + [FluentMember(2, "InSemester")] + protected int Semester { get; set; } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Student.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Student.cs new file mode 100644 index 0000000..a42bcfe --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Student.cs @@ -0,0 +1,18 @@ +// Non-nullable member is uninitialized +#pragma warning disable CS8618 +// ReSharper disable All + +using System; +using M31.FluentApi.Attributes; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassProtectedMembers; + +[FluentApi] +public class Student : Person +{ + [FluentMember(0, "WithName")] + protected string Name { get; set; } + + [FluentMember(1, "BornOn")] + protected DateOnly DateOfBirth{ get; set; } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreatePerson.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreatePerson.g.cs new file mode 100644 index 0000000..72e424f --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreatePerson.g.cs @@ -0,0 +1,57 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; +using System.Reflection; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassProtectedSetters; + +public class CreatePerson : + CreatePerson.ICreatePerson, + CreatePerson.IInSemester +{ + private readonly Person person; + private static readonly PropertyInfo semesterPropertyInfo; + + static CreatePerson() + { + semesterPropertyInfo = typeof(Person).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; + } + + private CreatePerson() + { + person = new Person(); + } + + public static ICreatePerson InitialStep() + { + return new CreatePerson(); + } + + public static Person InSemester(int semester) + { + CreatePerson createPerson = new CreatePerson(); + CreatePerson.semesterPropertyInfo.SetValue(createPerson.person, semester); + return createPerson.person; + } + + Person IInSemester.InSemester(int semester) + { + CreatePerson.semesterPropertyInfo.SetValue(person, semester); + return person; + } + + public interface ICreatePerson : IInSemester + { + } + + public interface IInSemester + { + Person InSemester(int semester); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.expected.txt new file mode 100644 index 0000000..afb803b --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.expected.txt @@ -0,0 +1,85 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; +using System.Reflection; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassProtectedSetters; + +public class CreateStudent : + CreateStudent.ICreateStudent, + CreateStudent.IWithName, + CreateStudent.IBornOn, + CreateStudent.IInSemester +{ + private readonly Student student; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + private static readonly PropertyInfo semesterPropertyInfo; + + static CreateStudent() + { + namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; + } + + private CreateStudent() + { + student = new Student(); + } + + public static ICreateStudent InitialStep() + { + return new CreateStudent(); + } + + public static IBornOn WithName(string name) + { + CreateStudent createStudent = new CreateStudent(); + CreateStudent.namePropertyInfo.SetValue(createStudent.student, name); + return createStudent; + } + + IBornOn IWithName.WithName(string name) + { + CreateStudent.namePropertyInfo.SetValue(student, name); + return this; + } + + IInSemester IBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreateStudent.dateOfBirthPropertyInfo.SetValue(student, dateOfBirth); + return this; + } + + Student IInSemester.InSemester(int semester) + { + CreateStudent.semesterPropertyInfo.SetValue(student, semester); + return student; + } + + public interface ICreateStudent : IWithName + { + } + + public interface IWithName + { + IBornOn WithName(string name); + } + + public interface IBornOn + { + IInSemester BornOn(System.DateOnly dateOfBirth); + } + + public interface IInSemester + { + Student InSemester(int semester); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.g.cs new file mode 100644 index 0000000..afb803b --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.g.cs @@ -0,0 +1,85 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; +using System.Reflection; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassProtectedSetters; + +public class CreateStudent : + CreateStudent.ICreateStudent, + CreateStudent.IWithName, + CreateStudent.IBornOn, + CreateStudent.IInSemester +{ + private readonly Student student; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + private static readonly PropertyInfo semesterPropertyInfo; + + static CreateStudent() + { + namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; + } + + private CreateStudent() + { + student = new Student(); + } + + public static ICreateStudent InitialStep() + { + return new CreateStudent(); + } + + public static IBornOn WithName(string name) + { + CreateStudent createStudent = new CreateStudent(); + CreateStudent.namePropertyInfo.SetValue(createStudent.student, name); + return createStudent; + } + + IBornOn IWithName.WithName(string name) + { + CreateStudent.namePropertyInfo.SetValue(student, name); + return this; + } + + IInSemester IBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreateStudent.dateOfBirthPropertyInfo.SetValue(student, dateOfBirth); + return this; + } + + Student IInSemester.InSemester(int semester) + { + CreateStudent.semesterPropertyInfo.SetValue(student, semester); + return student; + } + + public interface ICreateStudent : IWithName + { + } + + public interface IWithName + { + IBornOn WithName(string name); + } + + public interface IBornOn + { + IInSemester BornOn(System.DateOnly dateOfBirth); + } + + public interface IInSemester + { + Student InSemester(int semester); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Person.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Person.cs new file mode 100644 index 0000000..bb6b1fa --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Person.cs @@ -0,0 +1,15 @@ +// Non-nullable member is uninitialized +#pragma warning disable CS8618 +// ReSharper disable All + +using System; +using M31.FluentApi.Attributes; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassProtectedSetters; + +[FluentApi] +public class Person +{ + [FluentMember(2, "InSemester")] + public int Semester { get; protected set; } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Student.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Student.cs new file mode 100644 index 0000000..9385782 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Student.cs @@ -0,0 +1,18 @@ +// Non-nullable member is uninitialized +#pragma warning disable CS8618 +// ReSharper disable All + +using System; +using M31.FluentApi.Attributes; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassProtectedSetters; + +[FluentApi] +public class Student : Person +{ + [FluentMember(0, "WithName")] + public string Name { get; protected set; } + + [FluentMember(1, "BornOn")] + public DateOnly DateOfBirth{ get; protected set; } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs index 7aecebb..de73dee 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs @@ -57,7 +57,9 @@ internal class TestDataProvider : IEnumerable new object[] { "Abstract", "GetPrivateInitPropertyClass", "Student" }, new object[] { "Abstract", "GetPrivateSetPropertyClass", "Student" }, new object[] { "Abstract", "InternalPropertyClass", "Student" }, - new object[] { "Abstract", "InheritedClass", "Student|Person"}, + new object[] { "Abstract", "InheritedClass", "Student|Person" }, + new object[] { "Abstract", "InheritedClassProtectedMembers", "Student|Person" }, + new object[] { "Abstract", "InheritedClassProtectedSetters", "Student|Person" }, new object[] { "Abstract", "InternalClass", "Student" }, new object[] { "Abstract", "NonGenericCollectionMemberClass", "Student" }, new object[] { "Abstract", "NullablePredicateAndCollectionClass", "Student" }, From 01181a067b2599b5505ed4eac8565eabd94961c2 Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Tue, 24 Sep 2024 16:05:37 +0200 Subject: [PATCH 06/15] docs: mention inheritance in features --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 140f71d..97042e9 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Accompanying blog post: [www.m31coding.com>blog>fluent-api](https://www.m31codin - Optional (skippable) builder methods - Forking and branching capabilities - Support for returning arbitrary types -- Support for generics and partial classes +- Support for inheritance, generics, and partial classes ## Installing via NuGet From 7a1b61efb0159da6e2df2424da801f154e87665f Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Tue, 24 Sep 2024 16:13:01 +0200 Subject: [PATCH 07/15] fix: inheritance tests --- .../Abstract/InheritedClass/CreatePerson.g.cs | 30 +++++++++++----- .../Abstract/InheritedClass/Person.cs | 7 ++-- .../Abstract/InheritedClass/Student.cs | 7 ++-- .../CreatePerson.g.cs | 36 +++++++++++++------ .../CreateStudent.expected.txt | 4 +-- .../CreateStudent.g.cs | 4 +-- .../InheritedClassProtectedMembers/Person.cs | 7 ++-- .../InheritedClassProtectedMembers/Student.cs | 7 ++-- .../CreatePerson.g.cs | 36 +++++++++++++------ .../CreateStudent.expected.txt | 4 +-- .../CreateStudent.g.cs | 4 +-- .../InheritedClassProtectedSetters/Person.cs | 7 ++-- .../InheritedClassProtectedSetters/Student.cs | 7 ++-- 13 files changed, 100 insertions(+), 60 deletions(-) diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreatePerson.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreatePerson.g.cs index 53c656b..e0494f0 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreatePerson.g.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreatePerson.g.cs @@ -12,7 +12,8 @@ namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass public class CreatePerson : CreatePerson.ICreatePerson, - CreatePerson.IInSemester + CreatePerson.IWithName, + CreatePerson.IBornOn { private readonly Person person; @@ -26,25 +27,36 @@ public static ICreatePerson InitialStep() return new CreatePerson(); } - public static Person InSemester(int semester) + public static IBornOn WithName(string name) { CreatePerson createPerson = new CreatePerson(); - createPerson.person.Semester = semester; - return createPerson.person; + createPerson.person.Name = name; + return createPerson; } - Person IInSemester.InSemester(int semester) + IBornOn IWithName.WithName(string name) { - person.Semester = semester; + person.Name = name; + return this; + } + + Person IBornOn.BornOn(System.DateOnly dateOfBirth) + { + person.DateOfBirth = dateOfBirth; return person; } - public interface ICreatePerson : IInSemester + public interface ICreatePerson : IWithName + { + } + + public interface IWithName { + IBornOn WithName(string name); } - public interface IInSemester + public interface IBornOn { - Person InSemester(int semester); + Person BornOn(System.DateOnly dateOfBirth); } } \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Person.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Person.cs index b9c96b2..9138a12 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Person.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Person.cs @@ -10,6 +10,9 @@ namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass [FluentApi] public class Person { - [FluentMember(2, "InSemester")] - public int Semester { get; set; } + [FluentMember(0, "WithName")] + public string Name { get; set; } + + [FluentMember(1, "BornOn")] + public DateOnly DateOfBirth{ get; set; } } \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Student.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Student.cs index 529b6e4..5635793 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Student.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Student.cs @@ -10,9 +10,6 @@ namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass [FluentApi] public class Student : Person { - [FluentMember(0, "WithName")] - public string Name { get; set; } - - [FluentMember(1, "BornOn")] - public DateOnly DateOfBirth{ get; set; } + [FluentMember(2, "InSemester")] + public int Semester { get; set; } } \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreatePerson.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreatePerson.g.cs index 269bcae..e429f72 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreatePerson.g.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreatePerson.g.cs @@ -13,14 +13,17 @@ namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass public class CreatePerson : CreatePerson.ICreatePerson, - CreatePerson.IInSemester + CreatePerson.IWithName, + CreatePerson.IBornOn { private readonly Person person; - private static readonly PropertyInfo semesterPropertyInfo; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; static CreatePerson() { - semesterPropertyInfo = typeof(Person).GetProperty("Semester", BindingFlags.Instance | BindingFlags.NonPublic)!; + namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic)!; + dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.NonPublic)!; } private CreatePerson() @@ -33,25 +36,36 @@ public static ICreatePerson InitialStep() return new CreatePerson(); } - public static Person InSemester(int semester) + public static IBornOn WithName(string name) { CreatePerson createPerson = new CreatePerson(); - CreatePerson.semesterPropertyInfo.SetValue(createPerson.person, semester); - return createPerson.person; + CreatePerson.namePropertyInfo.SetValue(createPerson.person, name); + return createPerson; } - Person IInSemester.InSemester(int semester) + IBornOn IWithName.WithName(string name) { - CreatePerson.semesterPropertyInfo.SetValue(person, semester); + CreatePerson.namePropertyInfo.SetValue(person, name); + return this; + } + + Person IBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreatePerson.dateOfBirthPropertyInfo.SetValue(person, dateOfBirth); return person; } - public interface ICreatePerson : IInSemester + public interface ICreatePerson : IWithName + { + } + + public interface IWithName { + IBornOn WithName(string name); } - public interface IInSemester + public interface IBornOn { - Person InSemester(int semester); + Person BornOn(System.DateOnly dateOfBirth); } } \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.expected.txt index c747dc2..b264c7f 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.expected.txt +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.expected.txt @@ -18,15 +18,15 @@ public class CreateStudent : CreateStudent.IInSemester { private readonly Student student; + private static readonly PropertyInfo semesterPropertyInfo; private static readonly PropertyInfo namePropertyInfo; private static readonly PropertyInfo dateOfBirthPropertyInfo; - private static readonly PropertyInfo semesterPropertyInfo; static CreateStudent() { + semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.NonPublic)!; namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic)!; dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.NonPublic)!; - semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.NonPublic)!; } private CreateStudent() diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.g.cs index c747dc2..b264c7f 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.g.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.g.cs @@ -18,15 +18,15 @@ public class CreateStudent : CreateStudent.IInSemester { private readonly Student student; + private static readonly PropertyInfo semesterPropertyInfo; private static readonly PropertyInfo namePropertyInfo; private static readonly PropertyInfo dateOfBirthPropertyInfo; - private static readonly PropertyInfo semesterPropertyInfo; static CreateStudent() { + semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.NonPublic)!; namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic)!; dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.NonPublic)!; - semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.NonPublic)!; } private CreateStudent() diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Person.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Person.cs index 19a727c..8fb6b94 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Person.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Person.cs @@ -10,6 +10,9 @@ namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass [FluentApi] public class Person { - [FluentMember(2, "InSemester")] - protected int Semester { get; set; } + [FluentMember(0, "WithName")] + protected string Name { get; set; } + + [FluentMember(1, "BornOn")] + protected DateOnly DateOfBirth{ get; set; } } \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Student.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Student.cs index a42bcfe..dbee594 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Student.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Student.cs @@ -10,9 +10,6 @@ namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass [FluentApi] public class Student : Person { - [FluentMember(0, "WithName")] - protected string Name { get; set; } - - [FluentMember(1, "BornOn")] - protected DateOnly DateOfBirth{ get; set; } + [FluentMember(2, "InSemester")] + protected int Semester { get; set; } } \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreatePerson.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreatePerson.g.cs index 72e424f..ed0341a 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreatePerson.g.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreatePerson.g.cs @@ -13,14 +13,17 @@ namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass public class CreatePerson : CreatePerson.ICreatePerson, - CreatePerson.IInSemester + CreatePerson.IWithName, + CreatePerson.IBornOn { private readonly Person person; - private static readonly PropertyInfo semesterPropertyInfo; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; static CreatePerson() { - semesterPropertyInfo = typeof(Person).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; + namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; } private CreatePerson() @@ -33,25 +36,36 @@ public static ICreatePerson InitialStep() return new CreatePerson(); } - public static Person InSemester(int semester) + public static IBornOn WithName(string name) { CreatePerson createPerson = new CreatePerson(); - CreatePerson.semesterPropertyInfo.SetValue(createPerson.person, semester); - return createPerson.person; + CreatePerson.namePropertyInfo.SetValue(createPerson.person, name); + return createPerson; } - Person IInSemester.InSemester(int semester) + IBornOn IWithName.WithName(string name) { - CreatePerson.semesterPropertyInfo.SetValue(person, semester); + CreatePerson.namePropertyInfo.SetValue(person, name); + return this; + } + + Person IBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreatePerson.dateOfBirthPropertyInfo.SetValue(person, dateOfBirth); return person; } - public interface ICreatePerson : IInSemester + public interface ICreatePerson : IWithName + { + } + + public interface IWithName { + IBornOn WithName(string name); } - public interface IInSemester + public interface IBornOn { - Person InSemester(int semester); + Person BornOn(System.DateOnly dateOfBirth); } } \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.expected.txt index afb803b..8ccdd0e 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.expected.txt +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.expected.txt @@ -18,15 +18,15 @@ public class CreateStudent : CreateStudent.IInSemester { private readonly Student student; + private static readonly PropertyInfo semesterPropertyInfo; private static readonly PropertyInfo namePropertyInfo; private static readonly PropertyInfo dateOfBirthPropertyInfo; - private static readonly PropertyInfo semesterPropertyInfo; static CreateStudent() { + semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; - semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; } private CreateStudent() diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.g.cs index afb803b..8ccdd0e 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.g.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.g.cs @@ -18,15 +18,15 @@ public class CreateStudent : CreateStudent.IInSemester { private readonly Student student; + private static readonly PropertyInfo semesterPropertyInfo; private static readonly PropertyInfo namePropertyInfo; private static readonly PropertyInfo dateOfBirthPropertyInfo; - private static readonly PropertyInfo semesterPropertyInfo; static CreateStudent() { + semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; - semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; } private CreateStudent() diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Person.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Person.cs index bb6b1fa..e5206b2 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Person.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Person.cs @@ -10,6 +10,9 @@ namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass [FluentApi] public class Person { - [FluentMember(2, "InSemester")] - public int Semester { get; protected set; } + [FluentMember(0, "WithName")] + public string Name { get; protected set; } + + [FluentMember(1, "BornOn")] + public DateOnly DateOfBirth{ get; protected set; } } \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Student.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Student.cs index 9385782..b20c6b4 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Student.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Student.cs @@ -10,9 +10,6 @@ namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass [FluentApi] public class Student : Person { - [FluentMember(0, "WithName")] - public string Name { get; protected set; } - - [FluentMember(1, "BornOn")] - public DateOnly DateOfBirth{ get; protected set; } + [FluentMember(2, "InSemester")] + public int Semester { get; protected set; } } \ No newline at end of file From 521a6aab1ed67b4043194a32ebee51293e67a27e Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Tue, 24 Sep 2024 16:22:46 +0200 Subject: [PATCH 08/15] test: inherited record --- .../CodeGenerationExecutionTests.cs | 14 +++ .../InheritedRecord/CreatePerson.g.cs | 71 ++++++++++++++++ .../CreateStudent.expected.txt | 85 +++++++++++++++++++ .../InheritedRecord/CreateStudent.g.cs | 85 +++++++++++++++++++ .../Abstract/InheritedRecord/Person.cs | 13 +++ .../Abstract/InheritedRecord/Student.cs | 15 ++++ .../CodeGeneration/TestDataProvider.cs | 1 + 7 files changed, 284 insertions(+) create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreatePerson.g.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.expected.txt create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.g.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/Person.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/Student.cs diff --git a/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs b/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs index 3ecdcb0..92645e5 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs @@ -498,6 +498,20 @@ public void CanExecuteInheritedClassProtectedSetters() Assert.Equal(2, student.Semester); } + [Fact, Priority(1)] + public void CanExecuteInheritedRecord() + { + var student = TestClasses.Abstract.InheritedRecord + .CreateStudent + .WithName("Alice") + .BornOn(new DateOnly(2002, 8, 3)) + .InSemester(2); + + Assert.Equal("Alice", student.Name); + Assert.Equal(new DateOnly(2002, 8, 3), student.DateOfBirth); + Assert.Equal(2, student.Semester); + } + [Fact, Priority(1)] public void CanExecutePartialClass() { diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreatePerson.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreatePerson.g.cs new file mode 100644 index 0000000..168a7a5 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreatePerson.g.cs @@ -0,0 +1,71 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; +using System.Reflection; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedRecord; + +public class CreatePerson : + CreatePerson.ICreatePerson, + CreatePerson.IWithName, + CreatePerson.IBornOn +{ + private readonly Person person; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + + static CreatePerson() + { + namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + } + + private CreatePerson() + { + person = new Person(default!, default!); + } + + public static ICreatePerson InitialStep() + { + return new CreatePerson(); + } + + public static IBornOn WithName(string name) + { + CreatePerson createPerson = new CreatePerson(); + CreatePerson.namePropertyInfo.SetValue(createPerson.person, name); + return createPerson; + } + + IBornOn IWithName.WithName(string name) + { + CreatePerson.namePropertyInfo.SetValue(person, name); + return this; + } + + Person IBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreatePerson.dateOfBirthPropertyInfo.SetValue(person, dateOfBirth); + return person; + } + + public interface ICreatePerson : IWithName + { + } + + public interface IWithName + { + IBornOn WithName(string name); + } + + public interface IBornOn + { + Person BornOn(System.DateOnly dateOfBirth); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.expected.txt new file mode 100644 index 0000000..4ed5de1 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.expected.txt @@ -0,0 +1,85 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; +using System.Reflection; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedRecord; + +public class CreateStudent : + CreateStudent.ICreateStudent, + CreateStudent.IWithName, + CreateStudent.IBornOn, + CreateStudent.IInSemester +{ + private readonly Student student; + private static readonly PropertyInfo semesterPropertyInfo; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + + static CreateStudent() + { + semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; + namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + } + + private CreateStudent() + { + student = new Student(default!, default!, default!); + } + + public static ICreateStudent InitialStep() + { + return new CreateStudent(); + } + + public static IBornOn WithName(string name) + { + CreateStudent createStudent = new CreateStudent(); + CreateStudent.namePropertyInfo.SetValue(createStudent.student, name); + return createStudent; + } + + IBornOn IWithName.WithName(string name) + { + CreateStudent.namePropertyInfo.SetValue(student, name); + return this; + } + + IInSemester IBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreateStudent.dateOfBirthPropertyInfo.SetValue(student, dateOfBirth); + return this; + } + + Student IInSemester.InSemester(int semester) + { + CreateStudent.semesterPropertyInfo.SetValue(student, semester); + return student; + } + + public interface ICreateStudent : IWithName + { + } + + public interface IWithName + { + IBornOn WithName(string name); + } + + public interface IBornOn + { + IInSemester BornOn(System.DateOnly dateOfBirth); + } + + public interface IInSemester + { + Student InSemester(int semester); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.g.cs new file mode 100644 index 0000000..4ed5de1 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.g.cs @@ -0,0 +1,85 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; +using System.Reflection; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedRecord; + +public class CreateStudent : + CreateStudent.ICreateStudent, + CreateStudent.IWithName, + CreateStudent.IBornOn, + CreateStudent.IInSemester +{ + private readonly Student student; + private static readonly PropertyInfo semesterPropertyInfo; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + + static CreateStudent() + { + semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; + namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + } + + private CreateStudent() + { + student = new Student(default!, default!, default!); + } + + public static ICreateStudent InitialStep() + { + return new CreateStudent(); + } + + public static IBornOn WithName(string name) + { + CreateStudent createStudent = new CreateStudent(); + CreateStudent.namePropertyInfo.SetValue(createStudent.student, name); + return createStudent; + } + + IBornOn IWithName.WithName(string name) + { + CreateStudent.namePropertyInfo.SetValue(student, name); + return this; + } + + IInSemester IBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreateStudent.dateOfBirthPropertyInfo.SetValue(student, dateOfBirth); + return this; + } + + Student IInSemester.InSemester(int semester) + { + CreateStudent.semesterPropertyInfo.SetValue(student, semester); + return student; + } + + public interface ICreateStudent : IWithName + { + } + + public interface IWithName + { + IBornOn WithName(string name); + } + + public interface IBornOn + { + IInSemester BornOn(System.DateOnly dateOfBirth); + } + + public interface IInSemester + { + Student InSemester(int semester); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/Person.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/Person.cs new file mode 100644 index 0000000..e121273 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/Person.cs @@ -0,0 +1,13 @@ +// Non-nullable member is uninitialized +#pragma warning disable CS8618 +// ReSharper disable All + +using System; +using M31.FluentApi.Attributes; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedRecord; + +[FluentApi] +public record Person( + [property: FluentMember(0, "WithName")] string Name, + [property: FluentMember(1, "BornOn")] DateOnly DateOfBirth); \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/Student.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/Student.cs new file mode 100644 index 0000000..f2286bd --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/Student.cs @@ -0,0 +1,15 @@ +// Non-nullable member is uninitialized +#pragma warning disable CS8618 +// ReSharper disable All + +using System; +using M31.FluentApi.Attributes; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedRecord; + +[FluentApi] +public record Student( + string Name, + DateOnly DateOfBirth, + [property: FluentMember(2, "InSemester")] int Semester) + : Person(Name, DateOfBirth); \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs index de73dee..cf71722 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs @@ -60,6 +60,7 @@ internal class TestDataProvider : IEnumerable new object[] { "Abstract", "InheritedClass", "Student|Person" }, new object[] { "Abstract", "InheritedClassProtectedMembers", "Student|Person" }, new object[] { "Abstract", "InheritedClassProtectedSetters", "Student|Person" }, + new object[] { "Abstract", "InheritedRecord", "Student|Person" }, new object[] { "Abstract", "InternalClass", "Student" }, new object[] { "Abstract", "NonGenericCollectionMemberClass", "Student" }, new object[] { "Abstract", "NullablePredicateAndCollectionClass", "Student" }, From 41e2dd58d811e578415db4dd4b0ed638cc1439af Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Tue, 24 Sep 2024 16:52:10 +0200 Subject: [PATCH 09/15] improve(ExampleProject): add ExchangeStudent example --- src/ExampleProject/ExchangeStudent.cs | 14 ++++++ src/ExampleProject/OrderInheritance.cs | 68 -------------------------- src/ExampleProject/Program.cs | 24 +++------ 3 files changed, 22 insertions(+), 84 deletions(-) create mode 100644 src/ExampleProject/ExchangeStudent.cs delete mode 100644 src/ExampleProject/OrderInheritance.cs diff --git a/src/ExampleProject/ExchangeStudent.cs b/src/ExampleProject/ExchangeStudent.cs new file mode 100644 index 0000000..8b1efe2 --- /dev/null +++ b/src/ExampleProject/ExchangeStudent.cs @@ -0,0 +1,14 @@ +// Non-nullable member is uninitialized +#pragma warning disable CS8618 +// ReSharper disable All + +using M31.FluentApi.Attributes; + +namespace ExampleProject; + +[FluentApi] +public class ExchangeStudent : Student +{ + [FluentMember(6)] + public string HomeCountry { get; private set; } +} \ No newline at end of file diff --git a/src/ExampleProject/OrderInheritance.cs b/src/ExampleProject/OrderInheritance.cs deleted file mode 100644 index b6785d8..0000000 --- a/src/ExampleProject/OrderInheritance.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Non-nullable member is uninitialized -#pragma warning disable CS8618 -// ReSharper disable All - -// Example from https://youtu.be/qCIr30WxJQw?si=FRALafrpA1zWACA8. -// Implementation with arbitrary steps. - -using M31.FluentApi.Attributes; - -namespace ExampleProject; - -public class BaseOrder -{ - [FluentMember(0, "{Name}")] - [FluentContinueWith(0)] - public virtual DateTime? CreatedOn { get; protected set; } -} - -[FluentApi] -public class Order3 : BaseOrder -{ - [FluentMember(0)] - [FluentContinueWith(0)] - public int? Number { get; private set; } - - [FluentMember(0, "ShippedTo")] - [FluentContinueWith(0)] - public Address3? ShippingAddress { get; private set; } - - [FluentMethod(0)] - private void Build() - { - } -} - -[FluentApi] -public class Address3 -{ - [FluentMember(0, "{Name}")] - [FluentContinueWith(0)] - public string Street { get; private set; } - - [FluentMember(0, "{Name}")] - [FluentContinueWith(0)] - public string City { get; private set; } - - [FluentMember(0, "{Name}")] - [FluentContinueWith(0)] - public string Zip { get; private set; } - - [FluentMember(0, "{Name}")] - [FluentContinueWith(0)] - public string State { get; private set; } - - [FluentMember(0, "{Name}")] - [FluentContinueWith(0)] - public string Country { get; private set; } - - [FluentMethod(0)] - private void Build() - { - Street ??= "N/A"; - City ??= "N/A"; - Zip ??= "N/A"; - State ??= "N/A"; - Country ??= "N/A"; - } -} \ No newline at end of file diff --git a/src/ExampleProject/Program.cs b/src/ExampleProject/Program.cs index d996368..5dc8388 100644 --- a/src/ExampleProject/Program.cs +++ b/src/ExampleProject/Program.cs @@ -12,6 +12,14 @@ Console.WriteLine(JsonSerializer.Serialize(student1)); Console.WriteLine(JsonSerializer.Serialize(student2)); +// ExchangeStudent (inherited from Student) +// + +ExchangeStudent exchangeStudent = CreateExchangeStudent.Named("Bob", "Bishop").BornOn(new DateOnly(2002, 8, 3)) + .InSemester(2).LivingInBoston().WithUnknownMood().WhoseFriendIs("Alice").WithHomeCountry("United States"); + +Console.WriteLine(JsonSerializer.Serialize(exchangeStudent)); + // Person // @@ -59,22 +67,6 @@ Console.WriteLine(JsonSerializer.Serialize(order2)); -// Order (with inheritance) -// - -Order3 order3 = CreateOrder3 - .CreatedOn(DateTime.UtcNow) - .ShippedTo(a => a - .Country("country") - .Street("street") - .Zip("zip") - .City("city") - .Build()) - .WithNumber(10) - .Build(); - -Console.WriteLine(JsonSerializer.Serialize(order3)); - // HashCode // From 7b95c649002140f0d7172729ce808ee1e65a102a Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Tue, 24 Sep 2024 22:50:22 +0200 Subject: [PATCH 10/15] test: add failing test CanExecuteInheritedClassPrivateSetters --- .../CodeGenerationExecutionTests.cs | 14 +++ .../CreatePerson.g.cs | 71 ++++++++++++++++ .../CreateStudent.expected.txt | 85 +++++++++++++++++++ .../CreateStudent.g.cs | 85 +++++++++++++++++++ .../InheritedClassPrivateSetters/Person.cs | 18 ++++ .../InheritedClassPrivateSetters/Student.cs | 15 ++++ .../CodeGeneration/TestDataProvider.cs | 1 + 7 files changed, 289 insertions(+) create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreatePerson.g.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.expected.txt create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.g.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/Person.cs create mode 100644 src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/Student.cs diff --git a/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs b/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs index 92645e5..7b22e16 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs @@ -463,6 +463,20 @@ public void CanExecuteInheritedClass() Assert.Equal(2, student.Semester); } + [Fact, Priority(1)] + public void CanExecuteInheritedClassPrivateSetters() + { + var student = TestClasses.Abstract.InheritedClassPrivateSetters + .CreateStudent + .WithName("Alice") + .BornOn(new DateOnly(2002, 8, 3)) + .InSemester(2); + + Assert.Equal("Alice", student.Name); + Assert.Equal(new DateOnly(2002, 8, 3), student.DateOfBirth); + Assert.Equal(2, student.Semester); + } + [Fact, Priority(1)] public void CanExecuteInheritedClassProtectedMembers() { diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreatePerson.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreatePerson.g.cs new file mode 100644 index 0000000..95bec0f --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreatePerson.g.cs @@ -0,0 +1,71 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; +using System.Reflection; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassPrivateSetters; + +public class CreatePerson : + CreatePerson.ICreatePerson, + CreatePerson.IWithName, + CreatePerson.IBornOn +{ + private readonly Person person; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + + static CreatePerson() + { + namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + } + + private CreatePerson() + { + person = new Person(); + } + + public static ICreatePerson InitialStep() + { + return new CreatePerson(); + } + + public static IBornOn WithName(string name) + { + CreatePerson createPerson = new CreatePerson(); + CreatePerson.namePropertyInfo.SetValue(createPerson.person, name); + return createPerson; + } + + IBornOn IWithName.WithName(string name) + { + CreatePerson.namePropertyInfo.SetValue(person, name); + return this; + } + + Person IBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreatePerson.dateOfBirthPropertyInfo.SetValue(person, dateOfBirth); + return person; + } + + public interface ICreatePerson : IWithName + { + } + + public interface IWithName + { + IBornOn WithName(string name); + } + + public interface IBornOn + { + Person BornOn(System.DateOnly dateOfBirth); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.expected.txt new file mode 100644 index 0000000..96443ad --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.expected.txt @@ -0,0 +1,85 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; +using System.Reflection; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassPrivateSetters; + +public class CreateStudent : + CreateStudent.ICreateStudent, + CreateStudent.IWithName, + CreateStudent.IBornOn, + CreateStudent.IInSemester +{ + private readonly Student student; + private static readonly PropertyInfo semesterPropertyInfo; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + + static CreateStudent() + { + semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; + namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + } + + private CreateStudent() + { + student = new Student(); + } + + public static ICreateStudent InitialStep() + { + return new CreateStudent(); + } + + public static IBornOn WithName(string name) + { + CreateStudent createStudent = new CreateStudent(); + CreateStudent.namePropertyInfo.SetValue(createStudent.student, name); + return createStudent; + } + + IBornOn IWithName.WithName(string name) + { + CreateStudent.namePropertyInfo.SetValue(student, name); + return this; + } + + IInSemester IBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreateStudent.dateOfBirthPropertyInfo.SetValue(student, dateOfBirth); + return this; + } + + Student IInSemester.InSemester(int semester) + { + CreateStudent.semesterPropertyInfo.SetValue(student, semester); + return student; + } + + public interface ICreateStudent : IWithName + { + } + + public interface IWithName + { + IBornOn WithName(string name); + } + + public interface IBornOn + { + IInSemester BornOn(System.DateOnly dateOfBirth); + } + + public interface IInSemester + { + Student InSemester(int semester); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.g.cs new file mode 100644 index 0000000..96443ad --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.g.cs @@ -0,0 +1,85 @@ +// +// This code was generated by the library M31.FluentAPI. +// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#nullable enable + +using System; +using M31.FluentApi.Attributes; +using System.Reflection; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassPrivateSetters; + +public class CreateStudent : + CreateStudent.ICreateStudent, + CreateStudent.IWithName, + CreateStudent.IBornOn, + CreateStudent.IInSemester +{ + private readonly Student student; + private static readonly PropertyInfo semesterPropertyInfo; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + + static CreateStudent() + { + semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; + namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + } + + private CreateStudent() + { + student = new Student(); + } + + public static ICreateStudent InitialStep() + { + return new CreateStudent(); + } + + public static IBornOn WithName(string name) + { + CreateStudent createStudent = new CreateStudent(); + CreateStudent.namePropertyInfo.SetValue(createStudent.student, name); + return createStudent; + } + + IBornOn IWithName.WithName(string name) + { + CreateStudent.namePropertyInfo.SetValue(student, name); + return this; + } + + IInSemester IBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreateStudent.dateOfBirthPropertyInfo.SetValue(student, dateOfBirth); + return this; + } + + Student IInSemester.InSemester(int semester) + { + CreateStudent.semesterPropertyInfo.SetValue(student, semester); + return student; + } + + public interface ICreateStudent : IWithName + { + } + + public interface IWithName + { + IBornOn WithName(string name); + } + + public interface IBornOn + { + IInSemester BornOn(System.DateOnly dateOfBirth); + } + + public interface IInSemester + { + Student InSemester(int semester); + } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/Person.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/Person.cs new file mode 100644 index 0000000..72ef05a --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/Person.cs @@ -0,0 +1,18 @@ +// Non-nullable member is uninitialized +#pragma warning disable CS8618 +// ReSharper disable All + +using System; +using M31.FluentApi.Attributes; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassPrivateSetters; + +[FluentApi] +public class Person +{ + [FluentMember(0, "WithName")] + public string Name { get; private set; } + + [FluentMember(1, "BornOn")] + public DateOnly DateOfBirth{ get; private set; } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/Student.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/Student.cs new file mode 100644 index 0000000..2d75afb --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/Student.cs @@ -0,0 +1,15 @@ +// Non-nullable member is uninitialized +#pragma warning disable CS8618 +// ReSharper disable All + +using System; +using M31.FluentApi.Attributes; + +namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClassPrivateSetters; + +[FluentApi] +public class Student : Person +{ + [FluentMember(2, "InSemester")] + public int Semester { get; private set; } +} \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs index cf71722..6a0b15f 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs @@ -58,6 +58,7 @@ internal class TestDataProvider : IEnumerable new object[] { "Abstract", "GetPrivateSetPropertyClass", "Student" }, new object[] { "Abstract", "InternalPropertyClass", "Student" }, new object[] { "Abstract", "InheritedClass", "Student|Person" }, + new object[] { "Abstract", "InheritedClassPrivateSetters", "Student|Person" }, new object[] { "Abstract", "InheritedClassProtectedMembers", "Student|Person" }, new object[] { "Abstract", "InheritedClassProtectedSetters", "Student|Person" }, new object[] { "Abstract", "InheritedRecord", "Student|Person" }, From 8489b5f791d3381563249d353dea027c4a010f99 Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Thu, 26 Sep 2024 16:22:54 +0200 Subject: [PATCH 11/15] fix: make test InheritedClassPrivateSetters work --- .../InnerBodyForMemberGenerator.cs | 2 +- .../CodeBoardElements/BuilderAndTargetInfo.cs | 12 +-- .../CodeBoardElements/FluentApiSymbolInfo.cs | 11 ++- .../CodeBoardElements/MemberSymbolInfo.cs | 3 +- .../CodeBoardElements/MethodSymbolInfo.cs | 3 +- .../SourceGenerators/ClassInfoFactory.cs | 94 ++++++++++++------- .../SourceGenerators/FluentApiInfoCreator.cs | 7 +- .../SourceGenerators/Generics/GenericInfo.cs | 5 + .../SourceGenerators/SymbolInfoCreator.cs | 29 ++++-- .../SourceGenerators/TypeData.cs | 6 +- .../SourceGenerators/TypeDataCreator.cs | 7 +- .../CreateStudent.expected.txt | 4 +- .../CreateStudent.g.cs | 4 +- .../CreateStudent.expected.txt | 4 +- .../CreateStudent.g.cs | 4 +- .../CreateStudent.expected.txt | 4 +- .../CreateStudent.g.cs | 4 +- .../CreateStudent.expected.txt | 4 +- .../InheritedRecord/CreateStudent.g.cs | 4 +- 19 files changed, 128 insertions(+), 83 deletions(-) diff --git a/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardActors/InnerBodyGeneration/InnerBodyForMemberGenerator.cs b/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardActors/InnerBodyGeneration/InnerBodyForMemberGenerator.cs index 68d0cf0..c1a7f25 100644 --- a/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardActors/InnerBodyGeneration/InnerBodyForMemberGenerator.cs +++ b/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardActors/InnerBodyGeneration/InnerBodyForMemberGenerator.cs @@ -43,7 +43,7 @@ protected override void InitializeInfoField(string fieldName, MemberSymbolInfo s // semesterPropertyInfo = typeof(Student) // .GetProperty("Semester", BindingFlags.Instance | BindingFlags.NonPublic);); string code = $"{fieldName} =" + - $" typeof({CodeBoard.Info.FluentApiClassNameWithTypeParameters})" + + $" typeof({symbolInfo.DeclaringClassNameWithTypeParameters})" + $".Get{SymbolType(symbolInfo)}(\"{symbolInfo.Name}\", " + $"{InfoFieldBindingFlagsArgument(symbolInfo)})!;"; diff --git a/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/BuilderAndTargetInfo.cs b/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/BuilderAndTargetInfo.cs index 7db5996..fe9b12d 100644 --- a/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/BuilderAndTargetInfo.cs +++ b/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/BuilderAndTargetInfo.cs @@ -17,14 +17,16 @@ internal BuilderAndTargetInfo( { Namespace = @namespace; FluentApiClassName = fluentApiClassName; - FluentApiClassNameWithTypeParameters = WithTypeParameters(fluentApiClassName, genericInfo); + FluentApiClassNameWithTypeParameters = + ClassInfoFactory.AugmentTypeNameWithGenericParameters(fluentApiClassName, genericInfo); GenericInfo = genericInfo; FluentApiTypeIsStruct = fluentApiTypeIsStruct; FluentApiTypeIsInternal = fluentApiTypeIsInternal; DefaultAccessModifier = fluentApiTypeIsInternal ? "internal" : "public"; FluentApiTypeConstructorInfo = fluentApiTypeConstructorInfo; BuilderClassName = builderClassName; - BuilderClassNameWithTypeParameters = WithTypeParameters(builderClassName, genericInfo); + BuilderClassNameWithTypeParameters = + ClassInfoFactory.AugmentTypeNameWithGenericParameters(builderClassName, genericInfo); BuilderInstanceName = builderClassName.FirstCharToLower(); ClassInstanceName = fluentApiClassName.FirstCharToLower(); InitialStepInterfaceName = $"I{builderClassName}"; @@ -43,10 +45,4 @@ internal BuilderAndTargetInfo( internal string BuilderInstanceName { get; } internal string ClassInstanceName { get; } internal string InitialStepInterfaceName { get; } - - private static string WithTypeParameters(string typeName, GenericInfo? genericInfo) - { - string parameterListInAngleBrackets = genericInfo?.ParameterListInAngleBrackets ?? string.Empty; - return $"{typeName}{parameterListInAngleBrackets}"; - } } \ No newline at end of file diff --git a/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/FluentApiSymbolInfo.cs b/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/FluentApiSymbolInfo.cs index 65d079c..4902a9b 100644 --- a/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/FluentApiSymbolInfo.cs +++ b/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/FluentApiSymbolInfo.cs @@ -5,22 +5,29 @@ namespace M31.FluentApi.Generator.CodeGeneration.CodeBoardElements; internal abstract class FluentApiSymbolInfo { - internal FluentApiSymbolInfo(string name, Accessibility accessibility, bool requiresReflection) + internal FluentApiSymbolInfo( + string name, + string declaringClassNameWithTypeParameters, + Accessibility accessibility, + bool requiresReflection) { Name = name; NameInCamelCase = Name.TrimStart('_').FirstCharToLower(); + DeclaringClassNameWithTypeParameters = declaringClassNameWithTypeParameters; Accessibility = accessibility; RequiresReflection = requiresReflection; } internal string Name { get; } internal string NameInCamelCase { get; } + internal string DeclaringClassNameWithTypeParameters { get; } internal Accessibility Accessibility { get; } internal bool RequiresReflection { get; } protected bool Equals(FluentApiSymbolInfo other) { return Name == other.Name && + DeclaringClassNameWithTypeParameters == other.DeclaringClassNameWithTypeParameters && Accessibility == other.Accessibility && RequiresReflection == other.RequiresReflection; } @@ -35,6 +42,6 @@ public override bool Equals(object? obj) public override int GetHashCode() { - return new HashCode().Add(Name, Accessibility, RequiresReflection); + return new HashCode().Add(Name, DeclaringClassNameWithTypeParameters, Accessibility, RequiresReflection); } } \ No newline at end of file diff --git a/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/MemberSymbolInfo.cs b/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/MemberSymbolInfo.cs index 8473ee0..8fc7fa3 100644 --- a/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/MemberSymbolInfo.cs +++ b/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/MemberSymbolInfo.cs @@ -9,13 +9,14 @@ internal class MemberSymbolInfo : FluentApiSymbolInfo internal MemberSymbolInfo( string name, string type, + string declaringClassNameWithTypeParameters, Accessibility accessibility, bool requiresReflection, string typeForCodeGeneration, bool isNullable, bool isProperty, CollectionType? collectionType) - : base(name, accessibility, requiresReflection) + : base(name, declaringClassNameWithTypeParameters, accessibility, requiresReflection) { Type = type; TypeForCodeGeneration = typeForCodeGeneration; diff --git a/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/MethodSymbolInfo.cs b/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/MethodSymbolInfo.cs index cd1b6a0..8a534d4 100644 --- a/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/MethodSymbolInfo.cs +++ b/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardElements/MethodSymbolInfo.cs @@ -8,12 +8,13 @@ internal class MethodSymbolInfo : FluentApiSymbolInfo { internal MethodSymbolInfo( string name, + string declaringClassNameWithTypeParameters, Accessibility accessibility, bool requiresReflection, GenericInfo? genericInfo, IReadOnlyCollection parameterInfos, string returnType) - : base(name, accessibility, requiresReflection) + : base(name, declaringClassNameWithTypeParameters, accessibility, requiresReflection) { GenericInfo = genericInfo; ParameterInfos = parameterInfos; diff --git a/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs b/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs index e31629e..3c55555 100644 --- a/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs +++ b/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs @@ -57,10 +57,7 @@ private ClassInfoResult CreateFluentApiClassInfoInternal( bool isStruct = syntaxKind is SyntaxKind.StructDeclaration or SyntaxKind.RecordStructDeclaration; FluentApiClassInfo? classInfo = CreateFluentApiClassInfo( - typeData.Type, - typeData.GenericInfo, - typeData.AttributeData, - typeData.UsingStatements, + typeData, isStruct, generatorConfig.NewLineString, cancellationToken); @@ -75,36 +72,48 @@ private ClassInfoResult CreateFluentApiClassInfoInternal( } private FluentApiClassInfo? CreateFluentApiClassInfo( - INamedTypeSymbol type, - GenericInfo? genericInfo, - AttributeDataExtended attributeDataExtended, - IReadOnlyCollection usingStatements, + TypeData typeData, bool isStruct, string newLineString, CancellationToken cancellationToken) { - string className = type.Name; - string? @namespace = type.ContainingNamespace.IsGlobalNamespace ? null : type.ContainingNamespace.ToString(); - bool isInternal = type.DeclaredAccessibility == Accessibility.Internal; - ConstructorInfo? constructorInfo = TryGetConstructorInfo(type); + string className = typeData.Type.Name; + string? @namespace = typeData.Type.ContainingNamespace.IsGlobalNamespace + ? null + : typeData.Type.ContainingNamespace.ToString(); + bool isInternal = typeData.Type.DeclaredAccessibility == Accessibility.Internal; + ConstructorInfo? constructorInfo = TryGetConstructorInfo(typeData.Type); FluentApiAttributeInfo fluentApiAttributeInfo = - FluentApiAttributeInfo.Create(attributeDataExtended.AttributeData, className); + FluentApiAttributeInfo.Create(typeData.AttributeDataExtended.AttributeData, className); HashSet infos = new HashSet(); - ISymbol[] members = GetMembers(type).ToArray(); + (ITypeSymbol declaringType, ISymbol[] members)[] allMembers = + GetMembersOfTypeAndBaseTypes(typeData.Type).ToArray(); - foreach (ISymbol member in members) + foreach ((ITypeSymbol declaringType, ISymbol[] members) in allMembers) { - if (cancellationToken.IsCancellationRequested) + if (declaringType is not INamedTypeSymbol namedTypeSymbol) { - return null; + throw new GenerationException($"The type {declaringType.Name} is not a named type symbol."); } - FluentApiInfo? fluentApiInfo = TryCreateFluentApiInfo(member); + GenericInfo? genericInfo = GenericInfo.TryCreate(namedTypeSymbol); + string declaringClassNameWithGenericParameters = + AugmentTypeNameWithGenericParameters(namedTypeSymbol.Name, genericInfo); - if (fluentApiInfo != null) + foreach (ISymbol member in members) { - infos.Add(fluentApiInfo); + if (cancellationToken.IsCancellationRequested) + { + return null; + } + + FluentApiInfo? fluentApiInfo = TryCreateFluentApiInfo(member, declaringClassNameWithGenericParameters); + + if (fluentApiInfo != null) + { + infos.Add(fluentApiInfo); + } } } @@ -113,33 +122,40 @@ private ClassInfoResult CreateFluentApiClassInfoInternal( return new FluentApiClassInfo( className, @namespace, - genericInfo, + typeData.GenericInfo, isStruct, isInternal, constructorInfo!, fluentApiAttributeInfo.BuilderClassName, newLineString, infos, - usingStatements, + typeData.UsingStatements, new FluentApiClassAdditionalInfo(groups)); } - private static IEnumerable GetMembers(ITypeSymbol typeSymbol) + private static List<(ITypeSymbol declaringType, ISymbol[] members)> GetMembersOfTypeAndBaseTypes( + ITypeSymbol typeSymbol) { - foreach (ISymbol member in typeSymbol.GetMembers() - .Where(m => m.CanBeReferencedByName && m.Name != string.Empty)) - { - yield return member; - } + List<(ITypeSymbol declaringType, ISymbol[] members)> result = + new List<(ITypeSymbol declaringType, ISymbol[] members)>(); - if (typeSymbol.BaseType == null || typeSymbol.BaseType.SpecialType == SpecialType.System_Object) - { - yield break; - } + GetMembers(typeSymbol); + return result; - foreach (ISymbol member in GetMembers(typeSymbol.BaseType)) + void GetMembers(ITypeSymbol currentTypeSymbol) { - yield return member; + ISymbol[] members = currentTypeSymbol.GetMembers() + .Where(m => m.CanBeReferencedByName && m.Name != string.Empty).ToArray(); + + result.Add((currentTypeSymbol, members)); + + if (currentTypeSymbol.BaseType == null || + currentTypeSymbol.BaseType.SpecialType == SpecialType.System_Object) + { + return; + } + + GetMembers(currentTypeSymbol.BaseType); } } @@ -185,7 +201,7 @@ with the fewest parameters that is explicitly declared. */ constructors[0].DeclaredAccessibility != Accessibility.Public); } - private FluentApiInfo? TryCreateFluentApiInfo(ISymbol symbol) + private FluentApiInfo? TryCreateFluentApiInfo(ISymbol symbol, string declaringClassNameWithTypeParameters) { AttributeDataExtractor extractor = new AttributeDataExtractor(report); FluentApiAttributeData? attributeData = extractor.GetAttributeData(symbol); @@ -202,6 +218,12 @@ with the fewest parameters that is explicitly declared. */ } FluentApiInfoCreator fluentApiInfoCreator = new FluentApiInfoCreator(report); - return fluentApiInfoCreator.Create(symbol, attributeData); + return fluentApiInfoCreator.Create(symbol, attributeData, declaringClassNameWithTypeParameters); + } + + public static string AugmentTypeNameWithGenericParameters(string typeName, GenericInfo? genericInfo) + { + string parameterListInAngleBrackets = genericInfo?.ParameterListInAngleBrackets ?? string.Empty; + return $"{typeName}{parameterListInAngleBrackets}"; } } \ No newline at end of file diff --git a/src/M31.FluentApi.Generator/SourceGenerators/FluentApiInfoCreator.cs b/src/M31.FluentApi.Generator/SourceGenerators/FluentApiInfoCreator.cs index 884c5b1..9cc3d4b 100644 --- a/src/M31.FluentApi.Generator/SourceGenerators/FluentApiInfoCreator.cs +++ b/src/M31.FluentApi.Generator/SourceGenerators/FluentApiInfoCreator.cs @@ -17,9 +17,12 @@ internal FluentApiInfoCreator(ClassInfoReport classInfoReport) this.classInfoReport = classInfoReport; } - internal FluentApiInfo? Create(ISymbol symbol, FluentApiAttributeData attributeData) + internal FluentApiInfo? Create( + ISymbol symbol, + FluentApiAttributeData attributeData, + string declaringClassNameWithTypeParameters) { - FluentApiSymbolInfo symbolInfo = SymbolInfoCreator.Create(symbol); + FluentApiSymbolInfo symbolInfo = SymbolInfoCreator.Create(symbol, declaringClassNameWithTypeParameters); AttributeInfoBase? attributeInfo = CreateAttributeInfo(attributeData.MainAttributeData, symbol, symbolInfo); if (attributeInfo == null) diff --git a/src/M31.FluentApi.Generator/SourceGenerators/Generics/GenericInfo.cs b/src/M31.FluentApi.Generator/SourceGenerators/Generics/GenericInfo.cs index f06f47a..6c97a46 100644 --- a/src/M31.FluentApi.Generator/SourceGenerators/Generics/GenericInfo.cs +++ b/src/M31.FluentApi.Generator/SourceGenerators/Generics/GenericInfo.cs @@ -10,6 +10,11 @@ private GenericInfo(IReadOnlyCollection parameters) Parameters = parameters; } + internal static GenericInfo? TryCreate(INamedTypeSymbol type) + { + return type.IsGenericType ? Create(type.TypeParameters) : null; + } + internal static GenericInfo Create(IEnumerable typeParameters) { GenericTypeParameter[] parameters = diff --git a/src/M31.FluentApi.Generator/SourceGenerators/SymbolInfoCreator.cs b/src/M31.FluentApi.Generator/SourceGenerators/SymbolInfoCreator.cs index 2644041..36a689c 100644 --- a/src/M31.FluentApi.Generator/SourceGenerators/SymbolInfoCreator.cs +++ b/src/M31.FluentApi.Generator/SourceGenerators/SymbolInfoCreator.cs @@ -9,22 +9,31 @@ namespace M31.FluentApi.Generator.SourceGenerators; internal static class SymbolInfoCreator { - internal static FluentApiSymbolInfo Create(ISymbol symbol) + internal static FluentApiSymbolInfo Create(ISymbol symbol, string declaringClassNameWithTypeParameters) { return symbol switch { - IPropertySymbol propertySymbol => CreateMemberSymbolInfo(propertySymbol), - IFieldSymbol fieldSymbol => CreateMemberSymbolInfo(fieldSymbol), - IMethodSymbol methodSymbol => CreateMethodSymbolInfo(methodSymbol), + IPropertySymbol propertySymbol => CreateMemberSymbolInfo( + propertySymbol, + declaringClassNameWithTypeParameters), + IFieldSymbol fieldSymbol => CreateMemberSymbolInfo( + fieldSymbol, + declaringClassNameWithTypeParameters), + IMethodSymbol methodSymbol => CreateMethodSymbolInfo( + methodSymbol, + declaringClassNameWithTypeParameters), _ => throw new ArgumentException($"Unexpected symbol type: {symbol.GetType()}."), }; } - private static MemberSymbolInfo CreateMemberSymbolInfo(IFieldSymbol fieldSymbol) + private static MemberSymbolInfo CreateMemberSymbolInfo( + IFieldSymbol fieldSymbol, + string declaringClassNameWithTypeParameters) { return new MemberSymbolInfo( fieldSymbol.Name, fieldSymbol.Type.ToString(), + declaringClassNameWithTypeParameters, fieldSymbol.DeclaredAccessibility, RequiresReflection(fieldSymbol), CodeTypeExtractor.GetTypeForCodeGeneration(fieldSymbol.Type), @@ -33,11 +42,14 @@ private static MemberSymbolInfo CreateMemberSymbolInfo(IFieldSymbol fieldSymbol) CollectionInference.InferCollectionType(fieldSymbol.Type)); } - private static MemberSymbolInfo CreateMemberSymbolInfo(IPropertySymbol propertySymbol) + private static MemberSymbolInfo CreateMemberSymbolInfo( + IPropertySymbol propertySymbol, + string declaringClassNameWithTypeParameters) { return new MemberSymbolInfo( propertySymbol.Name, propertySymbol.Type.ToString(), + declaringClassNameWithTypeParameters, propertySymbol.DeclaredAccessibility, RequiresReflection(propertySymbol), CodeTypeExtractor.GetTypeForCodeGeneration(propertySymbol.Type), @@ -46,7 +58,9 @@ private static MemberSymbolInfo CreateMemberSymbolInfo(IPropertySymbol propertyS CollectionInference.InferCollectionType(propertySymbol.Type)); } - private static MethodSymbolInfo CreateMethodSymbolInfo(IMethodSymbol methodSymbol) + private static MethodSymbolInfo CreateMethodSymbolInfo( + IMethodSymbol methodSymbol, + string declaringClassNameWithTypeParameters) { GenericInfo? genericInfo = GetGenericInfo(methodSymbol); Dictionary typeParameterNameToTypeParameterPosition = genericInfo == null @@ -59,6 +73,7 @@ private static MethodSymbolInfo CreateMethodSymbolInfo(IMethodSymbol methodSymbo return new MethodSymbolInfo( methodSymbol.Name, + declaringClassNameWithTypeParameters, methodSymbol.DeclaredAccessibility, RequiresReflection(methodSymbol), genericInfo, diff --git a/src/M31.FluentApi.Generator/SourceGenerators/TypeData.cs b/src/M31.FluentApi.Generator/SourceGenerators/TypeData.cs index ba38bbf..be301ac 100644 --- a/src/M31.FluentApi.Generator/SourceGenerators/TypeData.cs +++ b/src/M31.FluentApi.Generator/SourceGenerators/TypeData.cs @@ -9,17 +9,17 @@ internal class TypeData internal TypeData( INamedTypeSymbol type, GenericInfo? genericInfo, - AttributeDataExtended attributeData, + AttributeDataExtended attributeDataExtended, IReadOnlyCollection usingStatements) { Type = type; GenericInfo = genericInfo; - AttributeData = attributeData; + AttributeDataExtended = attributeDataExtended; UsingStatements = usingStatements; } internal INamedTypeSymbol Type { get; } internal GenericInfo? GenericInfo { get; } - internal AttributeDataExtended AttributeData { get; } + internal AttributeDataExtended AttributeDataExtended { get; } internal IReadOnlyCollection UsingStatements { get; } } \ No newline at end of file diff --git a/src/M31.FluentApi.Generator/SourceGenerators/TypeDataCreator.cs b/src/M31.FluentApi.Generator/SourceGenerators/TypeDataCreator.cs index bce3dab..384279f 100644 --- a/src/M31.FluentApi.Generator/SourceGenerators/TypeDataCreator.cs +++ b/src/M31.FluentApi.Generator/SourceGenerators/TypeDataCreator.cs @@ -27,7 +27,7 @@ internal TypeDataCreator(ClassInfoReport report) return null; } - GenericInfo? genericInfo = GetGenericInfo(type); + GenericInfo? genericInfo = GenericInfo.TryCreate(type); AttributeDataExtended[] attributeData = type.GetAttributes().Select(AttributeDataExtended.Create) .OfType().Where(a => a.FullName == Attributes.FullNames.FluentApiAttribute) @@ -72,9 +72,4 @@ internal TypeDataCreator(ClassInfoReport report) return GetUsingStatements(syntaxNode.Parent); } - - private GenericInfo? GetGenericInfo(INamedTypeSymbol type) - { - return type.IsGenericType ? GenericInfo.Create(type.TypeParameters) : null; - } } \ No newline at end of file diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.expected.txt index 96443ad..4702ea6 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.expected.txt +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.expected.txt @@ -25,8 +25,8 @@ public class CreateStudent : static CreateStudent() { semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; - namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; - dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; } private CreateStudent() diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.g.cs index 96443ad..4702ea6 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.g.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.g.cs @@ -25,8 +25,8 @@ public class CreateStudent : static CreateStudent() { semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; - namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; - dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; } private CreateStudent() diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.expected.txt index b264c7f..268142c 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.expected.txt +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.expected.txt @@ -25,8 +25,8 @@ public class CreateStudent : static CreateStudent() { semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.NonPublic)!; - namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic)!; - dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.NonPublic)!; + namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic)!; + dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.NonPublic)!; } private CreateStudent() diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.g.cs index b264c7f..268142c 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.g.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.g.cs @@ -25,8 +25,8 @@ public class CreateStudent : static CreateStudent() { semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.NonPublic)!; - namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic)!; - dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.NonPublic)!; + namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic)!; + dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.NonPublic)!; } private CreateStudent() diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.expected.txt index 8ccdd0e..f48c704 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.expected.txt +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.expected.txt @@ -25,8 +25,8 @@ public class CreateStudent : static CreateStudent() { semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; - namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; - dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; } private CreateStudent() diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.g.cs index 8ccdd0e..f48c704 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.g.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.g.cs @@ -25,8 +25,8 @@ public class CreateStudent : static CreateStudent() { semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; - namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; - dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; } private CreateStudent() diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.expected.txt index 4ed5de1..c3c4286 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.expected.txt +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.expected.txt @@ -25,8 +25,8 @@ public class CreateStudent : static CreateStudent() { semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; - namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; - dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; } private CreateStudent() diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.g.cs index 4ed5de1..c3c4286 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.g.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedRecord/CreateStudent.g.cs @@ -25,8 +25,8 @@ public class CreateStudent : static CreateStudent() { semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; - namePropertyInfo = typeof(Student).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; - dateOfBirthPropertyInfo = typeof(Student).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; } private CreateStudent() From de56c0f20e2e822ddaa7b024ce4987906837bdaf Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Thu, 26 Sep 2024 16:35:59 +0200 Subject: [PATCH 12/15] fix: InnerBodyForMethodGenerator --- .../InnerBodyForMethodGenerator.cs | 2 +- .../CodeGenerationExecutionTests.cs | 2 +- .../CreateStudent.expected.txt | 34 ++++++++++++++----- .../CreateStudent.g.cs | 34 ++++++++++++++----- .../InheritedClassPrivateSetters/Person.cs | 13 +++++-- 5 files changed, 63 insertions(+), 22 deletions(-) diff --git a/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardActors/InnerBodyGeneration/InnerBodyForMethodGenerator.cs b/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardActors/InnerBodyGeneration/InnerBodyForMethodGenerator.cs index 2d14707..bad8118 100644 --- a/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardActors/InnerBodyGeneration/InnerBodyForMethodGenerator.cs +++ b/src/M31.FluentApi.Generator/CodeGeneration/CodeBoardActors/InnerBodyGeneration/InnerBodyForMethodGenerator.cs @@ -194,7 +194,7 @@ protected override void InitializeInfoField(string fieldName, MethodSymbolInfo s // Generic types are created via Type.MakeGenericMethodParameter(int position). In addition, a ref type is // specified via MakeByRefType(). staticConstructor.AppendBodyLine($"{fieldName} = " + - $"typeof({CodeBoard.Info.FluentApiClassNameWithTypeParameters}).GetMethod("); + $"typeof({symbolInfo.DeclaringClassNameWithTypeParameters}).GetMethod("); staticConstructor.AppendBodyLine($"{indentation}\"{symbolInfo.Name}\","); staticConstructor.AppendBodyLine($"{indentation}{GetGenericParameterCount(symbolInfo.GenericInfo)},"); staticConstructor.AppendBodyLine($"{indentation}{InfoFieldBindingFlagsArgument(symbolInfo)},"); diff --git a/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs b/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs index 7b22e16..f75069f 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs @@ -473,7 +473,7 @@ public void CanExecuteInheritedClassPrivateSetters() .InSemester(2); Assert.Equal("Alice", student.Name); - Assert.Equal(new DateOnly(2002, 8, 3), student.DateOfBirth); + Assert.Equal(22, student.Age); Assert.Equal(2, student.Semester); } diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.expected.txt index 4702ea6..a4ca5b5 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.expected.txt +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.expected.txt @@ -14,19 +14,27 @@ namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass public class CreateStudent : CreateStudent.ICreateStudent, CreateStudent.IWithName, - CreateStudent.IBornOn, + CreateStudent.IOfAgeBornOn, CreateStudent.IInSemester { private readonly Student student; private static readonly PropertyInfo semesterPropertyInfo; private static readonly PropertyInfo namePropertyInfo; - private static readonly PropertyInfo dateOfBirthPropertyInfo; + private static readonly PropertyInfo agePropertyInfo; + private static readonly MethodInfo bornOnMethodInfo; static CreateStudent() { semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; - dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + agePropertyInfo = typeof(Person).GetProperty("Age", BindingFlags.Instance | BindingFlags.Public)!; + bornOnMethodInfo = typeof(Person).GetMethod( + "BornOn", + 0, + BindingFlags.Instance | BindingFlags.NonPublic, + null, + new Type[] { typeof(System.DateOnly) }, + null)!; } private CreateStudent() @@ -39,22 +47,28 @@ public class CreateStudent : return new CreateStudent(); } - public static IBornOn WithName(string name) + public static IOfAgeBornOn WithName(string name) { CreateStudent createStudent = new CreateStudent(); CreateStudent.namePropertyInfo.SetValue(createStudent.student, name); return createStudent; } - IBornOn IWithName.WithName(string name) + IOfAgeBornOn IWithName.WithName(string name) { CreateStudent.namePropertyInfo.SetValue(student, name); return this; } - IInSemester IBornOn.BornOn(System.DateOnly dateOfBirth) + IInSemester IOfAgeBornOn.OfAge(int age) { - CreateStudent.dateOfBirthPropertyInfo.SetValue(student, dateOfBirth); + CreateStudent.agePropertyInfo.SetValue(student, age); + return this; + } + + IInSemester IOfAgeBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreateStudent.bornOnMethodInfo.Invoke(student, new object?[] { dateOfBirth }); return this; } @@ -70,11 +84,13 @@ public class CreateStudent : public interface IWithName { - IBornOn WithName(string name); + IOfAgeBornOn WithName(string name); } - public interface IBornOn + public interface IOfAgeBornOn { + IInSemester OfAge(int age); + IInSemester BornOn(System.DateOnly dateOfBirth); } diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.g.cs index 4702ea6..a4ca5b5 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.g.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.g.cs @@ -14,19 +14,27 @@ namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass public class CreateStudent : CreateStudent.ICreateStudent, CreateStudent.IWithName, - CreateStudent.IBornOn, + CreateStudent.IOfAgeBornOn, CreateStudent.IInSemester { private readonly Student student; private static readonly PropertyInfo semesterPropertyInfo; private static readonly PropertyInfo namePropertyInfo; - private static readonly PropertyInfo dateOfBirthPropertyInfo; + private static readonly PropertyInfo agePropertyInfo; + private static readonly MethodInfo bornOnMethodInfo; static CreateStudent() { semesterPropertyInfo = typeof(Student).GetProperty("Semester", BindingFlags.Instance | BindingFlags.Public)!; namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; - dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + agePropertyInfo = typeof(Person).GetProperty("Age", BindingFlags.Instance | BindingFlags.Public)!; + bornOnMethodInfo = typeof(Person).GetMethod( + "BornOn", + 0, + BindingFlags.Instance | BindingFlags.NonPublic, + null, + new Type[] { typeof(System.DateOnly) }, + null)!; } private CreateStudent() @@ -39,22 +47,28 @@ public static ICreateStudent InitialStep() return new CreateStudent(); } - public static IBornOn WithName(string name) + public static IOfAgeBornOn WithName(string name) { CreateStudent createStudent = new CreateStudent(); CreateStudent.namePropertyInfo.SetValue(createStudent.student, name); return createStudent; } - IBornOn IWithName.WithName(string name) + IOfAgeBornOn IWithName.WithName(string name) { CreateStudent.namePropertyInfo.SetValue(student, name); return this; } - IInSemester IBornOn.BornOn(System.DateOnly dateOfBirth) + IInSemester IOfAgeBornOn.OfAge(int age) { - CreateStudent.dateOfBirthPropertyInfo.SetValue(student, dateOfBirth); + CreateStudent.agePropertyInfo.SetValue(student, age); + return this; + } + + IInSemester IOfAgeBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreateStudent.bornOnMethodInfo.Invoke(student, new object?[] { dateOfBirth }); return this; } @@ -70,11 +84,13 @@ public interface ICreateStudent : IWithName public interface IWithName { - IBornOn WithName(string name); + IOfAgeBornOn WithName(string name); } - public interface IBornOn + public interface IOfAgeBornOn { + IInSemester OfAge(int age); + IInSemester BornOn(System.DateOnly dateOfBirth); } diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/Person.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/Person.cs index 72ef05a..195b03f 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/Person.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/Person.cs @@ -13,6 +13,15 @@ public class Person [FluentMember(0, "WithName")] public string Name { get; private set; } - [FluentMember(1, "BornOn")] - public DateOnly DateOfBirth{ get; private set; } + [FluentMember(1, "OfAge")] + public int Age { get; private set; } + + [FluentMethod(1)] + private void BornOn(DateOnly dateOfBirth) + { + DateOnly today = new DateOnly(2024, 9, 26); + int age = today.Year - dateOfBirth.Year; + if (dateOfBirth > today.AddYears(-age)) age--; + Age = age; + } } \ No newline at end of file From ac85cd3eefa4c6860eb9ef6e9681170470e8381f Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Thu, 26 Sep 2024 16:38:26 +0200 Subject: [PATCH 13/15] refactor(ClassInfoFactory): use List instead of HashSet --- .../SourceGenerators/ClassInfoFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs b/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs index 3c55555..829d953 100644 --- a/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs +++ b/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs @@ -86,7 +86,7 @@ private ClassInfoResult CreateFluentApiClassInfoInternal( FluentApiAttributeInfo fluentApiAttributeInfo = FluentApiAttributeInfo.Create(typeData.AttributeDataExtended.AttributeData, className); - HashSet infos = new HashSet(); + List infos = new List(); (ITypeSymbol declaringType, ISymbol[] members)[] allMembers = GetMembersOfTypeAndBaseTypes(typeData.Type).ToArray(); From 0a59bea133d7cb927c471ffab4a1ac1354395ae3 Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Thu, 26 Sep 2024 16:47:56 +0200 Subject: [PATCH 14/15] fix: commit generated file --- .../CreatePerson.g.cs | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreatePerson.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreatePerson.g.cs index 95bec0f..f78dd93 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreatePerson.g.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreatePerson.g.cs @@ -14,16 +14,24 @@ namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.InheritedClass public class CreatePerson : CreatePerson.ICreatePerson, CreatePerson.IWithName, - CreatePerson.IBornOn + CreatePerson.IOfAgeBornOn { private readonly Person person; private static readonly PropertyInfo namePropertyInfo; - private static readonly PropertyInfo dateOfBirthPropertyInfo; + private static readonly PropertyInfo agePropertyInfo; + private static readonly MethodInfo bornOnMethodInfo; static CreatePerson() { namePropertyInfo = typeof(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; - dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.Public)!; + agePropertyInfo = typeof(Person).GetProperty("Age", BindingFlags.Instance | BindingFlags.Public)!; + bornOnMethodInfo = typeof(Person).GetMethod( + "BornOn", + 0, + BindingFlags.Instance | BindingFlags.NonPublic, + null, + new Type[] { typeof(System.DateOnly) }, + null)!; } private CreatePerson() @@ -36,22 +44,28 @@ public static ICreatePerson InitialStep() return new CreatePerson(); } - public static IBornOn WithName(string name) + public static IOfAgeBornOn WithName(string name) { CreatePerson createPerson = new CreatePerson(); CreatePerson.namePropertyInfo.SetValue(createPerson.person, name); return createPerson; } - IBornOn IWithName.WithName(string name) + IOfAgeBornOn IWithName.WithName(string name) { CreatePerson.namePropertyInfo.SetValue(person, name); return this; } - Person IBornOn.BornOn(System.DateOnly dateOfBirth) + Person IOfAgeBornOn.OfAge(int age) { - CreatePerson.dateOfBirthPropertyInfo.SetValue(person, dateOfBirth); + CreatePerson.agePropertyInfo.SetValue(person, age); + return person; + } + + Person IOfAgeBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreatePerson.bornOnMethodInfo.Invoke(person, new object?[] { dateOfBirth }); return person; } @@ -61,11 +75,13 @@ public interface ICreatePerson : IWithName public interface IWithName { - IBornOn WithName(string name); + IOfAgeBornOn WithName(string name); } - public interface IBornOn + public interface IOfAgeBornOn { + Person OfAge(int age); + Person BornOn(System.DateOnly dateOfBirth); } } \ No newline at end of file From 3415ebcf4165d03ddaf8c01c42f268804be96a0e Mon Sep 17 00:00:00 2001 From: Kevin Schaal Date: Fri, 27 Sep 2024 12:56:21 +0200 Subject: [PATCH 15/15] chore: bump nuget version --- README.md | 2 +- src/M31.FluentApi.Generator/M31.FluentApi.Generator.csproj | 2 +- src/M31.FluentApi/M31.FluentApi.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 97042e9..5cdb1ab 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ PM> Install-Package M31.FluentApi A package reference will be added to your `csproj` file. Moreover, since this library provides code via source code generation, consumers of your project don't need the reference to `M31.FluentApi`. Therefore, it is recommended to use the `PrivateAssets` metadata tag: ```xml - + ``` If you would like to examine the generated code, you may emit it by adding the following lines to your `csproj` file: diff --git a/src/M31.FluentApi.Generator/M31.FluentApi.Generator.csproj b/src/M31.FluentApi.Generator/M31.FluentApi.Generator.csproj index 35f958d..fe5b9ee 100644 --- a/src/M31.FluentApi.Generator/M31.FluentApi.Generator.csproj +++ b/src/M31.FluentApi.Generator/M31.FluentApi.Generator.csproj @@ -11,7 +11,7 @@ true true true - 1.8.0 + 1.9.0 Kevin Schaal The generator package for M31.FluentAPI. Don't install this package explicitly, install M31.FluentAPI instead. fluentapi fluentbuilder fluentinterface fluentdesign fluent codegeneration diff --git a/src/M31.FluentApi/M31.FluentApi.csproj b/src/M31.FluentApi/M31.FluentApi.csproj index 84ee6e1..5d6e46a 100644 --- a/src/M31.FluentApi/M31.FluentApi.csproj +++ b/src/M31.FluentApi/M31.FluentApi.csproj @@ -7,7 +7,7 @@ enable true true - 1.8.0 + 1.9.0 Kevin Schaal Generate fluent builders in C#. fluentapi fluentbuilder fluentinterface fluentdesign fluent codegeneration