Exemplo n.º 1
0
        public static (ClassDeclarationSyntax, IGeneratedProxyDescription) Generate(
            LibraryTypes libraryTypes,
            IInvokableInterfaceDescription interfaceDescription,
            MetadataModel metadataModel)
        {
            var generatedClassName = GetSimpleClassName(interfaceDescription.InterfaceType);

            var ctors        = GenerateConstructors(generatedClassName, interfaceDescription).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);

            if (interfaceDescription.InterfaceType.TypeParameters.Length > 0)
            {
                classDeclaration = AddGenericTypeConstraints(classDeclaration, interfaceDescription.InterfaceType);
            }

            return(classDeclaration, new GeneratedProxyDescription(interfaceDescription));
        }
Exemplo n.º 2
0
        private static MemberDeclarationSyntax GenerateSetTargetMethod(
            LibraryTypes libraryTypes,
            IInvokableInterfaceDescription interfaceDescription,
            TargetFieldDescription targetField)
        {
            var type            = IdentifierName("TTargetHolder");
            var typeToken       = Identifier("TTargetHolder");
            var holderParameter = Identifier("holder");
            var holder          = IdentifierName("holder");

            var getTarget = InvocationExpression(
                MemberAccessExpression(
                    SyntaxKind.SimpleMemberAccessExpression,
                    holder,
                    GenericName(interfaceDescription.IsExtension ? "GetExtension" : "GetTarget")
                    .WithTypeArgumentList(
                        TypeArgumentList(
                            SingletonSeparatedList(interfaceDescription.InterfaceType.ToTypeSyntax())))))
                            .WithArgumentList(ArgumentList());

            var body =
                AssignmentExpression(
                    SyntaxKind.SimpleAssignmentExpression,
                    ThisExpression().Member(targetField.FieldName),
                    getTarget);

            return(MethodDeclaration(libraryTypes.Void.ToTypeSyntax(), "SetTarget")
                   .WithTypeParameterList(TypeParameterList(SingletonSeparatedList(TypeParameter(typeToken))))
                   .WithParameterList(ParameterList(SingletonSeparatedList(Parameter(holderParameter).WithType(type))))
                   .WithExpressionBody(ArrowExpressionClause(body))
                   .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))
                   .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword))));
        }
Exemplo n.º 3
0
        private static BlockSyntax CreateProxyMethodBody(
            LibraryTypes libraryTypes,
            MetadataModel metadataModel,
            IInvokableInterfaceDescription interfaceDescription,
            MethodDescription methodDescription)
        {
            var statements = new List <StatementSyntax>();

            // Create request object
            var requestVar = IdentifierName("request");

            var requestDescription = metadataModel.GeneratedInvokables[methodDescription];
            var createRequestExpr  = ObjectCreationExpression(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(parameter.Name))));

                parameterIndex++;
            }

            // Issue request
            statements.Add(
                ExpressionStatement(
                    AwaitExpression(
                        InvocationExpression(
                            BaseExpression().Member("Invoke"),
                            ArgumentList(SingletonSeparatedList(Argument(requestVar)))))));

            // Return result
            if (methodDescription.Method.ReturnType is INamedTypeSymbol named && named.TypeParameters.Length == 1)
            {
                statements.Add(ReturnStatement(requestVar.Member("result")));
            }

            return(Block(statements));
        }
