Skip to content

Commit

Permalink
big wip
Browse files Browse the repository at this point in the history
  • Loading branch information
ReubenBond committed Nov 20, 2023
1 parent 27e97a2 commit d42817d
Show file tree
Hide file tree
Showing 18 changed files with 336 additions and 246 deletions.
181 changes: 54 additions & 127 deletions src/Orleans.CodeGenerator/CodeGenerator.cs

Large diffs are not rendered by default.

184 changes: 105 additions & 79 deletions src/Orleans.CodeGenerator/InvokableGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Linq;
using Orleans.CodeGenerator.Diagnostics;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using System.ComponentModel;

namespace Orleans.CodeGenerator
{
Expand All @@ -15,64 +16,20 @@ namespace Orleans.CodeGenerator
/// </summary>
internal static class InvokableGenerator
{
public static (ClassDeclarationSyntax Syntax, GeneratedInvokerDescription InvokerDescription) Generate(
public static GeneratedInvokerDescription Generate(
LibraryTypes libraryTypes,
InvokableInterfaceDescription interfaceDescription,
MethodDescription method)
{
var generatedClassName = GetSimpleClassName(interfaceDescription, method);
INamedTypeSymbol baseClassType = GetBaseClassType(method);
var originalMethod = method.GetOriginalMethodDescription();
var generatedClassName = GetSimpleClassName(originalMethod);

var baseClassType = GetBaseClassType(originalMethod);
var fieldDescriptions = GetFieldDescriptions(method, interfaceDescription);
var fields = GetFieldDeclarations(method, fieldDescriptions, libraryTypes);
var (ctor, ctorArgs) = GenerateConstructor(libraryTypes, generatedClassName, method, baseClassType);

Accessibility accessibility = GetAccessibility(interfaceDescription);

var targetField = fieldDescriptions.OfType<TargetFieldDescription>().Single();

var accessibilityKind = accessibility switch
{
Accessibility.Public => SyntaxKind.PublicKeyword,
_ => SyntaxKind.InternalKeyword,
};
var compoundTypeAliasArgs = GetCompoundTypeAliasAttributeArguments(method);
var classDeclaration = ClassDeclaration(generatedClassName)
.AddBaseListTypes(SimpleBaseType(baseClassType.ToTypeSyntax(method.TypeParameterSubstitutions)))
.AddModifiers(Token(accessibilityKind), Token(SyntaxKind.SealedKeyword))
.AddAttributeLists(
AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax())),
AttributeList(SingletonSeparatedList(GetCompoundTypeAliasAttribute(libraryTypes, compoundTypeAliasArgs))))
.AddMembers(fields);

if (ctor != null)
{
classDeclaration = classDeclaration.AddMembers(ctor);
}

if (method.ResponseTimeoutTicks.HasValue)
{
classDeclaration = classDeclaration.AddMembers(GenerateResponseTimeoutPropertyMembers(libraryTypes, method.ResponseTimeoutTicks.Value));
}

classDeclaration = AddOptionalMembers(classDeclaration,
GenerateGetArgumentCount(method),
GenerateGetMethodName(libraryTypes, method),
GenerateGetInterfaceName(libraryTypes, method),
GenerateGetActivityName(libraryTypes, method),
GenerateGetInterfaceType(libraryTypes, method),
GenerateGetMethod(libraryTypes),
GenerateSetTargetMethod(libraryTypes, interfaceDescription, targetField),
GenerateGetTargetMethod(targetField),
GenerateDisposeMethod(fieldDescriptions, baseClassType),
GenerateGetArgumentMethod(method, fieldDescriptions),
GenerateSetArgumentMethod(method, fieldDescriptions),
GenerateInvokeInnerMethod(libraryTypes, method, fieldDescriptions, targetField));

var typeParametersWithNames = method.AllTypeParameters;
if (typeParametersWithNames.Count > 0)
{
classDeclaration = SyntaxFactoryUtility.AddGenericTypeParameters(classDeclaration, typeParametersWithNames);
}
var accessibility = GetAccessibility(interfaceDescription);
var compoundTypeAliases = GetCompoundTypeAliasAttributeArguments(method);

List<INamedTypeSymbol> serializationHooks = new();
if (baseClassType.GetAttributes(libraryTypes.SerializationCallbacksAttribute, out var hookAttributes))
Expand All @@ -84,6 +41,27 @@ public static (ClassDeclarationSyntax Syntax, GeneratedInvokerDescription Invoke
}
}

var targetField = fieldDescriptions.OfType<TargetFieldDescription>().Single();

var accessibilityKind = accessibility switch
{
Accessibility.Public => SyntaxKind.PublicKeyword,
_ => SyntaxKind.InternalKeyword,
};

var classDeclaration = method.IsInheritedFromInvokableInterface ? null : GetClassDeclarationSyntax(
libraryTypes,
interfaceDescription,
method,
generatedClassName,
baseClassType,
fieldDescriptions,
fields,
ctor,
compoundTypeAliases,
targetField,
accessibilityKind);

string returnValueInitializerMethod = null;
if (baseClassType.GetAttribute(libraryTypes.ReturnValueProxyAttribute) is { ConstructorArguments: { Length: > 0 } attrArgs })
{
Expand All @@ -100,13 +78,15 @@ public static (ClassDeclarationSyntax Syntax, GeneratedInvokerDescription Invoke
method,
accessibility,
generatedClassName,
originalMethod.ContainingInterface.GeneratedNamespace,
fieldDescriptions.OfType<IMemberDescription>().ToList(),
serializationHooks,
baseClassType,
ctorArgs,
compoundTypeAliasArgs,
returnValueInitializerMethod);
return (classDeclaration, invokerDescription);
compoundTypeAliases,
returnValueInitializerMethod,
classDeclaration);
return invokerDescription;

static Accessibility GetAccessibility(InvokableInterfaceDescription interfaceDescription)
{
Expand All @@ -126,6 +106,63 @@ static Accessibility GetAccessibility(InvokableInterfaceDescription interfaceDes
}
}

private static ClassDeclarationSyntax GetClassDeclarationSyntax(
LibraryTypes libraryTypes,
InvokableInterfaceDescription interfaceDescription,
MethodDescription method,
string generatedClassName,
INamedTypeSymbol baseClassType,
List<InvokerFieldDescripton> fieldDescriptions,
MemberDeclarationSyntax[] fields,
ConstructorDeclarationSyntax ctor,
List<CompoundTypeAliasComponent[]> compoundTypeAliases,
TargetFieldDescription targetField,
SyntaxKind accessibilityKind)
{
var classDeclaration = ClassDeclaration(generatedClassName)
.AddBaseListTypes(SimpleBaseType(baseClassType.ToTypeSyntax(method.TypeParameterSubstitutions)))
.AddModifiers(Token(accessibilityKind), Token(SyntaxKind.SealedKeyword))
.AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax())))
.AddMembers(fields);

