Add support for public and internal ProxyClass (#58)

* x

* fx

* .
This commit is contained in:
Stef Heyenrath
2023-02-24 16:22:26 +01:00
committed by GitHub
parent 4c7f7cde4d
commit eadcf8585f
15 changed files with 296 additions and 36 deletions
@@ -26,13 +26,35 @@ namespace ProxyInterfaceGenerator
{{
public Type Type {{ get; }}
public bool ProxyBaseClasses {{ get; }}
public ProxyClassAccessibility Accessibility {{ get; }}
public {ClassName}(Type type, bool proxyBaseClasses = false)
public {ClassName}(Type type) : this(type, false, ProxyClassAccessibility.Public)
{{
}}
public {ClassName}(Type type, bool proxyBaseClasses) : this(type, proxyBaseClasses, ProxyClassAccessibility.Public)
{{
}}
public {ClassName}(Type type, ProxyClassAccessibility accessibility) : this(type, false, accessibility)
{{
}}
public {ClassName}(Type type, bool proxyBaseClasses, ProxyClassAccessibility accessibility)
{{
Type = type;
ProxyBaseClasses = proxyBaseClasses;
Accessibility = accessibility;
}}
}}
[Flags]
internal enum ProxyClassAccessibility
{{
Public = 0,
Internal = 1
}}
}}");
}
}
@@ -5,6 +5,7 @@ using ProxyInterfaceSourceGenerator.Builders;
using ProxyInterfaceSourceGenerator.Enums;
using ProxyInterfaceSourceGenerator.Extensions;
using ProxyInterfaceSourceGenerator.Models;
using ProxyInterfaceSourceGenerator.Types;
using ProxyInterfaceSourceGenerator.Utils;
namespace ProxyInterfaceSourceGenerator.FileGenerators;
@@ -88,6 +89,8 @@ internal partial class ProxyClassesGenerator : BaseGenerator, IFilesGenerator
var (namespaceStart, namespaceEnd) = NamespaceBuilder.Build(pd.Namespace);
var accessibility = pd.Accessibility == ProxyClassAccessibility.Internal ? "internal" : "public";
return $@"//----------------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator.
@@ -101,7 +104,7 @@ internal partial class ProxyClassesGenerator : BaseGenerator, IFilesGenerator
using System;
{namespaceStart}
public {@abstract}partial class {className} : {extends}{interfaceName}
{accessibility} {@abstract}partial class {className} : {extends}{interfaceName}
{{
public {@new}{targetClassSymbol.Symbol} _Instance {{ get; }}
{instanceBaseDefinition}
@@ -1,3 +1,5 @@
using ProxyInterfaceSourceGenerator.Types;
namespace ProxyInterfaceSourceGenerator.Models;
internal class ProxyData
@@ -17,4 +19,6 @@ internal class ProxyData
public List<string> Usings { get; init; }
public bool ProxyBaseClasses { get; init; }
public ProxyClassAccessibility Accessibility { get; init; }
}
@@ -37,14 +37,18 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="IsExternalInit" Version="1.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0" PrivateAssets="all" />
<PackageReference Include="Polyfill.NET" Version="1.0.12">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PackageReference Include="Nullable" Version="1.3.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
@@ -59,10 +63,6 @@
</Compile>
</ItemGroup>
<!--<ItemGroup>
<None Remove="bin\Debug\netstandard2.0\ProxyInterfaceSourceGenerator.dll" />
</ItemGroup>-->
<ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
@@ -0,0 +1,82 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using ProxyInterfaceSourceGenerator.Types;
namespace ProxyInterfaceSourceGenerator.SyntaxReceiver;
internal static class AttributeArgumentListParser
{
public static ProxyInterfaceGeneratorAttributeArguments ParseAttributeArguments(AttributeArgumentListSyntax? argumentList)
{
if (argumentList is null || argumentList.Arguments.Count is < 1 or > 3)
{
throw new ArgumentException("The ProxyAttribute requires 1, 2 or 3 arguments.");
}
ProxyInterfaceGeneratorAttributeArguments result;
if (TryParseAsType(argumentList.Arguments[0].Expression, out var rawTypeValue))
{
result = new ProxyInterfaceGeneratorAttributeArguments(rawTypeValue);
}
else
{
throw new ArgumentException("The first argument from the ProxyAttribute should be a Type.");
}
foreach (var argument in argumentList.Arguments.Skip(1))
{
if (TryParseAsBoolean(argument.Expression, out var proxyBaseClasses))
{
result = result with { ProxyBaseClasses = proxyBaseClasses };
continue;
}
if (TryParseAsEnum<ProxyClassAccessibility>(argument.Expression, out var accessibility))
{
result = result with { Accessibility = accessibility };
}
}
return result;
}
private static bool TryParseAsBoolean(ExpressionSyntax expressionSyntax, out bool value)
{
value = default;
if (expressionSyntax is LiteralExpressionSyntax literalExpressionSyntax)
{
value = literalExpressionSyntax.Kind() == SyntaxKind.TrueLiteralExpression;
return true;
}
return false;
}
private static bool TryParseAsType(ExpressionSyntax expressionSyntax, [NotNullWhen(true)] out string? rawTypeName)
{
rawTypeName = null;
if (expressionSyntax is TypeOfExpressionSyntax typeOfExpressionSyntax)
{
rawTypeName = typeOfExpressionSyntax.Type.ToString();
return true;
}
return false;
}
private static bool TryParseAsEnum<TEnum>(ExpressionSyntax expressionSyntax, out TEnum value)
where TEnum : struct
{
var enumAsString = expressionSyntax.ToString();
if (enumAsString.Length > typeof(TEnum).Name.Length && Enum.TryParse(expressionSyntax.ToString().Substring(typeof(TEnum).Name.Length + 1), out value))
{
return true;
}
value = default;
return false;
}
}
@@ -31,19 +31,14 @@ internal class ProxySyntaxReceiver : ISyntaxReceiver
return false;
}
var attributeLists = interfaceDeclarationSyntax.AttributeLists.FirstOrDefault(x => x.Attributes.Any(a => GenerateProxyAttributes.Contains(a.Name.ToString())));
if (attributeLists is null)
var attributeList = interfaceDeclarationSyntax.AttributeLists.FirstOrDefault(x => x.Attributes.Any(a => GenerateProxyAttributes.Contains(a.Name.ToString())));
if (attributeList is null)
{
// InterfaceDeclarationSyntax should have the correct attribute
return false;
}
var argumentList = attributeLists.Attributes.FirstOrDefault()?.ArgumentList;
if (argumentList is null)
{
return false;
}
var usings = new List<string>();
string ns = interfaceDeclarationSyntax.GetNamespace();
@@ -60,29 +55,21 @@ internal class ProxySyntaxReceiver : ISyntaxReceiver
}
}
var typeSyntax = ((TypeOfExpressionSyntax)argumentList.Arguments[0].Expression).Type;
string rawTypeName = typeSyntax.ToString();
bool proxyBaseClasses;
try
{
proxyBaseClasses = bool.Parse(((LiteralExpressionSyntax)argumentList.Arguments[1].Expression).ToString());
}
catch
{
proxyBaseClasses = false;
}
var fluentBuilderAttributeArguments = AttributeArgumentListParser.ParseAttributeArguments(attributeList.Attributes.FirstOrDefault()?.ArgumentList);
var rawTypeNameAsString = fluentBuilderAttributeArguments.RawTypeName;
data = new ProxyData
{
Namespace = ns,
ShortInterfaceName = interfaceDeclarationSyntax.Identifier.ToString(),
FullInterfaceName = CreateFullInterfaceName(ns, interfaceDeclarationSyntax), // $"{ns}.{interfaceDeclarationSyntax.Identifier}",
FullRawTypeName = rawTypeName,
ShortTypeName = ConvertTypeName(rawTypeName).Split('.').Last(),
FullTypeName = ConvertTypeName(rawTypeName),
FullRawTypeName = rawTypeNameAsString,
ShortTypeName = ConvertTypeName(rawTypeNameAsString).Split('.').Last(),
FullTypeName = ConvertTypeName(rawTypeNameAsString),
Usings = usings,
ProxyBaseClasses = proxyBaseClasses
ProxyBaseClasses = fluentBuilderAttributeArguments.ProxyBaseClasses,
Accessibility = fluentBuilderAttributeArguments.Accessibility
};
return true;
@@ -0,0 +1,8 @@
namespace ProxyInterfaceSourceGenerator.Types;
internal record ProxyInterfaceGeneratorAttributeArguments(string RawTypeName)
{
public bool ProxyBaseClasses { get; set; }
public ProxyClassAccessibility Accessibility { get; set; }
}
@@ -0,0 +1,9 @@
namespace ProxyInterfaceSourceGenerator.Types;
[Flags]
internal enum ProxyClassAccessibility
{
Public = 0,
Internal = 1
}