Ejemplo n.º 1
0
        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));
        }
Ejemplo n.º 2
0
        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);
            }
        }
Ejemplo n.º 3
0
        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);
        }
Ejemplo n.º 4
0
            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);
            }
Ejemplo n.º 5
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));
        }
Ejemplo n.º 6
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));
        }
Ejemplo n.º 7
0
        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);
        }
Ejemplo n.º 8
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);