Exemplo n.º 4
0
        public static (ClassDeclarationSyntax, IGeneratedInvokerDescription) Generate(
            Compilation compilation,
            LibraryTypes libraryTypes,
            IInvokableInterfaceDescription interfaceDescription,
            MethodDescription methodDescription)
        {
            var method             = methodDescription.Method;
            var generatedClassName = GetSimpleClassName(method);

            var fieldDescriptions = GetFieldDescriptions(methodDescription.Method, interfaceDescription);
            var fields            = GetFieldDeclarations(fieldDescriptions, libraryTypes);
            var ctor = GenerateConstructor(generatedClassName, fieldDescriptions);

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

            var classDeclaration = ClassDeclaration(generatedClassName)
                                   .AddBaseListTypes(SimpleBaseType(libraryTypes.Invokable.ToTypeSyntax()))
                                   .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword))
                                   .AddAttributeLists(
                AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax())))
                                   .AddMembers(fields)
                                   .AddMembers(ctor)
                                   .AddMembers(
                GenerateGetArgumentCount(libraryTypes, methodDescription),
                GenerateSetTargetMethod(libraryTypes, interfaceDescription, targetField),
                GenerateGetTargetMethod(libraryTypes, targetField),
                GenerateResetMethod(libraryTypes, fieldDescriptions),
                GenerateGetArgumentMethod(libraryTypes, methodDescription, fieldDescriptions),
                GenerateSetArgumentMethod(libraryTypes, methodDescription, fieldDescriptions),
                GenerateInvokeMethod(libraryTypes, methodDescription, fieldDescriptions, targetField, resultField),
                GenerateSetResultProperty(libraryTypes, resultField),
                GenerateGetResultProperty(libraryTypes, resultField));

            var typeParameters = interfaceDescription.InterfaceType.TypeParameters.Select(tp => (tp, tp.Name))
                                 .Concat(method.TypeParameters.Select(tp => (tp, tp.Name)))
                                 .ToList();

            if (typeParameters.Count > 0)
            {
                classDeclaration = AddGenericTypeConstraints(classDeclaration, typeParameters);
            }

            return(classDeclaration,
                   new GeneratedInvokerDescription(
                       interfaceDescription,
                       methodDescription,
                       generatedClassName,
                       fieldDescriptions.OfType <IMemberDescription>().ToList()));
        }
Exemplo n.º 5
0
            public GeneratedInvokerDescription(
                IInvokableInterfaceDescription interfaceDescription,
                MethodDescription methodDescription,
                string generatedClassName,
                List <IMemberDescription> members)
            {
                this.InterfaceDescription = interfaceDescription;
                this.methodDescription    = methodDescription;
                this.Name    = generatedClassName;
                this.Members = members;

                this.TypeParameters = interfaceDescription.InterfaceType.TypeParameters
                                      .Concat(this.methodDescription.Method.TypeParameters)
                                      .ToImmutableArray();
            }
Exemplo n.º 6
0
        private static IEnumerable <MemberDeclarationSyntax> CreateProxyMethods(
            LibraryTypes libraryTypes,
            IInvokableInterfaceDescription 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(), method.Name)
                                  .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.AsyncKeyword))
                                  .AddParameterListParameters(method.Parameters.Select(GetParameterSyntax).ToArray())
                                  .WithBody(
                    CreateProxyMethodBody(libraryTypes, metadataModel, interfaceDescription, methodDescription));

                var typeParameters = GetTypeParametersWithConstraints(method.TypeParameters);

                foreach (var(name, constraints) in typeParameters)
                {
                    if (constraints.Count > 0)
                    {
                        declaration = declaration.AddConstraintClauses(
                            TypeParameterConstraintClause(name).AddConstraints(constraints.ToArray()));
                    }
                }

                if (typeParameters.Count > 0)
                {
                    declaration = declaration.WithTypeParameterList(
                        TypeParameterList(SeparatedList(typeParameters.Select(tp => TypeParameter(tp.Item1)))));
                }

                return(declaration);
            }
        }