foreach (var alias in compoundTypeAliases)
{
classDeclaration = classDeclaration.AddAttributeLists(
AttributeList(SingletonSeparatedList(GetCompoundTypeAliasAttribute(libraryTypes, alias))));
}

if (ctor != null)
{
classDeclaration = classDeclaration.AddMembers(ctor);
}

if (method.ResponseTimeoutTicks.HasValue)
{
classDeclaration = classDeclaration.AddMembers(GenerateResponseTimeoutPropertyMembers(libraryTypes, method.ResponseTimeoutTicks.Value));
}

classDeclaration = AddOptionalMembers(classDeclaration,
GenerateGetArgumentCount(method),
GenerateGetMethodName(libraryTypes, method),
GenerateGetInterfaceName(libraryTypes, method),
GenerateGetActivityName(libraryTypes, method),
GenerateGetInterfaceType(libraryTypes, method),
GenerateGetMethod(libraryTypes),
GenerateSetTargetMethod(libraryTypes, interfaceDescription, targetField),
GenerateGetTargetMethod(targetField),
GenerateDisposeMethod(fieldDescriptions, baseClassType),
GenerateGetArgumentMethod(method, fieldDescriptions),
GenerateSetArgumentMethod(method, fieldDescriptions),
GenerateInvokeInnerMethod(libraryTypes, method, fieldDescriptions, targetField));

if (method.AllTypeParameters.Count > 0)
{
classDeclaration = SyntaxFactoryUtility.AddGenericTypeParameters(classDeclaration, method.AllTypeParameters);
}

return classDeclaration;
}

