Пример #1
0
            static bool TryGetActivatorConstructor(INamedTypeSymbol type, LibraryTypes libraryTypes, out List <TypeSyntax> parameters)
            {
                parameters = null;
                if (type.IsAbstract)
                {
                    return(false);
                }

                foreach (var constructor in type.GetAllMembers <IMethodSymbol>())
                {
                    if (constructor.MethodKind != MethodKind.Constructor || constructor.DeclaredAccessibility == Accessibility.Private || constructor.IsImplicitlyDeclared)
                    {
                        continue;
                    }

                    if (constructor.HasAttribute(libraryTypes.GeneratedActivatorConstructorAttribute))
                    {
                        foreach (var parameter in constructor.Parameters)
                        {
                            var argumentType = parameter.Type.ToTypeSyntax();
                            (parameters ??= new()).Add(argumentType);
                        }

                        break;
                    }
                }

                return(parameters is not null);
            }
Пример #2
0
        private static ConstructorDeclarationSyntax GenerateConstructor(
            LibraryTypes libraryTypes,
            string simpleClassName,
            List <ConstructorArgument> orderedFields)
        {
            var parameters = new List <ParameterSyntax>();
            var body       = new List <StatementSyntax>();

            foreach (var field in orderedFields)
            {
                parameters.Add(Parameter(field.ParameterName.ToIdentifier()).WithType(field.Type));

                body.Add(ExpressionStatement(
                             AssignmentExpression(
                                 SyntaxKind.SimpleAssignmentExpression,
                                 ThisExpression().Member(field.FieldName.ToIdentifierName()),
                                 Unwrapped(field.ParameterName.ToIdentifierName()))));
            }

            var constructorDeclaration = ConstructorDeclaration(simpleClassName)
                                         .AddModifiers(Token(SyntaxKind.PublicKeyword))
                                         .AddParameterListParameters(parameters.ToArray())
                                         .AddBodyStatements(body.ToArray());

            return(constructorDeclaration);
Пример #3
0
            private static IEnumerable <IMemberDescription> GetUnionCaseDataMembers(LibraryTypes libraryTypes, INamedTypeSymbol symbol)
            {
                List <IPropertySymbol> dataMembers = new();

                foreach (var property in symbol.GetDeclaredInstanceMembers <IPropertySymbol>())
                {
                    if (!property.Name.StartsWith("Item", System.StringComparison.Ordinal))
                    {
                        continue;
                    }

                    dataMembers.Add(property);
                }

                dataMembers.Sort(FSharpUnionCasePropertyNameComparer.Default);

                ushort id = 0;

                foreach (var field in dataMembers)
                {
                    yield return(new FSharpUnionCaseFieldDescription(libraryTypes, field, id));

                    id++;
                }
            }
Пример #4
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));
        }
Пример #5
0
        private static List <GeneratedFieldDescription> GetFieldDescriptions(
            InvokableInterfaceDescription interfaceDescription,
            MetadataModel metadataModel,
            LibraryTypes libraryTypes)
        {
            var fields = new List <GeneratedFieldDescription>();

            // Add a codec field for any method parameter which does not have a static codec.
            var allTypes = interfaceDescription.Methods
                           .Where(method => method.MethodTypeParameters.Count == 0)
                           .SelectMany(method => metadataModel.GeneratedInvokables[method].Members);

            fields.AddRange(GetCopierFieldDescriptions(allTypes, libraryTypes));
            return(fields);
        }
Пример #6
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);
            }
        }
Пример #7
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);
        }
Пример #8
0
        public static List <AttributeListSyntax> GenerateSyntax(LibraryTypes wellKnownTypes, MetadataModel model)
        {
            var attributes = new List <AttributeListSyntax>();

            foreach (var assemblyName in model.ApplicationParts)
            {
                // Generate an assembly-level attribute with an instance of that class.
                var attribute = AttributeList(
                    AttributeTargetSpecifier(Token(SyntaxKind.AssemblyKeyword)),
                    SingletonSeparatedList(
                        Attribute(wellKnownTypes.ApplicationPartAttribute.ToNameSyntax())
                        .AddArgumentListArguments(AttributeArgument(assemblyName.GetLiteralExpression()))));
                attributes.Add(attribute);
            }

            return(attributes);
        }
