/// <summary>
        /// Generates the class for the provided grain types.
        /// </summary>
        internal TypeDeclarationSyntax GenerateClass(GrainInterfaceDescription description)
        {
            var generatedTypeName = description.ReferenceTypeName;
            var grainType         = description.Type;
            var genericTypes      = grainType.GetHierarchyTypeParameters()
                                    .Select(_ => TypeParameter(_.ToString()))
                                    .ToArray();

            // Create the special marker attribute.
            var grainTypeArgument = TypeOfExpression(grainType.WithoutTypeParameters().ToTypeSyntax());

            var attributes = AttributeList()
                             .AddAttributes(
                GeneratedCodeAttributeGenerator.GetGeneratedCodeAttributeSyntax(wellKnownTypes),
                Attribute(wellKnownTypes.SerializableAttribute.ToNameSyntax()),
                Attribute(wellKnownTypes.ExcludeFromCodeCoverageAttribute.ToNameSyntax()),
                Attribute(wellKnownTypes.GrainReferenceAttribute.ToNameSyntax())
                .AddArgumentListArguments(AttributeArgument(grainTypeArgument)));

            var classDeclaration =
                ClassDeclaration(generatedTypeName)
                .AddModifiers(Token(SyntaxKind.InternalKeyword))
                .AddBaseListTypes(
                    SimpleBaseType(wellKnownTypes.GrainReference.ToTypeSyntax()),
                    SimpleBaseType(grainType.ToTypeSyntax()))
                .AddConstraintClauses(grainType.GetTypeConstraintSyntax())
                .AddMembers(GenerateConstructors(generatedTypeName))
                .AddMembers(
                    GrainInterfaceCommon.GenerateInterfaceIdProperty(this.wellKnownTypes, description).AddModifiers(Token(SyntaxKind.OverrideKeyword)),
                    GrainInterfaceCommon.GenerateInterfaceVersionProperty(this.wellKnownTypes, description).AddModifiers(Token(SyntaxKind.OverrideKeyword)),
                    GenerateInterfaceNameProperty(description),
                    GenerateIsCompatibleMethod(description),
                    GenerateGetMethodNameMethod(description))
                .AddMembers(GenerateInvokeMethods(description))
                .AddAttributeLists(attributes);

            if (genericTypes.Length > 0)
            {
                classDeclaration = classDeclaration.AddTypeParameterListParameters(genericTypes);
            }

            if (this.options.DebuggerStepThrough)
            {
                var debuggerStepThroughAttribute = Attribute(this.wellKnownTypes.DebuggerStepThroughAttribute.ToNameSyntax());
                classDeclaration = classDeclaration.AddAttributeLists(AttributeList().AddAttributes(debuggerStepThroughAttribute));
            }

            return(classDeclaration);
        }
        /// <summary>
        /// Generates the class for the provided grain types.
        /// </summary>
        internal TypeDeclarationSyntax GenerateClass(GrainInterfaceDescription description)
        {
            var generatedTypeName = description.InvokerTypeName;
            var grainType         = description.Type;
            var baseTypes         = new List <BaseTypeSyntax> {
                SimpleBaseType(wellKnownTypes.IGrainMethodInvoker.ToTypeSyntax())
            };

            var genericTypes = grainType.GetHierarchyTypeParameters()
                               .Select(_ => TypeParameter(_.ToString()))
                               .ToArray();

            // Create the special method invoker marker attribute.
            var interfaceId         = description.InterfaceId;
            var interfaceIdArgument = interfaceId.ToHexLiteral();
            var grainTypeArgument   = TypeOfExpression(grainType.WithoutTypeParameters().ToTypeSyntax());
            var attributes          = new List <AttributeSyntax>
            {
                GeneratedCodeAttributeGenerator.GetGeneratedCodeAttributeSyntax(wellKnownTypes),
                Attribute(wellKnownTypes.MethodInvokerAttribute.ToNameSyntax())
                .AddArgumentListArguments(
                    AttributeArgument(grainTypeArgument),
                    AttributeArgument(interfaceIdArgument)),
                Attribute(wellKnownTypes.ExcludeFromCodeCoverageAttribute.ToNameSyntax())
            };

            var genericInvokerFields = GenerateGenericInvokerFields(wellKnownTypes, description.Methods);
            var members = new List <MemberDeclarationSyntax>(genericInvokerFields.Values.Select(x => x.Declaration))
            {
                GenerateInvokeMethod(wellKnownTypes, grainType, genericInvokerFields),
                GenerateInterfaceTypeProperty(wellKnownTypes, description, genericTypes),
                GenerateGetTargetMethod(wellKnownTypes, description)
            };

            // If this is an IGrainExtension, make the generated class implement IGrainExtensionMethodInvoker.
            if (grainType.HasInterface(wellKnownTypes.IGrainExtension))
            {
                baseTypes.Add(SimpleBaseType(wellKnownTypes.IGrainExtensionMethodInvoker.ToTypeSyntax()));
            }

            var classDeclaration =
                ClassDeclaration(generatedTypeName)
                .AddModifiers(Token(SyntaxKind.InternalKeyword))
                .AddBaseListTypes(baseTypes.ToArray())
                .AddConstraintClauses(grainType.GetTypeConstraintSyntax())
                .AddMembers(members.ToArray())
                .AddAttributeLists(AttributeList().AddAttributes(attributes.ToArray()));

            if (genericTypes.Length > 0)
            {
                classDeclaration = classDeclaration.AddTypeParameterListParameters(genericTypes);
            }

            if (this.options.DebuggerStepThrough)
            {
                var debuggerStepThroughAttribute = Attribute(this.wellKnownTypes.DebuggerStepThroughAttribute.ToNameSyntax());
                classDeclaration = classDeclaration.AddAttributeLists(AttributeList().AddAttributes(debuggerStepThroughAttribute));
            }

            return(classDeclaration);
        }
        private MethodDeclarationSyntax GenerateGetTargetMethod(WellKnownTypes wellKnownTypes, GrainInterfaceDescription description)
        {
            var method = wellKnownTypes.IGrainMethodInvoker.Method("GetTarget");
            var grainContextParameter = method.Parameters[0].Name.ToIdentifierName();

            ExpressionSyntax returnValue;

            if (description.Type.HasInterface(wellKnownTypes.IGrainExtension))
            {
                returnValue = InvocationExpression(grainContextParameter.Member("GetGrainExtension", description.Type), ArgumentList());
            }
            else
            {
                returnValue = grainContextParameter.Member("GrainInstance");
            }

            return
                (method.GetDeclarationSyntax()
                 .WithExpressionBody(ArrowExpressionClause(returnValue))
                 .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
        }
        private PropertyDeclarationSyntax GenerateInterfaceTypeProperty(WellKnownTypes wellKnownTypes, GrainInterfaceDescription description, TypeParameterSyntax[] genericTypes)
        {
            var property    = wellKnownTypes.IGrainMethodInvoker.Property("InterfaceType");
            var returnValue = TypeOfExpression(description.Type.ToTypeSyntax());

            return
                (PropertyDeclaration(wellKnownTypes.Type.ToTypeSyntax(), property.Name)
                 .WithExpressionBody(ArrowExpressionClause(returnValue))
                 .AddModifiers(Token(SyntaxKind.PublicKeyword))
                 .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
        }
        /// <summary>
        /// Generates invoker methods.
        /// </summary>
        private MemberDeclarationSyntax[] GenerateInvokeMethods(GrainInterfaceDescription description)
        {
            var baseReference = BaseExpression();
            var methods       = description.Methods;
            var members       = new List <MemberDeclarationSyntax>();

            foreach (var methodDescription in methods)
            {
                var method           = methodDescription.Method;
                var methodIdArgument = Argument(methodDescription.MethodId.ToHexLiteral());

                // Construct a new object array from all method arguments.
                var parameters = method.Parameters.Select((p, i) => (p, GetSanitizedName(p, i))).ToList <(IParameterSymbol Symbol, string Name)>();
                var body       = new List <StatementSyntax>();
                foreach (var parameter in parameters)
                {
                    if (parameter.Symbol.Type.HasInterface(wellKnownTypes.IGrainObserver))
                    {
                        body.Add(
                            ExpressionStatement(
                                InvocationExpression(wellKnownTypes.GrainFactoryBase.ToNameSyntax().Member("CheckGrainObserverParamInternal"))
                                .AddArgumentListArguments(Argument(parameter.Name.ToIdentifierName()))));
                    }
                }

                // Get the parameters argument value.
                var objectArrayType = wellKnownTypes.Object.ToTypeSyntax().GetArrayTypeSyntax();
                ExpressionSyntax args;
                if (method.IsGenericMethod)
                {
                    // Create an arguments array which includes the method's type parameters followed by the method's parameter list.
                    var allParameters = new List <ExpressionSyntax>();
                    foreach (var typeParameter in method.TypeParameters)
                    {
                        allParameters.Add(TypeOfExpression(typeParameter.ToTypeSyntax()));
                    }

                    allParameters.AddRange(parameters.Select(p => GetParameterForInvocation(p.Symbol, p.Name)));

                    args =
                        ArrayCreationExpression(objectArrayType)
                        .WithInitializer(
                            InitializerExpression(SyntaxKind.ArrayInitializerExpression)
                            .AddExpressions(allParameters.ToArray()));
                }
                else if (parameters.Count == 0)
                {
                    args = LiteralExpression(SyntaxKind.NullLiteralExpression);
                }
                else
                {
                    args =
                        ArrayCreationExpression(objectArrayType)
                        .WithInitializer(
                            InitializerExpression(SyntaxKind.ArrayInitializerExpression)
                            .AddExpressions(parameters.Select((p => GetParameterForInvocation(p.Symbol, p.Name))).ToArray()));
                }

                var options = GetInvokeOptions(method);

                // Construct the invocation call.
                bool asyncMethod;
                var  isOneWayTask = method.HasAttribute(wellKnownTypes.OneWayAttribute);
                if (method.ReturnsVoid || isOneWayTask)
                {
                    // One-way methods are never marked async.
                    asyncMethod = false;

                    var invocation = InvocationExpression(baseReference.Member("InvokeOneWayMethod"))
                                     .AddArgumentListArguments(methodIdArgument)
                                     .AddArgumentListArguments(Argument(args));

                    if (options != null)
                    {
                        invocation = invocation.AddArgumentListArguments(options);
                    }

                    body.Add(ExpressionStatement(invocation));

                    if (isOneWayTask)
                    {
                        if (!wellKnownTypes.Task.Equals(method.ReturnType))
                        {
                            throw new CodeGenerationException(
                                      $"Method {method} is marked with [{wellKnownTypes.OneWayAttribute.Name}], " +
                                      $"but has a return type which is not assignable from {typeof(Task)}");
                        }

                        var done = wellKnownTypes.Task.ToNameSyntax().Member((object _) => Task.CompletedTask);
                        body.Add(ReturnStatement(done));
                    }
                }
                else if (method.ReturnType is INamedTypeSymbol methodReturnType)
                {
                    // If the method doesn't return a Task type (eg, it returns ValueTask<T>), then we must make an async method and await the invocation result.
                    var isTaskMethod = wellKnownTypes.Task.Equals(methodReturnType) ||
                                       methodReturnType.IsGenericType && wellKnownTypes.Task_1.Equals(methodReturnType.ConstructedFrom);
                    asyncMethod = !isTaskMethod;

                    var returnType = methodReturnType.IsGenericType
                        ? methodReturnType.TypeArguments[0]
                        : wellKnownTypes.Object;
                    var invokeMethodAsync = "InvokeMethodAsync".ToGenericName().AddTypeArgumentListArguments(returnType.ToTypeSyntax());
                    var invocation        =
                        InvocationExpression(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                                    baseReference,
                                                                    invokeMethodAsync))
                        .AddArgumentListArguments(methodIdArgument)
                        .AddArgumentListArguments(Argument(args));

                    if (options != null)
                    {
                        invocation = invocation.AddArgumentListArguments(options);
                    }

                    var methodResult = asyncMethod ? AwaitExpression(invocation) : (ExpressionSyntax)invocation;
                    body.Add(ReturnStatement(methodResult));
                }
                else
                {
                    throw new NotSupportedException($"Method {method} has unsupported return type, {method.ReturnType}.");
                }

                var paramDeclaration  = method.Parameters.Select((p, i) => Parameter(GetSanitizedName(p, i).ToIdentifier()).WithType(p.Type.ToTypeSyntax()));
                var methodDeclaration = method.GetDeclarationSyntax()
                                        .WithParameterList(ParameterList().AddParameters(paramDeclaration.ToArray()))
                                        .WithModifiers(TokenList())
                                        .WithExplicitInterfaceSpecifier(ExplicitInterfaceSpecifier(method.ContainingType.ToNameSyntax()))
                                        .AddBodyStatements(body.ToArray())
                                        // Since explicit implementation is used, constraints must not be specified.
                                        .WithConstraintClauses(new SyntaxList <TypeParameterConstraintClauseSyntax>());

                if (asyncMethod)
                {
                    methodDeclaration = methodDeclaration.AddModifiers(Token(SyntaxKind.AsyncKeyword));
                }

                members.Add(methodDeclaration);
            }

            return(members.ToArray());

            ExpressionSyntax GetParameterForInvocation(IParameterSymbol arg, string name)
            {
                var identifier = name.ToIdentifierName();

                // Addressable arguments must be converted to references before passing.
                if (arg.Type.HasInterface(wellKnownTypes.IAddressable) &&
                    arg.Type.TypeKind == TypeKind.Interface)
                {
                    return
                        (ConditionalExpression(
                             BinaryExpression(SyntaxKind.IsExpression, identifier, wellKnownTypes.Grain.ToTypeSyntax()),
                             InvocationExpression(identifier.Member("AsReference".ToGenericName().AddTypeArgumentListArguments(arg.Type.ToTypeSyntax()))),
                             identifier));
                }

                return(identifier);
            }
        /// <summary>
        /// Generates invoker methods.
        /// </summary>
        private MemberDeclarationSyntax[] GenerateInvokeMethods(GrainInterfaceDescription description)
        {
            var baseReference = BaseExpression();
            var methods       = description.Methods;
            var members       = new List <MemberDeclarationSyntax>();

            foreach (var methodDescription in methods)
            {
                var method           = methodDescription.Method;
                var methodIdArgument = Argument(methodDescription.MethodId.ToHexLiteral());

                // Construct a new object array from all method arguments.
                var parameters = method.Parameters.Select((p, i) => (p, GetSanitizedName(p, i))).ToList <(IParameterSymbol Symbol, string Name)>();
                var body       = new List <StatementSyntax>();
                foreach (var parameter in parameters)
                {
                    if (parameter.Symbol.Type.HasInterface(wellKnownTypes.IGrainObserver))
                    {
                        body.Add(
                            ExpressionStatement(
                                InvocationExpression(wellKnownTypes.GrainFactoryBase.ToNameSyntax().Member("CheckGrainObserverParamInternal"))
                                .AddArgumentListArguments(Argument(parameter.Name.ToIdentifierName()))));
                    }
                }

                // Get the parameters argument value.
                var objectArrayType = wellKnownTypes.Object.ToTypeSyntax().GetArrayTypeSyntax();
                ExpressionSyntax args;
                if (method.IsGenericMethod)
                {
                    // Create an arguments array which includes the method's type parameters followed by the method's parameter list.
                    var allParameters = new List <ExpressionSyntax>();
                    foreach (var typeParameter in method.TypeParameters)
                    {
                        allParameters.Add(TypeOfExpression(typeParameter.ToTypeSyntax()));
                    }

                    allParameters.AddRange(parameters.Select(p => GetParameterForInvocation(p.Symbol, p.Name)));

                    args =
                        ArrayCreationExpression(objectArrayType)
                        .WithInitializer(
                            InitializerExpression(SyntaxKind.ArrayInitializerExpression)
                            .AddExpressions(allParameters.ToArray()));
                }
                else if (parameters.Count == 0)
                {
                    args = LiteralExpression(SyntaxKind.NullLiteralExpression);
                }
                else
                {
                    args =
                        ArrayCreationExpression(objectArrayType)
                        .WithInitializer(
                            InitializerExpression(SyntaxKind.ArrayInitializerExpression)
                            .AddExpressions(parameters.Select((p => GetParameterForInvocation(p.Symbol, p.Name))).ToArray()));
                }

                var options = GetInvokeOptions(method);

                // Construct the invocation call.
                bool asyncMethod;
                var  isOneWayTask = method.HasAttribute(wellKnownTypes.OneWayAttribute);
                if (method.ReturnsVoid || isOneWayTask)
                {
                    // One-way methods are never marked async.
                    asyncMethod = false;

                    var invocation = InvocationExpression(baseReference.Member("InvokeOneWayMethod"))
                                     .AddArgumentListArguments(methodIdArgument)
                                     .AddArgumentListArguments(Argument(args));

                    if (options != null)
                    {
                        invocation = invocation.AddArgumentListArguments(options);
                    }

                    body.Add(ExpressionStatement(invocation));

                    if (isOneWayTask)
                    {
                        if (!SymbolEqualityComparer.Default.Equals(wellKnownTypes.Task, method.ReturnType))
                        {
                            throw new CodeGenerationException(
                                      $"Method {method} is marked with [{wellKnownTypes.OneWayAttribute.Name}], " +
                                      $"but has a return type which is not assignable from {typeof(Task)}");
                        }

                        var done = wellKnownTypes.Task.ToNameSyntax().Member((object _) => Task.CompletedTask);
                        body.Add(ReturnStatement(done));
                    }
                }
                else if (method.ReturnType is INamedTypeSymbol methodReturnType)
                {
                    // If the method doesn't return a Task type (eg, it returns ValueTask<T>), then we must make an async method and await the invocation result.
                    var isTaskMethod = SymbolEqualityComparer.Default.Equals(wellKnownTypes.Task, methodReturnType) ||
                                       methodReturnType.IsGenericType && SymbolEqualityComparer.Default.Equals(wellKnownTypes.Task_1, methodReturnType.ConstructedFrom);
                    asyncMethod = !isTaskMethod;

                    var returnType = methodReturnType.IsGenericType
                        ? methodReturnType.TypeArguments[0]
                        : wellKnownTypes.Object;
                    var invokeMethodAsync = "InvokeMethodAsync".ToGenericName().AddTypeArgumentListArguments(returnType.ToTypeSyntax());
                    var invocation        =
                        InvocationExpression(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
                                                                    baseReference,
                                                                    invokeMethodAsync))
                        .AddArgumentListArguments(methodIdArgument)
                        .AddArgumentListArguments(Argument(args));

                    if (options != null)
                    {
                        invocation = invocation.AddArgumentListArguments(options);
                    }

                    var methodResult = asyncMethod ? AwaitExpression(invocation) : (ExpressionSyntax)invocation;

                    if (this.wellKnownTypes.ValueTask is WellKnownTypes.Some valueTask &&
                        SymbolEqualityComparer.Default.Equals(valueTask.Value, methodReturnType))
                    {
                        body.Add(ExpressionStatement(methodResult));
                    }
                    else
                    {
                        body.Add(ReturnStatement(methodResult));
                    }
                }
Ejemplo n.º 7
0
        public static PropertyDeclarationSyntax GenerateInterfaceIdProperty(WellKnownTypes wellKnownTypes, GrainInterfaceDescription description)
        {
            var property    = wellKnownTypes.GrainReference.Property("InterfaceTypeCode");
            var returnValue = description.InterfaceId.ToHexLiteral();

            return
                (PropertyDeclaration(wellKnownTypes.Int32.ToTypeSyntax(), property.Name)
                 .WithExpressionBody(ArrowExpressionClause(returnValue))
                 .AddModifiers(Token(SyntaxKind.PublicKeyword))
                 .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
        }
Ejemplo n.º 8
0
        public static PropertyDeclarationSyntax GenerateInterfaceVersionProperty(WellKnownTypes wellKnownTypes, GrainInterfaceDescription description)
        {
            var property    = wellKnownTypes.IGrainMethodInvoker.Property("InterfaceVersion");
            var returnValue = LiteralExpression(
                SyntaxKind.NumericLiteralExpression,
                Literal(description.InterfaceVersion));

            return
                (PropertyDeclaration(wellKnownTypes.UInt16.ToTypeSyntax(), property.Name)
                 .WithExpressionBody(ArrowExpressionClause(returnValue))
                 .AddModifiers(Token(SyntaxKind.PublicKeyword))
                 .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
        }
Ejemplo n.º 9
0
        private static MethodDeclarationSyntax GenerateGetMethodNameMethod(WellKnownTypes wellKnownTypes, GrainInterfaceDescription description)
        {
            var method            = wellKnownTypes.GrainReference.Method("GetMethodName");
            var methodDeclaration = method.GetDeclarationSyntax().AddModifiers(Token(SyntaxKind.OverrideKeyword));
            var parameters        = method.Parameters;

            var interfaceIdArgument = parameters[0].Name.ToIdentifierName();
            var methodIdArgument    = parameters[1].Name.ToIdentifierName();

            var callThrowMethodNotImplemented = InvocationExpression(IdentifierName("ThrowMethodNotImplemented"))
                                                .WithArgumentList(ArgumentList(SeparatedList(new[]
            {
                Argument(interfaceIdArgument),
                Argument(methodIdArgument)
            })));

            // This method is used directly after its declaration to create blocks for each interface id, comprising
            // primarily of a nested switch statement for each of the methods in the given interface.
            BlockSyntax ComposeInterfaceBlock(INamedTypeSymbol interfaceType, SwitchStatementSyntax methodSwitch)
            {
                return(Block(methodSwitch.AddSections(SwitchSection()
                                                      .AddLabels(DefaultSwitchLabel())
                                                      .AddStatements(
                                                          ExpressionStatement(callThrowMethodNotImplemented),
                                                          ReturnStatement(LiteralExpression(SyntaxKind.NullLiteralExpression))))));
            }

            var interfaceCases = GrainInterfaceCommon.GenerateGrainInterfaceAndMethodSwitch(
                wellKnownTypes,
                description.Type,
                methodIdArgument,
                methodType => new StatementSyntax[] { ReturnStatement(methodType.Name.ToLiteralExpression()) },
                ComposeInterfaceBlock);

            // Generate the default case, which will throw a NotImplementedException.
            var callThrowInterfaceNotImplemented = InvocationExpression(IdentifierName("ThrowInterfaceNotImplemented"))
                                                   .WithArgumentList(ArgumentList(SingletonSeparatedList(Argument(interfaceIdArgument))));
            var defaultCase = SwitchSection()
                              .AddLabels(DefaultSwitchLabel())
                              .AddStatements(
                ExpressionStatement(callThrowInterfaceNotImplemented),
                ReturnStatement(LiteralExpression(SyntaxKind.NullLiteralExpression)));

            var throwInterfaceNotImplemented = GrainInterfaceCommon.GenerateMethodNotImplementedFunction(wellKnownTypes);
            var throwMethodNotImplemented    = GrainInterfaceCommon.GenerateInterfaceNotImplementedFunction(wellKnownTypes);

            var interfaceIdSwitch =
                SwitchStatement(interfaceIdArgument).AddSections(interfaceCases.ToArray()).AddSections(defaultCase);

            return(methodDeclaration.AddBodyStatements(interfaceIdSwitch, throwInterfaceNotImplemented, throwMethodNotImplemented));
        }
Ejemplo n.º 10
0
        private static MemberDeclarationSyntax GenerateInterfaceNameProperty(WellKnownTypes wellKnownTypes, GrainInterfaceDescription description)
        {
            var returnValue = description.Type.Name.ToLiteralExpression();

            return
                (PropertyDeclaration(wellKnownTypes.String.ToTypeSyntax(), "InterfaceName")
                 .WithExpressionBody(ArrowExpressionClause(returnValue))
                 .AddModifiers(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword))
                 .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
        }
Ejemplo n.º 11
0
        private static MemberDeclarationSyntax GenerateIsCompatibleMethod(WellKnownTypes wellKnownTypes, GrainInterfaceDescription description)
        {
            var method = wellKnownTypes.GrainReference.Method("IsCompatible");
            var interfaceIdParameter = method.Parameters[0].Name.ToIdentifierName();

            var interfaceIds =
                new HashSet <int>(
                    new[] { description.InterfaceId }.Concat(
                        description.Type.AllInterfaces.Where(wellKnownTypes.IsGrainInterface).Select(wellKnownTypes.GetTypeId)));

            var returnValue = default(BinaryExpressionSyntax);

            foreach (var interfaceId in interfaceIds)
            {
                var check = BinaryExpression(
                    SyntaxKind.EqualsExpression,
                    interfaceIdParameter,
                    interfaceId.ToHexLiteral());

                // If this is the first check, assign it, otherwise OR this check with the previous checks.
                returnValue = returnValue == null
                                  ? check
                                  : BinaryExpression(SyntaxKind.LogicalOrExpression, returnValue, check);
            }

            return
                (method.GetDeclarationSyntax()
                 .AddModifiers(Token(SyntaxKind.OverrideKeyword))
                 .WithExpressionBody(ArrowExpressionClause(returnValue))
                 .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
        }