private static MemberDeclarationSyntax[] GenerateResponseTimeoutPropertyMembers(LibraryTypes libraryTypes, long value)
{
var timespanField = FieldDeclaration(
Expand Down Expand Up @@ -171,29 +208,28 @@ internal static AttributeSyntax GetCompoundTypeAliasAttribute(LibraryTypes libra
return Attribute(libraryTypes.CompoundTypeAliasAttribute.ToNameSyntax()).AddArgumentListArguments(args);
}

internal static CompoundTypeAliasComponent[] GetCompoundTypeAliasAttributeArguments(MethodDescription methodDescription)
internal static List<CompoundTypeAliasComponent[]> GetCompoundTypeAliasAttributeArguments(MethodDescription methodDescription)
{
var result = new List<CompoundTypeAliasComponent[]>(2);
if (methodDescription.HasAlias)
{
return new CompoundTypeAliasComponent[]
result.Add(new CompoundTypeAliasComponent[]
{
new("inv"),
new(methodDescription.ContainingInterface.ProxyBaseType),
new(methodDescription.ContainingInterface.InterfaceType),
new(methodDescription.Method.OriginalDefinition.ContainingType),
new(methodDescription.MethodId)
};
});
}
else

result.Add(new CompoundTypeAliasComponent[]
{
return new CompoundTypeAliasComponent[]
{
new("inv"),
new(methodDescription.ContainingInterface.ProxyBaseType),
new(methodDescription.ContainingInterface.InterfaceType),
new(methodDescription.MethodId)
};
}
new("inv"),
new(methodDescription.ContainingInterface.ProxyBaseType),
new(methodDescription.ContainingInterface.InterfaceType),
new(methodDescription.GeneratedMethodId)
});
return result;
}

private static INamedTypeSymbol GetBaseClassType(MethodDescription method)
Expand Down Expand Up @@ -537,21 +573,11 @@ private static MemberDeclarationSyntax GenerateGetMethod(
.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));

public static string GetSimpleClassName(InvokableInterfaceDescription interfaceDescription, MethodDescription method)
public static string GetSimpleClassName(MethodDescription method)
{
var genericArity = method.AllTypeParameters.Count;
var typeArgs = genericArity > 0 ? "_" + genericArity : string.Empty;
if (method.HasAlias)
{
if (method.Method.Name == "Eat")
{
}
return $"Invokable_{interfaceDescription.Name}_{method.Method.ReceiverType.Name}_{interfaceDescription.ProxyBaseType.Name}_{method.MethodId}{typeArgs}";
}
else
{
return $"Invokable_{interfaceDescription.Name}_{interfaceDescription.ProxyBaseType.Name}_{method.MethodId}{typeArgs}";
}
return $"Invokable_{method.ContainingInterface.Name}_{method.ContainingInterface.ProxyBaseType.Name}_{method.GeneratedMethodId}{typeArgs}";
}

