Skip to content

Commit

Permalink
Use internal Map methods if possible, else use Mapster (#88)
Browse files Browse the repository at this point in the history
* Map

* x

* tstst

* ok?

* cleanup

* x

* x
  • Loading branch information
StefH authored Jan 24, 2025
1 parent efc51ac commit 9ec0816
Show file tree
Hide file tree
Showing 26 changed files with 1,530 additions and 990 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static (string PropertyType, string? PropertyName, string GetSet)? ToProp
var set = setIsPublic ? "set; " : string.Empty;

var type = !string.IsNullOrEmpty(overrideType) ? overrideType
: BaseGenerator.FixType(property.Type.ToFullyQualifiedDisplayString(), property.NullableAnnotation);
: BaseGenerator.FixTypeForNullable(property.Type.ToFullyQualifiedDisplayString(), property.NullableAnnotation);

return (type!, property.GetSanitizedName(), $"{{ {get}{set}}}");
}
Expand Down
42 changes: 27 additions & 15 deletions src/ProxyInterfaceSourceGenerator/FileGenerators/BaseGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,10 @@ protected string GetReplacedTypeAsString(ITypeSymbol typeSymbol, out bool isRepl

if (TryFindProxyDataByTypeName(typeSymbolAsString, out var existing))
{
if (!Context.ReplacedTypes.ContainsKey(typeSymbolAsString))
{
Context.ReplacedTypes.Add(typeSymbolAsString, existing.FullInterfaceName);
}
TryAddDirect(typeSymbolAsString, existing);

isReplaced = true;
return FixType(existing.FullInterfaceName, typeSymbol.NullableAnnotation);
return FixTypeForNullable(existing.FullInterfaceName, typeSymbol.NullableAnnotation);
}

ITypeSymbol[] typeArguments;
Expand All @@ -155,32 +152,47 @@ protected string GetReplacedTypeAsString(ITypeSymbol typeSymbol, out bool isRepl
}
else if (typeSymbol is IArrayTypeSymbol arrayTypeSymbol)
{
typeArguments = new[] { arrayTypeSymbol.ElementType };
typeArguments = [arrayTypeSymbol.ElementType];
}
else
{
return FixType(typeSymbolAsString, typeSymbol.NullableAnnotation);
return FixTypeForNullable(typeSymbolAsString, typeSymbol.NullableAnnotation);
}

var propertyTypeAsStringToBeModified = nullableTypeSymbolAsString;
var elementTypeAsStringToBeModified = nullableTypeSymbolAsString;
foreach (var typeArgument in typeArguments)
{
var typeArgumentAsString = typeArgument.ToFullyQualifiedDisplayString();

if (TryFindProxyDataByTypeName(typeArgumentAsString, out var existingTypeArgument))
{
isReplaced = true;
var original = elementTypeAsStringToBeModified;

if (!Context.ReplacedTypes.ContainsKey(typeArgumentAsString))
elementTypeAsStringToBeModified = elementTypeAsStringToBeModified.Replace(typeArgumentAsString, existingTypeArgument.FullInterfaceName);

var foundIndirect = Context.ReplacedTypes.FirstOrDefault(r => !r.Direct && r.ClassType == original);
if (foundIndirect == null)
{
Context.ReplacedTypes.Add(typeArgumentAsString, existingTypeArgument.FullInterfaceName);
Context.ReplacedTypes.Add(new(original, elementTypeAsStringToBeModified, typeArgumentAsString, existingTypeArgument.FullInterfaceName, string.Empty, false));

TryAddDirect(typeArgumentAsString, existingTypeArgument);
}

propertyTypeAsStringToBeModified = propertyTypeAsStringToBeModified.Replace(typeArgumentAsString, existingTypeArgument.FullInterfaceName);
isReplaced = true;
}
}

return FixType(propertyTypeAsStringToBeModified, typeSymbol.NullableAnnotation);
return FixTypeForNullable(elementTypeAsStringToBeModified, typeSymbol.NullableAnnotation);
}

