diff --git a/docs/docs/configuration/static-mappers.md b/docs/docs/configuration/static-mappers.md index a2c53bf0c5..c49be0ba33 100644 --- a/docs/docs/configuration/static-mappers.md +++ b/docs/docs/configuration/static-mappers.md @@ -16,3 +16,24 @@ public static partial class CarMapper private static int TimeSpanToHours(TimeSpan t) => t.Hours; } ``` + +## Static methods in instantiable class + +Static methods are supported in non-static mapper classes. This supports the static interface use case. When a static mapping method is present, to simplify mapping method resolution and reduce confusion about which mapping method Mapperly uses, all methods must be static. + +```csharp +public interface ICarMapper +{ + static abstract CarDto ToDto(Car car); +} + +[Mapper] +// highlight-start +public partial class CarMapper : ICarMapper +// highlight-end +{ +// highlight-start + public static partial CarDto ToDto(Car car); +// highlight-end +} +``` diff --git a/docs/docs/contributing/architecture.md b/docs/docs/contributing/architecture.md index 45c7fe2d56..8416f61781 100644 --- a/docs/docs/contributing/architecture.md +++ b/docs/docs/contributing/architecture.md @@ -30,9 +30,9 @@ The `DescriptorBuilder` is responsible to build a `MapperDescriptor` which holds The `DescriptorBuilder` does this by following this process: 1. Extracting the configuration from the attributes -2. Extracting user implemented object factories -3. Extracting user implemented and user defined mapping methods. +2. Extracting user implemented and user defined mapping methods. It instantiates a `User*Mapping` (eg. `UserDefinedNewInstanceMethodMapping`) for each discovered mapping method and adds it to the queue of mappings to work on. +3. Extracting user implemented object factories 4. Extracting external mappings 5. For each mapping in the queue the `DescriptorBuilder` tries to build its implementation bodies. This is done by a so called `*MappingBodyBuilder`. diff --git a/src/Riok.Mapperly/AnalyzerReleases.Shipped.md b/src/Riok.Mapperly/AnalyzerReleases.Shipped.md index d8f8df9e79..02a59da661 100644 --- a/src/Riok.Mapperly/AnalyzerReleases.Shipped.md +++ b/src/Riok.Mapperly/AnalyzerReleases.Shipped.md @@ -126,3 +126,9 @@ Rule ID | Category | Severity | Notes RMG051 | Mapper | Warning | Invalid ignore source member found, nested ignores are not supported RMG052 | Mapper | Warning | Invalid ignore target member found, nested ignores are not supported RMG053 | Mapper | Error | The flag MemberVisibility.Accessible cannot be disabled, this feature requires .NET 8.0 or greater +RMG054 | Mapper | Error | Mapper class containing 'static partial' method must not have any instance methods + +### Removed Rules +Rule ID | Category | Severity | Notes +--------|----------|----------|------- +RMG018 | Mapper | Disabled | Partial static mapping method in an instance mapper diff --git a/src/Riok.Mapperly/Descriptors/DescriptorBuilder.cs b/src/Riok.Mapperly/Descriptors/DescriptorBuilder.cs index 64b95612f3..d9c7dd510a 100644 --- a/src/Riok.Mapperly/Descriptors/DescriptorBuilder.cs +++ b/src/Riok.Mapperly/Descriptors/DescriptorBuilder.cs @@ -6,6 +6,7 @@ using Riok.Mapperly.Descriptors.MappingBodyBuilders; using Riok.Mapperly.Descriptors.MappingBuilders; using Riok.Mapperly.Descriptors.ObjectFactories; +using Riok.Mapperly.Diagnostics; using Riok.Mapperly.Helpers; using Riok.Mapperly.Symbols; using Riok.Mapperly.Templates; @@ -28,8 +29,6 @@ public class DescriptorBuilder private readonly UnsafeAccessorContext _unsafeAccessorContext; private readonly MapperConfigurationReader _configurationReader; - private ObjectFactoryCollection _objectFactories = ObjectFactoryCollection.Empty; - public DescriptorBuilder( CompilationContext compilationContext, MapperDeclaration mapperDeclaration, @@ -63,8 +62,10 @@ MapperConfiguration defaultMapperConfiguration { ConfigureMemberVisibility(); ReserveMethodNames(); - ExtractObjectFactories(); ExtractUserMappings(); + // ExtractObjectFactories needs to be called after ExtractUserMappings due to configuring mapperDescriptor.Static + var objectFactories = ExtractObjectFactories(); + EnqueueUserMappings(objectFactories); ExtractExternalMappings(); _mappingBodyBuilder.BuildMappingBodies(cancellationToken); BuildMappingMethodNames(); @@ -106,24 +107,57 @@ private void ReserveMethodNames() } } - private void ExtractObjectFactories() + private void ExtractUserMappings() + { + _mapperDescriptor.Static = _mapperDescriptor.Symbol.IsStatic; + IMethodSymbol? firstNonStaticUserMapping = null; + + foreach (var userMapping in UserMethodMappingExtractor.ExtractUserMappings(_builderContext, _mapperDescriptor.Symbol)) + { + // if a user defined mapping method is static, all of them need to be static to avoid confusion for mapping method resolution + // however, user implemented mapping methods are allowed to be static in a non-static context. + // Therefore we are only interested in partial method definitions here. + if (userMapping.Method is { IsStatic: true, IsPartialDefinition: true }) + { + _mapperDescriptor.Static = true; + } + else if (firstNonStaticUserMapping == null && !userMapping.Method.IsStatic) + { + firstNonStaticUserMapping = userMapping.Method; + } + + _mappings.Add(userMapping); + } + + if (_mapperDescriptor.Static && firstNonStaticUserMapping is not null) + { + _diagnostics.Add( + Diagnostic.Create( + DiagnosticDescriptors.MixingStaticPartialWithInstanceMethod, + firstNonStaticUserMapping.Locations.FirstOrDefault(), + _mapperDescriptor.Symbol.ToDisplayString() + ) + ); + } + } + + private ObjectFactoryCollection ExtractObjectFactories() { - _objectFactories = ObjectFactoryBuilder.ExtractObjectFactories(_builderContext, _mapperDescriptor.Symbol); + return ObjectFactoryBuilder.ExtractObjectFactories(_builderContext, _mapperDescriptor.Symbol); } - private void ExtractUserMappings() + private void EnqueueUserMappings(ObjectFactoryCollection objectFactories) { - foreach (var userMapping in UserMethodMappingExtractor.ExtractUserMappings(_builderContext, _mapperDescriptor.Symbol)) + foreach (var userMapping in _mappings.UserMappings) { var ctx = new MappingBuilderContext( _builderContext, - _objectFactories, + objectFactories, userMapping.Method, userMapping.SourceType, userMapping.TargetType ); - _mappings.Add(userMapping); _mappings.EnqueueToBuildBody(userMapping, ctx); } } diff --git a/src/Riok.Mapperly/Descriptors/MapperDescriptor.cs b/src/Riok.Mapperly/Descriptors/MapperDescriptor.cs index 66c6d531b2..ce3fdc2aff 100644 --- a/src/Riok.Mapperly/Descriptors/MapperDescriptor.cs +++ b/src/Riok.Mapperly/Descriptors/MapperDescriptor.cs @@ -16,6 +16,8 @@ public class MapperDescriptor private readonly List _unsafeAccessors = new(); private readonly HashSet _requiredTemplates = new(); + public bool Static { get; set; } + public MapperDescriptor(MapperDeclaration declaration, UniqueNameBuilder nameBuilder) { _declaration = declaration; diff --git a/src/Riok.Mapperly/Descriptors/ObjectFactories/ObjectFactoryBuilder.cs b/src/Riok.Mapperly/Descriptors/ObjectFactories/ObjectFactoryBuilder.cs index 2f6bd4b8d3..54705ecdf5 100644 --- a/src/Riok.Mapperly/Descriptors/ObjectFactories/ObjectFactoryBuilder.cs +++ b/src/Riok.Mapperly/Descriptors/ObjectFactories/ObjectFactoryBuilder.cs @@ -28,6 +28,7 @@ public static ObjectFactoryCollection ExtractObjectFactories(SimpleMappingBuilde || methodSymbol.IsPartialDefinition || methodSymbol.MethodKind != MethodKind.Ordinary || methodSymbol.ReturnsVoid + || (!methodSymbol.IsStatic && ctx.Static) ) { ctx.ReportDiagnostic(DiagnosticDescriptors.InvalidObjectFactorySignature, methodSymbol, methodSymbol.Name); diff --git a/src/Riok.Mapperly/Descriptors/ObjectFactories/ObjectFactoryCollection.cs b/src/Riok.Mapperly/Descriptors/ObjectFactories/ObjectFactoryCollection.cs index d7e9ee3d6f..654d7a8fdf 100644 --- a/src/Riok.Mapperly/Descriptors/ObjectFactories/ObjectFactoryCollection.cs +++ b/src/Riok.Mapperly/Descriptors/ObjectFactories/ObjectFactoryCollection.cs @@ -5,8 +5,6 @@ namespace Riok.Mapperly.Descriptors.ObjectFactories; public class ObjectFactoryCollection { - public static readonly ObjectFactoryCollection Empty = new(Array.Empty()); - private readonly IReadOnlyCollection _objectFactories; private readonly Dictionary _concreteObjectFactories = new(SymbolEqualityComparer.IncludeNullability); diff --git a/src/Riok.Mapperly/Descriptors/SimpleMappingBuilderContext.cs b/src/Riok.Mapperly/Descriptors/SimpleMappingBuilderContext.cs index c00de0464f..71e0cc7c90 100644 --- a/src/Riok.Mapperly/Descriptors/SimpleMappingBuilderContext.cs +++ b/src/Riok.Mapperly/Descriptors/SimpleMappingBuilderContext.cs @@ -58,6 +58,8 @@ protected SimpleMappingBuilderContext(SimpleMappingBuilderContext ctx) public WellKnownTypes Types => _compilationContext.Types; + public bool Static => _descriptor.Static; + public SymbolAccessor SymbolAccessor { get; } public AttributeDataAccessor AttributeAccessor { get; } diff --git a/src/Riok.Mapperly/Descriptors/UserMethodMappingExtractor.cs b/src/Riok.Mapperly/Descriptors/UserMethodMappingExtractor.cs index bc3f112895..bdc7360c7e 100644 --- a/src/Riok.Mapperly/Descriptors/UserMethodMappingExtractor.cs +++ b/src/Riok.Mapperly/Descriptors/UserMethodMappingExtractor.cs @@ -17,8 +17,8 @@ internal static IEnumerable ExtractUserMappings(SimpleMappingBuild foreach (var methodSymbol in ExtractMethods(mapperSymbol)) { var mapping = - BuilderUserDefinedMapping(ctx, methodSymbol, mapperSymbol.IsStatic) - ?? BuildUserImplementedMapping(ctx, methodSymbol, null, false, mapperSymbol.IsStatic); + BuilderUserDefinedMapping(ctx, methodSymbol) + ?? BuildUserImplementedMapping(ctx, methodSymbol, receiver: null, allowPartial: false, mapperSymbol.IsStatic); if (mapping != null) yield return mapping; } @@ -109,18 +109,11 @@ bool isStatic : new UserImplementedMethodMapping(receiver, method, parameters.Source, parameters.ReferenceHandler); } - private static IUserMapping? BuilderUserDefinedMapping(SimpleMappingBuilderContext ctx, IMethodSymbol methodSymbol, bool isStatic) + private static IUserMapping? BuilderUserDefinedMapping(SimpleMappingBuilderContext ctx, IMethodSymbol methodSymbol) { if (!methodSymbol.IsPartialDefinition) return null; - if (!isStatic && methodSymbol.IsStatic) - { - ctx.ReportDiagnostic(DiagnosticDescriptors.PartialStaticMethodInInstanceMapper, methodSymbol, methodSymbol.Name); - - return null; - } - if (methodSymbol.IsAsync) { ctx.ReportDiagnostic(DiagnosticDescriptors.UnsupportedMappingMethodSignature, methodSymbol, methodSymbol.Name); diff --git a/src/Riok.Mapperly/Diagnostics/DiagnosticDescriptors.cs b/src/Riok.Mapperly/Diagnostics/DiagnosticDescriptors.cs index 36b45233ae..4dc7399376 100644 --- a/src/Riok.Mapperly/Diagnostics/DiagnosticDescriptors.cs +++ b/src/Riok.Mapperly/Diagnostics/DiagnosticDescriptors.cs @@ -159,15 +159,6 @@ public static class DiagnosticDescriptors true ); - public static readonly DiagnosticDescriptor PartialStaticMethodInInstanceMapper = new DiagnosticDescriptor( - "RMG018", - "Partial static mapping method in an instance mapper", - "{0} is a partial static mapping method in an instance mapper. Static mapping methods are only supported in static mappers.", - DiagnosticCategories.Mapper, - DiagnosticSeverity.Error, - true - ); - public static readonly DiagnosticDescriptor SourceMemberNotMapped = new DiagnosticDescriptor( "RMG020", "Source member is not mapped to any target member", @@ -473,4 +464,13 @@ public static class DiagnosticDescriptors DiagnosticSeverity.Error, true ); + + public static readonly DiagnosticDescriptor MixingStaticPartialWithInstanceMethod = new DiagnosticDescriptor( + "RMG054", + "Mapper class containing 'static partial' method must not have any instance methods", + "Mapper class {0} contains 'static partial' method. Use only instance method or only static methods.", + DiagnosticCategories.Mapper, + DiagnosticSeverity.Error, + true + ); } diff --git a/src/Riok.Mapperly/Emit/SourceEmitter.cs b/src/Riok.Mapperly/Emit/SourceEmitter.cs index a91c761403..f80cc93464 100644 --- a/src/Riok.Mapperly/Emit/SourceEmitter.cs +++ b/src/Riok.Mapperly/Emit/SourceEmitter.cs @@ -14,7 +14,7 @@ public static class SourceEmitter public static CompilationUnitSyntax Build(MapperDescriptor descriptor, CancellationToken cancellationToken) { var ctx = new SourceEmitterContext( - descriptor.Symbol.IsStatic, + descriptor.Static, descriptor.NameBuilder, new SyntaxFactoryHelper(descriptor.Symbol.ContainingAssembly.Name) ); diff --git a/src/Riok.Mapperly/MapperGenerator.cs b/src/Riok.Mapperly/MapperGenerator.cs index 1ff7968742..1631884d3c 100644 --- a/src/Riok.Mapperly/MapperGenerator.cs +++ b/src/Riok.Mapperly/MapperGenerator.cs @@ -1,4 +1,4 @@ -using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Riok.Mapperly.Abstractions; using Riok.Mapperly.Configuration; diff --git a/test/Riok.Mapperly.Tests/Mapping/DictionaryTest.cs b/test/Riok.Mapperly.Tests/Mapping/DictionaryTest.cs index cacc3c986f..45acb6eb5a 100644 --- a/test/Riok.Mapperly.Tests/Mapping/DictionaryTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/DictionaryTest.cs @@ -164,7 +164,11 @@ public void DictionaryToCustomDictionary() public void DictionaryToCustomDictionaryWithObjectFactory() { var source = TestSourceBuilder.MapperWithBodyAndTypes( - "[ObjectFactory] A CreateA() => new();" + "partial A Map(IDictionary source);", + """ + [ObjectFactory] + A CreateA() => new(); + partial A Map(IDictionary source); + """, "class A : Dictionary {}" ); TestHelper @@ -354,7 +358,11 @@ string IDictionary.this[string key] public void DictionaryToExplicitDictionaryWithObjectFactoryShouldCast() { var source = TestSourceBuilder.MapperWithBodyAndTypes( - "[ObjectFactory] A CreateA() => new();" + "partial A Map(Dictionary source);", + """ + [ObjectFactory] + A CreateA() => new(); + partial A Map(Dictionary source); + """, """ public class A : IDictionary { @@ -387,7 +395,11 @@ string IDictionary.this[string key] public void DictionaryToImplicitDictionaryWithObjectFactoryShouldNotCast() { var source = TestSourceBuilder.MapperWithBodyAndTypes( - "[ObjectFactory] A CreateA() => new();" + "partial A Map(Dictionary source);", + """ + [ObjectFactory] + A CreateA() => new(); + partial A Map(Dictionary source); + """, """ public class A : IDictionary { diff --git a/test/Riok.Mapperly.Tests/Mapping/InstantiableMapperWithStaticMethodsTest.cs b/test/Riok.Mapperly.Tests/Mapping/InstantiableMapperWithStaticMethodsTest.cs new file mode 100644 index 0000000000..bc448c3ce0 --- /dev/null +++ b/test/Riok.Mapperly.Tests/Mapping/InstantiableMapperWithStaticMethodsTest.cs @@ -0,0 +1,267 @@ +using Riok.Mapperly.Diagnostics; + +namespace Riok.Mapperly.Tests.Mapping; + +[UsesVerify] +public class InstantiableMapperWithStaticMethodsTest +{ + [Fact] + public Task StaticPartialMethod() + { + var source = TestSourceBuilder.CSharp( + """ + using Riok.Mapperly.Abstractions; + + record A(int Value); + record B(int Value); + + [Mapper] + public partial class Mapper + { + static partial B Map(A source); + } + """ + ); + + return TestHelper.VerifyGenerator(source); + } + + [Fact] + public Task MapperInNestedClassShouldWork() + { + var source = TestSourceBuilder.CSharp( + """ + using Riok.Mapperly.Abstractions; + + public static partial class CarFeature + { + public partial class Mappers + { + [Mapper] + public partial class CarMapper + { + static partial int ToInt(double value); + } + } + } + """ + ); + + return TestHelper.VerifyGenerator(source); + } + + [Fact] + public Task NestedMappingShouldWork() + { + var source = TestSourceBuilder.CSharp( + """ + using Riok.Mapperly.Abstractions; + + [Mapper] + public partial class CarMapper + { + static partial C MapToC(A value); + } + + public record A(B Value1); + public record B(int Value2); + + public record C(D Value1); + public record D(int Value2); + """ + ); + + return TestHelper.VerifyGenerator(source); + } + + [Fact] + public Task MappingWithUserMappingShouldWork() + { + var source = TestSourceBuilder.CSharp( + """ + using Riok.Mapperly.Abstractions; + + [Mapper] + public partial class CarMapper + { + static partial D MapToD(A value); + + static F MapToF(C value) => new F(value.Value3); + } + + public record A(B Value1); + public record B(C Value2); + public record C(int Value3); + + public record D(E Value1); + public record E(F Value2); + public record F(int Value3); + """ + ); + + return TestHelper.VerifyGenerator(source); + } + + [Fact] + public Task ShouldUseSimpleObjectFactory() + { + var source = TestSourceBuilder.CSharp( + """ + using Riok.Mapperly.Abstractions; + + [Mapper] + public partial class CarMapper + { + [ObjectFactory] + static B CreateB() => new B(); + + static partial B Map(A a); + } + + class A { public string StringValue { get; set; } } + class B { public string StringValue { get; set; } } + """ + ); + + return TestHelper.VerifyGenerator(source); + } + + [Fact] + public Task UseStaticGenericMapperStaticMethod() + { + var source = TestSourceBuilder.CSharp( + """ + using Riok.Mapperly.Abstractions; + + record A(AExternal Value); + record B(BExternal Value); + record AExternal(); + record BExternal(); + + class OtherMapper { + public static BExternal ToBExternal(AExternal source) => new BExternal(); + } + + [Mapper] + [UseStaticMapper] + public partial class Mapper + { + static partial B Map(A source); + } + """ + ); + + return TestHelper.VerifyGenerator(source); + } + + [Fact] + public Task IgnoreInstanceMethodFromStaticMapper() + { + var source = TestSourceBuilder.CSharp( + """ + using Riok.Mapperly.Abstractions; + using Riok.Mapperly.Abstractions.ReferenceHandling; + + record A(AExternal Value); + record B(BExternal Value); + record AExternal(); + record BExternal(); + + class OtherMapper { + public BExternal ToBExternal(AExternal source) => new BExternal(); + } + + [Mapper] + [UseStaticMapper] + public partial class Mapper + { + static partial B Map(A source); + } + """ + ); + + return TestHelper.VerifyGenerator(source); + } + + [Fact] + public void MixedStaticMethodWithPartialInstanceMethod() + { + var source = TestSourceBuilder.CSharp( + """ + using Riok.Mapperly.Abstractions; + + record A(int Value); + record B(int Value); + + [Mapper] + public partial class Mapper + { + static partial B Map(A source); + + partial B Map2(A source); + } + """ + ); + + TestHelper + .GenerateMapper(source, TestHelperOptions.AllowAllDiagnostics) + .Should() + .HaveDiagnostic(DiagnosticDescriptors.MixingStaticPartialWithInstanceMethod) + .HaveAssertedAllDiagnostics(); + } + + [Fact] + public void MixedStaticPartialMethodWithNonStaticFactory() + { + var source = TestSourceBuilder.CSharp( + """ + using Riok.Mapperly.Abstractions; + + [Mapper] + public partial class CarMapper + { + [ObjectFactory] + B CreateB() => new B(); + + public static partial B Map(A a); + } + + class A { public string StringValue { get; set; } } + class B { public string StringValue { get; set; } } + """ + ); + + TestHelper + .GenerateMapper(source, TestHelperOptions.AllowAllDiagnostics) + .Should() + .HaveDiagnostic(DiagnosticDescriptors.InvalidObjectFactorySignature) + .HaveAssertedAllDiagnostics(); + } + + [Fact] + public void MixedStaticMethodWithInstanceMethod() + { + var source = TestSourceBuilder.CSharp( + """ + using Riok.Mapperly.Abstractions; + + record A(int Value); + record B(int Value); + + [Mapper] + public partial class Mapper + { + static partial B Map(A source); + + private B Map2(A source); + } + """ + ); + + TestHelper + .GenerateMapper(source, TestHelperOptions.AllowAllDiagnostics) + .Should() + .HaveDiagnostic(DiagnosticDescriptors.MixingStaticPartialWithInstanceMethod) + .HaveAssertedAllDiagnostics(); + } +} diff --git a/test/Riok.Mapperly.Tests/Mapping/UserMethodTest.cs b/test/Riok.Mapperly.Tests/Mapping/UserMethodTest.cs index ebef5628bb..216160f53b 100644 --- a/test/Riok.Mapperly.Tests/Mapping/UserMethodTest.cs +++ b/test/Riok.Mapperly.Tests/Mapping/UserMethodTest.cs @@ -12,27 +12,6 @@ public Task WithNamespaceShouldWork() return TestHelper.VerifyGenerator(source); } - [Fact] - public Task InstanceMapperShouldEmitDiagnosticForPartialStaticMethods() - { - var source = TestSourceBuilder.CSharp( - """ - using System; - using System.Collections.Generic; - using Riok.Mapperly.Abstractions; - - [Mapper] - public partial class MyMapper - { - public static object StaticToObject(string s); - - public partial object InstanceToObject(string s); - } - """ - ); - return TestHelper.VerifyGenerator(source); - } - [Fact] public Task InstanceMapperShouldSupportUserDefinedStaticMethods() { diff --git a/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.IgnoreInstanceMethodFromStaticMapper#Mapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.IgnoreInstanceMethodFromStaticMapper#Mapper.g.verified.cs new file mode 100644 index 0000000000..890d6024f6 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.IgnoreInstanceMethodFromStaticMapper#Mapper.g.verified.cs @@ -0,0 +1,17 @@ +//HintName: Mapper.g.cs +// +#nullable enable +public partial class Mapper +{ + static partial global::B Map(global::A source) + { + var target = new global::B(MapToBExternal(source.Value)); + return target; + } + + private static global::BExternal MapToBExternal(global::AExternal source) + { + var target = new global::BExternal(); + return target; + } +} diff --git a/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.MapperInNestedClassShouldWork#CarFeature.Mappers.CarMapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.MapperInNestedClassShouldWork#CarFeature.Mappers.CarMapper.g.verified.cs new file mode 100644 index 0000000000..1d3d44acd2 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.MapperInNestedClassShouldWork#CarFeature.Mappers.CarMapper.g.verified.cs @@ -0,0 +1,16 @@ +//HintName: CarFeature.Mappers.CarMapper.g.cs +// +#nullable enable +public static partial class CarFeature +{ + public partial class Mappers + { + public partial class CarMapper + { + static partial int ToInt(double value) + { + return (int)value; + } + } + } +} diff --git a/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.MappingWithUserMappingShouldWork#CarMapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.MappingWithUserMappingShouldWork#CarMapper.g.verified.cs new file mode 100644 index 0000000000..774a3e126f --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.MappingWithUserMappingShouldWork#CarMapper.g.verified.cs @@ -0,0 +1,17 @@ +//HintName: CarMapper.g.cs +// +#nullable enable +public partial class CarMapper +{ + static partial global::D MapToD(global::A value) + { + var target = new global::D(MapToE(value.Value1)); + return target; + } + + private static global::E MapToE(global::B source) + { + var target = new global::E(MapToF(source.Value2)); + return target; + } +} diff --git a/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.NestedMappingShouldWork#CarMapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.NestedMappingShouldWork#CarMapper.g.verified.cs new file mode 100644 index 0000000000..cc01fff75c --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.NestedMappingShouldWork#CarMapper.g.verified.cs @@ -0,0 +1,17 @@ +//HintName: CarMapper.g.cs +// +#nullable enable +public partial class CarMapper +{ + static partial global::C MapToC(global::A value) + { + var target = new global::C(MapToD(value.Value1)); + return target; + } + + private static global::D MapToD(global::B source) + { + var target = new global::D(source.Value2); + return target; + } +} diff --git a/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.ShouldUseSimpleObjectFactory#CarMapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.ShouldUseSimpleObjectFactory#CarMapper.g.verified.cs new file mode 100644 index 0000000000..8b3f242c60 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.ShouldUseSimpleObjectFactory#CarMapper.g.verified.cs @@ -0,0 +1,12 @@ +//HintName: CarMapper.g.cs +// +#nullable enable +public partial class CarMapper +{ + static partial global::B Map(global::A a) + { + var target = CreateB(); + target.StringValue = a.StringValue; + return target; + } +} diff --git a/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.StaticPartialMethod#Mapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.StaticPartialMethod#Mapper.g.verified.cs new file mode 100644 index 0000000000..5ff6ef5d2b --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.StaticPartialMethod#Mapper.g.verified.cs @@ -0,0 +1,11 @@ +//HintName: Mapper.g.cs +// +#nullable enable +public partial class Mapper +{ + static partial global::B Map(global::A source) + { + var target = new global::B(source.Value); + return target; + } +} \ No newline at end of file diff --git a/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.UseStaticGenericMapperStaticMethod#Mapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.UseStaticGenericMapperStaticMethod#Mapper.g.verified.cs new file mode 100644 index 0000000000..a8b59243f4 --- /dev/null +++ b/test/Riok.Mapperly.Tests/_snapshots/InstantiableMapperWithStaticMethodsTest.UseStaticGenericMapperStaticMethod#Mapper.g.verified.cs @@ -0,0 +1,11 @@ +//HintName: Mapper.g.cs +// +#nullable enable +public partial class Mapper +{ + static partial global::B Map(global::A source) + { + var target = new global::B(global::OtherMapper.ToBExternal(source.Value)); + return target; + } +} diff --git a/test/Riok.Mapperly.Tests/_snapshots/UserMethodTest.InstanceMapperShouldEmitDiagnosticForPartialStaticMethods#MyMapper.g.verified.cs b/test/Riok.Mapperly.Tests/_snapshots/UserMethodTest.InstanceMapperShouldEmitDiagnosticForPartialStaticMethods#MyMapper.g.verified.cs deleted file mode 100644 index 8a8c6ba82d..0000000000 --- a/test/Riok.Mapperly.Tests/_snapshots/UserMethodTest.InstanceMapperShouldEmitDiagnosticForPartialStaticMethods#MyMapper.g.verified.cs +++ /dev/null @@ -1,10 +0,0 @@ -//HintName: MyMapper.g.cs -// -#nullable enable -public partial class MyMapper -{ - public partial object InstanceToObject(string s) - { - return (object)s; - } -} \ No newline at end of file