diff --git a/src/Speckle.ProxyGenerator/Extensions/PropertySymbolExtensions.cs b/src/Speckle.ProxyGenerator/Extensions/PropertySymbolExtensions.cs index 2ba5cec..c9a2a64 100644 --- a/src/Speckle.ProxyGenerator/Extensions/PropertySymbolExtensions.cs +++ b/src/Speckle.ProxyGenerator/Extensions/PropertySymbolExtensions.cs @@ -7,30 +7,4 @@ namespace Speckle.ProxyGenerator.Extensions; internal static class PropertySymbolExtensions { public static TypeEnum GetTypeEnum(this IPropertySymbol p) => p.Type.GetTypeEnum(); - - public static (string PropertyType, string? PropertyName, string GetSet)? ToPropertyDetails( - this IPropertySymbol property, - string? overrideType = null - ) - { - var getIsPublic = property.GetMethod.IsPublic(); - var setIsPublic = property.SetMethod.IsPublic(); - - if (!getIsPublic && !setIsPublic) - { - return null; - } - - var get = getIsPublic ? "get; " : string.Empty; - var set = setIsPublic ? "set; " : string.Empty; - - var type = !string.IsNullOrEmpty(overrideType) - ? overrideType - : BaseGenerator.FixType( - property.Type.ToFullyQualifiedDisplayString(), - property.NullableAnnotation - ); - - return (type!, property.GetSanitizedName(), $"{{ {get}{set}}}"); - } } diff --git a/src/Speckle.ProxyGenerator/FileGenerators/BaseGenerator.cs b/src/Speckle.ProxyGenerator/FileGenerators/BaseGenerator.cs index b7e8c3c..d31c047 100644 --- a/src/Speckle.ProxyGenerator/FileGenerators/BaseGenerator.cs +++ b/src/Speckle.ProxyGenerator/FileGenerators/BaseGenerator.cs @@ -21,14 +21,14 @@ internal abstract class BaseGenerator SupportsNullable = supportsNullable; } - protected string GetPropertyType(IPropertySymbol property, out bool isReplaced) + protected FixedType GetPropertyType(IPropertySymbol property, out bool isReplaced) { - return GetReplacedTypeAsString(property.Type, out isReplaced); + return GetReplacedTypeAsString(property.Type, null, out isReplaced); } - protected string GetParameterType(IParameterSymbol property, out bool isReplaced) + protected FixedType GetParameterType(IParameterSymbol property, out bool isReplaced) { - return GetReplacedTypeAsString(property.Type, out isReplaced); + return GetReplacedTypeAsString(property.Type, property.GetDefaultValue(), out isReplaced); } protected bool TryFindProxyDataByTypeName( @@ -119,7 +119,8 @@ internal abstract class BaseGenerator { if (replaceIt) { - constraints.Add(GetReplacedTypeAsString(namedTypeSymbol, out _)); + var (_, type) = GetReplacedTypeAsString(namedTypeSymbol, null, out _); + constraints.Add(type); } else { @@ -152,7 +153,11 @@ internal abstract class BaseGenerator | SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier ); - protected string GetReplacedTypeAsString(ITypeSymbol typeSymbol, out bool isReplaced) + protected FixedType GetReplacedTypeAsString( + ITypeSymbol typeSymbol, + string? defaultValue, + out bool isReplaced + ) { isReplaced = false; @@ -170,7 +175,7 @@ internal abstract class BaseGenerator } isReplaced = true; - return FixType(existing.FullInterfaceName, typeSymbol.NullableAnnotation); + return FixType(existing.FullInterfaceName, typeSymbol.NullableAnnotation, defaultValue); } ITypeSymbol[] typeArguments; @@ -184,7 +189,7 @@ internal abstract class BaseGenerator } else { - return FixType(typeSymbolAsString, typeSymbol.NullableAnnotation); + return FixType(typeSymbolAsString, typeSymbol.NullableAnnotation, defaultValue); } var propertyTypeAsStringToBeModified = nullableTypeSymbolAsString; @@ -211,7 +216,11 @@ internal abstract class BaseGenerator } } - return FixType(propertyTypeAsStringToBeModified, typeSymbol.NullableAnnotation); + return FixType( + propertyTypeAsStringToBeModified, + typeSymbol.NullableAnnotation, + defaultValue + ); } protected bool TryGetNamedTypeSymbolByFullName( @@ -272,13 +281,14 @@ internal abstract class BaseGenerator { if (parameterSymbol.GetTypeEnum() == TypeEnum.Complex) { - type = GetParameterType(parameterSymbol, out _); + (_, type) = GetParameterType(parameterSymbol, out _); } else { - type = FixType( + (_, type) = FixType( parameterSymbol.Type.ToFullyQualifiedDisplayString(), - parameterSymbol.NullableAnnotation + parameterSymbol.NullableAnnotation, + parameterSymbol.GetDefaultValue() ); } } @@ -316,15 +326,23 @@ internal abstract class BaseGenerator return extendsProxyClasses; } - internal static string FixType(string type, NullableAnnotation nullableAnnotation) + internal FixedType FixType( + string type, + NullableAnnotation nullableAnnotation, + string? defaultValue + ) { - if ( - nullableAnnotation == NullableAnnotation.Annotated - && !type.EndsWith("?", StringComparison.Ordinal) - ) + var na = nullableAnnotation; + if (SupportsNullable && defaultValue == " = null") { - return $"{type}?"; + na = NullableAnnotation.Annotated; } - return type; + if (na == NullableAnnotation.Annotated && !type.EndsWith("?", StringComparison.Ordinal)) + { + return new(true, $"{type}?"); + } + return new(false, type); } } + +internal record FixedType(bool Fixed, string Type); diff --git a/src/Speckle.ProxyGenerator/FileGenerators/ExtraFilesGenerator.cs b/src/Speckle.ProxyGenerator/FileGenerators/ExtraFilesGenerator.cs index 6d87a5d..3824b19 100644 --- a/src/Speckle.ProxyGenerator/FileGenerators/ExtraFilesGenerator.cs +++ b/src/Speckle.ProxyGenerator/FileGenerators/ExtraFilesGenerator.cs @@ -151,6 +151,18 @@ namespace Speckle.ProxyGenerator public static object CreateProxy(Type type, object toWrap) => s_proxyFactory[type](toWrap); public static T CreateProxy(object toWrap) => (T)CreateProxy(typeof(T), toWrap); }} + public static class MapsterAdapter + {{ + public static TDestination? AdaptNull(object? source) + {{ + if (source is null) + {{ + return default; + }} + + return Mapster.TypeAdapter.Adapt(source); + }} + }} {supportsNullable.IIf("#nullable restore")} }}" ); diff --git a/src/Speckle.ProxyGenerator/FileGenerators/PartialInterfacesGenerator.cs b/src/Speckle.ProxyGenerator/FileGenerators/PartialInterfacesGenerator.cs index 1426082..fbc08bc 100644 --- a/src/Speckle.ProxyGenerator/FileGenerators/PartialInterfacesGenerator.cs +++ b/src/Speckle.ProxyGenerator/FileGenerators/PartialInterfacesGenerator.cs @@ -191,11 +191,11 @@ methods} ) ) { - var type = GetPropertyType(property, out var isReplaced); + var (_, type) = GetPropertyType(property, out var isReplaced); var getterSetter = isReplaced - ? property.ToPropertyDetails(type) - : property.ToPropertyDetails(); + ? ToPropertyDetails(property, type) + : ToPropertyDetails(property); if (getterSetter is null) { continue; @@ -241,8 +241,9 @@ methods} str.AppendLine($" {attribute}"); } + var (_, type) = GetReplacedTypeAsString(method.ReturnType, null, out _); str.AppendLine( - $" {GetReplacedTypeAsString(method.ReturnType, out _)} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement};" + $" {type} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement};" ); str.AppendLine(); } @@ -262,10 +263,16 @@ methods} ) { var ps = @event.First().Parameters.First(); - var type = - ps.GetTypeEnum() == TypeEnum.Complex - ? GetParameterType(ps, out _) - : ps.Type.ToString(); + + string? type; + if (ps.GetTypeEnum() == TypeEnum.Complex) + { + (_, type) = GetParameterType(ps, out _); + } + else + { + type = ps.Type.ToString(); + } foreach (var attribute in ps.GetAttributesAsList()) { @@ -278,4 +285,37 @@ methods} return str.ToString(); } + + public (string PropertyType, string? PropertyName, string GetSet)? ToPropertyDetails( + IPropertySymbol property, + string? overrideType = null + ) + { + var getIsPublic = property.GetMethod.IsPublic(); + var setIsPublic = property.SetMethod.IsPublic(); + + if (!getIsPublic && !setIsPublic) + { + return null; + } + + var get = getIsPublic ? "get; " : string.Empty; + var set = setIsPublic ? "set; " : string.Empty; + + string? type; + if (!string.IsNullOrEmpty(overrideType)) + { + type = overrideType; + } + else + { + (_, type) = FixType( + property.Type.ToFullyQualifiedDisplayString(), + property.NullableAnnotation, + null + ); + } + + return (type!, property.GetSanitizedName(), $"{{ {get}{set}}}"); + } } diff --git a/src/Speckle.ProxyGenerator/FileGenerators/ProxyClassesGenerator.cs b/src/Speckle.ProxyGenerator/FileGenerators/ProxyClassesGenerator.cs index be1dc00..d2d0d10 100644 --- a/src/Speckle.ProxyGenerator/FileGenerators/ProxyClassesGenerator.cs +++ b/src/Speckle.ProxyGenerator/FileGenerators/ProxyClassesGenerator.cs @@ -182,7 +182,7 @@ using System; foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol, proxyData)) { - var type = GetPropertyType(property, out var isReplaced); + var (_, type) = GetPropertyType(property, out var isReplaced); var instance = !property.IsStatic ? "_Instance" : $"{targetClassSymbol.Symbol}"; @@ -261,7 +261,7 @@ using System; foreach (var parameterSymbol in method.Parameters) { - var type = GetParameterType(parameterSymbol, out _); + var (_, type) = GetParameterType(parameterSymbol, out _); methodParameters.Add(MethodParameterBuilder.Build(parameterSymbol, type)); @@ -285,8 +285,9 @@ using System; overrideOrVirtual = "virtual "; } - string returnTypeAsString = GetReplacedTypeAsString( + var (_, returnTypeAsString) = GetReplacedTypeAsString( method.ReturnType, + null, out var returnIsReplaced ); @@ -304,9 +305,10 @@ using System; foreach (var ps in method.Parameters.Where(p => !p.IsRef())) { - var type = FixType( + var (wasFixed, type) = FixType( ps.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), - ps.Type.NullableAnnotation + ps.Type.NullableAnnotation, + ps.GetDefaultValue() ); string normalOrMap = $" = {ps.GetSanitizedName()}"; if (ps.RefKind == RefKind.Out) @@ -318,8 +320,16 @@ using System; _ = GetParameterType(ps, out var isReplaced); // TODO : response is not used? if (isReplaced) { - normalOrMap = - $" = Mapster.TypeAdapter.Adapt<{type}>({ps.GetSanitizedName()})"; + if (wasFixed) + { + normalOrMap = + $" = Speckle.ProxyGenerator.MapsterAdapter.AdaptNull<{type}>({ps.GetSanitizedName()})"; + } + else + { + normalOrMap = + $" = Mapster.TypeAdapter.Adapt<{type}>({ps.GetSanitizedName()})"; + } } } @@ -350,7 +360,7 @@ using System; foreach (var ps in method.Parameters.Where(p => p.RefKind == RefKind.Out)) { string normalOrMap = $" = {ps.GetSanitizedName()}_"; - var type = GetParameterType(ps, out var isReplaced); + var (_, type) = GetParameterType(ps, out var isReplaced); if (isReplaced) { normalOrMap = $" = Mapster.TypeAdapter.Adapt<{type}>({ps.GetSanitizedName()}_)"; @@ -385,12 +395,21 @@ using System; var str = new StringBuilder(); foreach (var @event in MemberHelper.GetPublicEvents(targetClassSymbol, proxyData)) { + if (@event.Key.IsStatic) + { + continue; + } var name = @event.Key.GetSanitizedName(); var ps = @event.First().Parameters.First(); - var type = - ps.GetTypeEnum() == TypeEnum.Complex - ? GetParameterType(ps, out _) - : ps.Type.ToString(); + var type = string.Empty; + if (ps.GetTypeEnum() == TypeEnum.Complex) + { + (_, type) = GetParameterType(ps, out _); + } + else + { + type = ps.Type.ToString(); + } foreach (var attribute in ps.GetAttributesAsList()) { @@ -417,6 +436,10 @@ using System; private string GenerateOperators(ClassSymbol targetClassSymbol, ProxyData proxyData) { + if (targetClassSymbol.Symbol.TypeKind != TypeKind.Class) + { + return string.Empty; + } var str = new StringBuilder(); foreach ( var @operator in MemberHelper.GetPublicStaticOperators(targetClassSymbol, proxyData) @@ -438,7 +461,11 @@ using System; var operatorType = @operator.Name.ToLowerInvariant().Replace("op_", string.Empty); if (operatorType == "explicit") { - var returnTypeAsString = GetReplacedTypeAsString(@operator.ReturnType, out _); + var (_, returnTypeAsString) = GetReplacedTypeAsString( + @operator.ReturnType, + null, + out _ + ); str.AppendLine( $" public static explicit operator {returnTypeAsString}({proxyClassName} {parameter.Name})" @@ -451,7 +478,7 @@ using System; } else { - var returnTypeAsString = GetReplacedTypeAsString(parameter.Type, out _); + var (_, returnTypeAsString) = GetReplacedTypeAsString(parameter.Type, null, out _); str.AppendLine( $" public static implicit operator {proxyClassName}({returnTypeAsString} {parameter.Name})" diff --git a/src/Speckle.ProxyGenerator/Speckle.ProxyGenerator.csproj b/src/Speckle.ProxyGenerator/Speckle.ProxyGenerator.csproj index 7f64e4a..2c5ec14 100644 --- a/src/Speckle.ProxyGenerator/Speckle.ProxyGenerator.csproj +++ b/src/Speckle.ProxyGenerator/Speckle.ProxyGenerator.csproj @@ -1,7 +1,7 @@ - 0.1.9 + 0.1.10 netstandard2.0 Latest enable diff --git a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithArray_Should_GenerateCorrectFiles.verified.txt b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithArray_Should_GenerateCorrectFiles.verified.txt index 27db633..181d9f3 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithArray_Should_GenerateCorrectFiles.verified.txt +++ b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithArray_Should_GenerateCorrectFiles.verified.txt @@ -207,6 +207,18 @@ namespace Speckle.ProxyGenerator public static object CreateProxy(Type type, object toWrap) => s_proxyFactory[type](toWrap); public static T CreateProxy(object toWrap) => (T)CreateProxy(typeof(T), toWrap); } + public static class MapsterAdapter + { + public static TDestination? AdaptNull(object? source) + { + if (source is null) + { + return default; + } + + return Mapster.TypeAdapter.Adapt(source); + } + } #nullable restore } } diff --git a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithArray_Should_GenerateCorrectFiles_NotNullable.verified.txt b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithArray_Should_GenerateCorrectFiles_NotNullable.verified.txt new file mode 100644 index 0000000..29f5d0e --- /dev/null +++ b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithArray_Should_GenerateCorrectFiles_NotNullable.verified.txt @@ -0,0 +1,216 @@ +[ + { + HintName: ProxyInterfaceSourceGeneratorTests.Source.IFooNotNullable.g.cs, + Source: +//---------------------------------------------------------------------------------------- +// +// This code was generated by https://github.com/specklesystems/ProxyGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//---------------------------------------------------------------------------------------- + +#nullable enable +using System; + +namespace ProxyInterfaceSourceGeneratorTests.Source +{ + public partial interface IFooNotNullable + { + global::ProxyInterfaceSourceGeneratorTests.Source.FooNotNullable _Instance { get; } + + void Test(global::ProxyInterfaceSourceGeneratorTests.Source.FooEnum z = 1, global::System.Collections.Generic.IEnumerable? v = null); + } +} +#nullable restore + }, + { + HintName: ProxyInterfaceSourceGeneratorTests.Source.FooNotNullableProxy.g.cs, + Source: +//---------------------------------------------------------------------------------------- +// +// This code was generated by https://github.com/specklesystems/ProxyGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//---------------------------------------------------------------------------------------- + +#nullable enable +using System; + +namespace ProxyInterfaceSourceGeneratorTests.Source +{ + public partial class FooNotNullableProxy : global::ProxyInterfaceSourceGeneratorTests.Source.IFooNotNullable + { + public global::ProxyInterfaceSourceGeneratorTests.Source.FooNotNullable _Instance { get; } + + public void Test(global::ProxyInterfaceSourceGeneratorTests.Source.FooEnum z = 1, global::System.Collections.Generic.IEnumerable? v = null) + { + global::ProxyInterfaceSourceGeneratorTests.Source.FooEnum z_ = z; + global::System.Collections.Generic.IEnumerable? v_ = v; + _Instance.Test(z_, v_); + } + + + public FooNotNullableProxy(global::ProxyInterfaceSourceGeneratorTests.Source.FooNotNullable instance) + { + _Instance = instance; + + } + + } +} +#nullable restore + }, + { + HintName: Speckle.ProxyGenerator.Extra.g.cs, + Source: +//---------------------------------------------------------------------------------------- +// +// This code was generated by https://github.com/specklesystems/ProxyGenerator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//---------------------------------------------------------------------------------------- + +#nullable enable +using System; + +namespace Speckle.ProxyGenerator +{ + [AttributeUsage(AttributeTargets.Interface)] + internal sealed class ProxyAttribute : Attribute + { + public Type Type { get; } + public ImplementationOptions Options { get; } + public ProxyClassAccessibility Accessibility { get; } + public string[]? MembersToIgnore { get; } + + public ProxyAttribute(Type type) : this(type, ImplementationOptions.None, ProxyClassAccessibility.Public) + { + } + + public ProxyAttribute(Type type, ImplementationOptions options) : this(type, options, ProxyClassAccessibility.Public) + { + } + + public ProxyAttribute(Type type, ProxyClassAccessibility accessibility) : this(type, ImplementationOptions.None, accessibility) + { + } + + public ProxyAttribute(Type type, ImplementationOptions options, ProxyClassAccessibility accessibility) : this(type, options, accessibility, null) + { + } + + public ProxyAttribute(Type type, string[]? membersToIgnore) : this(type, ImplementationOptions.None, ProxyClassAccessibility.Public, null) + { + } + + public ProxyAttribute(Type type, ImplementationOptions options, string[]? membersToIgnore) : this(type, options, ProxyClassAccessibility.Public, null) + { + } + + public ProxyAttribute(Type type, ImplementationOptions options, ProxyClassAccessibility accessibility, string[]? membersToIgnore) + { + Type = type; + Options = options; + Accessibility = accessibility; + MembersToIgnore = membersToIgnore; + } + } + + [Flags] + internal enum ProxyClassAccessibility + { + Public = 0, + + Internal = 1 + } + [Flags] + internal enum ImplementationOptions + { + None = 0, + + ProxyBaseClasses = 1, + + ProxyInterfaces = 2, + + UseExtendedInterfaces = 4, + + ProxyForBaseInterface = 8 + } + + public static class ProxyMap + { + private static readonly global::System.Collections.Concurrent.ConcurrentDictionary s_revitToInterfaceMap = new(); + private static readonly global::System.Collections.Concurrent.ConcurrentDictionary s_proxyToInterfaceMap = new(); + private static readonly global::System.Collections.Concurrent.ConcurrentDictionary s_interfaceToRevit = new(); + private static readonly global::System.Collections.Concurrent.ConcurrentDictionary> s_proxyFactory = new(); + + static ProxyMap() + { + Add(x => new ProxyInterfaceSourceGeneratorTests.Source.FooNotNullableProxy(x)); + + } + + private static void Add(Func f) + where TInterface : notnull + where TProxy : TInterface + { + s_revitToInterfaceMap.TryAdd(typeof(T), typeof(TInterface)); + s_proxyToInterfaceMap.TryAdd(typeof(TProxy), typeof(TInterface)); + s_proxyFactory.TryAdd(typeof(TInterface), w => f((T)w)); + s_interfaceToRevit.TryAdd(typeof(TInterface), typeof(T)); + } + + public static Type? GetMappedTypeFromHostType(Type type) + { + if (s_revitToInterfaceMap.TryGetValue(type, out var t)) + { + return t; + } + return null; + } + + public static Type? GetMappedTypeFromProxyType(Type type) + { + if (s_proxyToInterfaceMap.TryGetValue(type, out var t)) + { + return t; + } + + return null; + } + + public static Type? GetHostTypeFromMappedType(Type type) + { + if (s_interfaceToRevit.TryGetValue(type, out var t)) + { + return t; + } + + return null; + } + + public static object CreateProxy(Type type, object toWrap) => s_proxyFactory[type](toWrap); + public static T CreateProxy(object toWrap) => (T)CreateProxy(typeof(T), toWrap); + } + public static class MapsterAdapter + { + public static TDestination? AdaptNull(object? source) + { + if (source is null) + { + return default; + } + + return Mapster.TypeAdapter.Adapt(source); + } + } +#nullable restore +} + } +] \ No newline at end of file diff --git a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithIgnores.verified.txt b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithIgnores.verified.txt index b6784e0..7bd8172 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithIgnores.verified.txt +++ b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWithIgnores.verified.txt @@ -215,6 +215,18 @@ namespace Speckle.ProxyGenerator public static object CreateProxy(Type type, object toWrap) => s_proxyFactory[type](toWrap); public static T CreateProxy(object toWrap) => (T)CreateProxy(typeof(T), toWrap); } + public static class MapsterAdapter + { + public static TDestination? AdaptNull(object? source) + { + if (source is null) + { + return default; + } + + return Mapster.TypeAdapter.Adapt(source); + } + } #nullable restore } } diff --git a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWith_BaseInterface.verified.txt b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWith_BaseInterface.verified.txt index 8e92e97..b0d7993 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWith_BaseInterface.verified.txt +++ b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWith_BaseInterface.verified.txt @@ -217,6 +217,18 @@ namespace Speckle.ProxyGenerator public static object CreateProxy(Type type, object toWrap) => s_proxyFactory[type](toWrap); public static T CreateProxy(object toWrap) => (T)CreateProxy(typeof(T), toWrap); } + public static class MapsterAdapter + { + public static TDestination? AdaptNull(object? source) + { + if (source is null) + { + return default; + } + + return Mapster.TypeAdapter.Adapt(source); + } + } #nullable restore } } diff --git a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWith_Extended.verified.txt b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWith_Extended.verified.txt index 99834c9..8602f1b 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWith_Extended.verified.txt +++ b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForClassWith_Extended.verified.txt @@ -268,6 +268,18 @@ Add s_proxyFactory[type](toWrap); public static T CreateProxy(object toWrap) => (T)CreateProxy(typeof(T), toWrap); } + public static class MapsterAdapter + { + public static TDestination? AdaptNull(object? source) + { + if (source is null) + { + return default; + } + + return Mapster.TypeAdapter.Adapt(source); + } + } #nullable restore } } diff --git a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForStruct_Should_GenerateProxyCode.verified.txt b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForStruct_Should_GenerateProxyCode.verified.txt index b62befe..3c5100b 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForStruct_Should_GenerateProxyCode.verified.txt +++ b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.GenerateFiles_ForStruct_Should_GenerateProxyCode.verified.txt @@ -280,6 +280,18 @@ Add s_proxyFactory[type](toWrap); public static T CreateProxy(object toWrap) => (T)CreateProxy(typeof(T), toWrap); } + public static class MapsterAdapter + { + public static TDestination? AdaptNull(object? source) + { + if (source is null) + { + return default; + } + + return Mapster.TypeAdapter.Adapt(source); + } + } #nullable restore } } diff --git a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs index c3141ec..cabafb6 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs +++ b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs @@ -73,6 +73,40 @@ public class ProxyInterfaceSourceGeneratorTest return Verify(results); } + [Fact] + public Task GenerateFiles_ForClassWithArray_Should_GenerateCorrectFiles_NotNullable() + { + // Arrange + var fileNames = new[] + { + "ProxyInterfaceSourceGeneratorTests.Source.IFooNotNullable.g.cs", + "ProxyInterfaceSourceGeneratorTests.Source.FooNotNullableProxy.g.cs" + }; + + var path = "./Source/IFooNotNullable.cs"; + var sourceFile = new SourceFile + { + Path = path, + Text = File.ReadAllText(path), + AttributeToAddToInterface = new ExtraAttribute + { + Name = "Speckle.ProxyGenerator.Proxy", + ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.FooNotNullable)" + } + }; + + // Act + var result = _sut.Execute(new[] { sourceFile }); + + // Assert + result.Valid.Should().BeTrue(); + result.Files.Should().HaveCount(fileNames.Length + 1); + + // Verify + var results = result.GeneratorDriver.GetRunResult().Results.First().GeneratedSources; + return Verify(results); + } + [Fact] public Task GenerateFiles_ForClassWithArray_Should_GenerateCorrectFiles() { diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Source/FooEnumImplement.cs b/tests/ProxyInterfaceSourceGeneratorTests/Source/FooEnumImplement.cs new file mode 100644 index 0000000..8346ae2 --- /dev/null +++ b/tests/ProxyInterfaceSourceGeneratorTests/Source/FooEnumImplement.cs @@ -0,0 +1,7 @@ +namespace ProxyInterfaceSourceGeneratorTests.Source; + +public enum FooEnumImplement +{ + X, + Y +} diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Source/FooNotNullable.cs b/tests/ProxyInterfaceSourceGeneratorTests/Source/FooNotNullable.cs new file mode 100644 index 0000000..31ab059 --- /dev/null +++ b/tests/ProxyInterfaceSourceGeneratorTests/Source/FooNotNullable.cs @@ -0,0 +1,14 @@ +namespace ProxyInterfaceSourceGeneratorTests.Source; + +#nullable disable +public class FooNotNullable +{ + public void Test(FooEnum z = FooEnum.Y, IEnumerable v = null) { } +} + +public enum FooEnum +{ + X, + Y +} +#nullable restore diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Source/IFooNotNullable.cs b/tests/ProxyInterfaceSourceGeneratorTests/Source/IFooNotNullable.cs new file mode 100644 index 0000000..b5556ce --- /dev/null +++ b/tests/ProxyInterfaceSourceGeneratorTests/Source/IFooNotNullable.cs @@ -0,0 +1,6 @@ +namespace ProxyInterfaceSourceGeneratorTests.Source; + +public partial interface IFooNotNullable +{ + public void Test(FooEnumImplement z = FooEnumImplement.Y, IEnumerable? v = null) { } +}