Exemplo n.º 7
0
        private static IEnumerable <MemberDeclarationSyntax> GenerateConstructors(
            string simpleClassName,
            IInvokableInterfaceDescription interfaceDescription)
        {
            var baseType = interfaceDescription.ProxyBaseType;

            foreach (var member in baseType.GetMembers())
            {
                if (member is not IMethodSymbol method)
                {
                    continue;
                }

                if (method.MethodKind != MethodKind.Constructor)
                {
                    continue;
                }

                if (method.DeclaredAccessibility == Accessibility.Private)
                {
                    continue;
                }

                yield return(CreateConstructor(method));
            }

            ConstructorDeclarationSyntax CreateConstructor(IMethodSymbol baseConstructor)
            {
                return(ConstructorDeclaration(simpleClassName)
                       .AddParameterListParameters(baseConstructor.Parameters.Select(GetParameterSyntax).ToArray())
                       .WithModifiers(TokenList(GetModifiers(baseConstructor)))
                       .WithInitializer(
                           ConstructorInitializer(
                               SyntaxKind.BaseConstructorInitializer,
                               ArgumentList(
                                   SeparatedList(baseConstructor.Parameters.Select(GetBaseInitializerArgument)))))
                       .WithBody(Block()));
            }
Exemplo n.º 8
0
 public GeneratedProxyDescription(IInvokableInterfaceDescription interfaceDescription)
 {
     InterfaceDescription = interfaceDescription;
 }
Exemplo n.º 9
0
        public static (ClassDeclarationSyntax, IGeneratedInvokerDescription) Generate(
            Compilation compilation,
            LibraryTypes libraryTypes,
            IInvokableInterfaceDescription interfaceDescription,
            MethodDescription methodDescription)
        {
            var method             = methodDescription.Method;
            var generatedClassName = GetSimpleClassName(method);

            var fieldDescriptions = GetFieldDescriptions(methodDescription.Method, interfaceDescription);
            var fields            = GetFieldDeclarations(fieldDescriptions, libraryTypes);
            var ctor = GenerateConstructor(generatedClassName, fieldDescriptions);

            var targetField      = fieldDescriptions.OfType <TargetFieldDescription>().Single();
            var methodReturnType = (INamedTypeSymbol)method.ReturnType;

            ITypeSymbol baseClassType;

            if (methodReturnType.TypeArguments.Length == 1)
            {
                if (methodReturnType.ConstructedFrom.Equals(libraryTypes.ValueTask_1))
                {
                    baseClassType = libraryTypes.Request_1.Construct(methodReturnType.TypeArguments[0]);
                }
                else if (methodReturnType.ConstructedFrom.Equals(libraryTypes.Task_1))
                {
                    baseClassType = libraryTypes.TaskRequest_1.Construct(methodReturnType.TypeArguments[0]);
                }
                else
                {
                    throw new InvalidOperationException($"Unsupported return type {methodReturnType}. Constructed from: {methodReturnType.ConstructedFrom}");
                }
            }
            else
            {
                if (methodReturnType.Equals(libraryTypes.ValueTask))
                {
                    baseClassType = libraryTypes.Request;
                }
                else if (methodReturnType.Equals(libraryTypes.Task))
                {
                    baseClassType = libraryTypes.TaskRequest;
                }
                else
                {
                    throw new InvalidOperationException($"Unsupported return type {methodReturnType}");
                }
            }

            var classDeclaration = ClassDeclaration(generatedClassName)
                                   .AddBaseListTypes(SimpleBaseType(baseClassType.ToTypeSyntax()))
                                   .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword))
                                   .AddAttributeLists(
                AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax())))
                                   .AddMembers(fields)
                                   .AddMembers(ctor)
                                   .AddMembers(
                GenerateGetArgumentCount(libraryTypes, methodDescription),
                GenerateSetTargetMethod(libraryTypes, interfaceDescription, targetField),
                GenerateGetTargetMethod(libraryTypes, targetField),
                GenerateDisposeMethod(libraryTypes, fieldDescriptions),
                GenerateGetArgumentMethod(libraryTypes, methodDescription, fieldDescriptions),
                GenerateSetArgumentMethod(libraryTypes, methodDescription, fieldDescriptions),
                GenerateInvokeInnerMethod(libraryTypes, methodDescription, fieldDescriptions, targetField));

            var typeParameters = interfaceDescription.InterfaceType.TypeParameters.Select(tp => (tp, tp.Name))
                                 .Concat(method.TypeParameters.Select(tp => (tp, tp.Name)))
                                 .ToList();

            if (typeParameters.Count > 0)
            {
                classDeclaration = AddGenericTypeConstraints(classDeclaration, typeParameters);
            }

            return(classDeclaration,
                   new GeneratedInvokerDescription(
                       interfaceDescription,
                       methodDescription,
                       generatedClassName,
                       fieldDescriptions.OfType <IMemberDescription>().ToList()));
        }
