Example #1
0
        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;
        }
Example #2
0
        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));
        }
Example #3
0
        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));
        }
Example #4
0
        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);