Fixed TryFindProxyDataByTypeName (#30)
* pnp * . * . * okee * ns * . * o * . * , * x * t * co * . * r * CastTo
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
using ProxyInterfaceSourceGenerator.Models;
|
||||
@@ -26,14 +27,118 @@ internal abstract class BaseGenerator
|
||||
return GetReplacedType(property.Type, out isReplaced);
|
||||
}
|
||||
|
||||
protected bool TryFindProxyDataByTypeName(string type, [NotNullWhen(true)] out ProxyData? proxyData)
|
||||
{
|
||||
proxyData = Context.CandidateInterfaces.Values.FirstOrDefault(x => x.FullRawTypeName == type);
|
||||
if (proxyData != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var ci in Context.CandidateInterfaces.Values)
|
||||
{
|
||||
foreach (var u in ci.Usings)
|
||||
{
|
||||
if ($"{u}.{ci.FullRawTypeName}" == type)
|
||||
{
|
||||
proxyData = ci;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected string GetWhereStatementFromMethod(IMethodSymbol method)
|
||||
{
|
||||
if (!method.IsGenericMethod)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var list = new List<string>();
|
||||
foreach (var typeParameterSymbol in method.TypeParameters)
|
||||
{
|
||||
if (TryGetWhereConstraints(typeParameterSymbol, false, out var constraint))
|
||||
{
|
||||
list.Add(constraint.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return string.Concat(list);
|
||||
}
|
||||
|
||||
protected string ResolveInterfaceNameWithOptionalTypeConstraints(INamedTypeSymbol namedTypeSymbol, string interfaceName)
|
||||
{
|
||||
if (!namedTypeSymbol.IsGenericType)
|
||||
{
|
||||
return interfaceName;
|
||||
}
|
||||
|
||||
var str = new StringBuilder($"{interfaceName}<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>");
|
||||
|
||||
foreach (var typeParameterSymbol in namedTypeSymbol.TypeArguments.OfType<ITypeParameterSymbol>())
|
||||
{
|
||||
if (TryGetWhereConstraints(typeParameterSymbol, false, out var constraint))
|
||||
{
|
||||
str.Append(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://www.codeproject.com/Articles/871704/Roslyn-Code-Analysis-in-Easy-Samples-Part-2
|
||||
/// </summary>
|
||||
public bool TryGetWhereConstraints(ITypeParameterSymbol typeParameterSymbol, bool replaceIt, [NotNullWhen(true)] out ConstraintInfo? constraint)
|
||||
{
|
||||
var constraints = new List<string>();
|
||||
if (typeParameterSymbol.HasReferenceTypeConstraint)
|
||||
{
|
||||
constraints.Add("class");
|
||||
}
|
||||
|
||||
if (typeParameterSymbol.HasValueTypeConstraint)
|
||||
{
|
||||
constraints.Add("struct");
|
||||
}
|
||||
|
||||
if (typeParameterSymbol.HasConstructorConstraint)
|
||||
{
|
||||
constraints.Add("new()");
|
||||
}
|
||||
|
||||
foreach (var namedTypeSymbol in typeParameterSymbol.ConstraintTypes.OfType<INamedTypeSymbol>())
|
||||
{
|
||||
if (replaceIt)
|
||||
{
|
||||
constraints.Add(GetReplacedType(namedTypeSymbol, out _));
|
||||
}
|
||||
else
|
||||
{
|
||||
constraints.Add(namedTypeSymbol.GetFullType());
|
||||
}
|
||||
}
|
||||
|
||||
if (!constraints.Any())
|
||||
{
|
||||
constraint = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
constraint = new(typeParameterSymbol.Name, constraints);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected string GetReplacedType(ITypeSymbol typeSymbol, out bool isReplaced)
|
||||
{
|
||||
isReplaced = false;
|
||||
|
||||
var typeSymbolAsString = typeSymbol.ToString();
|
||||
|
||||
var existing = Context.CandidateInterfaces.Values.FirstOrDefault(x => x.RawTypeName == typeSymbolAsString);
|
||||
if (existing is not null)
|
||||
if (TryFindProxyDataByTypeName(typeSymbolAsString, out var existing))
|
||||
{
|
||||
if (!Context.ReplacedTypes.ContainsKey(typeSymbolAsString))
|
||||
{
|
||||
@@ -50,17 +155,17 @@ internal abstract class BaseGenerator
|
||||
foreach (var typeArgument in namedTypedSymbol.TypeArguments)
|
||||
{
|
||||
var typeArgumentAsString = typeArgument.ToString();
|
||||
var exist = Context.CandidateInterfaces.Values.FirstOrDefault(x => x.RawTypeName == typeArgumentAsString);
|
||||
if (exist is not null)
|
||||
|
||||
if (TryFindProxyDataByTypeName(typeArgumentAsString, out var existingTypeArgument))
|
||||
{
|
||||
isReplaced = true;
|
||||
|
||||
if (!Context.ReplacedTypes.ContainsKey(typeArgumentAsString))
|
||||
{
|
||||
Context.ReplacedTypes.Add(typeArgumentAsString, exist.FullInterfaceName);
|
||||
Context.ReplacedTypes.Add(typeArgumentAsString, existingTypeArgument.FullInterfaceName);
|
||||
}
|
||||
|
||||
propertyTypeAsStringToBeModified = propertyTypeAsStringToBeModified.Replace(typeArgumentAsString, exist.FullInterfaceName);
|
||||
propertyTypeAsStringToBeModified = propertyTypeAsStringToBeModified.Replace(typeArgumentAsString, existingTypeArgument.FullInterfaceName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,12 +36,12 @@ internal class PartialInterfacesGenerator : BaseGenerator, IFilesGenerator
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryGetNamedTypeSymbolByFullName(TypeKind.Class, pd.TypeName, pd.Usings, out var targetClassSymbol))
|
||||
if (!TryGetNamedTypeSymbolByFullName(TypeKind.Class, pd.FullTypeName, pd.Usings, out var targetClassSymbol))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var interfaceName = targetClassSymbol.Symbol.ResolveInterfaceNameWithOptionalTypeConstraints(pd.ShortInterfaceName);
|
||||
var interfaceName = ResolveInterfaceNameWithOptionalTypeConstraints(targetClassSymbol.Symbol, pd.ShortInterfaceName);
|
||||
|
||||
fileData = new FileData(
|
||||
$"{sourceInterfaceSymbol.Symbol.GetFileName()}.g.cs",
|
||||
@@ -113,7 +113,12 @@ namespace {ns}
|
||||
methodParameters.Add($"{ps.GetParamsPrefix()}{ps.GetRefPrefix()}{type} {ps.GetSanitizedName()}{ps.GetDefaultValue()}");
|
||||
}
|
||||
|
||||
str.AppendLine($" {GetReplacedType(method.ReturnType, out _)} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){method.GetWhereStatement()};");
|
||||
var whereStatement = GetWhereStatementFromMethod(method);
|
||||
|
||||
//public static string GetWhereStatement(this IMethodSymbol method) =>
|
||||
// !method.IsGenericMethod ? string.Empty : string.Join("", method.TypeParameters.Select(tp => tp.GetWhereConstraints()));
|
||||
|
||||
str.AppendLine($" {GetReplacedType(method.ReturnType, out _)} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement};");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Text;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal partial class ProxyClassesGenerator
|
||||
{
|
||||
private static string GeneratePrivateAutoMapper()
|
||||
{
|
||||
return " private readonly IMapper _mapper;";
|
||||
}
|
||||
|
||||
private string GenerateMapperConfigurationForAutoMapper()
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
str.AppendLine(" _mapper = new MapperConfiguration(cfg =>");
|
||||
str.AppendLine(" {");
|
||||
foreach (var replacedType in Context.ReplacedTypes)
|
||||
{
|
||||
TryFindProxyDataByTypeName(replacedType.Key, out var fullTypeName);
|
||||
var classNameProxy = $"{fullTypeName!.Namespace}.{fullTypeName.ShortTypeName}Proxy";
|
||||
|
||||
var instance = $"instance{(replacedType.Key + replacedType.Value).GetDeterministicHashCodeAsString()}";
|
||||
var proxy = $"proxy{(replacedType.Value + replacedType.Key).GetDeterministicHashCodeAsString()}";
|
||||
|
||||
str.AppendLine($" cfg.CreateMap<{replacedType.Key}, {replacedType.Value}>().ConstructUsing({instance} => new {classNameProxy}({instance}));");
|
||||
str.AppendLine($" cfg.CreateMap<{replacedType.Value}, {replacedType.Key}>().ConstructUsing({proxy} => (({classNameProxy}) {proxy})._Instance);");
|
||||
}
|
||||
str.AppendLine(" }).CreateMapper();");
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
}
|
||||
@@ -30,20 +30,20 @@ internal partial class ProxyClassesGenerator : BaseGenerator, IFilesGenerator
|
||||
{
|
||||
fileData = default;
|
||||
|
||||
if (!TryGetNamedTypeSymbolByFullName(TypeKind.Class, pd.TypeName, pd.Usings, out var targetClassSymbol))
|
||||
if (!TryGetNamedTypeSymbolByFullName(TypeKind.Class, pd.FullTypeName, pd.Usings, out var targetClassSymbol))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var interfaceName = targetClassSymbol.Symbol.ResolveInterfaceNameWithOptionalTypeConstraints(pd.ShortInterfaceName);
|
||||
var interfaceName = ResolveInterfaceNameWithOptionalTypeConstraints(targetClassSymbol.Symbol, pd.ShortInterfaceName);
|
||||
var className = targetClassSymbol.Symbol.ResolveProxyClassName();
|
||||
var constructorName = $"{targetClassSymbol.Symbol.Name}Proxy";
|
||||
|
||||
var extendsProxyClasses = targetClassSymbol.BaseTypes
|
||||
.Join(
|
||||
Context.CandidateInterfaces.Values.Select(v => v.RawTypeName),
|
||||
bt => bt.ToString(),
|
||||
ci => ci, (bt, _) => bt
|
||||
Context.CandidateInterfaces.Values,
|
||||
namedTypeSymbol => namedTypeSymbol.ToString(),
|
||||
proxyData => proxyData.FullRawTypeName, (_, proxyData) => proxyData
|
||||
).ToList();
|
||||
|
||||
fileData = new FileData(
|
||||
@@ -57,20 +57,19 @@ internal partial class ProxyClassesGenerator : BaseGenerator, IFilesGenerator
|
||||
private string CreateProxyClassCode(
|
||||
ProxyData pd,
|
||||
ClassSymbol targetClassSymbol,
|
||||
List<INamedTypeSymbol> extendsProxyClasses,
|
||||
List<ProxyData> extendsProxyClasses,
|
||||
string interfaceName,
|
||||
string className,
|
||||
string constructorName)
|
||||
{
|
||||
var extendsFullNames = extendsProxyClasses.Select(e => e.ResolveFullProxyClassName()).ToList();
|
||||
var extends = extendsProxyClasses.Any() ? $"{string.Join(", ", extendsFullNames)}, " : string.Empty;
|
||||
var extends = extendsProxyClasses.Select(e => $"{e.Namespace}.{e.ShortTypeName}Proxy, ").FirstOrDefault() ?? string.Empty;
|
||||
var @base = extendsProxyClasses.Any() ? " : base(instance)" : string.Empty;
|
||||
var @new = extendsProxyClasses.Any() ? "new " : string.Empty;
|
||||
var instanceBaseDefinition = extendsProxyClasses.Any() ? $"public {extendsProxyClasses.First()} _InstanceBase {{ get; }}\r\n" : string.Empty;
|
||||
var instanceBaseDefinition = extendsProxyClasses.Any() ? $"public {extendsProxyClasses[0].FullRawTypeName} _InstanceBase {{ get; }}\r\n" : string.Empty;
|
||||
var instanceBaseSet = extendsProxyClasses.Any() ? "_InstanceBase = instance;" : string.Empty;
|
||||
|
||||
var properties = GeneratePublicProperties(targetClassSymbol, pd.ProxyBaseClasses);
|
||||
var methods = GeneratePublicMethods(targetClassSymbol, pd.ProxyBaseClasses);
|
||||
var methods = GeneratePublicMethods(targetClassSymbol, pd.ProxyBaseClasses, extendsProxyClasses);
|
||||
var events = GenerateEvents(targetClassSymbol, pd.ProxyBaseClasses);
|
||||
|
||||
var configurationForAutoMapper = string.Empty;
|
||||
@@ -123,29 +122,6 @@ namespace {pd.Namespace}
|
||||
{(SupportsNullable ? "#nullable disable" : string.Empty)}";
|
||||
}
|
||||
|
||||
private static string GeneratePrivateAutoMapper()
|
||||
{
|
||||
return " private readonly IMapper _mapper;";
|
||||
}
|
||||
|
||||
private string GenerateMapperConfigurationForAutoMapper()
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
str.AppendLine(" _mapper = new MapperConfiguration(cfg =>");
|
||||
str.AppendLine(" {");
|
||||
foreach (var replacedType in Context.ReplacedTypes)
|
||||
{
|
||||
var proxy = $"{replacedType.Key}Proxy";
|
||||
|
||||
str.AppendLine($" cfg.CreateMap<{replacedType.Key}, {replacedType.Value}>().ConstructUsing(instance => new {proxy}(instance));");
|
||||
str.AppendLine($" cfg.CreateMap<{replacedType.Value}, {replacedType.Key}>().ConstructUsing(proxy => (({proxy}) proxy)._Instance);");
|
||||
}
|
||||
str.AppendLine(" }).CreateMapper();");
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GeneratePublicProperties(ClassSymbol targetClassSymbol, bool proxyBaseClasses)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
@@ -153,6 +129,7 @@ namespace {pd.Namespace}
|
||||
foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol, proxyBaseClasses))
|
||||
{
|
||||
var type = GetPropertyType(property, out var isReplaced);
|
||||
|
||||
if (isReplaced)
|
||||
{
|
||||
str.AppendLine($" public {property.ToPropertyTextForClass(targetClassSymbol, type)}");
|
||||
@@ -167,7 +144,7 @@ namespace {pd.Namespace}
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GeneratePublicMethods(ClassSymbol targetClassSymbol, bool proxyBaseClasses)
|
||||
private string GeneratePublicMethods(ClassSymbol targetClassSymbol, bool proxyBaseClasses, List<ProxyData> extendsProxyClasses)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var method in MemberHelper.GetPublicMethods(targetClassSymbol, proxyBaseClasses))
|
||||
@@ -183,9 +160,25 @@ namespace {pd.Namespace}
|
||||
invokeParameters.Add($"{ps.GetRefPrefix()}{ps.GetSanitizedName()}_");
|
||||
}
|
||||
|
||||
string overrideOrVirtual = string.Empty;
|
||||
if (method.IsOverride && method.OverriddenMethod != null)
|
||||
{
|
||||
var baseType = method.OverriddenMethod.ContainingType.GetFullType();
|
||||
if (TryGetNamedTypeSymbolByFullName(TypeKind.Class, baseType, Enumerable.Empty<string>(), out _))
|
||||
{
|
||||
overrideOrVirtual = "override ";
|
||||
}
|
||||
}
|
||||
else if (method.IsVirtual)
|
||||
{
|
||||
overrideOrVirtual = "virtual ";
|
||||
}
|
||||
|
||||
string returnTypeAsString = GetReplacedType(method.ReturnType, out var returnIsReplaced);
|
||||
|
||||
str.AppendLine($" public {returnTypeAsString} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){method.GetWhereStatement()}");
|
||||
var whereStatement = GetWhereStatementFromMethod(method);
|
||||
|
||||
str.AppendLine($" public {overrideOrVirtual}{returnTypeAsString} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){whereStatement}");
|
||||
str.AppendLine(" {");
|
||||
foreach (var ps in method.Parameters)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user