Add support for using a simple type-name (#22)

This commit is contained in:
Stef Heyenrath
2021-08-02 11:49:41 +02:00
committed by GitHub
parent a778c35728
commit 7baf050c12
10 changed files with 75 additions and 23 deletions
@@ -1,4 +1,4 @@
namespace ProxyInterfaceConsumer
namespace DifferentNamespace
{
public class Address
{
@@ -1,6 +1,10 @@
namespace ProxyInterfaceConsumer
using DifferentNamespace;
using System;
using System.Linq;
namespace ProxyInterfaceConsumer
{
// [ProxyInterfaceGenerator.Proxy(typeof(ProxyInterfaceConsumer.Address))]
[ProxyInterfaceGenerator.Proxy(typeof(Address))]
public partial interface IAddress
{
}
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using DifferentNamespace;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ProxyInterfaceConsumer
@@ -0,0 +1,18 @@
// https://stackoverflow.com/questions/61573959/how-to-resolve-error-notnullwhen-attribute-is-inaccessible-due-to-its-protectio
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>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; }
}
}
@@ -1,11 +1,12 @@
using Microsoft.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
namespace ProxyInterfaceSourceGenerator.Extensions
{
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, out T? result) where T : SyntaxNode
public static bool TryGetParentSyntax<T>(this SyntaxNode? syntaxNode, [NotNullWhen(true)] out T? result) where T : SyntaxNode
{
result = null;
@@ -25,7 +26,7 @@ namespace ProxyInterfaceSourceGenerator.Extensions
if (syntaxNode.GetType() == typeof(T))
{
result = syntaxNode as T;
result = (T)syntaxNode;
return true;
}
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
@@ -67,16 +68,28 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators
return typeSymbolAsString;
}
protected INamedTypeSymbol GetNamedTypeSymbolByFullName(string fullName)
protected INamedTypeSymbol 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(fullName);
if (symbol is null)
{
throw new Exception($"The type '{fullName}' is not found.");
var symbol = _context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName(name);
if (symbol is not null)
{
return symbol;
}
if (usings is not null)
{
foreach (var @using in usings)
{
symbol = _context.GeneratorExecutionContext.Compilation.GetTypeByMetadataName($"{@using}.{name}");
if (symbol is not null)
{
return symbol;
}
}
}
return symbol;
throw new Exception($"The type '{name}' is not found.");
}
}
}
@@ -26,7 +26,7 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators
private FileData GenerateFile(ProxyData pd)
{
var targetClassSymbol = GetNamedTypeSymbolByFullName(pd.TypeName);
var targetClassSymbol = GetNamedTypeSymbolByFullName(pd.TypeName, pd.Usings);
var interfaceName = targetClassSymbol.ResolveInterfaceNameWithOptionalTypeConstraints(pd.InterfaceName);
var file = new FileData(
@@ -26,7 +26,7 @@ namespace ProxyInterfaceSourceGenerator.FileGenerators
private FileData GenerateFile(ProxyData pd)
{
var targetClassSymbol = GetNamedTypeSymbolByFullName(pd.TypeName);
var targetClassSymbol = GetNamedTypeSymbolByFullName(pd.TypeName, pd.Usings);
var interfaceName = targetClassSymbol.ResolveInterfaceNameWithOptionalTypeConstraints(pd.InterfaceName);
var className = targetClassSymbol.ResolveProxyClassName();
var constructorName = $"{targetClassSymbol.Name}Proxy";
@@ -1,6 +1,8 @@
namespace ProxyInterfaceSourceGenerator.SyntaxReceiver
using System.Collections.Generic;
namespace ProxyInterfaceSourceGenerator.SyntaxReceiver
{
internal record ProxyData(string Namespace, string InterfaceName, string RawTypeName, string TypeName, bool ProxyAll)
internal record ProxyData(string Namespace, string InterfaceName, string RawTypeName, string TypeName, List<string> Usings, bool ProxyAll)
{
public string FileName => TypeName.Replace('.', '_').Replace('`', '_');
}
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -20,9 +21,9 @@ namespace ProxyInterfaceSourceGenerator.SyntaxReceiver
}
}
private static bool TryGet(InterfaceDeclarationSyntax interfaceDeclarationSyntax, out ProxyData data)
private static bool TryGet(InterfaceDeclarationSyntax interfaceDeclarationSyntax, [NotNullWhen(true)] out ProxyData? data)
{
data = new(string.Empty, string.Empty, string.Empty, string.Empty, false);
data = null;
if (interfaceDeclarationSyntax.Modifiers.Select(m => m.ToString()).Except(Modifiers).Count() != 0)
{
@@ -42,27 +43,39 @@ namespace ProxyInterfaceSourceGenerator.SyntaxReceiver
return false;
}
var usings = new List<string>();
string ns = string.Empty;
if (SyntaxNodeUtils.TryGetParentSyntax(interfaceDeclarationSyntax, out NamespaceDeclarationSyntax namespaceDeclarationSyntax))
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();
string rawTypeName = ((TypeOfExpressionSyntax)argumentList.Arguments[0].Expression).Type.ToString();
data = new
(
ns,
interfaceDeclarationSyntax.Identifier.ToString(),
rawTypename,
ResolveType(rawTypename),
rawTypeName,
ConvertTypeName(rawTypeName),
usings,
false //bool.Parse(argumentList.Arguments[1].Expression.GetText().ToString())
);
return true;
}
private static string ResolveType(string typeName)
private static string ConvertTypeName(string typeName)
{
return !(typeName.Contains('<') && typeName.Contains('>')) ?
typeName :