/// <summary> /// Generates the class for the provided grain types. /// </summary> internal static TypeDeclarationSyntax GenerateClass(WellKnownTypes wellKnownTypes, 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) { GenerateInvokeMethod(wellKnownTypes, grainType), GrainInterfaceCommon.GenerateInterfaceIdProperty(wellKnownTypes, description), GrainInterfaceCommon.GenerateInterfaceVersionProperty(wellKnownTypes, description) }; // If this is an IGrainExtension, make the generated class implement IGrainExtensionMethodInvoker. if (grainType.HasInterface(wellKnownTypes.IGrainExtension)) { baseTypes.Add(SimpleBaseType(wellKnownTypes.IGrainExtensionMethodInvoker.ToTypeSyntax())); members.Add(GenerateExtensionInvokeMethod(wellKnownTypes, grainType)); } 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); } return(classDeclaration); }
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)); }
/// <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 syntax for an invoke method. /// </summary> private MethodDeclarationSyntax GenerateInvokeMethod( WellKnownTypes wellKnownTypes, INamedTypeSymbol grainType, IMethodSymbol invokeMethod, Dictionary <IMethodSymbol, GenericInvokerField> genericInvokerFields) { var parameters = invokeMethod.Parameters; var grainArgument = parameters[0].Name.ToIdentifierName(); var requestArgument = parameters[1].Name.ToIdentifierName(); var interfaceIdProperty = wellKnownTypes.InvokeMethodRequest.Property("InterfaceTypeCode"); var methodIdProperty = wellKnownTypes.InvokeMethodRequest.Property("MethodId"); var argumentsProperty = wellKnownTypes.InvokeMethodRequest.Property("Arguments"); // Store the relevant values from the request in local variables. var interfaceIdDeclaration = LocalDeclarationStatement( VariableDeclaration(wellKnownTypes.Int32.ToTypeSyntax()) .AddVariables( VariableDeclarator("interfaceTypeCode") .WithInitializer(EqualsValueClause(requestArgument.Member(interfaceIdProperty.Name))))); var interfaceIdVariable = IdentifierName("interfaceTypeCode"); var methodIdDeclaration = LocalDeclarationStatement( VariableDeclaration(wellKnownTypes.Int32.ToTypeSyntax()) .AddVariables( VariableDeclarator("methodId") .WithInitializer(EqualsValueClause(requestArgument.Member(methodIdProperty.Name))))); var methodIdVariable = IdentifierName("methodId"); var argumentsDeclaration = LocalDeclarationStatement( VariableDeclaration(IdentifierName("var")) .AddVariables( VariableDeclarator("arguments") .WithInitializer(EqualsValueClause(requestArgument.Member(argumentsProperty.Name))))); var argumentsVariable = IdentifierName("arguments"); var methodDeclaration = invokeMethod.GetDeclarationSyntax() .AddModifiers(Token(SyntaxKind.AsyncKeyword)) .AddBodyStatements(interfaceIdDeclaration, methodIdDeclaration, argumentsDeclaration); var callThrowMethodNotImplemented = InvocationExpression(IdentifierName("ThrowMethodNotImplemented")) .WithArgumentList(ArgumentList(SeparatedList(new[] { Argument(interfaceIdVariable), Argument(methodIdVariable) }))); // 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) { ExpressionSyntax targetObject; if (grainType.HasInterface(wellKnownTypes.IGrainExtension)) { targetObject = InvocationExpression(grainArgument.Member("GetGrainExtension", interfaceType), ArgumentList()); } else { targetObject = grainArgument.Member("GrainInstance"); } var typedGrainDeclaration = LocalDeclarationStatement( VariableDeclaration(IdentifierName("var")) .AddVariables( VariableDeclarator("casted") .WithInitializer(EqualsValueClause(ParenthesizedExpression(CastExpression(interfaceType.ToTypeSyntax(), targetObject)))))); return(Block(typedGrainDeclaration, methodSwitch.AddSections(SwitchSection() .AddLabels(DefaultSwitchLabel()) .AddStatements( ExpressionStatement(callThrowMethodNotImplemented), ReturnStatement(LiteralExpression(SyntaxKind.NullLiteralExpression)))))); } var interfaceCases = GrainInterfaceCommon.GenerateGrainInterfaceAndMethodSwitch( wellKnownTypes, grainType, methodIdVariable, methodType => GenerateInvokeForMethod(wellKnownTypes, IdentifierName("casted"), methodType, argumentsVariable, genericInvokerFields), ComposeInterfaceBlock); var throwInterfaceNotImplemented = GrainInterfaceCommon.GenerateMethodNotImplementedFunction(wellKnownTypes); var throwMethodNotImplemented = GrainInterfaceCommon.GenerateInterfaceNotImplementedFunction(wellKnownTypes); // Generate the default case, which will call the above local function to throw . var callThrowInterfaceNotImplemented = InvocationExpression(IdentifierName("ThrowInterfaceNotImplemented")) .WithArgumentList(ArgumentList(SingletonSeparatedList(Argument(interfaceIdVariable)))); var defaultCase = SwitchSection() .AddLabels(DefaultSwitchLabel()) .AddStatements( ExpressionStatement(callThrowInterfaceNotImplemented), ReturnStatement(LiteralExpression(SyntaxKind.NullLiteralExpression))); var interfaceIdSwitch = SwitchStatement(interfaceIdVariable).AddSections(interfaceCases.ToArray()).AddSections(defaultCase); return(methodDeclaration.AddBodyStatements(interfaceIdSwitch, throwInterfaceNotImplemented, throwMethodNotImplemented)); }