diff --git a/README.md b/README.md index 140f71d..5cdb1ab 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 @@ -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/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/Program.cs b/src/ExampleProject/Program.cs index 645728c..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 // 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/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.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/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.Generator/SourceGenerators/ClassInfoFactory.cs b/src/M31.FluentApi.Generator/SourceGenerators/ClassInfoFactory.cs index 7cd340e..829d953 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,35 +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); List infos = new List(); + (ITypeSymbol declaringType, ISymbol[] members)[] allMembers = + GetMembersOfTypeAndBaseTypes(typeData.Type).ToArray(); - foreach (var member in type.GetMembers().Where(m => m.CanBeReferencedByName && m.Name != string.Empty)) + 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); + } } } @@ -112,17 +122,43 @@ 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 List<(ITypeSymbol declaringType, ISymbol[] members)> GetMembersOfTypeAndBaseTypes( + ITypeSymbol typeSymbol) + { + List<(ITypeSymbol declaringType, ISymbol[] members)> result = + new List<(ITypeSymbol declaringType, ISymbol[] members)>(); + + GetMembers(typeSymbol); + return result; + + void GetMembers(ITypeSymbol currentTypeSymbol) + { + 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); + } + } + private ConstructorInfo? TryGetConstructorInfo(INamedTypeSymbol type) { /* Look for the default constructor. If it is not present, take the constructor @@ -165,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); @@ -182,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/CodeGenerationExecutionTests.cs b/src/M31.FluentApi.Tests/CodeGeneration/CodeGenerationExecutionTests.cs index 04770f8..f75069f 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,83 @@ 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 CanExecuteInheritedClassPrivateSetters() + { + var student = TestClasses.Abstract.InheritedClassPrivateSetters + .CreateStudent + .WithName("Alice") + .BornOn(new DateOnly(2002, 8, 3)) + .InSemester(2); + + Assert.Equal("Alice", student.Name); + Assert.Equal(22, student.Age); + 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 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/InheritedClass/CreatePerson.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreatePerson.g.cs new file mode 100644 index 0000000..e0494f0 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/CreatePerson.g.cs @@ -0,0 +1,62 @@ +// +// 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.IWithName, + CreatePerson.IBornOn +{ + private readonly Person person; + + private CreatePerson() + { + person = new Person(); + } + + public static ICreatePerson InitialStep() + { + return new CreatePerson(); + } + + public static IBornOn WithName(string name) + { + CreatePerson createPerson = new CreatePerson(); + createPerson.person.Name = name; + return createPerson; + } + + IBornOn IWithName.WithName(string name) + { + person.Name = name; + return this; + } + + Person IBornOn.BornOn(System.DateOnly dateOfBirth) + { + person.DateOfBirth = 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/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..9138a12 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/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.InheritedClass; + +[FluentApi] +public class 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/TestClasses/Abstract/InheritedClass/Student.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/Student.cs new file mode 100644 index 0000000..5635793 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClass/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.InheritedClass; + +[FluentApi] +public class Student : 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/InheritedClassPrivateSetters/CreatePerson.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreatePerson.g.cs new file mode 100644 index 0000000..f78dd93 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreatePerson.g.cs @@ -0,0 +1,87 @@ +// +// 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.IOfAgeBornOn +{ + private readonly Person person; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo agePropertyInfo; + private static readonly MethodInfo bornOnMethodInfo; + + static CreatePerson() + { + namePropertyInfo = typeof(Person).GetProperty("Name", 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() + { + person = new Person(); + } + + public static ICreatePerson InitialStep() + { + return new CreatePerson(); + } + + public static IOfAgeBornOn WithName(string name) + { + CreatePerson createPerson = new CreatePerson(); + CreatePerson.namePropertyInfo.SetValue(createPerson.person, name); + return createPerson; + } + + IOfAgeBornOn IWithName.WithName(string name) + { + CreatePerson.namePropertyInfo.SetValue(person, name); + return this; + } + + Person IOfAgeBornOn.OfAge(int age) + { + CreatePerson.agePropertyInfo.SetValue(person, age); + return person; + } + + Person IOfAgeBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreatePerson.bornOnMethodInfo.Invoke(person, new object?[] { dateOfBirth }); + return person; + } + + public interface ICreatePerson : IWithName + { + } + + public interface IWithName + { + IOfAgeBornOn WithName(string name); + } + + public interface IOfAgeBornOn + { + Person OfAge(int age); + + 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..a4ca5b5 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.expected.txt @@ -0,0 +1,101 @@ +// +// 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.IOfAgeBornOn, + CreateStudent.IInSemester +{ + private readonly Student student; + private static readonly PropertyInfo semesterPropertyInfo; + private static readonly PropertyInfo namePropertyInfo; + 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)!; + 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() + { + student = new Student(); + } + + public static ICreateStudent InitialStep() + { + return new CreateStudent(); + } + + public static IOfAgeBornOn WithName(string name) + { + CreateStudent createStudent = new CreateStudent(); + CreateStudent.namePropertyInfo.SetValue(createStudent.student, name); + return createStudent; + } + + IOfAgeBornOn IWithName.WithName(string name) + { + CreateStudent.namePropertyInfo.SetValue(student, name); + return this; + } + + IInSemester IOfAgeBornOn.OfAge(int age) + { + CreateStudent.agePropertyInfo.SetValue(student, age); + return this; + } + + IInSemester IOfAgeBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreateStudent.bornOnMethodInfo.Invoke(student, new object?[] { dateOfBirth }); + return this; + } + + Student IInSemester.InSemester(int semester) + { + CreateStudent.semesterPropertyInfo.SetValue(student, semester); + return student; + } + + public interface ICreateStudent : IWithName + { + } + + public interface IWithName + { + IOfAgeBornOn WithName(string name); + } + + public interface IOfAgeBornOn + { + IInSemester OfAge(int age); + + 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..a4ca5b5 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/CreateStudent.g.cs @@ -0,0 +1,101 @@ +// +// 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.IOfAgeBornOn, + CreateStudent.IInSemester +{ + private readonly Student student; + private static readonly PropertyInfo semesterPropertyInfo; + private static readonly PropertyInfo namePropertyInfo; + 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)!; + 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() + { + student = new Student(); + } + + public static ICreateStudent InitialStep() + { + return new CreateStudent(); + } + + public static IOfAgeBornOn WithName(string name) + { + CreateStudent createStudent = new CreateStudent(); + CreateStudent.namePropertyInfo.SetValue(createStudent.student, name); + return createStudent; + } + + IOfAgeBornOn IWithName.WithName(string name) + { + CreateStudent.namePropertyInfo.SetValue(student, name); + return this; + } + + IInSemester IOfAgeBornOn.OfAge(int age) + { + CreateStudent.agePropertyInfo.SetValue(student, age); + return this; + } + + IInSemester IOfAgeBornOn.BornOn(System.DateOnly dateOfBirth) + { + CreateStudent.bornOnMethodInfo.Invoke(student, new object?[] { dateOfBirth }); + return this; + } + + Student IInSemester.InSemester(int semester) + { + CreateStudent.semesterPropertyInfo.SetValue(student, semester); + return student; + } + + public interface ICreateStudent : IWithName + { + } + + public interface IWithName + { + IOfAgeBornOn WithName(string name); + } + + public interface IOfAgeBornOn + { + IInSemester OfAge(int age); + + 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..195b03f --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassPrivateSetters/Person.cs @@ -0,0 +1,27 @@ +// 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, "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 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/TestClasses/Abstract/InheritedClassProtectedMembers/CreatePerson.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreatePerson.g.cs new file mode 100644 index 0000000..e429f72 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/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.InheritedClassProtectedMembers; + +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.NonPublic)!; + dateOfBirthPropertyInfo = typeof(Person).GetProperty("DateOfBirth", BindingFlags.Instance | BindingFlags.NonPublic)!; + } + + 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/InheritedClassProtectedMembers/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/CreateStudent.expected.txt new file mode 100644 index 0000000..268142c --- /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 semesterPropertyInfo; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + + static CreateStudent() + { + semesterPropertyInfo = typeof(Student).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 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..268142c --- /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 semesterPropertyInfo; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + + static CreateStudent() + { + semesterPropertyInfo = typeof(Student).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 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..8fb6b94 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/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.InheritedClassProtectedMembers; + +[FluentApi] +public class 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/InheritedClassProtectedMembers/Student.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/Student.cs new file mode 100644 index 0000000..dbee594 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedMembers/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.InheritedClassProtectedMembers; + +[FluentApi] +public class Student : 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/InheritedClassProtectedSetters/CreatePerson.g.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreatePerson.g.cs new file mode 100644 index 0000000..ed0341a --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/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.InheritedClassProtectedSetters; + +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/InheritedClassProtectedSetters/CreateStudent.expected.txt b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/CreateStudent.expected.txt new file mode 100644 index 0000000..f48c704 --- /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 semesterPropertyInfo; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + + 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)!; + } + + 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..f48c704 --- /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 semesterPropertyInfo; + private static readonly PropertyInfo namePropertyInfo; + private static readonly PropertyInfo dateOfBirthPropertyInfo; + + 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)!; + } + + 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..e5206b2 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/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.InheritedClassProtectedSetters; + +[FluentApi] +public class 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/TestClasses/Abstract/InheritedClassProtectedSetters/Student.cs b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/Student.cs new file mode 100644 index 0000000..b20c6b4 --- /dev/null +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestClasses/Abstract/InheritedClassProtectedSetters/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.InheritedClassProtectedSetters; + +[FluentApi] +public class Student : 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/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..c3c4286 --- /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(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Person).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..c3c4286 --- /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(Person).GetProperty("Name", BindingFlags.Instance | BindingFlags.Public)!; + dateOfBirthPropertyInfo = typeof(Person).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 cba4ff3..6a0b15f 100644 --- a/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs +++ b/src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs @@ -57,6 +57,11 @@ 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", "InheritedClassPrivateSetters", "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" }, 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