private static MemberDeclarationSyntax[] GetFieldDeclarations(
Expand Down
2 changes: 1 addition & 1 deletion src/Orleans.CodeGenerator/MetadataGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public static ClassDeclarationSyntax GenerateMetadata(Compilation compilation, M
}

var addInvokableInterfaceMethod = configParam.Member("Interfaces").Member("Add");
foreach (var type in metadataModel.InvokableInterfaces)
foreach (var type in metadataModel.InvokableInterfaces.Values)
{
body.Add(ExpressionStatement(InvocationExpression(addInvokableInterfaceMethod,
ArgumentList(SingletonSeparatedList(Argument(TypeOfExpression(type.InterfaceType.ToOpenTypeSyntax())))))));
Expand Down
21 changes: 13 additions & 8 deletions src/Orleans.CodeGenerator/Model/IGeneratedInvokerDescription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,28 @@ public GeneratedInvokerDescription(
MethodDescription methodDescription,
Accessibility accessibility,
string generatedClassName,
string generatedNamespaceName,
List<IMemberDescription> members,
List<INamedTypeSymbol> serializationHooks,
INamedTypeSymbol baseType,
List<TypeSyntax> constructorArguments,
CompoundTypeAliasComponent[] compoundTypeAliasArguments,
string returnValueInitializerMethod)
List<CompoundTypeAliasComponent[]> compoundTypeAliases,
string returnValueInitializerMethod,
ClassDeclarationSyntax classDeclarationSyntax)
{
InterfaceDescription = interfaceDescription;
_methodDescription = methodDescription;
BaseType = baseType;
Name = generatedClassName;
GeneratedNamespace = generatedNamespaceName;
Members = members;

Accessibility = accessibility;
SerializationHooks = serializationHooks;
ActivatorConstructorParameters = constructorArguments;
CompoundTypeAliasArguments = compoundTypeAliasArguments;
CompoundTypeAliases = compoundTypeAliases;
ReturnValueInitializerMethod = returnValueInitializerMethod;
ClassDeclarationSyntax = classDeclarationSyntax;
}

public Accessibility Accessibility { get; }
Expand All @@ -47,7 +51,7 @@ public GeneratedInvokerDescription(
public INamedTypeSymbol BaseType { get; }
public TypeSyntax BaseTypeSyntax => _baseTypeSyntax ??= BaseType.ToTypeSyntax(_methodDescription.TypeParameterSubstitutions);
public string Namespace => GeneratedNamespace;
public string GeneratedNamespace => InterfaceDescription.GeneratedNamespace;
public string GeneratedNamespace { get; }
public string Name { get; }
public bool IsValueType => false;
public bool IsSealedType => true;
Expand All @@ -56,7 +60,7 @@ public GeneratedInvokerDescription(
public bool IsGenericType => TypeParameters.Count > 0;
public List<IMemberDescription> Members { get; }
public InvokableInterfaceDescription InterfaceDescription { get; }
public SemanticModel SemanticModel => InterfaceDescription.SemanticModel;
public Compilation Compilation => InterfaceDescription.CodeGenerator.Compilation;
public bool IsEmptyConstructable => ActivatorConstructorParameters is not { Count: > 0 };
public bool UseActivator => ActivatorConstructorParameters is { Count: > 0 };
public bool TrackReferences => false;
Expand All @@ -69,14 +73,15 @@ public GeneratedInvokerDescription(
public bool IsExceptionType => false;
public List<TypeSyntax> ActivatorConstructorParameters { get; }
public bool HasActivatorConstructor => UseActivator;
public CompoundTypeAliasComponent[] CompoundTypeAliasArguments {get;}
public List<CompoundTypeAliasComponent[]> CompoundTypeAliases {get;}
public ClassDeclarationSyntax ClassDeclarationSyntax { get; }
public string ReturnValueInitializerMethod { get; }

public ExpressionSyntax GetObjectCreationExpression(LibraryTypes libraryTypes) => ObjectCreationExpression(TypeSyntax, ArgumentList(), null);

private TypeSyntax CreateTypeSyntax()
{
var simpleName = InvokableGenerator.GetSimpleClassName(InterfaceDescription, _methodDescription);
var simpleName = InvokableGenerator.GetSimpleClassName(_methodDescription.GetOriginalMethodDescription());
return (TypeParameters, Namespace) switch
{
({ Count: > 0 }, { Length: > 0 }) => QualifiedName(ParseName(Namespace), GenericName(Identifier(simpleName), TypeArgumentList(SeparatedList<TypeSyntax>(TypeParameters.Select(p => IdentifierName(p.Name)))))),
Expand All @@ -88,7 +93,7 @@ private TypeSyntax CreateTypeSyntax()

private TypeSyntax CreateOpenTypeSyntax()
{
var simpleName = InvokableGenerator.GetSimpleClassName(InterfaceDescription, _methodDescription);
var simpleName = InvokableGenerator.GetSimpleClassName(_methodDescription.GetOriginalMethodDescription());
return (TypeParameters, Namespace) switch
{
({ Count: > 0 }, { Length: > 0 }) => QualifiedName(ParseName(Namespace), GenericName(Identifier(simpleName), TypeArgumentList(SeparatedList<TypeSyntax>(TypeParameters.Select(p => OmittedTypeArgument()))))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal interface ISerializableTypeDescription
bool IsGenericType { get; }
List<(string Name, ITypeParameterSymbol Parameter)> TypeParameters { get; }
List<IMemberDescription> Members { get; }
SemanticModel SemanticModel { get; }
Compilation Compilation { get; }
bool UseActivator { get; }
bool IsEmptyConstructable { get; }
bool HasActivatorConstructor { get; }
Expand Down
Loading

0 comments on commit d42817d

Please sign in to comment.