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); } } }
/// <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()); }