Пример #9
0
        public SerializableTypeDescription(SemanticModel semanticModel, INamedTypeSymbol type, IEnumerable <IMemberDescription> members, LibraryTypes libraryTypes)
        {
            Type          = type;
            Members       = members.ToList();
            SemanticModel = semanticModel;
            _libraryTypes = libraryTypes;

            var           t             = type;
            Accessibility accessibility = t.DeclaredAccessibility;

            while (t is not null)
            {
                if ((int)t.DeclaredAccessibility < (int)accessibility)
                {
                    accessibility = t.DeclaredAccessibility;
                }

                t = t.ContainingType;
            }

            Accessibility  = accessibility;
            TypeParameters = new();
            var names = new HashSet <string>(StringComparer.Ordinal);

            foreach (var tp in type.GetAllTypeParameters())
            {
                var tpName = GetTypeParameterName(names, tp);
                TypeParameters.Add((tpName, tp));
            }

            SerializationHooks = new();
            if (type.GetAttributes(libraryTypes.SerializationCallbacksAttribute, out var hookAttributes))
            {
                foreach (var hookAttribute in hookAttributes)
                {
                    var hookType = (INamedTypeSymbol)hookAttribute.ConstructorArguments[0].Value;
                    SerializationHooks.Add(hookType);
                }
            }

            if (TryGetActivatorConstructor(type, _libraryTypes, out var constructorParameters))
            {
                HasActivatorConstructor        = true;
                ActivatorConstructorParameters = constructorParameters;
            }
Пример #10
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 or IPropertyDescription)
                {
                    members.Add(new SerializableMember(libraryTypes, type, member, members.Count));
                }
Пример #11
0
        public static bool IsUnionCase(LibraryTypes libraryTypes, INamedTypeSymbol symbol, out INamedTypeSymbol sumType)
        {
            sumType = default;
            var compilationAttributeType = libraryTypes.FSharpCompilationMappingAttributeOrDefault;
            var sourceConstructFlagsType = libraryTypes.FSharpSourceConstructFlagsOrDefault;
            var baseType = symbol.BaseType;

            if (compilationAttributeType is null || sourceConstructFlagsType is null || baseType is null)
            {
                return(false);
            }

            if (!baseType.GetAttributes(compilationAttributeType, out var compilationAttributes) || compilationAttributes.Length == 0)
            {
                return(false);
            }

            var           compilationAttribute         = compilationAttributes[0];
            var           foundArg                     = false;
            TypedConstant sourceConstructFlagsArgument = default;

            foreach (var arg in compilationAttribute.ConstructorArguments)
            {
                if (SymbolEqualityComparer.Default.Equals(arg.Type, sourceConstructFlagsType))
                {
                    sourceConstructFlagsArgument = arg;
                    foundArg = true;
                    break;
                }
            }

            if (!foundArg)
            {
                return(false);
            }

            if ((int)sourceConstructFlagsArgument.Value != SourceConstructFlagsSumTypeValue)
            {
                return(false);
            }

            sumType = baseType;
            return(true);
        }
Пример #12
0
            private static IEnumerable <IMemberDescription> GetRecordDataMembers(LibraryTypes libraryTypes, INamedTypeSymbol symbol)
            {
                List <(IPropertySymbol, ushort)> dataMembers = new();

                foreach (var property in symbol.GetDeclaredInstanceMembers <IPropertySymbol>())
                {
                    var id = CodeGenerator.GetId(libraryTypes, property);
                    if (!id.HasValue)
                    {
                        continue;
                    }

                    dataMembers.Add((property, id.Value));
                }

                foreach (var(property, id) in dataMembers)
                {
                    yield return(new FSharpRecordPropertyDescription(libraryTypes, property, id));
                }
            }
Пример #13
0
 public FSharpRecordPropertyDescription(LibraryTypes libraryTypes, IPropertySymbol property, ushort ordinal)
 {
     _libraryTypes = libraryTypes;
     FieldId       = ordinal;
     _property     = property;
 }
Пример #14
0
 public FSharpRecordTypeDescription(SemanticModel semanticModel, INamedTypeSymbol type, LibraryTypes libraryTypes) : base(semanticModel, type, GetRecordDataMembers(libraryTypes, type), libraryTypes)
 {
 }
Пример #15
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));
        }
Пример #16
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);
Пример #17
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);
        }