Exemplo n.º 10
0
        private static IEnumerable <MemberDeclarationSyntax> GenerateConstructors(
            string simpleClassName,
            LibraryTypes libraryTypes,
            IInvokableInterfaceDescription interfaceDescription)
        {
            var baseType = interfaceDescription.ProxyBaseType;

            foreach (var member in baseType.GetMembers())
            {
                if (!(member is IMethodSymbol method))
                {
                    continue;
                }
                if (method.MethodKind != MethodKind.Constructor)
                {
                    continue;
                }
                if (method.DeclaredAccessibility == Accessibility.Private)
                {
                    continue;
                }
                yield return(CreateConstructor(method));
            }

            ConstructorDeclarationSyntax CreateConstructor(IMethodSymbol baseConstructor)
            {
                return(ConstructorDeclaration(simpleClassName)
                       .AddParameterListParameters(baseConstructor.Parameters.Select(GetParameterSyntax).ToArray())
                       .WithModifiers(TokenList(GetModifiers(baseConstructor)))
                       .WithInitializer(
                           ConstructorInitializer(
                               SyntaxKind.BaseConstructorInitializer,
                               ArgumentList(
                                   SeparatedList(baseConstructor.Parameters.Select(GetBaseInitializerArgument)))))
                       .WithBody(Block()));
            }

            IEnumerable <SyntaxToken> GetModifiers(IMethodSymbol method)
            {
                switch (method.DeclaredAccessibility)
                {
                case Accessibility.Public:
                case Accessibility.Protected:
                    yield return(Token(SyntaxKind.PublicKeyword));

                    break;

                case Accessibility.Internal:
                case Accessibility.ProtectedOrInternal:
                case Accessibility.ProtectedAndInternal:
                    yield return(Token(SyntaxKind.InternalKeyword));

                    break;

                default:
                    break;
                }
            }

            ArgumentSyntax GetBaseInitializerArgument(IParameterSymbol parameter)
            {
                var result = Argument(IdentifierName(parameter.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);
            }
        }
Exemplo n.º 11
0
        private static BlockSyntax CreateProxyMethodBody(
            LibraryTypes libraryTypes,
            MetadataModel metadataModel,
            IInvokableInterfaceDescription interfaceDescription,
            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(parameter.Name))));

                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()))
                                       .WithArgumentList(ArgumentList(SeparatedList <ArgumentSyntax>()));

            statements.Add(
                LocalDeclarationStatement(
                    VariableDeclaration(
                        ParseTypeName("var"),
                        SingletonSeparatedList(
                            VariableDeclarator(
                                Identifier("completion"))
                            .WithInitializer(
                                EqualsValueClause(createCompletionExpr))))));

            // Issue request
            statements.Add(
                ExpressionStatement(
                    InvocationExpression(
                        BaseExpression().Member("SendRequest"),
                        ArgumentList(SeparatedList(new[] { Argument(completionVar), Argument(requestVar) })))));

            // Return result
            string valueTaskMethodName;

            if (methodReturnType.TypeArguments.Length == 1)
            {
                valueTaskMethodName = "AsValueTask";
            }
            else
            {
                valueTaskMethodName = "AsVoidValueTask";
            }

            var returnVal = InvocationExpression(completionVar.Member(valueTaskMethodName));

            if (methodReturnType.ConstructedFrom.Equals(libraryTypes.Task_1) || methodReturnType.Equals(libraryTypes.Task))
            {
                returnVal = InvocationExpression(returnVal.Member("AsTask"));
            }

            statements.Add(ReturnStatement(returnVal));

            return(Block(statements));
        }