Fixed generated code when a class extends multiple classes (#38)

* .

* .

* pnp

* ok

* compiles

* ?

* e

* set

* .ToArray()

* n

* ...

* ok

* pnp

* .

* .

* mapster
This commit is contained in:
Stef Heyenrath
2022-09-04 11:13:16 +02:00
committed by GitHub
parent ee35d1916f
commit 69fa995982
36 changed files with 824 additions and 340 deletions
@@ -26,4 +26,9 @@ internal static class StringExtensions
return result.ToString().Replace('-', '_');
}
}
public static string GetLastPart(this string fullTypeName)
{
return fullTypeName.Split('.').LastOrDefault() ?? fullTypeName;
}
}
@@ -31,13 +31,13 @@ internal abstract class BaseGenerator
protected bool TryFindProxyDataByTypeName(string type, [NotNullWhen(true)] out ProxyData? proxyData)
{
proxyData = Context.CandidateInterfaces.Values.FirstOrDefault(x => x.FullRawTypeName == type);
proxyData = Context.Candidates.Values.FirstOrDefault(x => x.FullRawTypeName == type);
if (proxyData != null)
{
return true;
}
foreach (var ci in Context.CandidateInterfaces.Values)
foreach (var ci in Context.Candidates.Values)
{
foreach (var u in ci.Usings)
{
@@ -18,7 +18,7 @@ internal class PartialInterfacesGenerator : BaseGenerator, IFilesGenerator
public IEnumerable<FileData> GenerateFiles()
{
foreach (var ci in Context.CandidateInterfaces)
foreach (var ci in Context.Candidates)
{
if (TryGenerateFile(ci.Key, ci.Value, out var file))
{
@@ -26,6 +26,7 @@ internal partial class ProxyClassesGenerator
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();
}
str.AppendLine(" }).CreateMapper();");
@@ -16,7 +16,7 @@ internal partial class ProxyClassesGenerator : BaseGenerator, IFilesGenerator
public IEnumerable<FileData> GenerateFiles()
{
foreach (var ci in Context.CandidateInterfaces)
foreach (var ci in Context.Candidates)
{
if (TryGenerateFile(ci.Value, out var file))
{
@@ -39,12 +39,30 @@ internal partial class ProxyClassesGenerator : BaseGenerator, IFilesGenerator
var className = targetClassSymbol.Symbol.ResolveProxyClassName();
var constructorName = $"{targetClassSymbol.Symbol.Name}Proxy";
var extendsProxyClasses = targetClassSymbol.BaseTypes
.Join(
Context.CandidateInterfaces.Values,
namedTypeSymbol => namedTypeSymbol.ToString(),
proxyData => proxyData.FullRawTypeName, (_, proxyData) => proxyData
).ToList();
var extendsProxyClasses = new List<ProxyData>();
foreach (var baseType in targetClassSymbol.BaseTypes)
{
var candidate = Context.Candidates.Values.FirstOrDefault(ci => ci.FullRawTypeName == baseType.ToString());
if (candidate is not null)
{
extendsProxyClasses.Add(candidate);
break;
}
// Try to find with usings
foreach (var @using in pd.Usings)
{
candidate = Context.Candidates.Values.FirstOrDefault(ci => $"{@using}.{ci.FullRawTypeName}" == baseType.ToString());
if (candidate is not null)
{
// Update the FullRawTypeName
candidate.FullRawTypeName = $"{@using}.{candidate.FullRawTypeName}";
extendsProxyClasses.Add(candidate);
break;
}
}
}
fileData = new FileData(
$"{targetClassSymbol.Symbol.GetFileName()}Proxy.g.cs",
@@ -62,12 +80,23 @@ internal partial class ProxyClassesGenerator : BaseGenerator, IFilesGenerator
string className,
string constructorName)
{
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[0].FullRawTypeName} _InstanceBase {{ get; }}\r\n" : string.Empty;
var instanceBaseSet = extendsProxyClasses.Any() ? "_InstanceBase = instance;" : string.Empty;
var firstExtends = extendsProxyClasses.FirstOrDefault();
var extends = string.Empty;
var @base = string.Empty;
var @new = string.Empty;
var instanceBaseDefinition = string.Empty;
var instanceBaseSetter = string.Empty;
if (firstExtends is not null)
{
extends = $"{firstExtends.Namespace}.{firstExtends.ShortTypeName}Proxy, ";
@base = " : base(instance)";
@new = "new ";
instanceBaseDefinition = $"public {firstExtends.FullRawTypeName} _Instance{firstExtends.FullRawTypeName.GetLastPart()} {{ get; }}";
instanceBaseSetter = $"_Instance{firstExtends.FullRawTypeName.GetLastPart()} = instance;";
}
var @abstract = string.Empty; // targetClassSymbol.Symbol.IsAbstract ? "abstract " : string.Empty;
var properties = GeneratePublicProperties(targetClassSymbol, pd.ProxyBaseClasses);
var methods = GeneratePublicMethods(targetClassSymbol, pd.ProxyBaseClasses, extendsProxyClasses);
var events = GenerateEvents(targetClassSymbol, pd.ProxyBaseClasses);
@@ -97,7 +126,7 @@ using System;
namespace {pd.Namespace}
{{
public partial class {className} : {extends}{interfaceName}
public {@abstract}partial class {className} : {extends}{interfaceName}
{{
public {@new}{targetClassSymbol.Symbol} _Instance {{ get; }}
{instanceBaseDefinition}
@@ -111,7 +140,7 @@ namespace {pd.Namespace}
public {constructorName}({targetClassSymbol} instance){@base}
{{
_Instance = instance;
{instanceBaseSet}
{instanceBaseSetter}
{configurationForAutoMapper}
}}
@@ -220,7 +249,7 @@ namespace {pd.Namespace}
}
else
{
var type = GetParameterType(ps, out var isReplaced);
_ = GetParameterType(ps, out var isReplaced); // TODO : response is not used?
if (isReplaced)
{
normalOrMap = $" = _mapper.Map<{ps.Type}>({ps.GetSanitizedName()})";
@@ -9,7 +9,7 @@ internal record Context
// public List<ContextData> GeneratedData { get; } = new List<ContextData>();
public IDictionary<InterfaceDeclarationSyntax, ProxyData> CandidateInterfaces { get; init; } = default!;
public IDictionary<InterfaceDeclarationSyntax, ProxyData> Candidates { get; init; } = default!;
public Dictionary<string, string> ReplacedTypes { get; } = new();
}
@@ -5,7 +5,7 @@ internal class ProxyData
public string Namespace { get; init; }
public string ShortInterfaceName { get; init; }
public string FullInterfaceName { get; init; }
public string FullRawTypeName { get; init; }
public string FullRawTypeName { get; set; }
public string ShortTypeName { get; init; }
public string FullTypeName { get; init; }
public List<string> Usings { get; init; }
@@ -63,7 +63,7 @@ internal class ProxyInterfaceCodeGenerator : ISourceGenerator
var context = new Context
{
GeneratorExecutionContext = ctx,
CandidateInterfaces = receiver.CandidateInterfaces
Candidates = receiver.CandidateInterfaces
};
var attributeData = _proxyAttributeGenerator.GenerateFile();
@@ -75,7 +75,7 @@ internal class ProxyInterfaceCodeGenerator : ISourceGenerator
var context = new Context
{
GeneratorExecutionContext = ctx,
CandidateInterfaces = receiver.CandidateInterfaces
Candidates = receiver.CandidateInterfaces
};
var partialInterfacesGenerator = new PartialInterfacesGenerator(context, supportsNullable);
@@ -90,7 +90,7 @@ internal class ProxyInterfaceCodeGenerator : ISourceGenerator
var context = new Context
{
GeneratorExecutionContext = ctx,
CandidateInterfaces = receiver.CandidateInterfaces
Candidates = receiver.CandidateInterfaces
};
var proxyClassesGenerator = new ProxyClassesGenerator(context, supportsNullable);
@@ -77,7 +77,7 @@ internal class ProxySyntaxReceiver : ISyntaxReceiver
{
Namespace = ns,
ShortInterfaceName = interfaceDeclarationSyntax.Identifier.ToString(),
FullInterfaceName = CreateFullBuilderClassName(ns, interfaceDeclarationSyntax), // $"{ns}.{interfaceDeclarationSyntax.Identifier}",
FullInterfaceName = CreateFullInterfaceName(ns, interfaceDeclarationSyntax), // $"{ns}.{interfaceDeclarationSyntax.Identifier}",
FullRawTypeName = rawTypeName,
ShortTypeName = ConvertTypeName(rawTypeName).Split('.').Last(),
FullTypeName = ConvertTypeName(rawTypeName),
@@ -95,7 +95,7 @@ internal class ProxySyntaxReceiver : ISyntaxReceiver
$"{typeName.Replace("<", string.Empty).Replace(">", string.Empty).Replace(",", string.Empty).Trim()}`{typeName.Count(c => c == ',') + 1}";
}
private static string CreateFullBuilderClassName(string ns, BaseTypeDeclarationSyntax classDeclarationSyntax)
private static string CreateFullInterfaceName(string ns, BaseTypeDeclarationSyntax classDeclarationSyntax)
{
return !string.IsNullOrEmpty(ns) ? $"{ns}.{classDeclarationSyntax.Identifier}" : classDeclarationSyntax.Identifier.ToString();
}