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

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

                {
                    // First check Type.FullName matches.
                    var expected = type.FullName;
                    var actual   = RoslynTypeNameFormatter.Format(symbol, RoslynTypeNameFormatter.Style.FullName);
                    this.output.WriteLine($"Expected FullName: {expected}\nActual FullName:   {actual}");
                    Assert.Equal(expected, actual);
                }
                {
                    var expected = TypeUtils.GetTemplatedName(
                        TypeUtils.GetFullName(type),
                        type,
                        type.GetGenericArguments(),
                        t => false);
                    var named  = Assert.IsAssignableFrom <INamedTypeSymbol>(symbol);
                    var actual = OrleansLegacyCompat.FormatTypeForIdComputation(named);
                    this.output.WriteLine($"Expected format: {expected}\nActual format:   {actual}");
                    Assert.Equal(expected, actual);
                }
                {
                    var expected = GrainInterfaceUtils.GetGrainInterfaceId(type);
                    var named    = Assert.IsAssignableFrom <INamedTypeSymbol>(symbol);
                    var actual   = wellKnownTypes.GetTypeId(named);
                    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());
        }