public void MethodIdsMatch()
        {
            var wellKnownTypes = new WellKnownTypes(this.compilation);

            foreach (var(type, typeSymbol) in GetTypeSymbolPairs(nameof(Grains)))
            {
                this.output.WriteLine($"Type: {RuntimeTypeNameFormatter.Format(type)}");

                var methods       = type.GetMethods();
                var methodSymbols = methods.Select(m => typeSymbol.GetMembers(m.Name).SingleOrDefault()).OfType <IMethodSymbol>();

                foreach (var(method, methodSymbol) in methods.Zip(methodSymbols, ValueTuple.Create))
                {
                    this.output.WriteLine($"IMethodSymbol: {methodSymbol}, MethodInfo: {method}");
                    Assert.NotNull(methodSymbol);

                    {
                        var expected = GrainInterfaceUtils.FormatMethodForIdComputation(method);
                        var actual   = OrleansLegacyCompat.FormatMethodForMethodIdComputation(methodSymbol);
                        this.output.WriteLine($"Expected format: {expected}\nActual format:   {actual}");
                        Assert.Equal(expected, actual);
                    }

                    {
                        var expected = GrainInterfaceUtils.ComputeMethodId(method);
                        var actual   = wellKnownTypes.GetMethodId(methodSymbol);
                        this.output.WriteLine($"Expected Id: 0x{expected:X}\nActual Id:   0x{actual:X}");
                        Assert.Equal(expected, actual);
                    }
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Generates switch cases for the provided grain type.
        /// </summary>
        /// <param name="types" />
        /// <param name="grainType" />
        /// <param name="methodIdArgument">
        /// The method id argument, which is used to select the correct switch label.
        /// </param>
        /// <param name="generateMethodHandler">
        /// The function used to generate switch block statements for each method.
        /// </param>
        /// <param name="composeInterfaceBlock">
        /// The function used to compose method switch blocks for each interface.
        /// </param>
        /// <returns>
        /// The switch cases for the provided grain type.
        /// </returns>
        public static SwitchSectionSyntax[] GenerateGrainInterfaceAndMethodSwitch(
            WellKnownTypes types,
            INamedTypeSymbol grainType,
            ExpressionSyntax methodIdArgument,
            Func <IMethodSymbol, StatementSyntax[]> generateMethodHandler,
            Func <INamedTypeSymbol, SwitchStatementSyntax, BlockSyntax> composeInterfaceBlock)
        {
            var interfaces = new List <INamedTypeSymbol> {
                grainType
            };

            interfaces.AddRange(grainType.AllInterfaces.Where(types.IsGrainInterface));

            // Switch on interface id.
            var interfaceCases = new List <SwitchSectionSyntax>();

            foreach (var type in interfaces)
            {
                var interfaceId = types.GetTypeId(type);
                var typeInterfaces = new[] { type }.Concat(type.AllInterfaces);

                var allMethods = new Dictionary <int, IMethodSymbol>();
                foreach (var typeInterface in typeInterfaces)
                {
                    foreach (var method in typeInterface.GetDeclaredInstanceMembers <IMethodSymbol>())
                    {
                        allMethods[types.GetMethodId(method)] = method;
                    }
                }

                var methodCases = new List <SwitchSectionSyntax>();

                // Switch on method id.
                foreach (var method in allMethods)
                {
                    // Generate the switch label for this method id.
                    var methodIdSwitchLabel = CaseSwitchLabel(method.Key.ToHexLiteral());

                    // Generate the switch body.
                    var methodInvokeStatement = generateMethodHandler(method.Value);

                    methodCases.Add(
                        SwitchSection().AddLabels(methodIdSwitchLabel).AddStatements(methodInvokeStatement));
                }

                // Generate the switch label for this interface id.
                var interfaceIdSwitchLabel = CaseSwitchLabel(interfaceId.ToHexLiteral());

                // Generate switch statements for the methods in this interface.
                var methodSwitchStatements = composeInterfaceBlock(type, SwitchStatement(methodIdArgument).AddSections(methodCases.ToArray()));

                // Generate the switch section for this interface.
                interfaceCases.Add(
                    SwitchSection().AddLabels(interfaceIdSwitchLabel).AddStatements(methodSwitchStatements));
            }

            return(interfaceCases.ToArray());
        }