private void TryAddDirect(string typeSymbolAsString, ProxyData existing)
{
var found = Context.ReplacedTypes.FirstOrDefault(r => r.Direct && r.ClassType == typeSymbolAsString);
if (found == null)
{
var proxy = $"global::{existing.NamespaceDot}{existing.ShortMetadataName}Proxy"; // global::ProxyInterfaceSourceGeneratorTests.Source.TimeProviderProxy
Context.ReplacedTypes.Add(new(typeSymbolAsString, existing.FullInterfaceName, string.Empty, string.Empty, proxy, true));
}
}

protected bool TryGetNamedTypeSymbolByFullName(TypeKind kind, string name, IEnumerable<string> usings, [NotNullWhen(true)] out ClassSymbol? classSymbol)
Expand Down Expand Up @@ -228,7 +240,7 @@ protected IReadOnlyList<string> GetMethodParameters(ImmutableArray<IParameterSym
}
else
{
type = FixType(parameterSymbol.Type.ToFullyQualifiedDisplayString(), parameterSymbol.NullableAnnotation);
type = FixTypeForNullable(parameterSymbol.Type.ToFullyQualifiedDisplayString(), parameterSymbol.NullableAnnotation);
}
}

Expand All @@ -253,7 +265,7 @@ protected IReadOnlyList<ProxyData> GetExtendsProxyData(ProxyData proxyData, Clas
return extendsProxyClasses;
}

