public static (ClassDeclarationSyntax, GeneratedProxyDescription) Generate( LibraryTypes libraryTypes, InvokableInterfaceDescription interfaceDescription, MetadataModel metadataModel) { var generatedClassName = GetSimpleClassName(interfaceDescription); var ctors = GenerateConstructors(generatedClassName, interfaceDescription.ProxyBaseType).ToArray(); var proxyMethods = CreateProxyMethods(libraryTypes, interfaceDescription, metadataModel).ToArray(); var classDeclaration = ClassDeclaration(generatedClassName) .AddBaseListTypes( SimpleBaseType(interfaceDescription.ProxyBaseType.ToTypeSyntax()), SimpleBaseType(interfaceDescription.InterfaceType.ToTypeSyntax())) .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword)) .AddAttributeLists( AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax()))) .AddMembers(ctors) .AddMembers(proxyMethods); var typeParameters = interfaceDescription.TypeParameters; if (typeParameters.Count > 0) { classDeclaration = SyntaxFactoryUtility.AddGenericTypeParameters(classDeclaration, typeParameters); } return(classDeclaration, new GeneratedProxyDescription(interfaceDescription)); }
private static IEnumerable <MemberDeclarationSyntax> CreateProxyMethods( LibraryTypes libraryTypes, InvokableInterfaceDescription interfaceDescription, MetadataModel metadataModel) { foreach (var methodDescription in interfaceDescription.Methods) { yield return(CreateProxyMethod(methodDescription)); } MethodDeclarationSyntax CreateProxyMethod(MethodDescription methodDescription) { var method = methodDescription.Method; var declaration = MethodDeclaration(method.ReturnType.ToTypeSyntax(methodDescription.TypeParameterSubstitutions), method.Name.EscapeIdentifier()) .AddParameterListParameters(method.Parameters.Select((p, i) => GetParameterSyntax(i, p, methodDescription.TypeParameterSubstitutions)).ToArray()) .WithBody( CreateAsyncProxyMethodBody(libraryTypes, metadataModel, methodDescription)); if (methodDescription.HasCollision) { declaration = declaration.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))); // Type parameter constrains are not valid on explicit interface definitions var typeParameters = SyntaxFactoryUtility.GetTypeParameterConstraints(methodDescription.MethodTypeParameters); foreach (var(name, constraints) in typeParameters) { if (constraints.Count > 0) { declaration = declaration.AddConstraintClauses( TypeParameterConstraintClause(name).AddConstraints(constraints.ToArray())); } } } else { var explicitInterfaceSpecifier = ExplicitInterfaceSpecifier(methodDescription.Method.ContainingType.ToNameSyntax()); declaration = declaration.WithExplicitInterfaceSpecifier(explicitInterfaceSpecifier); } if (methodDescription.MethodTypeParameters.Count > 0) { declaration = declaration.WithTypeParameterList( TypeParameterList(SeparatedList(methodDescription.MethodTypeParameters.Select(tp => TypeParameter(tp.Name))))); } return(declaration); } }
public static ClassDeclarationSyntax GenerateActivator(LibraryTypes libraryTypes, ISerializableTypeDescription type) { var simpleClassName = GetSimpleClassName(type); var baseInterface = libraryTypes.IActivator_1.ToTypeSyntax(type.TypeSyntax); var orderedFields = new List <ConstructorArgument>(); var index = 0; if (type.ActivatorConstructorParameters is { Count : > 0 } parameters) { foreach (var arg in parameters) { orderedFields.Add(new ConstructorArgument { Type = arg, FieldName = $"_arg{index}", ParameterName = $"arg{index}" }); index++; } } var members = new List <MemberDeclarationSyntax>(); foreach (var field in orderedFields) { members.Add( FieldDeclaration(VariableDeclaration(field.Type, SingletonSeparatedList(VariableDeclarator(field.FieldName)))) .AddModifiers( Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword))); } members.Add(GenerateConstructor(libraryTypes, simpleClassName, orderedFields)); members.Add(GenerateCreateMethod(libraryTypes, type, orderedFields)); var classDeclaration = ClassDeclaration(simpleClassName) .AddBaseListTypes(SimpleBaseType(baseInterface)) .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword)) .AddAttributeLists(AttributeList(SingletonSeparatedList(Attribute(libraryTypes.RegisterActivatorAttribute.ToNameSyntax())))) .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax()))) .AddMembers(members.ToArray()); if (type.IsGenericType) { classDeclaration = SyntaxFactoryUtility.AddGenericTypeParameters(classDeclaration, type.TypeParameters); } return(classDeclaration); }
static ArgumentSyntax GetBaseInitializerArgument(IParameterSymbol parameter, int index) { var name = SyntaxFactoryUtility.GetSanitizedName(parameter, index); var result = Argument(IdentifierName(name)); switch (parameter.RefKind) { case RefKind.None: break; case RefKind.Ref: result = result.WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)); break; case RefKind.Out: result = result.WithRefOrOutKeyword(Token(SyntaxKind.OutKeyword)); break; default: break; } return(result); }
private static BlockSyntax CreateAsyncProxyMethodBody( LibraryTypes libraryTypes, MetadataModel metadataModel, MethodDescription methodDescription) { var statements = new List <StatementSyntax>(); var requestVar = IdentifierName("request"); var requestDescription = metadataModel.GeneratedInvokables[methodDescription]; var createRequestExpr = InvocationExpression(ThisExpression().Member("GetInvokable", requestDescription.TypeSyntax)) .WithArgumentList(ArgumentList(SeparatedList <ArgumentSyntax>())); statements.Add( LocalDeclarationStatement( VariableDeclaration( ParseTypeName("var"), SingletonSeparatedList( VariableDeclarator( Identifier("request")) .WithInitializer( EqualsValueClause(createRequestExpr)))))); // Set request object fields from method parameters. var parameterIndex = 0; foreach (var parameter in methodDescription.Method.Parameters) { statements.Add( ExpressionStatement( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, requestVar.Member($"arg{parameterIndex}"), IdentifierName(SyntaxFactoryUtility.GetSanitizedName(parameter, parameterIndex))))); parameterIndex++; } var invokeMethodName = "InvokeAsync"; foreach (var attr in methodDescription.Method.GetAttributes()) { if (attr.AttributeClass.GetAttributes(libraryTypes.InvokeMethodNameAttribute, out var attrs)) { foreach (var methodAttr in attrs) { invokeMethodName = (string)methodAttr.ConstructorArguments.First().Value; } } } ITypeSymbol resultType; var methodReturnType = (INamedTypeSymbol)methodDescription.Method.ReturnType; if (methodReturnType.TypeArguments.Length == 1) { // Task<T> / ValueTask<T> resultType = methodReturnType.TypeArguments[0]; } else if (SymbolEqualityComparer.Default.Equals(methodReturnType, libraryTypes.Void)) { // void resultType = libraryTypes.Object; } else { // Task / ValueTask resultType = libraryTypes.Object; } // C#: base.InvokeAsync<TReturn>(request); var invocationExpression = InvocationExpression( BaseExpression().Member(invokeMethodName, resultType.ToTypeSyntax(methodDescription.TypeParameterSubstitutions)), ArgumentList(SeparatedList(new[] { Argument(requestVar) }))); var rt = methodReturnType.ConstructedFrom; if (SymbolEqualityComparer.Default.Equals(rt, libraryTypes.Task_1) || SymbolEqualityComparer.Default.Equals(methodReturnType, libraryTypes.Task)) { // C#: return <invocation>.AsTask() statements.Add(ReturnStatement(InvocationExpression(invocationExpression.Member("AsTask"), ArgumentList()))); } else if (SymbolEqualityComparer.Default.Equals(rt, libraryTypes.ValueTask_1)) { // C#: return <invocation> statements.Add(ReturnStatement(invocationExpression)); } else if (SymbolEqualityComparer.Default.Equals(methodReturnType, libraryTypes.ValueTask)) { // C#: return new ValueTask(<invocation>) statements.Add(ReturnStatement(ObjectCreationExpression(libraryTypes.ValueTask.ToTypeSyntax()).WithArgumentList(ArgumentList(SeparatedList(new[] { Argument(InvocationExpression(invocationExpression.Member("AsTask"), ArgumentList())) }))))); } else { // C#: _ = <invocation> statements.Add(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, IdentifierName("_"), invocationExpression))); } return(Block(statements)); }
private static BlockSyntax CreateProxyMethodBody( LibraryTypes libraryTypes, MetadataModel metadataModel, MethodDescription methodDescription) { var statements = new List <StatementSyntax>(); var completionVar = IdentifierName("completion"); var requestVar = IdentifierName("request"); var requestDescription = metadataModel.GeneratedInvokables[methodDescription]; var createRequestExpr = InvocationExpression(libraryTypes.InvokablePool.ToTypeSyntax().Member("Get", requestDescription.TypeSyntax)) .WithArgumentList(ArgumentList(SeparatedList <ArgumentSyntax>())); statements.Add( LocalDeclarationStatement( VariableDeclaration( ParseTypeName("var"), SingletonSeparatedList( VariableDeclarator( Identifier("request")) .WithInitializer( EqualsValueClause(createRequestExpr)))))); // Set request object fields from method parameters. var parameterIndex = 0; foreach (var parameter in methodDescription.Method.Parameters) { statements.Add( ExpressionStatement( AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, requestVar.Member($"arg{parameterIndex}"), IdentifierName(SyntaxFactoryUtility.GetSanitizedName(parameter, parameterIndex))))); parameterIndex++; } ITypeSymbol returnType; var methodReturnType = (INamedTypeSymbol)methodDescription.Method.ReturnType; if (methodReturnType.TypeParameters.Length == 1) { returnType = methodReturnType.TypeArguments[0]; } else { returnType = libraryTypes.Object; } var createCompletionExpr = InvocationExpression(libraryTypes.ResponseCompletionSourcePool.ToTypeSyntax().Member("Get", returnType.ToTypeSyntax(methodDescription.TypeParameterSubstitutions))) .WithArgumentList(ArgumentList(SeparatedList <ArgumentSyntax>())); statements.Add( LocalDeclarationStatement( VariableDeclaration( ParseTypeName("var"), SingletonSeparatedList( VariableDeclarator( Identifier("completion")) .WithInitializer( EqualsValueClause(createCompletionExpr)))))); var sendRequestMethodName = "SendRequest"; foreach (var attr in methodDescription.Method.GetAttributes()) { if (attr.AttributeClass.GetAttributes(libraryTypes.InvokeMethodNameAttribute, out var attrs)) { foreach (var methodAttr in attrs) { sendRequestMethodName = (string)methodAttr.ConstructorArguments.First().Value; } } } // Issue request statements.Add( ExpressionStatement( InvocationExpression( BaseExpression().Member(sendRequestMethodName), ArgumentList(SeparatedList(new[] { Argument(completionVar), Argument(requestVar) }))))); // Return result string valueTaskMethodName; if (methodReturnType.TypeArguments.Length == 1) { valueTaskMethodName = "AsValueTask"; } else if (SymbolEqualityComparer.Default.Equals(methodReturnType, libraryTypes.Void)) { valueTaskMethodName = null; } else { valueTaskMethodName = "AsVoidValueTask"; } if (valueTaskMethodName is not null) { var returnVal = InvocationExpression(completionVar.Member(valueTaskMethodName)); if (SymbolEqualityComparer.Default.Equals(methodReturnType.ConstructedFrom, libraryTypes.Task_1) || SymbolEqualityComparer.Default.Equals(methodReturnType, libraryTypes.Task)) { returnVal = InvocationExpression(returnVal.Member("AsTask")); } statements.Add(ReturnStatement(returnVal)); } return(Block(statements)); }
public static ClassDeclarationSyntax GenerateCopier( LibraryTypes libraryTypes, ISerializableTypeDescription type) { var simpleClassName = GetSimpleClassName(type); var members = new List <ISerializableMember>(); foreach (var member in type.Members) { if (member is ISerializableMember serializable) { members.Add(serializable); } else if (member is IFieldDescription field) { members.Add(new SerializableMember(libraryTypes, type, field, members.Count)); } else if (member is MethodParameterFieldDescription methodParameter) { members.Add(new SerializableMethodMember(methodParameter)); } } var accessibility = type.Accessibility switch { Accessibility.Public => SyntaxKind.PublicKeyword, _ => SyntaxKind.InternalKeyword, }; var classDeclaration = ClassDeclaration(simpleClassName) .AddBaseListTypes(SimpleBaseType(libraryTypes.DeepCopier_1.ToTypeSyntax(type.TypeSyntax))) .AddModifiers(Token(accessibility), Token(SyntaxKind.SealedKeyword)) .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax()))); if (type.IsImmutable) { var copyMethod = GenerateImmutableTypeCopyMethod(type, libraryTypes); classDeclaration = classDeclaration.AddMembers(copyMethod); } else { var fieldDescriptions = GetFieldDescriptions(type, members, libraryTypes); var fieldDeclarations = GetFieldDeclarations(fieldDescriptions); var ctor = GenerateConstructor(libraryTypes, simpleClassName, fieldDescriptions); var copyMethod = GenerateMemberwiseDeepCopyMethod(type, fieldDescriptions, members, libraryTypes); classDeclaration = classDeclaration .AddMembers(copyMethod) .AddMembers(fieldDeclarations) .AddMembers(ctor); if (!type.IsSealedType) { classDeclaration = classDeclaration .AddMembers(GenerateBaseCopierDeepCopyMethod(type, fieldDescriptions, members, libraryTypes)) .AddBaseListTypes(SimpleBaseType(libraryTypes.BaseCopier_1.ToTypeSyntax(type.TypeSyntax))); } } if (type.IsGenericType) { classDeclaration = SyntaxFactoryUtility.AddGenericTypeParameters(classDeclaration, type.TypeParameters); } return(classDeclaration); }
public static (ClassDeclarationSyntax, GeneratedInvokerDescription) Generate( LibraryTypes libraryTypes, InvokableInterfaceDescription interfaceDescription, MethodDescription method) { var generatedClassName = GetSimpleClassName(interfaceDescription, method); INamedTypeSymbol baseClassType = GetBaseClassType(method); var fieldDescriptions = GetFieldDescriptions(method, interfaceDescription); var fields = GetFieldDeclarations(method, fieldDescriptions, libraryTypes); var(ctor, ctorArgs) = GenerateConstructor(libraryTypes, generatedClassName, method, fieldDescriptions, baseClassType); Accessibility accessibility = GetAccessibility(interfaceDescription); var targetField = fieldDescriptions.OfType <TargetFieldDescription>().Single(); var accessibilityKind = accessibility switch { Accessibility.Public => SyntaxKind.PublicKeyword, _ => SyntaxKind.InternalKeyword, }; var classDeclaration = ClassDeclaration(generatedClassName) .AddBaseListTypes(SimpleBaseType(baseClassType.ToTypeSyntax(method.TypeParameterSubstitutions))) .AddModifiers(Token(accessibilityKind), Token(SyntaxKind.SealedKeyword), Token(SyntaxKind.PartialKeyword)) .AddAttributeLists( AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax()))) .AddMembers(fields) .AddMembers(ctor) .AddMembers( GenerateGetArgumentCount(libraryTypes, method), GenerateGetMethodName(libraryTypes, method), GenerateGetInterfaceName(libraryTypes, method), GenerateGetInterfaceType(libraryTypes, method), GenerateGetInterfaceTypeArguments(libraryTypes, method), GenerateGetMethodTypeArguments(libraryTypes, method), GenerateGetParameterTypes(libraryTypes, method), GenerateGetMethod(libraryTypes), GenerateSetTargetMethod(libraryTypes, interfaceDescription, targetField), GenerateGetTargetMethod(targetField), GenerateDisposeMethod(libraryTypes, method, fieldDescriptions, baseClassType), GenerateGetArgumentMethod(libraryTypes, method, fieldDescriptions), GenerateSetArgumentMethod(libraryTypes, method, fieldDescriptions), GenerateInvokeInnerMethod(libraryTypes, method, fieldDescriptions, targetField)); var typeParametersWithNames = method.AllTypeParameters; if (typeParametersWithNames.Count > 0) { classDeclaration = SyntaxFactoryUtility.AddGenericTypeParameters(classDeclaration, typeParametersWithNames); } List <INamedTypeSymbol> serializationHooks = new(); if (baseClassType.GetAttributes(libraryTypes.SerializationCallbacksAttribute, out var hookAttributes)) { foreach (var hookAttribute in hookAttributes) { var hookType = (INamedTypeSymbol)hookAttribute.ConstructorArguments[0].Value; serializationHooks.Add(hookType); } } var invokerDescription = new GeneratedInvokerDescription( interfaceDescription, method, accessibility, generatedClassName, fieldDescriptions.OfType <IMemberDescription>().ToList(), serializationHooks, baseClassType, ctorArgs); return(classDeclaration, invokerDescription);