public GeneratedInvokerDescription( InvokableInterfaceDescription interfaceDescription, MethodDescription methodDescription, Accessibility accessibility, string generatedClassName, List <IMemberDescription> members, List <INamedTypeSymbol> serializationHooks, INamedTypeSymbol baseType, List <TypeSyntax> constructorArguments) { InterfaceDescription = interfaceDescription; _methodDescription = methodDescription; BaseType = baseType; Name = generatedClassName; Members = members; Accessibility = accessibility; SerializationHooks = serializationHooks; ActivatorConstructorParameters = constructorArguments; }
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, 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);