internal static string FixType(string type, NullableAnnotation nullableAnnotation)
internal static string FixTypeForNullable(string type, NullableAnnotation nullableAnnotation)
{
if (nullableAnnotation == NullableAnnotation.Annotated && !type.EndsWith("?", StringComparison.Ordinal))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,73 @@
using System.Text;
using ProxyInterfaceSourceGenerator.Extensions;

namespace ProxyInterfaceSourceGenerator.FileGenerators;

internal partial class ProxyClassesGenerator
{
private string GenerateMapperConfigurationForMapster(string className)
{
if (Context.ReplacedTypes.Count == 0)
{
return string.Empty;
}

var str = new StringBuilder();

str.AppendLine($" static {className}()");
str.AppendLine(@" {");

foreach (var replacedType in Context.ReplacedTypes)
{
TryFindProxyDataByTypeName(replacedType.Key, out var fullTypeName);

var classNameProxy = $"global::{fullTypeName!.NamespaceDot}{fullTypeName!.ShortMetadataName}Proxy";

var instance = $"instance{(replacedType.Key + replacedType.Value).GetDeterministicHashCodeAsString()}";
var proxy = $"proxy{(replacedType.Value + replacedType.Key).GetDeterministicHashCodeAsString()}";

str.AppendLine($" Mapster.TypeAdapterConfig<{replacedType.Key}, {replacedType.Value}>.NewConfig().ConstructUsing({instance} => new {classNameProxy}({instance}));");
str.AppendLine($" Mapster.TypeAdapterConfig<{replacedType.Value}, {replacedType.Key}>.NewConfig().MapWith({proxy} => (({classNameProxy}) {proxy})._Instance);");
str.AppendLine();
}

str.AppendLine(@" }");


return str.ToString();
}
using System.Text;
using ProxyInterfaceSourceGenerator.Extensions;

namespace ProxyInterfaceSourceGenerator.FileGenerators;

internal partial class ProxyClassesGenerator
{
private string GenerateMapperConfigurationForMapster(string className)
{
if (Context.ReplacedTypes.Count == 0)
{
return string.Empty;
}

var str = new StringBuilder();

var indirectReplacedTypes = Context.ReplacedTypes.Where(r => !r.Direct).ToArray();
var directReplacedTypes = Context.ReplacedTypes.Where(r => r.Direct).ToArray();

if (indirectReplacedTypes.Length > 0)
{
str.AppendLine($" static {className}()");
str.AppendLine(@" {");

foreach (var direct in directReplacedTypes)
{
var hash = (direct.ClassType + direct.InterfaceType).GetDeterministicHashCodeAsString();
var instance = $"instance{hash}";
var proxy = $"proxy{hash}";

str.AppendLine($" Mapster.TypeAdapterConfig<{direct.ClassType}, {direct.InterfaceType}>.NewConfig().ConstructUsing({instance} => new {direct.Proxy}({instance}));");
str.AppendLine($" Mapster.TypeAdapterConfig<{direct.InterfaceType}, {direct.ClassType}>.NewConfig().MapWith({proxy} => {proxy}._Instance);");
str.AppendLine();
}

str.AppendLine(@" }");
}

str.AppendLine();

foreach (var indirect in indirectReplacedTypes)
{
str.AppendLine($" private static {indirect.InterfaceType} MapToInterface({indirect.ClassType} value)");
str.AppendLine(@" {");
str.AppendLine($" return Mapster.TypeAdapter.Adapt<{indirect.InterfaceType}>(value);");
str.AppendLine(@" }");
str.AppendLine();

str.AppendLine($" private static {indirect.ClassType} MapToInstance({indirect.InterfaceType} value)");
str.AppendLine(@" {");
str.AppendLine($" return Mapster.TypeAdapter.Adapt<{indirect.ClassType}>(value);");
str.AppendLine(@" }");
str.AppendLine();
}

foreach (var direct in directReplacedTypes)
{
str.AppendLine($" private static {direct.InterfaceType} MapToInterface({direct.ClassType} value)");
str.AppendLine(@" {");
str.AppendLine($" return new {direct.Proxy}(value);");
str.AppendLine(@" }");
str.AppendLine();

str.AppendLine($" private static {direct.ClassType} MapToInstance({direct.InterfaceType} value)");
str.AppendLine(@" {");
str.AppendLine($" return value._Instance;");
str.AppendLine(@" }");
str.AppendLine();
}

return str.ToString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,7 @@ private string CreateProxyClassCode(
var events = GenerateEvents(targetClassSymbol, proxyData);
var operators = GenerateOperators(targetClassSymbol, proxyData);

var configurationForMapster = string.Empty;
if (Context.ReplacedTypes.Count > 0)
{
configurationForMapster = GenerateMapperConfigurationForMapster(className);
}
var configurationForMapster = GenerateMapperConfigurationForMapster(className);

var (namespaceStart, namespaceEnd) = NamespaceBuilder.Build(proxyData.Namespace);

Expand Down Expand Up @@ -173,18 +169,18 @@ private string GeneratePublicProperties(ClassSymbol targetClassSymbol, ProxyData
{
if (getIsPublic)
{
var mapster = $"Mapster.TypeAdapter.Adapt<{type}>({instancePropertyName})";
var mapMethod = $"MapToInterface({instancePropertyName})";
get = propertyIsNullable ?
$"get => {instancePropertyName} != null ? {mapster} : null; " :
$"get => {mapster}; ";
$"get => {instancePropertyName} != null ? {mapMethod} : null; " :
$"get => {mapMethod}; ";
}

if (setIsPublic)
{
var mapster = $"Mapster.TypeAdapter.Adapt<{property.Type}>(value)";
var mapMethod = "MapToInstance(value)";
set = propertyIsNullable ?
$"set => {instancePropertyName} = value != null ? {mapster} : null; " :
$"set => {instancePropertyName} = {mapster}; ";
$"set => {instancePropertyName} = value != null ? {mapMethod} : null; " :
$"set => {instancePropertyName} = {mapMethod}; ";
}
}
else
Expand Down Expand Up @@ -261,7 +257,7 @@ private string GeneratePublicMethods(ClassSymbol targetClassSymbol, ProxyData pr

foreach (var ps in method.Parameters.Where(p => !p.IsRef()))
{
var type = FixType(ps.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), ps.Type.NullableAnnotation);
var type = FixTypeForNullable(ps.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), ps.Type.NullableAnnotation);
var name = ps.GetSanitizedName();
var normalOrMap = $" = {name}";
if (ps.RefKind == RefKind.Out)
Expand All @@ -270,13 +266,13 @@ private string GeneratePublicMethods(ClassSymbol targetClassSymbol, ProxyData pr
}
else
{
_ = GetParameterType(ps, out var isReplaced); // TODO : response is not used?
_ = GetParameterType(ps, out var isReplaced);
if (isReplaced)
{
var mapster = $"Mapster.TypeAdapter.Adapt<{type}>({name})";
var mapMethod = $"MapToInstance({name})";
normalOrMap = ps.IsNullable() ?
$" = {name} != null ? {mapster} : null" :
$" = {mapster}";
$" = {name} != null ? {mapMethod} : null" :
$" = {mapMethod}";
}
}

Expand All @@ -303,13 +299,13 @@ private string GeneratePublicMethods(ClassSymbol targetClassSymbol, ProxyData pr
var normalOrMap = $" = {name}_";
if (ps.GetTypeEnum() == TypeEnum.Complex)
{
var type = GetParameterType(ps, out var isReplaced);
_ = GetParameterType(ps, out var isReplaced);
if (isReplaced)
{
var mapster = $"Mapster.TypeAdapter.Adapt<{type}>({name}_)";
var mapMethod = $"MapToInstance({name}_)";
normalOrMap = ps.IsNullable() ?
$" = {name}_ != null ? {mapster} : null" :
$" = {mapster}";
$" = {name}_ != null ? {mapMethod} : null" :
$" = {mapMethod}";
}
}

Expand All @@ -320,10 +316,10 @@ private string GeneratePublicMethods(ClassSymbol targetClassSymbol, ProxyData pr
{
if (returnIsReplaced)
{
var mapster = $"Mapster.TypeAdapter.Adapt<{returnTypeAsString}>({alternateReturnVariableName})";
var mapMethod = $"MapToInterface({alternateReturnVariableName})";
str.AppendLine(method.ReturnType.IsNullable() ?
$" return {alternateReturnVariableName} != null ? {mapster} : null;" :
$" return {mapster};");
$" return {alternateReturnVariableName} != null ? {mapMethod} : null;" :
$" return {mapMethod};");
}
else
{
Expand Down Expand Up @@ -358,6 +354,7 @@ private string GenerateEvents(ClassSymbol targetClassSymbol, ProxyData proxyData
{
str.Append($" add {{ _Instance.{name} += value; }}");
}

if (@event.Any(e => e.MethodKind == MethodKind.EventRemove))
{
str.Append($" remove {{ _Instance.{name} -= value; }}");
Expand Down
24 changes: 12 additions & 12 deletions src/ProxyInterfaceSourceGenerator/Models/Context.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace ProxyInterfaceSourceGenerator.Models;

internal record Context
{
public GeneratorExecutionContext GeneratorExecutionContext { get; init; }

public IDictionary<InterfaceDeclarationSyntax, ProxyData> Candidates { get; init; } = default!;

public Dictionary<string, string> ReplacedTypes { get; } = new();
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace ProxyInterfaceSourceGenerator.Models;

internal record Context
{
public GeneratorExecutionContext GeneratorExecutionContext { get; init; }

public IDictionary<InterfaceDeclarationSyntax, ProxyData> Candidates { get; init; } = default!;

public List<ReplacedTypeInfo> ReplacedTypes { get; } = new();
}
11 changes: 11 additions & 0 deletions src/ProxyInterfaceSourceGenerator/Models/ReplacedTypeInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace ProxyInterfaceSourceGenerator.Models;

internal record ReplacedTypeInfo
(
string ClassType,
string InterfaceType,
string ElementType,
string ElementInterfaceType,
string Proxy,
bool Direct
);
Loading

0 comments on commit 9ec0816

Please sign in to comment.