Пример #18
0
        public static ClassDeclarationSyntax GenerateMetadata(Compilation compilation, MetadataModel metadataModel, LibraryTypes libraryTypes)
        {
            var configParam         = "config".ToIdentifierName();
            var addSerializerMethod = configParam.Member("Serializers").Member("Add");
            var addCopierMethod     = configParam.Member("Copiers").Member("Add");
            var body = new List <StatementSyntax>();

            body.AddRange(
                metadataModel.SerializableTypes.Select(
                    type =>
                    (StatementSyntax)ExpressionStatement(
                        InvocationExpression(
                            addSerializerMethod,
                            ArgumentList(
                                SingletonSeparatedList(
                                    Argument(TypeOfExpression(GetCodecTypeName(type)))))))
                    ));
            body.AddRange(
                metadataModel.SerializableTypes.Select(
                    type =>
                    (StatementSyntax)ExpressionStatement(
                        InvocationExpression(
                            addCopierMethod,
                            ArgumentList(
                                SingletonSeparatedList(
                                    Argument(TypeOfExpression(GetCopierTypeName(type)))))))
                    ));
            body.AddRange(
                metadataModel.DetectedCopiers.Select(
                    type =>
                    (StatementSyntax)ExpressionStatement(
                        InvocationExpression(
                            addCopierMethod,
                            ArgumentList(
                                SingletonSeparatedList(
                                    Argument(TypeOfExpression(type.ToOpenTypeSyntax()))))))
                    ));
            body.AddRange(
                metadataModel.DetectedSerializers.Select(
                    type =>
                    (StatementSyntax)ExpressionStatement(
                        InvocationExpression(
                            addSerializerMethod,
                            ArgumentList(
                                SingletonSeparatedList(
                                    Argument(TypeOfExpression(type.ToOpenTypeSyntax()))))))
                    ));
            var addProxyMethod = configParam.Member("InterfaceProxies").Member("Add");

            body.AddRange(
                metadataModel.GeneratedProxies.Select(
                    type =>
                    (StatementSyntax)ExpressionStatement(
                        InvocationExpression(
                            addProxyMethod,
                            ArgumentList(
                                SingletonSeparatedList(
                                    Argument(TypeOfExpression(type.TypeSyntax))))))
                    ));
            var addInvokableInterfaceMethod = configParam.Member("Interfaces").Member("Add");

            body.AddRange(
                metadataModel.InvokableInterfaces.Select(
                    type =>
                    (StatementSyntax)ExpressionStatement(
                        InvocationExpression(
                            addInvokableInterfaceMethod,
                            ArgumentList(
                                SingletonSeparatedList(
                                    Argument(TypeOfExpression(type.InterfaceType.ToOpenTypeSyntax()))))))
                    ));
            var addInvokableInterfaceImplementationMethod = configParam.Member("InterfaceImplementations").Member("Add");

            body.AddRange(
                metadataModel.InvokableInterfaceImplementations.Select(
                    type =>
                    (StatementSyntax)ExpressionStatement(
                        InvocationExpression(
                            addInvokableInterfaceImplementationMethod,
                            ArgumentList(
                                SingletonSeparatedList(
                                    Argument(TypeOfExpression(type.ToOpenTypeSyntax()))))))
                    ));

            var addActivatorMethod = configParam.Member("Activators").Member("Add");

            body.AddRange(
                metadataModel.ActivatableTypes.Select(
                    type =>
                    (StatementSyntax)ExpressionStatement(
                        InvocationExpression(
                            addActivatorMethod,
                            ArgumentList(
                                SingletonSeparatedList(
                                    Argument(TypeOfExpression(GetActivatorTypeName(type)))))))
                    ));
            body.AddRange(
                metadataModel.DetectedActivators.Select(
                    type =>
                    (StatementSyntax)ExpressionStatement(
                        InvocationExpression(
                            addActivatorMethod,
                            ArgumentList(
                                SingletonSeparatedList(
                                    Argument(TypeOfExpression(type.ToOpenTypeSyntax()))))))
                    ));

            var addWellKnownTypeIdMethod = configParam.Member("WellKnownTypeIds").Member("Add");

            body.AddRange(
                metadataModel.WellKnownTypeIds.Select(
                    type =>
                    (StatementSyntax)ExpressionStatement(
                        InvocationExpression(
                            addWellKnownTypeIdMethod,
                            ArgumentList(SeparatedList(
                                             new[]
            {
                Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(type.Id))),
                Argument(TypeOfExpression(type.Type))
            }))))
                    ));

            var addTypeAliasMethod = configParam.Member("WellKnownTypeAliases").Member("Add");

            body.AddRange(
                metadataModel.TypeAliases.Select(
                    type =>
                    (StatementSyntax)ExpressionStatement(
                        InvocationExpression(
                            addTypeAliasMethod,
                            ArgumentList(SeparatedList(
                                             new[]
            {
                Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(type.Alias))),
                Argument(TypeOfExpression(type.Type))
            }))))
                    ));

            var configType      = libraryTypes.TypeManifestOptions;
            var configureMethod = MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), "Configure")
                                  .AddModifiers(Token(SyntaxKind.PublicKeyword))
                                  .AddParameterListParameters(
                Parameter(configParam.Identifier).WithType(configType.ToTypeSyntax()))
                                  .AddBodyStatements(body.ToArray());

            var interfaceType = libraryTypes.ITypeManifestProvider;

            return(ClassDeclaration("Metadata_" + SyntaxGeneration.Identifier.SanitizeIdentifierName(compilation.AssemblyName))
                   .AddBaseListTypes(SimpleBaseType(interfaceType.ToTypeSyntax()))
                   .AddModifiers(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.SealedKeyword))
                   .AddAttributeLists(AttributeList(SingletonSeparatedList(CodeGenerator.GetGeneratedCodeAttributeSyntax())))
                   .AddMembers(configureMethod));
        }
Пример #19
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));
        }