ProxyBaseClasses (#27)
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Usings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
@@ -38,6 +38,17 @@ public partial interface IPerson
|
||||
}
|
||||
```
|
||||
|
||||
#### ProxyBaseClasses
|
||||
In case also want to proxy the properties/methods/events from the base class(es), use this:
|
||||
|
||||
``` c#
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(ProxyInterfaceConsumer.Person), true)] // 👈 Provide `true` as second parameter.
|
||||
public partial interface IPerson
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### When the code is compiled, this source generator creates the following
|
||||
|
||||
#### :one: An additional partial interface
|
||||
@@ -80,4 +91,4 @@ public class PersonProxy : IPerson
|
||||
IPerson p = new PersonProxy(new Person());
|
||||
p.Name = "test";
|
||||
p.HelloWorld("stef");
|
||||
```
|
||||
```
|
||||
@@ -1,11 +1,9 @@
|
||||
using DifferentNamespace;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(Address))]
|
||||
public partial interface IAddress
|
||||
{
|
||||
}
|
||||
using DifferentNamespace;
|
||||
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(Address))]
|
||||
public partial interface IAddress
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace ProxyInterfaceConsumer
|
||||
namespace ProxyInterfaceConsumer
|
||||
{
|
||||
[ProxyInterfaceGenerator.Proxy(typeof(ProxyInterfaceConsumer.PersonT<>))]
|
||||
public partial interface IPersonT<T> where T : struct
|
||||
public partial interface IPersonT //<T> where T : struct
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -15,16 +15,16 @@ namespace ProxyInterfaceConsumer
|
||||
|
||||
public static void Main()
|
||||
{
|
||||
IPersonT<int> pT = new PersonTProxy<int>(new PersonT<int>());
|
||||
pT.TVal = 1;
|
||||
Console.WriteLine(JsonSerializer.Serialize(pT, JsonSerializerOptions));
|
||||
Console.WriteLine(new string('-', 80));
|
||||
//IPersonT<int> pT = new PersonTProxy<int>(new PersonT<int>());
|
||||
//pT.TVal = 1;
|
||||
//Console.WriteLine(JsonSerializer.Serialize(pT, JsonSerializerOptions));
|
||||
//Console.WriteLine(new string('-', 80));
|
||||
|
||||
IPersonTT<int, Program> pTT = new PersonTTProxy<int, Program>(new PersonTT<int, Program>());
|
||||
pTT.TVal1 = 42;
|
||||
pTT.TVal2 = new Program();
|
||||
Console.WriteLine(JsonSerializer.Serialize(pTT, JsonSerializerOptions));
|
||||
Console.WriteLine(new string('-', 80));
|
||||
//IPersonTT<int, Program> pTT = new PersonTTProxy<int, Program>(new PersonTT<int, Program>());
|
||||
//pTT.TVal1 = 42;
|
||||
//pTT.TVal2 = new Program();
|
||||
//Console.WriteLine(JsonSerializer.Serialize(pTT, JsonSerializerOptions));
|
||||
//Console.WriteLine(new string('-', 80));
|
||||
|
||||
var ap = new AddressProxy(new Address { HouseNumber = 42 });
|
||||
ap.HouseNumber = -1;
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="IPersonT.cs" />
|
||||
<Compile Remove="IPersonTT.cs" />
|
||||
<Compile Remove="PersonT.cs" />
|
||||
<Compile Remove="PersonTT.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="10.1.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2">
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
// https://stackoverflow.com/questions/61573959/how-to-resolve-error-notnullwhen-attribute-is-inaccessible-due-to-its-protectio
|
||||
// https://stackoverflow.com/questions/61573959/how-to-resolve-error-notnullwhen-attribute-is-inaccessible-due-to-its-protectio
|
||||
|
||||
namespace System.Diagnostics.CodeAnalysis
|
||||
namespace System.Diagnostics.CodeAnalysis;
|
||||
|
||||
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
|
||||
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
|
||||
internal sealed class NotNullWhenAttribute : Attribute
|
||||
{
|
||||
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
|
||||
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
|
||||
internal sealed class NotNullWhenAttribute : Attribute
|
||||
{
|
||||
/// <summary>Initializes the attribute with the specified return value condition.</summary>
|
||||
/// <param name="returnValue">
|
||||
/// The return value condition. If the method returns this value, the associated parameter will not be null.
|
||||
/// </param>
|
||||
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
|
||||
/// <summary>Initializes the attribute with the specified return value condition.</summary>
|
||||
/// <param name="returnValue">
|
||||
/// The return value condition. If the method returns this value, the associated parameter will not be null.
|
||||
/// </param>
|
||||
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
|
||||
|
||||
/// <summary>Gets the return value condition.</summary>
|
||||
public bool ReturnValue { get; }
|
||||
}
|
||||
/// <summary>Gets the return value condition.</summary>
|
||||
public bool ReturnValue { get; }
|
||||
}
|
||||
@@ -1,18 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using ProxyInterfaceSourceGenerator.SyntaxReceiver;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator
|
||||
namespace ProxyInterfaceSourceGenerator;
|
||||
|
||||
internal record Context
|
||||
{
|
||||
internal record Context
|
||||
{
|
||||
public GeneratorExecutionContext GeneratorExecutionContext { get; init; }
|
||||
public GeneratorExecutionContext GeneratorExecutionContext { get; init; }
|
||||
|
||||
// public List<ContextData> GeneratedData { get; } = new List<ContextData>();
|
||||
// public List<ContextData> GeneratedData { get; } = new List<ContextData>();
|
||||
|
||||
public IDictionary<InterfaceDeclarationSyntax, ProxyData> CandidateInterfaces { get; init; } = default!;
|
||||
public IDictionary<InterfaceDeclarationSyntax, ProxyData> CandidateInterfaces { get; init; } = default!;
|
||||
|
||||
public Dictionary<string, string> ReplacedTypes { get; } = new Dictionary<string, string>();
|
||||
}
|
||||
public Dictionary<string, string> ReplacedTypes { get; } = new Dictionary<string, string>();
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
using ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator
|
||||
namespace ProxyInterfaceSourceGenerator;
|
||||
|
||||
internal record ContextData
|
||||
{
|
||||
internal record ContextData
|
||||
{
|
||||
public string? InterfaceName { get; init; }
|
||||
public string? InterfaceName { get; init; }
|
||||
|
||||
public string? ClassName { get; init; }
|
||||
public string? ClassName { get; init; }
|
||||
|
||||
public FileData FileData { get; init; } = default!;
|
||||
}
|
||||
public FileData FileData { get; init; } = default!;
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
namespace ProxyInterfaceSourceGenerator.Enums
|
||||
namespace ProxyInterfaceSourceGenerator.Enums;
|
||||
|
||||
internal enum TypeEnum
|
||||
{
|
||||
internal enum TypeEnum
|
||||
{
|
||||
ValueTypeOrString,
|
||||
ValueTypeOrString,
|
||||
|
||||
Interface,
|
||||
Interface,
|
||||
|
||||
Complex
|
||||
}
|
||||
Complex
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions
|
||||
{
|
||||
internal static class MethodSymbolExtensions
|
||||
{
|
||||
public static string GetMethodNameWithOptionalTypeParameters(this IMethodSymbol method) =>
|
||||
!method.IsGenericMethod ? method.Name : $"{method.Name}<{string.Join(", ", method.TypeParameters.Select(tp => tp.Name))}>";
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
public static string GetWhereStatement(this IMethodSymbol method) =>
|
||||
!method.IsGenericMethod ? string.Empty : string.Join("", method.TypeParameters.Select(tp => tp.GetWhereStatement()));
|
||||
}
|
||||
internal static class MethodSymbolExtensions
|
||||
{
|
||||
public static string GetMethodNameWithOptionalTypeParameters(this IMethodSymbol method) =>
|
||||
!method.IsGenericMethod ? method.Name : $"{method.Name}<{string.Join(", ", method.TypeParameters.Select(tp => tp.Name))}>";
|
||||
|
||||
public static string GetWhereStatement(this IMethodSymbol method) =>
|
||||
!method.IsGenericMethod ? string.Empty : string.Join("", method.TypeParameters.Select(tp => tp.GetWhereStatement()));
|
||||
}
|
||||
@@ -1,57 +1,74 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class NamedTypeSymbolExtensions
|
||||
{
|
||||
internal static class NamedTypeSymbolExtensions
|
||||
public static List<INamedTypeSymbol> GetBaseTypes(this INamedTypeSymbol? type)
|
||||
{
|
||||
public static string GetFileName(this INamedTypeSymbol namedTypeSymbol)
|
||||
var types = new List<INamedTypeSymbol>();
|
||||
|
||||
bool me = true;
|
||||
while (type != null && type.SpecialType != SpecialType.System_Object)
|
||||
{
|
||||
var typeName = namedTypeSymbol.GetFullType();
|
||||
return !(typeName.Contains('<') && typeName.Contains('>')) ?
|
||||
typeName :
|
||||
$"{typeName.Replace('.', '_').Replace('<', '_').Replace('>', '_').Replace(", ", "-")}_{typeName.Count(c => c == ',') + 1}";
|
||||
}
|
||||
|
||||
public static string GetFullType(this INamedTypeSymbol namedTypeSymbol)
|
||||
{
|
||||
// https://www.codeproject.com/Articles/861548/Roslyn-Code-Analysis-in-Easy-Samples-Part
|
||||
//var str = new StringBuilder(namedTypeSymbol.Name);
|
||||
|
||||
//if (namedTypeSymbol.TypeArguments.Count() > 0)
|
||||
//{
|
||||
// str.AppendFormat("<{0}>", string.Join(", ", namedTypeSymbol.TypeArguments.OfType<INamedTypeSymbol>().Select(typeArg => typeArg.GetFullType())));
|
||||
//}
|
||||
|
||||
return namedTypeSymbol.OriginalDefinition.ToString();// str.ToString();
|
||||
}
|
||||
|
||||
public static string ResolveInterfaceNameWithOptionalTypeConstraints(this INamedTypeSymbol namedTypeSymbol, string interfaceName)
|
||||
{
|
||||
if (!namedTypeSymbol.IsGenericType)
|
||||
if (!me)
|
||||
{
|
||||
return interfaceName;
|
||||
types.Add(type);
|
||||
}
|
||||
|
||||
var str = new StringBuilder($"{interfaceName}<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>");
|
||||
|
||||
foreach (var typeParameterSymbol in namedTypeSymbol.TypeArguments.OfType<ITypeParameterSymbol>())
|
||||
{
|
||||
str.Append(typeParameterSymbol.GetWhereStatement());
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
type = type.BaseType;
|
||||
me = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See https://stackoverflow.com/questions/24157101/roslyns-gettypebymetadataname-and-generic-types
|
||||
/// </summary>
|
||||
public static string ResolveProxyClassName(this INamedTypeSymbol namedTypeSymbol)
|
||||
return types;
|
||||
}
|
||||
|
||||
public static string GetFileName(this INamedTypeSymbol namedTypeSymbol)
|
||||
{
|
||||
var typeName = namedTypeSymbol.GetFullType();
|
||||
return !(typeName.Contains('<') && typeName.Contains('>')) ?
|
||||
typeName :
|
||||
$"{typeName.Replace('.', '_').Replace('<', '_').Replace('>', '_').Replace(", ", "-")}_{typeName.Count(c => c == ',') + 1}";
|
||||
}
|
||||
|
||||
public static string GetFullType(this INamedTypeSymbol namedTypeSymbol)
|
||||
{
|
||||
// https://www.codeproject.com/Articles/861548/Roslyn-Code-Analysis-in-Easy-Samples-Part
|
||||
//var str = new StringBuilder(namedTypeSymbol.Name);
|
||||
|
||||
//if (namedTypeSymbol.TypeArguments.Count() > 0)
|
||||
//{
|
||||
// str.AppendFormat("<{0}>", string.Join(", ", namedTypeSymbol.TypeArguments.OfType<INamedTypeSymbol>().Select(typeArg => typeArg.GetFullType())));
|
||||
//}
|
||||
|
||||
return namedTypeSymbol.OriginalDefinition.ToString();// str.ToString();
|
||||
}
|
||||
|
||||
public static string ResolveInterfaceNameWithOptionalTypeConstraints(this INamedTypeSymbol namedTypeSymbol, string interfaceName)
|
||||
{
|
||||
if (!namedTypeSymbol.IsGenericType)
|
||||
{
|
||||
return !namedTypeSymbol.IsGenericType ?
|
||||
$"{namedTypeSymbol.Name}Proxy" :
|
||||
$"{namedTypeSymbol.Name}Proxy<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>";
|
||||
return interfaceName;
|
||||
}
|
||||
|
||||
var str = new StringBuilder($"{interfaceName}<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>");
|
||||
|
||||
foreach (var typeParameterSymbol in namedTypeSymbol.TypeArguments.OfType<ITypeParameterSymbol>())
|
||||
{
|
||||
str.Append(typeParameterSymbol.GetWhereStatement());
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See https://stackoverflow.com/questions/24157101/roslyns-gettypebymetadataname-and-generic-types
|
||||
/// </summary>
|
||||
public static string ResolveProxyClassName(this INamedTypeSymbol namedTypeSymbol)
|
||||
{
|
||||
return !namedTypeSymbol.IsGenericType ?
|
||||
$"{namedTypeSymbol.Name}Proxy" :
|
||||
$"{namedTypeSymbol.Name}Proxy<{string.Join(", ", namedTypeSymbol.TypeArguments.Select(ta => ta.Name))}>";
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,34 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using ProxyInterfaceSourceGenerator.Enums;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class ParameterSymbolExtensions
|
||||
{
|
||||
internal static class ParameterSymbolExtensions
|
||||
public static string GetRefPrefix(this IParameterSymbol ps)
|
||||
{
|
||||
public static string GetRefPrefix(this IParameterSymbol ps)
|
||||
switch (ps.RefKind)
|
||||
{
|
||||
switch (ps.RefKind)
|
||||
{
|
||||
case RefKind.In:
|
||||
return "in ";
|
||||
case RefKind.In:
|
||||
return "in ";
|
||||
|
||||
case RefKind.Out:
|
||||
return "out ";
|
||||
case RefKind.Out:
|
||||
return "out ";
|
||||
|
||||
case RefKind.Ref:
|
||||
return "ref ";
|
||||
case RefKind.Ref:
|
||||
return "ref ";
|
||||
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public static string GetParamsPrefix(this IParameterSymbol ps) =>
|
||||
ps.IsParams ? "params " : string.Empty;
|
||||
|
||||
public static string GetDefaultValue(this IParameterSymbol ps) =>
|
||||
ps.HasExplicitDefaultValue ? $" = {ps.ExplicitDefaultValue}" : string.Empty;
|
||||
|
||||
public static TypeEnum GetTypeEnum(this IParameterSymbol p) =>
|
||||
p.Type.GetTypeEnum();
|
||||
}
|
||||
|
||||
public static string GetParamsPrefix(this IParameterSymbol ps) =>
|
||||
ps.IsParams ? "params " : string.Empty;
|
||||
|
||||
public static string GetDefaultValue(this IParameterSymbol ps) =>
|
||||
ps.HasExplicitDefaultValue ? $" = {ps.ExplicitDefaultValue}" : string.Empty;
|
||||
|
||||
public static TypeEnum GetTypeEnum(this IParameterSymbol p) =>
|
||||
p.Type.GetTypeEnum();
|
||||
}
|
||||
@@ -1,37 +1,36 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using ProxyInterfaceSourceGenerator.Enums;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class PropertySymbolExtensions
|
||||
{
|
||||
internal static class PropertySymbolExtensions
|
||||
public static TypeEnum GetTypeEnum(this IPropertySymbol p) =>
|
||||
p.Type.GetTypeEnum();
|
||||
|
||||
public static string ToPropertyText(this IPropertySymbol property, string? overrideType = null)
|
||||
{
|
||||
public static TypeEnum GetTypeEnum(this IPropertySymbol p) =>
|
||||
p.Type.GetTypeEnum();
|
||||
var get = property.GetMethod != null ? "get; " : string.Empty;
|
||||
var set = property.SetMethod != null ? "set; " : string.Empty;
|
||||
|
||||
public static string ToPropertyText(this IPropertySymbol property, string? overrideType = null)
|
||||
{
|
||||
var get = property.GetMethod != null ? "get; " : string.Empty;
|
||||
var set = property.SetMethod != null ? "set; " : string.Empty;
|
||||
var type = !string.IsNullOrEmpty(overrideType) ? overrideType : $"{property.Type}";
|
||||
|
||||
var type = !string.IsNullOrEmpty(overrideType) ? overrideType : $"{property.Type}";
|
||||
return $"{type} {property.GetSanitizedName()} {{ {get}{set}}}";
|
||||
}
|
||||
|
||||
return $"{type} {property.GetSanitizedName()} {{ {get}{set}}}";
|
||||
}
|
||||
public static string ToPropertyTextForClass(this IPropertySymbol property)
|
||||
{
|
||||
var get = property.GetMethod != null ? $"get => _Instance.{property.GetSanitizedName()}; " : string.Empty;
|
||||
var set = property.SetMethod != null ? $"set => _Instance.{property.GetSanitizedName()} = value; " : string.Empty;
|
||||
|
||||
public static string ToPropertyTextForClass(this IPropertySymbol property)
|
||||
{
|
||||
var get = property.GetMethod != null ? $"get => _Instance.{property.GetSanitizedName()}; " : string.Empty;
|
||||
var set = property.SetMethod != null ? $"set => _Instance.{property.GetSanitizedName()} = value; " : string.Empty;
|
||||
return $"{property.Type} {property.GetSanitizedName()} {{ {get}{set}}}";
|
||||
}
|
||||
|
||||
return $"{property.Type} {property.GetSanitizedName()} {{ {get}{set}}}";
|
||||
}
|
||||
public static string ToPropertyTextForClass(this IPropertySymbol property, string overrideType)
|
||||
{
|
||||
var get = property.GetMethod != null ? $"get => _mapper.Map<{overrideType}>(_Instance.{property.GetSanitizedName()}); " : string.Empty;
|
||||
var set = property.SetMethod != null ? $"set => _Instance.{property.GetSanitizedName()} = _mapper.Map<{property.Type}>(value); " : string.Empty;
|
||||
|
||||
public static string ToPropertyTextForClass(this IPropertySymbol property, string overrideType)
|
||||
{
|
||||
var get = property.GetMethod != null ? $"get => _mapper.Map<{overrideType}>(_Instance.{property.GetSanitizedName()}); " : string.Empty;
|
||||
var set = property.SetMethod != null ? $"set => _Instance.{property.GetSanitizedName()} = _mapper.Map<{property.Type}>(value); " : string.Empty;
|
||||
|
||||
return $"{overrideType} {property.GetSanitizedName()} {{ {get}{set}}}";
|
||||
}
|
||||
return $"{overrideType} {property.GetSanitizedName()} {{ {get}{set}}}";
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions
|
||||
{
|
||||
internal static class SymbolExtensions
|
||||
{
|
||||
public static bool IsKeywordOrReserved(this ISymbol symbol) =>
|
||||
SyntaxFacts.GetKeywordKind(symbol.Name) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(symbol.Name) != SyntaxKind.None;
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
public static string GetSanitizedName(this ISymbol symbol) =>
|
||||
symbol.IsKeywordOrReserved() ? $"@{symbol.Name}" : symbol.Name;
|
||||
}
|
||||
internal static class SymbolExtensions
|
||||
{
|
||||
public static bool IsKeywordOrReserved(this ISymbol symbol) =>
|
||||
SyntaxFacts.GetKeywordKind(symbol.Name) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(symbol.Name) != SyntaxKind.None;
|
||||
|
||||
public static string GetSanitizedName(this ISymbol symbol) =>
|
||||
symbol.IsKeywordOrReserved() ? $"@{symbol.Name}" : symbol.Name;
|
||||
}
|
||||
@@ -1,41 +1,40 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class SyntaxNodeUtils
|
||||
{
|
||||
internal static class SyntaxNodeUtils
|
||||
// https://stackoverflow.com/questions/20458457/getting-class-fullname-including-namespace-from-roslyn-classdeclarationsyntax
|
||||
public static bool TryGetParentSyntax<T>(this SyntaxNode? syntaxNode, [NotNullWhen(true)] out T? result) where T : SyntaxNode
|
||||
{
|
||||
// https://stackoverflow.com/questions/20458457/getting-class-fullname-including-namespace-from-roslyn-classdeclarationsyntax
|
||||
public static bool TryGetParentSyntax<T>(this SyntaxNode? syntaxNode, [NotNullWhen(true)] out T? result) where T : SyntaxNode
|
||||
result = null;
|
||||
|
||||
if (syntaxNode is null)
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
syntaxNode = syntaxNode.Parent;
|
||||
|
||||
if (syntaxNode is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
if (syntaxNode.GetType() == typeof(T))
|
||||
{
|
||||
syntaxNode = syntaxNode.Parent;
|
||||
|
||||
if (syntaxNode is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (syntaxNode.GetType() == typeof(T))
|
||||
{
|
||||
result = (T)syntaxNode;
|
||||
return true;
|
||||
}
|
||||
|
||||
return TryGetParentSyntax(syntaxNode, out result);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
result = (T)syntaxNode;
|
||||
return true;
|
||||
}
|
||||
|
||||
return TryGetParentSyntax(syntaxNode, out result);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class TypeParameterSymbolExtensions
|
||||
{
|
||||
internal static class TypeParameterSymbolExtensions
|
||||
/// <summary>
|
||||
/// https://www.codeproject.com/Articles/871704/Roslyn-Code-Analysis-in-Easy-Samples-Part-2
|
||||
/// </summary>
|
||||
public static string GetWhereStatement(this ITypeParameterSymbol typeParameterSymbol)
|
||||
{
|
||||
/// <summary>
|
||||
/// https://www.codeproject.com/Articles/871704/Roslyn-Code-Analysis-in-Easy-Samples-Part-2
|
||||
/// </summary>
|
||||
public static string GetWhereStatement(this ITypeParameterSymbol typeParameterSymbol)
|
||||
var constraints = new List<string>();
|
||||
if (typeParameterSymbol.HasReferenceTypeConstraint)
|
||||
{
|
||||
var constraints = new List<string>();
|
||||
if (typeParameterSymbol.HasReferenceTypeConstraint)
|
||||
{
|
||||
constraints.Add("class");
|
||||
}
|
||||
|
||||
if (typeParameterSymbol.HasValueTypeConstraint)
|
||||
{
|
||||
constraints.Add("struct");
|
||||
}
|
||||
|
||||
if (typeParameterSymbol.HasConstructorConstraint)
|
||||
{
|
||||
constraints.Add("new()");
|
||||
}
|
||||
|
||||
constraints.AddRange(typeParameterSymbol.ConstraintTypes.OfType<INamedTypeSymbol>().Select(contstraintType => contstraintType.GetFullType()));
|
||||
|
||||
if (!constraints.Any())
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return $" where {typeParameterSymbol.Name} : {string.Join(", ", constraints)}";
|
||||
constraints.Add("class");
|
||||
}
|
||||
|
||||
if (typeParameterSymbol.HasValueTypeConstraint)
|
||||
{
|
||||
constraints.Add("struct");
|
||||
}
|
||||
|
||||
if (typeParameterSymbol.HasConstructorConstraint)
|
||||
{
|
||||
constraints.Add("new()");
|
||||
}
|
||||
|
||||
constraints.AddRange(typeParameterSymbol.ConstraintTypes.OfType<INamedTypeSymbol>().Select(contstraintType => contstraintType.GetFullType()));
|
||||
|
||||
if (!constraints.Any())
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return $" where {typeParameterSymbol.Name} : {string.Join(", ", constraints)}";
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,27 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using ProxyInterfaceSourceGenerator.Enums;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions
|
||||
namespace ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
internal static class TypeSymbolExtensions
|
||||
{
|
||||
internal static class TypeSymbolExtensions
|
||||
public static TypeEnum GetTypeEnum(this ITypeSymbol ts)
|
||||
{
|
||||
public static TypeEnum GetTypeEnum(this ITypeSymbol ts)
|
||||
if (ts.IsValueType || ts.IsString())
|
||||
{
|
||||
if (ts.IsValueType || ts.IsString())
|
||||
{
|
||||
return TypeEnum.ValueTypeOrString;
|
||||
}
|
||||
|
||||
if (ts.TypeKind == TypeKind.Interface)
|
||||
{
|
||||
return TypeEnum.Interface;
|
||||
}
|
||||
|
||||
return TypeEnum.Complex;
|
||||
return TypeEnum.ValueTypeOrString;
|
||||
}
|
||||
|
||||
public static bool IsString(this ITypeSymbol ts)
|
||||
if (ts.TypeKind == TypeKind.Interface)
|
||||
{
|
||||
return ts.ToString() == "string" || ts.ToString() == "string?";
|
||||
return TypeEnum.Interface;
|
||||
}
|
||||
|
||||
return TypeEnum.Complex;
|
||||
}
|
||||
|
||||
public static bool IsString(this ITypeSymbol ts)
|
||||
{
|
||||
return ts.ToString() == "string" || ts.ToString() == "string?";
|
||||
}
|
||||
}
|
||||
@@ -1,97 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
using ProxyInterfaceSourceGenerator.Model;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal abstract class BaseGenerator
|
||||
{
|
||||
internal abstract class BaseGenerator
|
||||
protected readonly Context Context;
|
||||
protected readonly bool SupportsNullable;
|
||||
|
||||
protected BaseGenerator(Context context, bool supportsNullable)
|
||||
{
|
||||
protected readonly Context _context;
|
||||
protected readonly bool _supportsNullable;
|
||||
Context = context;
|
||||
SupportsNullable = supportsNullable;
|
||||
}
|
||||
|
||||
public BaseGenerator(Context context, bool supportsNullable)
|
||||
protected string GetPropertyType(IPropertySymbol property, out bool isReplaced)
|
||||
{
|
||||
return GetReplacedType(property.Type, out isReplaced);
|
||||
}
|
||||
|
||||
protected string GetParameterType(IParameterSymbol property, out bool isReplaced)
|
||||
{
|
||||
return GetReplacedType(property.Type, out isReplaced);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
_context = context;
|
||||
_supportsNullable = supportsNullable;
|
||||
}
|
||||
|
||||
protected string GetPropertyType(IPropertySymbol property, out bool isReplaced)
|
||||
{
|
||||
return GetReplacedType(property.Type, out isReplaced);
|
||||
}
|
||||
|
||||
protected string GetParameterType(IParameterSymbol property, out bool isReplaced)
|
||||
{
|
||||
return GetReplacedType(property.Type, out isReplaced);
|
||||
}
|
||||
|
||||
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 (!Context.ReplacedTypes.ContainsKey(typeSymbolAsString))
|
||||
{
|
||||
if (!_context.ReplacedTypes.ContainsKey(typeSymbolAsString))
|
||||
{
|
||||
_context.ReplacedTypes.Add(typeSymbolAsString, existing.InterfaceName);
|
||||
}
|
||||
|
||||
isReplaced = true;
|
||||
return existing.InterfaceName;
|
||||
Context.ReplacedTypes.Add(typeSymbolAsString, existing.InterfaceName);
|
||||
}
|
||||
|
||||
if (typeSymbol is INamedTypeSymbol namedTypedSymbol)
|
||||
isReplaced = true;
|
||||
return existing.InterfaceName;
|
||||
}
|
||||
|
||||
if (typeSymbol is INamedTypeSymbol namedTypedSymbol)
|
||||
{
|
||||
var propertyTypeAsStringToBeModified = typeSymbolAsString;
|
||||
foreach (var typeArgument in namedTypedSymbol.TypeArguments)
|
||||
{
|
||||
var propertyTypeAsStringToBeModified = typeSymbolAsString;
|
||||
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)
|
||||
{
|
||||
var typeArgumentAsString = typeArgument.ToString();
|
||||
var exist = _context.CandidateInterfaces.Values.FirstOrDefault(x => x.RawTypeName == typeArgumentAsString);
|
||||
if (exist is not null)
|
||||
isReplaced = true;
|
||||
|
||||
if (!Context.ReplacedTypes.ContainsKey(typeArgumentAsString))
|
||||
{
|
||||
isReplaced = true;
|
||||
|
||||
if (!_context.ReplacedTypes.ContainsKey(typeArgumentAsString))
|
||||
{
|
||||
_context.ReplacedTypes.Add(typeArgumentAsString, exist.InterfaceName);
|
||||
}
|
||||
|
||||
propertyTypeAsStringToBeModified = propertyTypeAsStringToBeModified.Replace(typeArgumentAsString, exist.InterfaceName);
|
||||
Context.ReplacedTypes.Add(typeArgumentAsString, exist.InterfaceName);
|
||||
}
|
||||
}
|
||||
|
||||
return propertyTypeAsStringToBeModified;
|
||||
propertyTypeAsStringToBeModified = propertyTypeAsStringToBeModified.Replace(typeArgumentAsString, exist.InterfaceName);
|
||||
}
|
||||
}
|
||||
|
||||
return typeSymbolAsString;
|
||||
return propertyTypeAsStringToBeModified;
|
||||
}
|
||||
|
||||
protected INamedTypeSymbol GetNamedTypeSymbolByFullName(string name, IEnumerable<string>? usings = null)
|
||||
return typeSymbolAsString;
|
||||
}
|
||||
|
||||
protected ClassSymbol GetNamedTypeSymbolByFullName(string name, IEnumerable<string>? usings = null)
|
||||
{
|
||||
// The GetTypeByMetadataName method returns null if no type matches the full name or if 2 or more types (in different assemblies) match the full name.
|
||||
var symbol = Context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName(name);
|
||||
if (symbol is not null)
|
||||
{
|
||||
// The GetTypeByMetadataName method returns null if no type matches the full name or if 2 or more types (in different assemblies) match the full name.
|
||||
var symbol = _context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName(name);
|
||||
if (symbol is not null)
|
||||
{
|
||||
return symbol;
|
||||
}
|
||||
return new ClassSymbol(symbol, symbol.GetBaseTypes());
|
||||
}
|
||||
|
||||
if (usings is not null)
|
||||
if (usings is not null)
|
||||
{
|
||||
foreach (var @using in usings)
|
||||
{
|
||||
foreach (var @using in usings)
|
||||
symbol = Context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName($"{@using}.{name}");
|
||||
if (symbol is not null)
|
||||
{
|
||||
symbol = _context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName($"{@using}.{name}");
|
||||
if (symbol is not null)
|
||||
{
|
||||
return symbol;
|
||||
}
|
||||
return new ClassSymbol(symbol, symbol.GetBaseTypes());
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception($"The type '{name}' is not found.");
|
||||
}
|
||||
|
||||
throw new Exception($"The type '{name}' is not found.");
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,3 @@
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators
|
||||
{
|
||||
internal record FileData(string FileName, string Text)
|
||||
{
|
||||
}
|
||||
}
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal record FileData(string FileName, string Text);
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal interface IFileGenerator
|
||||
{
|
||||
internal interface IFileGenerator
|
||||
{
|
||||
FileData GenerateFile();
|
||||
}
|
||||
FileData GenerateFile();
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators
|
||||
internal interface IFilesGenerator
|
||||
{
|
||||
internal interface IFilesGenerator
|
||||
{
|
||||
IEnumerable<FileData> GenerateFiles();
|
||||
}
|
||||
IEnumerable<FileData> GenerateFiles();
|
||||
}
|
||||
@@ -1,47 +1,47 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using ProxyInterfaceSourceGenerator.Enums;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
using ProxyInterfaceSourceGenerator.Model;
|
||||
using ProxyInterfaceSourceGenerator.SyntaxReceiver;
|
||||
using ProxyInterfaceSourceGenerator.Utils;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal class PartialInterfacesGenerator : BaseGenerator, IFilesGenerator
|
||||
{
|
||||
internal class PartialInterfacesGenerator : BaseGenerator, IFilesGenerator
|
||||
public PartialInterfacesGenerator(Context context, bool supportsNullable) :
|
||||
base(context, supportsNullable)
|
||||
{
|
||||
public PartialInterfacesGenerator(Context context, bool supportsNullable) :
|
||||
base(context, supportsNullable)
|
||||
}
|
||||
|
||||
public IEnumerable<FileData> GenerateFiles()
|
||||
{
|
||||
foreach (var ci in Context.CandidateInterfaces)
|
||||
{
|
||||
yield return GenerateFile(ci.Key, ci.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<FileData> GenerateFiles()
|
||||
{
|
||||
foreach (var ci in _context.CandidateInterfaces)
|
||||
{
|
||||
yield return GenerateFile(ci.Key, ci.Value);
|
||||
}
|
||||
}
|
||||
private FileData GenerateFile(InterfaceDeclarationSyntax ci, ProxyData pd)
|
||||
{
|
||||
var sourceInterfaceSymbol = GetNamedTypeSymbolByFullName(ci.Identifier.ToString(), pd.Usings);
|
||||
var targetClassSymbol = GetNamedTypeSymbolByFullName(pd.TypeName, pd.Usings);
|
||||
var interfaceName = targetClassSymbol.Symbol.ResolveInterfaceNameWithOptionalTypeConstraints(pd.InterfaceName);
|
||||
|
||||
private FileData GenerateFile(InterfaceDeclarationSyntax ci, ProxyData pd)
|
||||
{
|
||||
var sourceInterfaceSymbol = GetNamedTypeSymbolByFullName(ci.Identifier.ToString(), pd.Usings);
|
||||
var targetClassSymbol = GetNamedTypeSymbolByFullName(pd.TypeName, pd.Usings);
|
||||
var interfaceName = targetClassSymbol.ResolveInterfaceNameWithOptionalTypeConstraints(pd.InterfaceName);
|
||||
var file = new FileData(
|
||||
$"{sourceInterfaceSymbol.Symbol.GetFileName()}.g.cs",
|
||||
CreatePartialInterfaceCode(pd.Namespace, targetClassSymbol, interfaceName, pd.ProxyBaseClasses)
|
||||
);
|
||||
|
||||
var file = new FileData(
|
||||
$"{sourceInterfaceSymbol.GetFileName()}.g.cs",
|
||||
CreatePartialInterfaceCode(pd.Namespace, targetClassSymbol, interfaceName, pd.ProxyAll)
|
||||
);
|
||||
return file;
|
||||
}
|
||||
|
||||
// _context.GeneratedData.Add(new() { InterfaceName = interfaceName, ClassName = null, FileData = file });
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
private string CreatePartialInterfaceCode(string ns, INamedTypeSymbol targetClassSymbol, string interfaceName, bool proxyAll) => $@"//----------------------------------------------------------------------------------------
|
||||
private string CreatePartialInterfaceCode(
|
||||
string ns,
|
||||
ClassSymbol classSymbol,
|
||||
string interfaceName,
|
||||
bool proxyBaseClasses) => $@"//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
@@ -50,74 +50,73 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators
|
||||
// </auto-generated>
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
{(_supportsNullable ? "#nullable enable" : string.Empty)}
|
||||
{(SupportsNullable ? "#nullable enable" : string.Empty)}
|
||||
using System;
|
||||
|
||||
namespace {ns}
|
||||
{{
|
||||
public partial interface {interfaceName}
|
||||
{{
|
||||
{GenerateProperties(targetClassSymbol, proxyAll)}
|
||||
{GenerateProperties(classSymbol, proxyBaseClasses)}
|
||||
|
||||
{GenerateMethods(targetClassSymbol)}
|
||||
{GenerateMethods(classSymbol, proxyBaseClasses)}
|
||||
|
||||
{GenerateEvents(targetClassSymbol)}
|
||||
{GenerateEvents(classSymbol, proxyBaseClasses)}
|
||||
}}
|
||||
}}
|
||||
{(_supportsNullable ? "#nullable disable" : string.Empty)}";
|
||||
{(SupportsNullable ? "#nullable disable" : string.Empty)}";
|
||||
|
||||
private string GenerateProperties(INamedTypeSymbol targetClassSymbol, bool proxyAll)
|
||||
private string GenerateProperties(ClassSymbol targetClassSymbol, bool proxyBaseClasses)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol, proxyBaseClasses))
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol))
|
||||
var type = GetPropertyType(property, out var isReplaced);
|
||||
if (isReplaced)
|
||||
{
|
||||
var type = GetPropertyType(property, out var isReplaced);
|
||||
if (isReplaced)
|
||||
{
|
||||
str.AppendLine($" {property.ToPropertyText(type)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
str.AppendLine($" {property.ToPropertyText()}");
|
||||
}
|
||||
str.AppendLine();
|
||||
str.AppendLine($" {property.ToPropertyText(type)}");
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
else
|
||||
{
|
||||
str.AppendLine($" {property.ToPropertyText()}");
|
||||
}
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
private string GenerateMethods(INamedTypeSymbol targetClassSymbol)
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GenerateMethods(ClassSymbol targetClassSymbol, bool proxyBaseClasses)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var method in MemberHelper.GetPublicMethods(targetClassSymbol, proxyBaseClasses))
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var method in MemberHelper.GetPublicMethods(targetClassSymbol))
|
||||
var methodParameters = new List<string>();
|
||||
foreach (var ps in method.Parameters)
|
||||
{
|
||||
var methodParameters = new List<string>();
|
||||
foreach (var ps in method.Parameters)
|
||||
{
|
||||
var type = ps.GetTypeEnum() == TypeEnum.Complex ? GetParameterType(ps, out _) : ps.Type.ToString();
|
||||
methodParameters.Add($"{ps.GetParamsPrefix()}{ps.GetRefPrefix()}{type} {ps.GetSanitizedName()}{ps.GetDefaultValue()}");
|
||||
}
|
||||
|
||||
str.AppendLine($" {GetReplacedType(method.ReturnType, out _)} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){method.GetWhereStatement()};");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GenerateEvents(INamedTypeSymbol targetClassSymbol)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var @event in MemberHelper.GetPublicEvents(targetClassSymbol))
|
||||
{
|
||||
var ps = @event.First().Parameters.First();
|
||||
var type = ps.GetTypeEnum() == TypeEnum.Complex ? GetParameterType(ps, out _) : ps.Type.ToString();
|
||||
str.AppendLine($" event {type} {@event.Key.GetSanitizedName()};");
|
||||
str.AppendLine();
|
||||
methodParameters.Add($"{ps.GetParamsPrefix()}{ps.GetRefPrefix()}{type} {ps.GetSanitizedName()}{ps.GetDefaultValue()}");
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
str.AppendLine($" {GetReplacedType(method.ReturnType, out _)} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){method.GetWhereStatement()};");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GenerateEvents(ClassSymbol targetClassSymbol, bool proxyBaseClasses)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var @event in MemberHelper.GetPublicEvents(targetClassSymbol, proxyBaseClasses))
|
||||
{
|
||||
var ps = @event.First().Parameters.First();
|
||||
var type = ps.GetTypeEnum() == TypeEnum.Complex ? GetParameterType(ps, out _) : ps.Type.ToString();
|
||||
str.AppendLine($" event {type} {@event.Key.GetSanitizedName()};");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators
|
||||
{
|
||||
internal class ProxyAttributeGenerator : IFileGenerator
|
||||
{
|
||||
private const string ClassName = "ProxyAttribute";
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
public FileData GenerateFile()
|
||||
{
|
||||
return new FileData($"ProxyInterfaceGenerator.{ClassName}.g.cs", $@"//----------------------------------------------------------------------------------------
|
||||
internal class ProxyAttributeGenerator : IFileGenerator
|
||||
{
|
||||
private const string ClassName = "ProxyAttribute";
|
||||
|
||||
public FileData GenerateFile()
|
||||
{
|
||||
return new FileData($"ProxyInterfaceGenerator.{ClassName}.g.cs", $@"//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
@@ -23,15 +23,14 @@ namespace ProxyInterfaceGenerator
|
||||
public class {ClassName} : Attribute
|
||||
{{
|
||||
public Type Type {{ get; }}
|
||||
public bool ProxyAll {{ get; }}
|
||||
public bool ProxyBaseClasses {{ get; }}
|
||||
|
||||
public {ClassName}(Type type, bool proxyAll = false)
|
||||
public {ClassName}(Type type, bool proxyBaseClasses = false)
|
||||
{{
|
||||
Type = type;
|
||||
ProxyAll = proxyAll;
|
||||
ProxyBaseClasses = proxyBaseClasses;
|
||||
}}
|
||||
}}
|
||||
}}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using ProxyInterfaceSourceGenerator.Enums;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
using ProxyInterfaceSourceGenerator.Model;
|
||||
using ProxyInterfaceSourceGenerator.SyntaxReceiver;
|
||||
using ProxyInterfaceSourceGenerator.Utils;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators
|
||||
namespace ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
|
||||
internal class ProxyClassesGenerator : BaseGenerator, IFilesGenerator
|
||||
{
|
||||
internal class ProxyClassesGenerator : BaseGenerator, IFilesGenerator
|
||||
public ProxyClassesGenerator(Context context, bool supportsNullable) : base(context, supportsNullable)
|
||||
{
|
||||
public ProxyClassesGenerator(Context context, bool supportsNullable) : base(context, supportsNullable)
|
||||
}
|
||||
|
||||
public IEnumerable<FileData> GenerateFiles()
|
||||
{
|
||||
foreach (var ci in Context.CandidateInterfaces)
|
||||
{
|
||||
yield return GenerateFile(ci.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<FileData> GenerateFiles()
|
||||
{
|
||||
foreach (var ci in _context.CandidateInterfaces)
|
||||
{
|
||||
yield return GenerateFile(ci.Value);
|
||||
}
|
||||
}
|
||||
private FileData GenerateFile(ProxyData pd)
|
||||
{
|
||||
var targetClassSymbol = GetNamedTypeSymbolByFullName(pd.TypeName, pd.Usings);
|
||||
var interfaceName = targetClassSymbol.Symbol.ResolveInterfaceNameWithOptionalTypeConstraints(pd.InterfaceName);
|
||||
var className = targetClassSymbol.Symbol.ResolveProxyClassName();
|
||||
var constructorName = $"{targetClassSymbol.Symbol.Name}Proxy";
|
||||
|
||||
private FileData GenerateFile(ProxyData pd)
|
||||
{
|
||||
var targetClassSymbol = GetNamedTypeSymbolByFullName(pd.TypeName, pd.Usings);
|
||||
var interfaceName = targetClassSymbol.ResolveInterfaceNameWithOptionalTypeConstraints(pd.InterfaceName);
|
||||
var className = targetClassSymbol.ResolveProxyClassName();
|
||||
var constructorName = $"{targetClassSymbol.Name}Proxy";
|
||||
var file = new FileData(
|
||||
$"{targetClassSymbol.Symbol.GetFileName()}Proxy.g.cs",
|
||||
CreateProxyClassCode(pd.Namespace, targetClassSymbol, pd.ProxyBaseClasses, interfaceName, className, constructorName)
|
||||
);
|
||||
|
||||
var file = new FileData(
|
||||
$"{targetClassSymbol.GetFileName()}Proxy.g.cs",
|
||||
CreateProxyClassCode(pd.Namespace, targetClassSymbol, interfaceName, className, constructorName)
|
||||
);
|
||||
return file;
|
||||
}
|
||||
|
||||
// _context.GeneratedData.Add(new() { InterfaceName = interfaceName, ClassName = pd.ClassName, FileData = file });
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
private string CreateProxyClassCode(
|
||||
string ns,
|
||||
INamedTypeSymbol targetClassSymbol,
|
||||
string interfaceName,
|
||||
string className,
|
||||
string constructorName) => $@"//----------------------------------------------------------------------------------------
|
||||
private string CreateProxyClassCode(
|
||||
string ns,
|
||||
ClassSymbol targetClassSymbol,
|
||||
bool proxyBaseClasses,
|
||||
string interfaceName,
|
||||
string className,
|
||||
string constructorName) => $@"//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
@@ -55,7 +52,7 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators
|
||||
// </auto-generated>
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
{(_supportsNullable ? "#nullable enable" : string.Empty)}
|
||||
{(SupportsNullable ? "#nullable enable" : string.Empty)}
|
||||
using System;
|
||||
using AutoMapper;
|
||||
|
||||
@@ -63,13 +60,13 @@ namespace {ns}
|
||||
{{
|
||||
public class {className} : {interfaceName}
|
||||
{{
|
||||
public {targetClassSymbol} _Instance {{ get; }}
|
||||
public {targetClassSymbol.Symbol} _Instance {{ get; }}
|
||||
|
||||
{GeneratePublicProperties(targetClassSymbol, false)}
|
||||
{GeneratePublicProperties(targetClassSymbol, proxyBaseClasses)}
|
||||
|
||||
{GeneratePublicMethods(targetClassSymbol)}
|
||||
{GeneratePublicMethods(targetClassSymbol, proxyBaseClasses)}
|
||||
|
||||
{GenerateEvents(targetClassSymbol)}
|
||||
{GenerateEvents(targetClassSymbol, proxyBaseClasses)}
|
||||
|
||||
public {constructorName}({targetClassSymbol} instance)
|
||||
{{
|
||||
@@ -81,165 +78,164 @@ namespace {ns}
|
||||
{GeneratePrivateAutoMapper()}
|
||||
}}
|
||||
}}
|
||||
{(_supportsNullable ? "#nullable disable" : string.Empty)}";
|
||||
private string GeneratePrivateAutoMapper()
|
||||
{(SupportsNullable ? "#nullable disable" : string.Empty)}";
|
||||
private string GeneratePrivateAutoMapper()
|
||||
{
|
||||
return Context.ReplacedTypes.Count == 0 ? string.Empty : " private readonly IMapper _mapper;";
|
||||
}
|
||||
|
||||
private string GenerateMapperConfigurationForAutoMapper()
|
||||
{
|
||||
if (Context.ReplacedTypes.Count == 0)
|
||||
{
|
||||
return _context.ReplacedTypes.Count == 0 ? string.Empty : " private readonly IMapper _mapper;";
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private string GenerateMapperConfigurationForAutoMapper()
|
||||
var str = new StringBuilder();
|
||||
|
||||
str.AppendLine(" _mapper = new MapperConfiguration(cfg =>");
|
||||
str.AppendLine(" {");
|
||||
foreach (var replacedType in Context.ReplacedTypes)
|
||||
{
|
||||
if (_context.ReplacedTypes.Count == 0)
|
||||
str.AppendLine($" cfg.CreateMap<{replacedType.Key}, {replacedType.Value}>();");
|
||||
str.AppendLine($" cfg.CreateMap<{replacedType.Value}, {replacedType.Key}>();");
|
||||
}
|
||||
str.AppendLine(" }).CreateMapper();");
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GeneratePublicProperties(ClassSymbol targetClassSymbol, bool proxyBaseClasses)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
|
||||
foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol, proxyBaseClasses))
|
||||
{
|
||||
var type = GetPropertyType(property, out var isReplaced);
|
||||
if (isReplaced)
|
||||
{
|
||||
return string.Empty;
|
||||
str.AppendLine($" public {property.ToPropertyTextForClass(type)}");
|
||||
}
|
||||
|
||||
var str = new StringBuilder();
|
||||
|
||||
str.AppendLine(" _mapper = new MapperConfiguration(cfg =>");
|
||||
str.AppendLine(" {");
|
||||
foreach (var replacedType in _context.ReplacedTypes)
|
||||
else
|
||||
{
|
||||
str.AppendLine($" cfg.CreateMap<{replacedType.Key}, {replacedType.Value}>();");
|
||||
str.AppendLine($" cfg.CreateMap<{replacedType.Value}, {replacedType.Key}>();");
|
||||
str.AppendLine($" public {property.ToPropertyTextForClass()}");
|
||||
}
|
||||
str.AppendLine(" }).CreateMapper();");
|
||||
|
||||
return str.ToString();
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
private string GeneratePublicProperties(INamedTypeSymbol targetClassSymbol, bool proxyAll)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
foreach (var property in MemberHelper.GetPublicProperties(targetClassSymbol))
|
||||
private string GeneratePublicMethods(ClassSymbol targetClassSymbol, bool proxyBaseClasses)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var method in MemberHelper.GetPublicMethods(targetClassSymbol, proxyBaseClasses))
|
||||
{
|
||||
var methodParameters = new List<string>();
|
||||
var invokeParameters = new List<string>();
|
||||
|
||||
foreach (var ps in method.Parameters)
|
||||
{
|
||||
var type = GetPropertyType(property, out var isReplaced);
|
||||
if (isReplaced)
|
||||
var type = GetParameterType(ps, out _);
|
||||
|
||||
methodParameters.Add($"{ps.GetParamsPrefix()}{ps.GetRefPrefix()}{type} {ps.GetSanitizedName()}{ps.GetDefaultValue()}");
|
||||
invokeParameters.Add($"{ps.GetRefPrefix()}{ps.GetSanitizedName()}_");
|
||||
}
|
||||
|
||||
string returnTypeAsString = GetReplacedType(method.ReturnType, out var returnIsReplaced);
|
||||
|
||||
str.AppendLine($" public {returnTypeAsString} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){method.GetWhereStatement()}");
|
||||
str.AppendLine(" {");
|
||||
foreach (var ps in method.Parameters)
|
||||
{
|
||||
string normalOrMap = $" = {ps.GetSanitizedName()}";
|
||||
if (ps.RefKind == RefKind.Out)
|
||||
{
|
||||
str.AppendLine($" public {property.ToPropertyTextForClass(type)}");
|
||||
normalOrMap = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
str.AppendLine($" public {property.ToPropertyTextForClass()}");
|
||||
var type = GetParameterType(ps, out var isReplaced);
|
||||
if (isReplaced)
|
||||
{
|
||||
normalOrMap = $" = _mapper.Map<{ps.Type}>({ps.GetSanitizedName()})";
|
||||
}
|
||||
}
|
||||
str.AppendLine();
|
||||
|
||||
str.AppendLine($" {ps.Type} {ps.GetSanitizedName()}_{normalOrMap};");
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GeneratePublicMethods(INamedTypeSymbol targetClassSymbol)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var method in MemberHelper.GetPublicMethods(targetClassSymbol))
|
||||
{
|
||||
var methodParameters = new List<string>();
|
||||
var invokeParameters = new List<string>();
|
||||
|
||||
foreach (var ps in method.Parameters)
|
||||
{
|
||||
var type = GetParameterType(ps, out _);
|
||||
|
||||
methodParameters.Add($"{ps.GetParamsPrefix()}{ps.GetRefPrefix()}{type} {ps.GetSanitizedName()}{ps.GetDefaultValue()}");
|
||||
invokeParameters.Add($"{ps.GetRefPrefix()}{ps.GetSanitizedName()}_");
|
||||
}
|
||||
|
||||
string returnTypeAsString = GetReplacedType(method.ReturnType, out var returnIsReplaced);
|
||||
|
||||
str.AppendLine($" public {returnTypeAsString} {method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", methodParameters)}){method.GetWhereStatement()}");
|
||||
str.AppendLine(" {");
|
||||
foreach (var ps in method.Parameters)
|
||||
{
|
||||
string normalOrMap = $" = {ps.GetSanitizedName()}";
|
||||
if (ps.RefKind == RefKind.Out)
|
||||
{
|
||||
normalOrMap = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
var type = GetParameterType(ps, out var isReplaced);
|
||||
if (isReplaced)
|
||||
{
|
||||
normalOrMap = $" = _mapper.Map<{ps.Type}>({ps.GetSanitizedName()})";
|
||||
}
|
||||
}
|
||||
|
||||
str.AppendLine($" {ps.Type} {ps.GetSanitizedName()}_{normalOrMap};");
|
||||
}
|
||||
|
||||
#pragma warning disable RS1024 // Compare symbols correctly
|
||||
int hash = method.ReturnType.GetHashCode();
|
||||
int hash = method.ReturnType.GetHashCode();
|
||||
#pragma warning restore RS1024 // Compare symbols correctly
|
||||
var alternateReturnVariableName = $"result_{Math.Abs(hash)}";
|
||||
var alternateReturnVariableName = $"result_{Math.Abs(hash)}";
|
||||
|
||||
if (returnTypeAsString == "void")
|
||||
if (returnTypeAsString == "void")
|
||||
{
|
||||
str.AppendLine($" _Instance.{method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", invokeParameters)});");
|
||||
}
|
||||
else
|
||||
{
|
||||
str.AppendLine($" var {alternateReturnVariableName} = _Instance.{method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", invokeParameters)});");
|
||||
}
|
||||
|
||||
foreach (var ps in method.Parameters.Where(p => p.RefKind == RefKind.Out))
|
||||
{
|
||||
string normalOrMap = $" = {ps.GetSanitizedName()}_";
|
||||
if (ps.GetTypeEnum() == TypeEnum.Complex)
|
||||
{
|
||||
str.AppendLine($" _Instance.{method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", invokeParameters)});");
|
||||
var type = GetParameterType(ps, out var isReplaced);
|
||||
if (isReplaced)
|
||||
{
|
||||
normalOrMap = $" = _mapper.Map<{type}>({ps.GetSanitizedName()}_)";
|
||||
}
|
||||
}
|
||||
|
||||
str.AppendLine($" {ps.GetSanitizedName()}{normalOrMap};");
|
||||
}
|
||||
|
||||
if (returnTypeAsString != "void")
|
||||
{
|
||||
if (returnIsReplaced)
|
||||
{
|
||||
str.AppendLine($" return _mapper.Map<{returnTypeAsString}>({alternateReturnVariableName});");
|
||||
}
|
||||
else
|
||||
{
|
||||
str.AppendLine($" var {alternateReturnVariableName} = _Instance.{method.GetMethodNameWithOptionalTypeParameters()}({string.Join(", ", invokeParameters)});");
|
||||
str.AppendLine($" return {alternateReturnVariableName};");
|
||||
}
|
||||
|
||||
foreach (var ps in method.Parameters.Where(p => p.RefKind == RefKind.Out))
|
||||
{
|
||||
string normalOrMap = $" = {ps.GetSanitizedName()}_";
|
||||
if (ps.GetTypeEnum() == TypeEnum.Complex)
|
||||
{
|
||||
var type = GetParameterType(ps, out var isReplaced);
|
||||
if (isReplaced)
|
||||
{
|
||||
normalOrMap = $" = _mapper.Map<{type}>({ps.GetSanitizedName()}_)";
|
||||
}
|
||||
}
|
||||
|
||||
str.AppendLine($" {ps.GetSanitizedName()}{normalOrMap};");
|
||||
}
|
||||
|
||||
if (returnTypeAsString != "void")
|
||||
{
|
||||
if (returnIsReplaced)
|
||||
{
|
||||
str.AppendLine($" return _mapper.Map<{returnTypeAsString}>({alternateReturnVariableName});");
|
||||
}
|
||||
else
|
||||
{
|
||||
str.AppendLine($" return {alternateReturnVariableName};");
|
||||
}
|
||||
}
|
||||
|
||||
str.AppendLine(" }");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
str.AppendLine(" }");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
private string GenerateEvents(INamedTypeSymbol targetClassSymbol)
|
||||
return str.ToString();
|
||||
}
|
||||
|
||||
private string GenerateEvents(ClassSymbol targetClassSymbol, bool proxyBaseClasses)
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var @event in MemberHelper.GetPublicEvents(targetClassSymbol, proxyBaseClasses))
|
||||
{
|
||||
var str = new StringBuilder();
|
||||
foreach (var @event in MemberHelper.GetPublicEvents(targetClassSymbol))
|
||||
var name = @event.Key.GetSanitizedName();
|
||||
var ps = @event.First().Parameters.First();
|
||||
var type = ps.GetTypeEnum() == TypeEnum.Complex ? GetParameterType(ps, out _) : ps.Type.ToString();
|
||||
str.Append($" public event {type} {name} {{");
|
||||
|
||||
if (@event.Any(e => e.MethodKind == MethodKind.EventAdd))
|
||||
{
|
||||
var name = @event.Key.GetSanitizedName();
|
||||
var ps = @event.First().Parameters.First();
|
||||
var type = ps.GetTypeEnum() == TypeEnum.Complex ? GetParameterType(ps, out _) : ps.Type.ToString();
|
||||
str.Append($" public event {type} {name} {{");
|
||||
|
||||
if (@event.Any(e => e.MethodKind == MethodKind.EventAdd))
|
||||
{
|
||||
str.Append($" add {{ _Instance.{name} += value; }}");
|
||||
}
|
||||
if (@event.Any(e => e.MethodKind == MethodKind.EventRemove))
|
||||
{
|
||||
str.Append($" remove {{ _Instance.{name} -= value; }}");
|
||||
}
|
||||
|
||||
str.AppendLine(" }");
|
||||
str.AppendLine();
|
||||
str.Append($" add {{ _Instance.{name} += value; }}");
|
||||
}
|
||||
if (@event.Any(e => e.MethodKind == MethodKind.EventRemove))
|
||||
{
|
||||
str.Append($" remove {{ _Instance.{name} -= value; }}");
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
str.AppendLine(" }");
|
||||
str.AppendLine();
|
||||
}
|
||||
|
||||
return str.ToString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Model;
|
||||
|
||||
internal record ClassSymbol(INamedTypeSymbol Symbol, List<INamedTypeSymbol> BaseTypes)
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return Symbol.ToString();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
@@ -6,83 +5,95 @@ using Microsoft.CodeAnalysis.Text;
|
||||
using ProxyInterfaceSourceGenerator.FileGenerators;
|
||||
using ProxyInterfaceSourceGenerator.SyntaxReceiver;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator
|
||||
namespace ProxyInterfaceSourceGenerator;
|
||||
|
||||
[Generator]
|
||||
internal class ProxyInterfaceCodeGenerator : ISourceGenerator
|
||||
{
|
||||
[Generator]
|
||||
internal class ProxyInterfaceCodeGenerator : ISourceGenerator
|
||||
private readonly ProxyAttributeGenerator _proxyAttributeGenerator = new ProxyAttributeGenerator();
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
private readonly ProxyAttributeGenerator _proxyAttributeGenerator = new ProxyAttributeGenerator();
|
||||
//if (!System.Diagnostics.Debugger.IsAttached)
|
||||
//{
|
||||
// System.Diagnostics.Debugger.Launch();
|
||||
//}
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
context.RegisterForSyntaxNotifications(() => new ProxySyntaxReceiver());
|
||||
}
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
if (context.ParseOptions is not CSharpParseOptions csharpParseOptions)
|
||||
{
|
||||
//if (!System.Diagnostics.Debugger.IsAttached)
|
||||
//{
|
||||
// System.Diagnostics.Debugger.Launch();
|
||||
//}
|
||||
|
||||
context.RegisterForSyntaxNotifications(() => new ProxySyntaxReceiver());
|
||||
throw new NotSupportedException("Only C# is supported.");
|
||||
}
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
if (context.SyntaxReceiver is not ProxySyntaxReceiver receiver)
|
||||
{
|
||||
if (context.ParseOptions is not CSharpParseOptions csharpParseOptions)
|
||||
{
|
||||
throw new NotSupportedException("Only C# is supported.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.SyntaxReceiver is not ProxySyntaxReceiver receiver)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// https://github.com/reactiveui/refit/blob/main/InterfaceStubGenerator.Core/InterfaceStubGenerator.cs
|
||||
var supportsNullable = csharpParseOptions.LanguageVersion >= LanguageVersion.CSharp8;
|
||||
// https://github.com/reactiveui/refit/blob/main/InterfaceStubGenerator.Core/InterfaceStubGenerator.cs
|
||||
var supportsNullable = csharpParseOptions.LanguageVersion >= LanguageVersion.CSharp8;
|
||||
|
||||
try
|
||||
{
|
||||
GenerateProxyAttribute(context, receiver);
|
||||
GeneratePartialInterfaces(context, receiver, supportsNullable);
|
||||
GenerateProxyClasses(context, receiver, supportsNullable);
|
||||
}
|
||||
|
||||
private void GenerateProxyAttribute(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver)
|
||||
catch (Exception exception)
|
||||
{
|
||||
var context = new Context
|
||||
{
|
||||
GeneratorExecutionContext = ctx,
|
||||
CandidateInterfaces = receiver.CandidateInterfaces
|
||||
};
|
||||
|
||||
var attributeData = _proxyAttributeGenerator.GenerateFile();
|
||||
context.GeneratorExecutionContext.AddSource(attributeData.FileName, SourceText.From(attributeData.Text, Encoding.UTF8));
|
||||
GenerateError(context, exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static void GeneratePartialInterfaces(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver, bool supportsNullable)
|
||||
private void GenerateError(GeneratorExecutionContext context, Exception exception)
|
||||
{
|
||||
var message = $"/*\r\n{nameof(ProxyInterfaceCodeGenerator)}\r\n\r\n{exception}\r\n*/";
|
||||
context.AddSource("Error.g", SourceText.From(message, Encoding.UTF8));
|
||||
}
|
||||
|
||||
private void GenerateProxyAttribute(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver)
|
||||
{
|
||||
var context = new Context
|
||||
{
|
||||
var context = new Context
|
||||
{
|
||||
GeneratorExecutionContext = ctx,
|
||||
CandidateInterfaces = receiver.CandidateInterfaces
|
||||
};
|
||||
GeneratorExecutionContext = ctx,
|
||||
CandidateInterfaces = receiver.CandidateInterfaces
|
||||
};
|
||||
|
||||
var partialInterfacesGenerator = new PartialInterfacesGenerator(context, supportsNullable);
|
||||
foreach (var data in partialInterfacesGenerator.GenerateFiles())
|
||||
{
|
||||
context.GeneratorExecutionContext.AddSource(data.FileName, SourceText.From(data.Text, Encoding.UTF8));
|
||||
}
|
||||
var attributeData = _proxyAttributeGenerator.GenerateFile();
|
||||
context.GeneratorExecutionContext.AddSource(attributeData.FileName, SourceText.From(attributeData.Text, Encoding.UTF8));
|
||||
}
|
||||
|
||||
private static void GeneratePartialInterfaces(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver, bool supportsNullable)
|
||||
{
|
||||
var context = new Context
|
||||
{
|
||||
GeneratorExecutionContext = ctx,
|
||||
CandidateInterfaces = receiver.CandidateInterfaces
|
||||
};
|
||||
|
||||
var partialInterfacesGenerator = new PartialInterfacesGenerator(context, supportsNullable);
|
||||
foreach (var data in partialInterfacesGenerator.GenerateFiles())
|
||||
{
|
||||
context.GeneratorExecutionContext.AddSource(data.FileName, SourceText.From(data.Text, Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateProxyClasses(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver, bool supportsNullable)
|
||||
private static void GenerateProxyClasses(GeneratorExecutionContext ctx, ProxySyntaxReceiver receiver, bool supportsNullable)
|
||||
{
|
||||
var context = new Context
|
||||
{
|
||||
var context = new Context
|
||||
{
|
||||
GeneratorExecutionContext = ctx,
|
||||
CandidateInterfaces = receiver.CandidateInterfaces
|
||||
};
|
||||
GeneratorExecutionContext = ctx,
|
||||
CandidateInterfaces = receiver.CandidateInterfaces
|
||||
};
|
||||
|
||||
var proxyClassesGenerator = new ProxyClassesGenerator(context, supportsNullable);
|
||||
foreach (var data in proxyClassesGenerator.GenerateFiles())
|
||||
{
|
||||
context.GeneratorExecutionContext.AddSource(data.FileName, SourceText.From(data.Text, Encoding.UTF8));
|
||||
}
|
||||
var proxyClassesGenerator = new ProxyClassesGenerator(context, supportsNullable);
|
||||
foreach (var data in proxyClassesGenerator.GenerateFiles())
|
||||
{
|
||||
context.GeneratorExecutionContext.AddSource(data.FileName, SourceText.From(data.Text, Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<Version>0.0.11</Version>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<ProjectGuid>{12344228-91F4-4502-9595-39584E5ABB34}</ProjectGuid>
|
||||
<LangVersion>9</LangVersion>
|
||||
<LangVersion>10</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<Authors>Stef Heyenrath</Authors>
|
||||
<Description></Description>
|
||||
@@ -24,6 +24,7 @@
|
||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)Generated</CompilerGeneratedFilesOutputPath>
|
||||
<DevelopmentDependency>true</DevelopmentDependency>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
@@ -31,7 +32,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="../../PackageReadme.md" Pack="true" PackagePath=""/>
|
||||
<None Include="../../PackageReadme.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
namespace ProxyInterfaceSourceGenerator.SyntaxReceiver;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.SyntaxReceiver
|
||||
{
|
||||
internal record ProxyData(string Namespace, string InterfaceName, string RawTypeName, string TypeName, List<string> Usings, bool ProxyAll)
|
||||
{
|
||||
}
|
||||
}
|
||||
internal record ProxyData
|
||||
(
|
||||
string Namespace,
|
||||
string InterfaceName,
|
||||
string RawTypeName,
|
||||
string TypeName,
|
||||
List<string> Usings,
|
||||
bool ProxyBaseClasses
|
||||
);
|
||||
@@ -1,85 +1,91 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using ProxyInterfaceSourceGenerator.Extensions;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.SyntaxReceiver
|
||||
namespace ProxyInterfaceSourceGenerator.SyntaxReceiver;
|
||||
|
||||
internal class ProxySyntaxReceiver : ISyntaxReceiver
|
||||
{
|
||||
internal class ProxySyntaxReceiver : ISyntaxReceiver
|
||||
private static readonly string[] Modifiers = { "public", "partial" };
|
||||
|
||||
public IDictionary<InterfaceDeclarationSyntax, ProxyData> CandidateInterfaces { get; } = new Dictionary<InterfaceDeclarationSyntax, ProxyData>();
|
||||
|
||||
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||
{
|
||||
private static readonly string[] Modifiers = new[] { "public", "partial" };
|
||||
|
||||
public IDictionary<InterfaceDeclarationSyntax, ProxyData> CandidateInterfaces { get; } = new Dictionary<InterfaceDeclarationSyntax, ProxyData>();
|
||||
|
||||
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||
if (syntaxNode is InterfaceDeclarationSyntax interfaceDeclarationSyntax && TryGet(interfaceDeclarationSyntax, out var data))
|
||||
{
|
||||
if (syntaxNode is InterfaceDeclarationSyntax interfaceDeclarationSyntax && TryGet(interfaceDeclarationSyntax, out var data))
|
||||
{
|
||||
CandidateInterfaces.Add(interfaceDeclarationSyntax, data);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGet(InterfaceDeclarationSyntax interfaceDeclarationSyntax, [NotNullWhen(true)] out ProxyData? data)
|
||||
{
|
||||
data = null;
|
||||
|
||||
if (interfaceDeclarationSyntax.Modifiers.Select(m => m.ToString()).Except(Modifiers).Count() != 0)
|
||||
{
|
||||
// InterfaceDeclarationSyntax should be "public" and "partial"
|
||||
return false;
|
||||
}
|
||||
|
||||
var attributeLists = interfaceDeclarationSyntax.AttributeLists.FirstOrDefault(x => x.Attributes.Any(a => a.Name.ToString().Equals("ProxyInterfaceGenerator.Proxy")));
|
||||
if (attributeLists is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var argumentList = attributeLists.Attributes.FirstOrDefault()?.ArgumentList;
|
||||
if (argumentList is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var usings = new List<string>();
|
||||
|
||||
string ns = string.Empty;
|
||||
if (SyntaxNodeUtils.TryGetParentSyntax(interfaceDeclarationSyntax, out NamespaceDeclarationSyntax? namespaceDeclarationSyntax))
|
||||
{
|
||||
ns = namespaceDeclarationSyntax.Name.ToString();
|
||||
usings.Add(ns);
|
||||
}
|
||||
|
||||
if (SyntaxNodeUtils.TryGetParentSyntax(interfaceDeclarationSyntax, out CompilationUnitSyntax? cc))
|
||||
{
|
||||
foreach (var @using in cc.Usings)
|
||||
{
|
||||
usings.Add(@using.Name.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
string rawTypeName = ((TypeOfExpressionSyntax)argumentList.Arguments[0].Expression).Type.ToString();
|
||||
|
||||
data = new
|
||||
(
|
||||
ns,
|
||||
interfaceDeclarationSyntax.Identifier.ToString(),
|
||||
rawTypeName,
|
||||
ConvertTypeName(rawTypeName),
|
||||
usings,
|
||||
false //bool.Parse(argumentList.Arguments[1].Expression.GetText().ToString())
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string ConvertTypeName(string typeName)
|
||||
{
|
||||
return !(typeName.Contains('<') && typeName.Contains('>')) ?
|
||||
typeName :
|
||||
$"{typeName.Replace("<", string.Empty).Replace(">", string.Empty).Replace(",", string.Empty).Trim()}`{typeName.Count(c => c == ',') + 1}";
|
||||
CandidateInterfaces.Add(interfaceDeclarationSyntax, data);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGet(InterfaceDeclarationSyntax interfaceDeclarationSyntax, [NotNullWhen(true)] out ProxyData? data)
|
||||
{
|
||||
data = null;
|
||||
|
||||
if (interfaceDeclarationSyntax.Modifiers.Select(m => m.ToString()).Except(Modifiers).Count() != 0)
|
||||
{
|
||||
// InterfaceDeclarationSyntax should be "public" and "partial"
|
||||
return false;
|
||||
}
|
||||
|
||||
var attributeLists = interfaceDeclarationSyntax.AttributeLists.FirstOrDefault(x => x.Attributes.Any(a => a.Name.ToString().Equals("ProxyInterfaceGenerator.Proxy")));
|
||||
if (attributeLists is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var argumentList = attributeLists.Attributes.FirstOrDefault()?.ArgumentList;
|
||||
if (argumentList is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var usings = new List<string>();
|
||||
|
||||
string ns = string.Empty;
|
||||
if (SyntaxNodeUtils.TryGetParentSyntax(interfaceDeclarationSyntax, out NamespaceDeclarationSyntax? namespaceDeclarationSyntax))
|
||||
{
|
||||
ns = namespaceDeclarationSyntax.Name.ToString();
|
||||
usings.Add(ns);
|
||||
}
|
||||
|
||||
if (SyntaxNodeUtils.TryGetParentSyntax(interfaceDeclarationSyntax, out CompilationUnitSyntax? cc))
|
||||
{
|
||||
foreach (var @using in cc.Usings)
|
||||
{
|
||||
usings.Add(@using.Name.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
string rawTypeName = ((TypeOfExpressionSyntax)argumentList.Arguments[0].Expression).Type.ToString();
|
||||
bool proxyAllClasses;
|
||||
try
|
||||
{
|
||||
proxyAllClasses = bool.Parse(((LiteralExpressionSyntax)argumentList.Arguments[1].Expression).ToString());
|
||||
}
|
||||
catch
|
||||
{
|
||||
proxyAllClasses = false;
|
||||
}
|
||||
|
||||
data = new
|
||||
(
|
||||
ns,
|
||||
interfaceDeclarationSyntax.Identifier.ToString(),
|
||||
rawTypeName,
|
||||
ConvertTypeName(rawTypeName),
|
||||
usings,
|
||||
proxyAllClasses
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string ConvertTypeName(string typeName)
|
||||
{
|
||||
return !(typeName.Contains('<') && typeName.Contains('>')) ?
|
||||
typeName :
|
||||
$"{typeName.Replace("<", string.Empty).Replace(">", string.Empty).Replace(",", string.Empty).Trim()}`{typeName.Count(c => c == ',') + 1}";
|
||||
}
|
||||
}
|
||||
@@ -1,87 +1,105 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ProxyInterfaceSourceGenerator.Model;
|
||||
|
||||
namespace ProxyInterfaceSourceGenerator.Utils
|
||||
namespace ProxyInterfaceSourceGenerator.Utils;
|
||||
|
||||
internal static class MemberHelper
|
||||
{
|
||||
internal static class MemberHelper
|
||||
private static readonly string[] ExcludedMethods = { "ToString", "GetHashCode" };
|
||||
|
||||
public static IEnumerable<IPropertySymbol> GetPublicProperties(
|
||||
ClassSymbol classSymbol,
|
||||
bool proxyBaseClasses,
|
||||
params Func<IPropertySymbol, bool>[] filters)
|
||||
{
|
||||
private static string[] _excludedMethods = new string[] { "ToString", "GetHashCode" };
|
||||
|
||||
public static IEnumerable<IPropertySymbol> GetPublicProperties(INamedTypeSymbol classSymbol, params Func<IPropertySymbol, bool>[] filters)
|
||||
var allFilters = new List<Func<IPropertySymbol, bool>>(filters)
|
||||
{
|
||||
var allFilters = new List<Func<IPropertySymbol, bool>>(filters);
|
||||
allFilters.Add(p => p.Kind == SymbolKind.Property);
|
||||
p => p.Kind == SymbolKind.Property
|
||||
};
|
||||
|
||||
return GetPublicMembers(classSymbol, allFilters.ToArray());
|
||||
return GetPublicMembers(classSymbol, proxyBaseClasses, allFilters.ToArray());
|
||||
}
|
||||
|
||||
public static IEnumerable<IMethodSymbol> GetPublicMethods(
|
||||
ClassSymbol classSymbol,
|
||||
bool proxyBaseClasses,
|
||||
Func<IMethodSymbol, bool>? filter = null)
|
||||
{
|
||||
if (filter is null)
|
||||
{
|
||||
filter = _ => true;
|
||||
}
|
||||
|
||||
public static IEnumerable<IMethodSymbol> GetPublicMethods(INamedTypeSymbol classSymbol, Func<IMethodSymbol, bool>? filter = null)
|
||||
{
|
||||
if (filter is null)
|
||||
{
|
||||
filter = _ => true;
|
||||
}
|
||||
return GetPublicMembers(classSymbol,
|
||||
proxyBaseClasses,
|
||||
m => m.Kind == SymbolKind.Method,
|
||||
m => m.MethodKind == MethodKind.Ordinary,
|
||||
m => !ExcludedMethods.Contains(m.Name),
|
||||
filter);
|
||||
}
|
||||
|
||||
return GetPublicMembers(classSymbol,
|
||||
m => m.Kind == SymbolKind.Method,
|
||||
m => m.MethodKind == MethodKind.Ordinary,
|
||||
m => !_excludedMethods.Contains(m.Name),
|
||||
filter);
|
||||
public static IEnumerable<IGrouping<ISymbol, IMethodSymbol>> GetPublicEvents(
|
||||
ClassSymbol classSymbol,
|
||||
bool proxyBaseClasses,
|
||||
Func<IMethodSymbol, bool>? filter = null)
|
||||
{
|
||||
if (filter is null)
|
||||
{
|
||||
filter = _ => true;
|
||||
}
|
||||
|
||||
public static IEnumerable<IGrouping<ISymbol, IMethodSymbol>> GetPublicEvents(INamedTypeSymbol classSymbol, Func<IMethodSymbol, bool>? filter = null)
|
||||
{
|
||||
if (filter is null)
|
||||
{
|
||||
filter = _ => true;
|
||||
}
|
||||
|
||||
#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type.
|
||||
#pragma warning disable RS1024 // Compare symbols correctly
|
||||
return GetPublicMembers(classSymbol,
|
||||
return GetPublicMembers(classSymbol,
|
||||
proxyBaseClasses,
|
||||
m => m.MethodKind == MethodKind.EventAdd || m.MethodKind == MethodKind.EventRemove/* || m.MethodKind == MethodKind.EventRaise*/,
|
||||
filter)
|
||||
.GroupBy(e => e.AssociatedSymbol);
|
||||
.GroupBy(e => e.AssociatedSymbol);
|
||||
#pragma warning restore RS1024 // Compare symbols correctly
|
||||
#pragma warning restore CS8619 // Nullability of reference types in value doesn't match target type.
|
||||
}
|
||||
|
||||
// TODO : do we need also to check for "SanitizedName()" here?
|
||||
private static IEnumerable<T> GetPublicMembers<T>(
|
||||
ClassSymbol classSymbol,
|
||||
bool proxyBaseClasses,
|
||||
params Func<T, bool>[] filters) where T : ISymbol
|
||||
{
|
||||
var membersQuery = classSymbol.Symbol.GetMembers().OfType<T>()
|
||||
.Where(m => m.DeclaredAccessibility == Accessibility.Public);
|
||||
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
membersQuery = membersQuery.Where(filter);
|
||||
}
|
||||
|
||||
// TODO : do we need also to check for "SanitizedName()" here?
|
||||
private static IEnumerable<T> GetPublicMembers<T>(INamedTypeSymbol classSymbol, params Func<T, bool>[] filters) where T : ISymbol
|
||||
var ownMembers = membersQuery.ToList();
|
||||
var ownPropertyNames = ownMembers.Select(x => x.Name);
|
||||
|
||||
if (!proxyBaseClasses)
|
||||
{
|
||||
var membersQuery = classSymbol.GetMembers().OfType<T>()
|
||||
.Where(m => m.DeclaredAccessibility == Accessibility.Public);
|
||||
return ownMembers;
|
||||
}
|
||||
|
||||
var allMembers = ownMembers;
|
||||
var baseType = classSymbol.Symbol.BaseType;
|
||||
|
||||
while (baseType != null && baseType.SpecialType != SpecialType.System_Object)
|
||||
{
|
||||
var baseMembers = baseType.GetMembers().OfType<T>()
|
||||
.Where(m => m.DeclaredAccessibility == Accessibility.Public)
|
||||
.Where(x => !ownPropertyNames.Contains(x.Name));
|
||||
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
membersQuery = membersQuery.Where(filter);
|
||||
baseMembers = baseMembers.Where(filter);
|
||||
}
|
||||
|
||||
var members = membersQuery.ToList();
|
||||
allMembers.AddRange(baseMembers);
|
||||
|
||||
var propertyNames = membersQuery.Select(x => x.Name);
|
||||
|
||||
var baseType = classSymbol.BaseType;
|
||||
|
||||
while (baseType != null)
|
||||
{
|
||||
var baseMembers = baseType.GetMembers().OfType<T>()
|
||||
.Where(m => m.DeclaredAccessibility == Accessibility.Public)
|
||||
.Where(x => !propertyNames.Contains(x.Name));
|
||||
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
baseMembers = baseMembers.Where(filter);
|
||||
}
|
||||
|
||||
members.AddRange(baseMembers);
|
||||
|
||||
baseType = baseType.BaseType;
|
||||
}
|
||||
|
||||
return membersQuery;
|
||||
baseType = baseType.BaseType;
|
||||
}
|
||||
|
||||
return allMembers;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
#nullable enable
|
||||
using System;
|
||||
using AutoMapper;
|
||||
|
||||
namespace ProxyInterfaceSourceGeneratorTests.Source
|
||||
{
|
||||
public class HumanProxy : IHuman
|
||||
{
|
||||
public ProxyInterfaceSourceGeneratorTests.Source.Human _Instance { get; }
|
||||
|
||||
public bool IsAlive { get => _Instance.IsAlive; set => _Instance.IsAlive = value; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public HumanProxy(ProxyInterfaceSourceGeneratorTests.Source.Human instance)
|
||||
{
|
||||
_Instance = instance;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
#nullable enable
|
||||
using System;
|
||||
|
||||
namespace ProxyInterfaceSourceGeneratorTests.Source
|
||||
{
|
||||
public partial interface IHuman
|
||||
{
|
||||
bool IsAlive { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
|
||||
namespace ProxyInterfaceSourceGeneratorTests.DTO
|
||||
namespace ProxyInterfaceSourceGeneratorTests.Source
|
||||
{
|
||||
public partial interface IPerson
|
||||
{
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
#nullable enable
|
||||
using System;
|
||||
|
||||
namespace ProxyInterfaceSourceGeneratorTests.Source
|
||||
{
|
||||
public partial interface IPersonExtends
|
||||
{
|
||||
string Name { get; set; }
|
||||
|
||||
string? StringNullable { get; set; }
|
||||
|
||||
long? NullableLong { get; }
|
||||
|
||||
object @object { get; set; }
|
||||
|
||||
bool IsAlive { get; set; }
|
||||
|
||||
bool X { get; set; }
|
||||
|
||||
|
||||
|
||||
void Void();
|
||||
|
||||
string HelloWorld(string name);
|
||||
|
||||
void WithParams(params string[] values);
|
||||
|
||||
string Add(string s, string @string);
|
||||
|
||||
int DefaultValue(int x = 100);
|
||||
|
||||
void In_Out_Ref1(in int a, out int b, ref int c);
|
||||
|
||||
bool Generic2<T1, T2>(int x, T1 t1, T2 t2) where T1 : struct where T2 : class, new();
|
||||
|
||||
System.Threading.Tasks.Task Method1Async();
|
||||
|
||||
System.Threading.Tasks.Task<int> Method2Async();
|
||||
|
||||
System.Threading.Tasks.Task<string?> Method3Async();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
//----------------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
#nullable enable
|
||||
using System;
|
||||
using AutoMapper;
|
||||
|
||||
namespace ProxyInterfaceSourceGeneratorTests.Source
|
||||
{
|
||||
public class PersonExtendsProxy : IPersonExtends
|
||||
{
|
||||
public ProxyInterfaceSourceGeneratorTests.Source.PersonExtends _Instance { get; }
|
||||
|
||||
public string Name { get => _Instance.Name; set => _Instance.Name = value; }
|
||||
|
||||
public string? StringNullable { get => _Instance.StringNullable; set => _Instance.StringNullable = value; }
|
||||
|
||||
public long? NullableLong { get => _Instance.NullableLong; }
|
||||
|
||||
public object @object { get => _Instance.@object; set => _Instance.@object = value; }
|
||||
|
||||
public bool IsAlive { get => _Instance.IsAlive; set => _Instance.IsAlive = value; }
|
||||
|
||||
public bool X { get => _Instance.X; set => _Instance.X = value; }
|
||||
|
||||
|
||||
|
||||
public void Void()
|
||||
{
|
||||
_Instance.Void();
|
||||
}
|
||||
|
||||
public string HelloWorld(string name)
|
||||
{
|
||||
string name_ = name;
|
||||
var result_58477331 = _Instance.HelloWorld(name_);
|
||||
return result_58477331;
|
||||
}
|
||||
|
||||
public void WithParams(params string[] values)
|
||||
{
|
||||
string[] values_ = values;
|
||||
_Instance.WithParams(values_);
|
||||
}
|
||||
|
||||
public string Add(string s, string @string)
|
||||
{
|
||||
string s_ = s;
|
||||
string @string_ = @string;
|
||||
var result_58477331 = _Instance.Add(s_, @string_);
|
||||
return result_58477331;
|
||||
}
|
||||
|
||||
public int DefaultValue(int x = 100)
|
||||
{
|
||||
int x_ = x;
|
||||
var result_42930144 = _Instance.DefaultValue(x_);
|
||||
return result_42930144;
|
||||
}
|
||||
|
||||
public void In_Out_Ref1(in int a, out int b, ref int c)
|
||||
{
|
||||
int a_ = a;
|
||||
int b_;
|
||||
int c_ = c;
|
||||
_Instance.In_Out_Ref1(in a_, out b_, ref c_);
|
||||
b = b_;
|
||||
}
|
||||
|
||||
public bool Generic2<T1, T2>(int x, T1 t1, T2 t2) where T1 : struct where T2 : class, new()
|
||||
{
|
||||
int x_ = x;
|
||||
T1 t1_ = t1;
|
||||
T2 t2_ = t2;
|
||||
var result_38995950 = _Instance.Generic2<T1, T2>(x_, t1_, t2_);
|
||||
return result_38995950;
|
||||
}
|
||||
|
||||
public System.Threading.Tasks.Task Method1Async()
|
||||
{
|
||||
var result_51708797 = _Instance.Method1Async();
|
||||
return result_51708797;
|
||||
}
|
||||
|
||||
public System.Threading.Tasks.Task<int> Method2Async()
|
||||
{
|
||||
var result_1620952573 = _Instance.Method2Async();
|
||||
return result_1620952573;
|
||||
}
|
||||
|
||||
public System.Threading.Tasks.Task<string?> Method3Async()
|
||||
{
|
||||
var result_1636499760 = _Instance.Method3Async();
|
||||
return result_1636499760;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public PersonExtendsProxy(ProxyInterfaceSourceGeneratorTests.Source.PersonExtends instance)
|
||||
{
|
||||
_Instance = instance;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
+32
-32
@@ -11,11 +11,11 @@
|
||||
using System;
|
||||
using AutoMapper;
|
||||
|
||||
namespace ProxyInterfaceSourceGeneratorTests.DTO
|
||||
namespace ProxyInterfaceSourceGeneratorTests.Source
|
||||
{
|
||||
public class PersonProxy : IPerson
|
||||
{
|
||||
public ProxyInterfaceSourceGeneratorTests.DTO.Person _Instance { get; }
|
||||
public ProxyInterfaceSourceGeneratorTests.Source.Person _Instance { get; }
|
||||
|
||||
public string Name { get => _Instance.Name; set => _Instance.Name = value; }
|
||||
|
||||
@@ -29,78 +29,78 @@ namespace ProxyInterfaceSourceGeneratorTests.DTO
|
||||
|
||||
public void Void()
|
||||
{
|
||||
_Instance.Void();
|
||||
_Instance.Void();
|
||||
}
|
||||
|
||||
public string HelloWorld(string name)
|
||||
{
|
||||
string name_ = name;
|
||||
var result_15289640 = _Instance.HelloWorld(name_);
|
||||
return result_15289640;
|
||||
string name_ = name;
|
||||
var result_56365455 = _Instance.HelloWorld(name_);
|
||||
return result_56365455;
|
||||
}
|
||||
|
||||
public void WithParams(params string[] values)
|
||||
{
|
||||
string[] values_ = values;
|
||||
_Instance.WithParams(values_);
|
||||
string[] values_ = values;
|
||||
_Instance.WithParams(values_);
|
||||
}
|
||||
|
||||
public string Add(string s, string @string)
|
||||
{
|
||||
string s_ = s;
|
||||
string @string_ = @string;
|
||||
var result_15289640 = _Instance.Add(s_, @string_);
|
||||
return result_15289640;
|
||||
string s_ = s;
|
||||
string @string_ = @string;
|
||||
var result_56365455 = _Instance.Add(s_, @string_);
|
||||
return result_56365455;
|
||||
}
|
||||
|
||||
public int DefaultValue(int x = 100)
|
||||
{
|
||||
int x_ = x;
|
||||
var result_54302544 = _Instance.DefaultValue(x_);
|
||||
return result_54302544;
|
||||
int x_ = x;
|
||||
var result_39875940 = _Instance.DefaultValue(x_);
|
||||
return result_39875940;
|
||||
}
|
||||
|
||||
public void In_Out_Ref1(in int a, out int b, ref int c)
|
||||
{
|
||||
int a_ = a;
|
||||
int b_;
|
||||
int c_ = c;
|
||||
_Instance.In_Out_Ref1(in a_, out b_, ref c_);
|
||||
b = b_;
|
||||
int a_ = a;
|
||||
int b_;
|
||||
int c_ = c;
|
||||
_Instance.In_Out_Ref1(in a_, out b_, ref c_);
|
||||
b = b_;
|
||||
}
|
||||
|
||||
public bool Generic2<T1, T2>(int x, T1 t1, T2 t2) where T1 : struct where T2 : class, new()
|
||||
{
|
||||
int x_ = x;
|
||||
T1 t1_ = t1;
|
||||
T2 t2_ = t2;
|
||||
var result_40004473 = _Instance.Generic2<T1, T2>(x_, t1_, t2_);
|
||||
return result_40004473;
|
||||
int x_ = x;
|
||||
T1 t1_ = t1;
|
||||
T2 t2_ = t2;
|
||||
var result_41799290 = _Instance.Generic2<T1, T2>(x_, t1_, t2_);
|
||||
return result_41799290;
|
||||
}
|
||||
|
||||
public System.Threading.Tasks.Task Method1Async()
|
||||
{
|
||||
var result_50153955 = _Instance.Method1Async();
|
||||
return result_50153955;
|
||||
var result_32599313 = _Instance.Method1Async();
|
||||
return result_32599313;
|
||||
}
|
||||
|
||||
public System.Threading.Tasks.Task<int> Method2Async()
|
||||
{
|
||||
var result_1151242754 = _Instance.Method2Async();
|
||||
return result_1151242754;
|
||||
var result_1620495907 = _Instance.Method2Async();
|
||||
return result_1620495907;
|
||||
}
|
||||
|
||||
public System.Threading.Tasks.Task<string?> Method3Async()
|
||||
{
|
||||
var result_1190255658 = _Instance.Method3Async();
|
||||
return result_1190255658;
|
||||
var result_1604006392 = _Instance.Method3Async();
|
||||
return result_1604006392;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public PersonProxy(ProxyInterfaceSourceGeneratorTests.DTO.Person instance)
|
||||
public PersonProxy(ProxyInterfaceSourceGeneratorTests.Source.Person instance)
|
||||
{
|
||||
_Instance = instance;
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using AnyOfTypes;
|
||||
using CSharp.SourceGenerators.Extensions;
|
||||
using CSharp.SourceGenerators.Extensions.Models;
|
||||
using FluentAssertions;
|
||||
using ProxyInterfaceSourceGenerator;
|
||||
using Xunit;
|
||||
|
||||
namespace FluentBuilderGeneratorTests
|
||||
namespace ProxyInterfaceSourceGeneratorTests
|
||||
{
|
||||
public class ProxyInterfaceSourceGeneratorTest
|
||||
{
|
||||
private bool Write = true;
|
||||
|
||||
private readonly ProxyInterfaceCodeGenerator _sut;
|
||||
|
||||
public ProxyInterfaceSourceGeneratorTest()
|
||||
@@ -21,10 +25,10 @@ namespace FluentBuilderGeneratorTests
|
||||
{
|
||||
// Arrange
|
||||
var attributeFilename = "ProxyInterfaceGenerator.ProxyAttribute.g.cs";
|
||||
var interfaceFilename = "ProxyInterfaceSourceGeneratorTests.DTO.IPerson.g.cs";
|
||||
var proxyClassFilename = "ProxyInterfaceSourceGeneratorTests.DTO.PersonProxy.g.cs";
|
||||
var interfaceFilename = "ProxyInterfaceSourceGeneratorTests.Source.IPersonExtends.g.cs";
|
||||
var proxyClassFilename = "ProxyInterfaceSourceGeneratorTests.Source.PersonExtendsProxy.g.cs";
|
||||
|
||||
var path = "./Source/IPerson.cs";
|
||||
var path = "./Source/IPersonExtends.cs";
|
||||
var sourceFile = new SourceFile
|
||||
{
|
||||
Path = path,
|
||||
@@ -32,7 +36,7 @@ namespace FluentBuilderGeneratorTests
|
||||
AttributeToAddToInterface = new ExtraAttribute
|
||||
{
|
||||
Name = "ProxyInterfaceGenerator.Proxy",
|
||||
ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.DTO.Person)"
|
||||
ArgumentList = new [] { "typeof(ProxyInterfaceSourceGeneratorTests.Source.PersonExtends)", "true" }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -43,16 +47,16 @@ namespace FluentBuilderGeneratorTests
|
||||
result.Valid.Should().BeTrue();
|
||||
result.Files.Should().HaveCount(3);
|
||||
|
||||
// Assert interface
|
||||
var @attribute = result.Files[0].SyntaxTree;
|
||||
@attribute.FilePath.Should().EndWith(attributeFilename);
|
||||
// Assert attribute
|
||||
var attribute = result.Files[0].SyntaxTree;
|
||||
attribute.FilePath.Should().EndWith(attributeFilename);
|
||||
|
||||
// Assert interface
|
||||
var @interface = result.Files[1].SyntaxTree;
|
||||
@interface.FilePath.Should().EndWith(interfaceFilename);
|
||||
|
||||
var interfaceCode = @interface.ToString();
|
||||
File.WriteAllText($"../../../Destination/{interfaceFilename}", interfaceCode);
|
||||
if (Write) File.WriteAllText($"../../../Destination/{interfaceFilename}", interfaceCode);
|
||||
interfaceCode.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{interfaceFilename}"));
|
||||
|
||||
// Assert Proxy
|
||||
@@ -60,8 +64,90 @@ namespace FluentBuilderGeneratorTests
|
||||
proxyClass.FilePath.Should().EndWith(proxyClassFilename);
|
||||
|
||||
var proxyCode = proxyClass.ToString();
|
||||
File.WriteAllText($"../../../Destination/{proxyClassFilename}", proxyCode);
|
||||
if (Write) File.WriteAllText($"../../../Destination/{proxyClassFilename}", proxyCode);
|
||||
proxyCode.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{proxyClassFilename}"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GenerateFiles_ForTwoClasses_Should_GenerateCorrectFiles()
|
||||
{
|
||||
// Arrange
|
||||
var attributeFilename = "ProxyInterfaceGenerator.ProxyAttribute.g.cs";
|
||||
var interfaceHumanFilename = "ProxyInterfaceSourceGeneratorTests.Source.IHuman.g.cs";
|
||||
var proxyClassHumanFilename = "ProxyInterfaceSourceGeneratorTests.Source.HumanProxy.g.cs";
|
||||
var interfacePersonFilename = "ProxyInterfaceSourceGeneratorTests.Source.IPerson.g.cs";
|
||||
var proxyClassPersonFilename = "ProxyInterfaceSourceGeneratorTests.Source.PersonProxy.g.cs";
|
||||
|
||||
var pathPerson = "./Source/IPerson.cs";
|
||||
var sourceFilePerson = new SourceFile
|
||||
{
|
||||
Path = pathPerson,
|
||||
Text = File.ReadAllText(pathPerson),
|
||||
AttributeToAddToInterface = new ExtraAttribute
|
||||
{
|
||||
Name = "ProxyInterfaceGenerator.Proxy",
|
||||
ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.Person)"
|
||||
}
|
||||
};
|
||||
|
||||
var pathHuman = "./Source/IHuman.cs";
|
||||
var sourceFileHuman = new SourceFile
|
||||
{
|
||||
Path = pathHuman,
|
||||
Text = File.ReadAllText(pathHuman),
|
||||
AttributeToAddToInterface = new ExtraAttribute
|
||||
{
|
||||
Name = "ProxyInterfaceGenerator.Proxy",
|
||||
ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.Human)"
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _sut.Execute(new[] { sourceFileHuman, sourceFilePerson });
|
||||
|
||||
// Assert
|
||||
result.Valid.Should().BeTrue();
|
||||
result.Files.Should().HaveCount(5);
|
||||
|
||||
// Assert attribute
|
||||
var attribute = result.Files[0].SyntaxTree;
|
||||
attribute.FilePath.Should().EndWith(attributeFilename);
|
||||
|
||||
|
||||
// Assert interface Human
|
||||
var interfaceHuman = result.Files[1].SyntaxTree;
|
||||
interfaceHuman.FilePath.Should().EndWith(interfaceHumanFilename);
|
||||
|
||||
var interfaceCodeHuman = interfaceHuman.ToString();
|
||||
if (Write) File.WriteAllText($"../../../Destination/{interfaceHumanFilename}", interfaceCodeHuman);
|
||||
interfaceCodeHuman.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{interfaceHumanFilename}"));
|
||||
|
||||
|
||||
// Assert interface Person
|
||||
var interfacePerson = result.Files[2].SyntaxTree;
|
||||
interfacePerson.FilePath.Should().EndWith(interfacePersonFilename);
|
||||
|
||||
var interfaceCodePerson = interfacePerson.ToString();
|
||||
if (Write) File.WriteAllText($"../../../Destination/{interfacePersonFilename}", interfaceCodePerson);
|
||||
interfaceCodePerson.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{interfacePersonFilename}"));
|
||||
|
||||
|
||||
// Assert Proxy Human
|
||||
var proxyClassHuman = result.Files[3].SyntaxTree;
|
||||
proxyClassHuman.FilePath.Should().EndWith(proxyClassHumanFilename);
|
||||
|
||||
var proxyCodeHuman = proxyClassHuman.ToString();
|
||||
if (Write) File.WriteAllText($"../../../Destination/{proxyClassHumanFilename}", proxyCodeHuman);
|
||||
proxyCodeHuman.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{proxyClassHumanFilename}"));
|
||||
|
||||
|
||||
// Assert Proxy Person
|
||||
var proxyClassPerson = result.Files[4].SyntaxTree;
|
||||
proxyClassPerson.FilePath.Should().EndWith(proxyClassPersonFilename);
|
||||
|
||||
var proxyCode = proxyClassPerson.ToString();
|
||||
if (Write) File.WriteAllText($"../../../Destination/{proxyClassPersonFilename}", proxyCode);
|
||||
proxyCode.Should().NotBeNullOrEmpty().And.Be(File.ReadAllText($"../../../Destination/{proxyClassPersonFilename}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-17
@@ -8,11 +8,6 @@
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Destination\ProxyInterfaceSourceGeneratorTests.DTO.IPerson.g.cs" />
|
||||
<Compile Remove="Destination\ProxyInterfaceSourceGeneratorTests.DTO.PersonProxy.g.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="5.10.3" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
||||
@@ -32,22 +27,29 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CSharp.SourceGenerators.Extensions" Version="0.0.5" />
|
||||
<PackageReference Include="CSharp.SourceGenerators.Extensions" Version="0.0.6" />
|
||||
<!--<ProjectReference Include="..\..\..\FluentBuilder\src-extensions\CSharp.SourceGenerators.Extensions\CSharp.SourceGenerators.Extensions.csproj" />-->
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Source\IPerson.cs">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
<Compile Update="Source\Person.cs">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Destination\ProxyInterfaceSourceGeneratorTests.DTO.IPerson.g.cs" />
|
||||
<None Include="Destination\ProxyInterfaceSourceGeneratorTests.DTO.PersonProxy.g.cs" />
|
||||
<Compile Update="Source\Human.cs">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
<Compile Update="Source\IHuman.cs">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
<Compile Update="Source\IPersonExtends.cs">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
<Compile Update="Source\IPerson.cs">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
<Compile Update="Source\PersonExtends.cs">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
<Compile Update="Source\Person.cs">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace ProxyInterfaceSourceGeneratorTests.Source
|
||||
{
|
||||
public class Human : Animal
|
||||
{
|
||||
public bool IsAlive { get; set; }
|
||||
}
|
||||
|
||||
public class Animal
|
||||
{
|
||||
public bool X { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace ProxyInterfaceSourceGeneratorTests.Source
|
||||
{
|
||||
public partial interface IHuman
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace ProxyInterfaceSourceGeneratorTests.DTO
|
||||
namespace ProxyInterfaceSourceGeneratorTests.Source
|
||||
{
|
||||
public partial interface IPerson
|
||||
{
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace ProxyInterfaceSourceGeneratorTests.Source
|
||||
{
|
||||
public partial interface IPersonExtends
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxyInterfaceSourceGeneratorTests.DTO
|
||||
namespace ProxyInterfaceSourceGeneratorTests.Source
|
||||
{
|
||||
public class Person
|
||||
{
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ProxyInterfaceSourceGeneratorTests.Source
|
||||
{
|
||||
public class PersonExtends : Human
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string? StringNullable { get; set; }
|
||||
|
||||
public long? NullableLong { get; }
|
||||
|
||||
public object @object { get; set; }
|
||||
|
||||
public void Void()
|
||||
{
|
||||
}
|
||||
|
||||
public string HelloWorld(string name)
|
||||
{
|
||||
return $"Hello {name} !";
|
||||
}
|
||||
|
||||
public void WithParams(params string[] values)
|
||||
{
|
||||
}
|
||||
|
||||
public string Add(string s, string @string)
|
||||
{
|
||||
return s + @string;
|
||||
}
|
||||
|
||||
public int DefaultValue(int x = 100)
|
||||
{
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
public void In_Out_Ref1(in int a, out int b, ref int c)
|
||||
{
|
||||
b = 1;
|
||||
}
|
||||
|
||||
public bool Generic2<T1, T2>(int x, T1 t1, T2 t2)
|
||||
where T1 : struct
|
||||
where T2 : class, new()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public Task Method1Async()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<int> Method2Async()
|
||||
{
|
||||
return Task.FromResult(1);
|
||||
}
|
||||
|
||||
public Task<string?> Method3Async()
|
||||
{
|
||||
return Task.FromResult((string?)"");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user