private static MemberDeclarationSyntax GenerateConstructor(string className, List <FieldInfoMember> fields) { var body = new List <StatementSyntax>(); Expression <Action <Type> > getField = _ => _.GetField(string.Empty, BindingFlags.Default); Expression <Action <IFieldUtils> > getGetter = _ => _.GetGetter(default(FieldInfo)); Expression <Action <IFieldUtils> > getReferenceSetter = _ => _.GetReferenceSetter(default(FieldInfo)); Expression <Action <IFieldUtils> > getValueSetter = _ => _.GetValueSetter(default(FieldInfo)); // Expressions for specifying binding flags. var bindingFlags = SyntaxFactoryExtensions.GetBindingFlagsParenthesizedExpressionSyntax( SyntaxKind.BitwiseOrExpression, BindingFlags.Instance, BindingFlags.NonPublic, BindingFlags.Public); var fieldUtils = SF.IdentifierName("fieldUtils"); foreach (var field in fields) { // Get the field var fieldInfoField = SF.IdentifierName(field.InfoFieldName); var fieldInfo = getField.Invoke(SF.TypeOfExpression(field.FieldInfo.DeclaringType.GetTypeSyntax())) .AddArgumentListArguments( SF.Argument(field.FieldInfo.Name.GetLiteralExpression()), SF.Argument(bindingFlags)); var fieldInfoVariable = SF.VariableDeclarator(field.InfoFieldName).WithInitializer(SF.EqualsValueClause(fieldInfo)); if (!field.IsGettableProperty || !field.IsSettableProperty) { body.Add(SF.LocalDeclarationStatement( SF.VariableDeclaration(typeof(FieldInfo).GetTypeSyntax()).AddVariables(fieldInfoVariable))); } // Set the getter/setter of the field if (!field.IsGettableProperty) { var getterType = typeof(Func <,>).MakeGenericType(field.FieldInfo.DeclaringType, field.FieldInfo.FieldType) .GetTypeSyntax(); var getterInvoke = SF.CastExpression( getterType, getGetter.Invoke(fieldUtils).AddArgumentListArguments(SF.Argument(fieldInfoField))); body.Add(SF.ExpressionStatement( SF.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SF.IdentifierName(field.GetterFieldName), getterInvoke))); } if (!field.IsSettableProperty) { if (field.FieldInfo.DeclaringType != null && field.FieldInfo.DeclaringType.IsValueType) { var setterType = typeof(ValueTypeSetter <,>).MakeGenericType( field.FieldInfo.DeclaringType, field.FieldInfo.FieldType).GetTypeSyntax(); var getValueSetterInvoke = SF.CastExpression( setterType, getValueSetter.Invoke(fieldUtils) .AddArgumentListArguments(SF.Argument(fieldInfoField))); body.Add(SF.ExpressionStatement( SF.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SF.IdentifierName(field.SetterFieldName), getValueSetterInvoke))); } else { var setterType = typeof(Action <,>).MakeGenericType(field.FieldInfo.DeclaringType, field.FieldInfo.FieldType) .GetTypeSyntax(); var getReferenceSetterInvoke = SF.CastExpression( setterType, getReferenceSetter.Invoke(fieldUtils) .AddArgumentListArguments(SF.Argument(fieldInfoField))); body.Add(SF.ExpressionStatement( SF.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, SF.IdentifierName(field.SetterFieldName), getReferenceSetterInvoke))); } } } return (SF.ConstructorDeclaration(className) .AddModifiers(SF.Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters( SF.Parameter(fieldUtils.Identifier).WithType(typeof(IFieldUtils).GetTypeSyntax())) .AddBodyStatements(body.ToArray())); }
/// <summary> /// Generates syntax to invoke a method on a grain. /// </summary> /// <param name="grainType"> /// The grain type. /// </param> /// <param name="grain"> /// The grain instance expression. /// </param> /// <param name="method"> /// The method. /// </param> /// <param name="arguments"> /// The arguments expression. /// </param> /// <returns> /// Syntax to invoke a method on a grain. /// </returns> private static StatementSyntax[] GenerateInvokeForMethod( Type grainType, IdentifierNameSyntax grain, MethodInfo method, ExpressionSyntax arguments) { var castGrain = SF.ParenthesizedExpression(SF.CastExpression(grainType.GetTypeSyntax(), grain)); // Construct expressions to retrieve each of the method's parameters. var parameters = new List <ExpressionSyntax>(); var methodParameters = method.GetParameters().ToList(); for (var i = 0; i < methodParameters.Count; i++) { var parameter = methodParameters[i]; var parameterType = parameter.ParameterType.GetTypeSyntax(); var indexArg = SF.Argument(SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(i))); var arg = SF.CastExpression( parameterType, SF.ElementAccessExpression(arguments).AddArgumentListArguments(indexArg)); parameters.Add(arg); } // If the method is a generic method definition, use the generic method invoker field to invoke the method. if (method.IsGenericMethodDefinition) { var invokerFieldName = GetGenericMethodInvokerFieldName(method); var invokerCall = SF.InvocationExpression( SF.IdentifierName(invokerFieldName) .Member((GenericMethodInvoker invoker) => invoker.Invoke(null, null))) .AddArgumentListArguments(SF.Argument(grain), SF.Argument(arguments)); return(new StatementSyntax[] { SF.ReturnStatement(SF.AwaitExpression(invokerCall)) }); } // Invoke the method. var grainMethodCall = SF.InvocationExpression(castGrain.Member(method.Name)) .AddArgumentListArguments(parameters.Select(SF.Argument).ToArray()); // For void methods, invoke the method and return null. if (method.ReturnType == typeof(void)) { return(new StatementSyntax[] { SF.ExpressionStatement(grainMethodCall), SF.ReturnStatement(SF.LiteralExpression(SyntaxKind.NullLiteralExpression)) }); } // For methods which return non-generic Task, await the method and return null. if (method.ReturnType == typeof(Task)) { return(new StatementSyntax[] { SF.ExpressionStatement(SF.AwaitExpression(grainMethodCall)), SF.ReturnStatement(SF.LiteralExpression(SyntaxKind.NullLiteralExpression)) }); } return(new StatementSyntax[] { SF.ReturnStatement(SF.AwaitExpression(grainMethodCall)) }); }
/// <summary> /// Generates invoker methods. /// </summary> /// <param name="grainType">The grain type.</param> /// <param name="onEncounteredType"> /// The callback which is invoked when a type is encountered. /// </param> /// <returns>Invoker methods for the provided grain type.</returns> private static MemberDeclarationSyntax[] GenerateInvokeMethods(Type grainType, Action <Type> onEncounteredType) { var baseReference = SF.BaseExpression(); var methods = GrainInterfaceUtils.GetMethods(grainType); var members = new List <MemberDeclarationSyntax>(); foreach (var method in methods) { onEncounteredType(method.ReturnType); var methodId = GrainInterfaceUtils.ComputeMethodId(method); var methodIdArgument = SF.Argument(SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(methodId))); // Construct a new object array from all method arguments. var parameters = method.GetParameters(); var body = new List <StatementSyntax>(); foreach (var parameter in parameters) { onEncounteredType(parameter.ParameterType); if (typeof(IGrainObserver).IsAssignableFrom(parameter.ParameterType)) { body.Add( SF.ExpressionStatement( CheckGrainObserverParamInternalExpression.Invoke() .AddArgumentListArguments(SF.Argument(parameter.Name.ToIdentifierName())))); } } // Get the parameters argument value. ExpressionSyntax args; if (parameters.Length == 0) { args = SF.LiteralExpression(SyntaxKind.NullLiteralExpression); } else { args = SF.ArrayCreationExpression(typeof(object).GetArrayTypeSyntax()) .WithInitializer( SF.InitializerExpression(SyntaxKind.ArrayInitializerExpression) .AddExpressions(parameters.Select(GetParameterForInvocation).ToArray())); } var options = GetInvokeOptions(method); // Construct the invocation call. if (method.ReturnType == typeof(void)) { var invocation = SF.InvocationExpression(baseReference.Member("InvokeOneWayMethod")) .AddArgumentListArguments(methodIdArgument) .AddArgumentListArguments(SF.Argument(args)); if (options != null) { invocation = invocation.AddArgumentListArguments(options); } body.Add(SF.ExpressionStatement(invocation)); } else { var returnType = method.ReturnType == typeof(Task) ? typeof(object) : method.ReturnType.GenericTypeArguments[0]; var invocation = SF.InvocationExpression(baseReference.Member("InvokeMethodAsync", returnType)) .AddArgumentListArguments(methodIdArgument) .AddArgumentListArguments(SF.Argument(args)); if (options != null) { invocation = invocation.AddArgumentListArguments(options); } body.Add(SF.ReturnStatement(invocation)); } members.Add(method.GetDeclarationSyntax().AddBodyStatements(body.ToArray())); } return(members.ToArray()); }
public ExpressionSyntax GetFullExpressionForVbObjectComparison(VBSyntax.BinaryExpressionSyntax node, ExpressionSyntax lhs, ExpressionSyntax rhs) { _extraUsingDirectives.Add("Microsoft.VisualBasic.CompilerServices"); var optionCompareTextCaseInsensitive = SyntaxFactory.Argument(SyntaxFactory.LiteralExpression(OptionCompareTextCaseInsensitive ? SyntaxKind.TrueKeyword : SyntaxKind.FalseLiteralExpression)); var compareObject = SyntaxFactory.InvocationExpression(ValidSyntaxFactory.MemberAccess(nameof(Operators), nameof(Operators.ConditionalCompareObjectEqual)), SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.Argument(lhs), SyntaxFactory.Argument(rhs), optionCompareTextCaseInsensitive }))); return(NegateIfNeeded(node, compareObject)); }
/// <summary> /// Generates syntax for an invoke method. /// </summary> /// <param name="grainType"> /// The grain type. /// </param> /// <param name="invokeMethod"> /// The invoke method to generate. /// </param> /// <returns> /// Syntax for an invoke method. /// </returns> private static MethodDeclarationSyntax GenerateInvokeMethod(Type grainType, MethodInfo invokeMethod) { var parameters = invokeMethod.GetParameters(); var grainArgument = parameters[0].Name.ToIdentifierName(); var requestArgument = parameters[1].Name.ToIdentifierName(); // Store the relevant values from the request in local variables. var interfaceIdDeclaration = SF.LocalDeclarationStatement( SF.VariableDeclaration(typeof(int).GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("interfaceId") .WithInitializer(SF.EqualsValueClause(requestArgument.Member((InvokeMethodRequest _) => _.InterfaceId))))); var interfaceIdVariable = SF.IdentifierName("interfaceId"); var methodIdDeclaration = SF.LocalDeclarationStatement( SF.VariableDeclaration(typeof(int).GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("methodId") .WithInitializer(SF.EqualsValueClause(requestArgument.Member((InvokeMethodRequest _) => _.MethodId))))); var methodIdVariable = SF.IdentifierName("methodId"); var argumentsDeclaration = SF.LocalDeclarationStatement( SF.VariableDeclaration(typeof(object[]).GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("arguments") .WithInitializer(SF.EqualsValueClause(requestArgument.Member((InvokeMethodRequest _) => _.Arguments))))); var argumentsVariable = SF.IdentifierName("arguments"); var methodDeclaration = invokeMethod.GetDeclarationSyntax() .AddModifiers(SF.Token(SyntaxKind.AsyncKeyword)) .AddBodyStatements(interfaceIdDeclaration, methodIdDeclaration, argumentsDeclaration); var interfaceCases = CodeGeneratorCommon.GenerateGrainInterfaceAndMethodSwitch( grainType, methodIdVariable, methodType => GenerateInvokeForMethod(grainType, grainArgument, methodType, argumentsVariable)); // Generate the default case, which will throw a NotImplementedException. var errorMessage = SF.BinaryExpression( SyntaxKind.AddExpression, "interfaceId=".GetLiteralExpression(), interfaceIdVariable); var throwStatement = SF.ThrowStatement( SF.ObjectCreationExpression(typeof(NotImplementedException).GetTypeSyntax()) .AddArgumentListArguments(SF.Argument(errorMessage))); var defaultCase = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(throwStatement); var interfaceIdSwitch = SF.SwitchStatement(interfaceIdVariable).AddSections(interfaceCases.ToArray()).AddSections(defaultCase); // If the provided grain is null, throw an argument exception. var argumentNullException = SF.ObjectCreationExpression(typeof(ArgumentNullException).GetTypeSyntax()) .AddArgumentListArguments(SF.Argument(parameters[0].Name.GetLiteralExpression())); var grainArgumentCheck = SF.IfStatement( SF.BinaryExpression( SyntaxKind.EqualsExpression, grainArgument, SF.LiteralExpression(SyntaxKind.NullLiteralExpression)), SF.ThrowStatement(argumentNullException)); return(methodDeclaration.AddBodyStatements(grainArgumentCheck, interfaceIdSwitch)); }
/// <summary> /// Generates switch cases for the provided grain type. /// </summary> /// <param name="grainType"> /// The grain type. /// </param> /// <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> /// <returns> /// The switch cases for the provided grain type. /// </returns> public static SwitchSectionSyntax[] GenerateGrainInterfaceAndMethodSwitch( Type grainType, ExpressionSyntax methodIdArgument, Func <MethodInfo, StatementSyntax[]> generateMethodHandler) { var interfaces = GrainInterfaceUtils.GetRemoteInterfaces(grainType); interfaces[GrainInterfaceUtils.GetGrainInterfaceId(grainType)] = grainType; // Switch on interface id. var interfaceCases = new List <SwitchSectionSyntax>(); foreach (var @interface in interfaces) { var interfaceType = @interface.Value; var interfaceId = @interface.Key; var methods = GrainInterfaceUtils.GetMethods(interfaceType); var methodCases = new List <SwitchSectionSyntax>(); // Switch on method id. foreach (var method in methods) { // Generate switch case. var methodId = GrainInterfaceUtils.ComputeMethodId(method); var methodType = method; // Generate the switch label for this interface id. var methodIdSwitchLabel = SF.CaseSwitchLabel( SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(methodId))); // Generate the switch body. var methodInvokeStatement = generateMethodHandler(methodType); methodCases.Add( SF.SwitchSection().AddLabels(methodIdSwitchLabel).AddStatements(methodInvokeStatement)); } // Generate the switch label for this interface id. var interfaceIdSwitchLabel = SF.CaseSwitchLabel( SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId))); // Generate the default case, which will throw a NotImplementedException. var errorMessage = SF.BinaryExpression( SyntaxKind.AddExpression, "interfaceId=".GetLiteralExpression(), SF.BinaryExpression( SyntaxKind.AddExpression, SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(interfaceId)), SF.BinaryExpression( SyntaxKind.AddExpression, ",methodId=".GetLiteralExpression(), methodIdArgument))); var throwStatement = SF.ThrowStatement( SF.ObjectCreationExpression(typeof(NotImplementedException).GetTypeSyntax()) .AddArgumentListArguments(SF.Argument(errorMessage))); var defaultCase = SF.SwitchSection().AddLabels(SF.DefaultSwitchLabel()).AddStatements(throwStatement); // Generate switch statements for the methods in this interface. var methodSwitchStatements = SF.SwitchStatement(methodIdArgument).AddSections(methodCases.ToArray()).AddSections(defaultCase); // Generate the switch section for this interface. interfaceCases.Add( SF.SwitchSection().AddLabels(interfaceIdSwitchLabel).AddStatements(methodSwitchStatements)); } return(interfaceCases.ToArray()); }
private static MemberDeclarationSyntax GenerateDeepCopierMethod(Type type, List <FieldInfoMember> fields) { var originalVariable = SF.IdentifierName("original"); var inputVariable = SF.IdentifierName("input"); var resultVariable = SF.IdentifierName("result"); var boxedResultVariable = resultVariable; var body = new List <StatementSyntax>(); if (type.GetCustomAttribute <ImmutableAttribute>() != null) { // Immutable types do not require copying. body.Add(SF.ReturnStatement(originalVariable)); } else { body.Add( SF.LocalDeclarationStatement( SF.VariableDeclaration(type.GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("input") .WithInitializer( SF.EqualsValueClause( SF.ParenthesizedExpression( SF.CastExpression(type.GetTypeSyntax(), originalVariable))))))); body.Add( SF.LocalDeclarationStatement( SF.VariableDeclaration(type.GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("result") .WithInitializer(SF.EqualsValueClause(GetObjectCreationExpressionSyntax(type)))))); if (type.IsValueType) { // For value types, we need to box the result for reflection-based setters to work. body.Add(SF.LocalDeclarationStatement( SF.VariableDeclaration(typeof(object).GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("boxedResult").WithInitializer(SF.EqualsValueClause(resultVariable))))); boxedResultVariable = SF.IdentifierName("boxedResult"); } // Record this serialization. Expression <Action> recordObject = () => SerializationContext.Current.RecordObject(default(object), default(object)); var currentSerializationContext = SyntaxFactory.AliasQualifiedName( SF.IdentifierName(SF.Token(SyntaxKind.GlobalKeyword)), SF.IdentifierName("Orleans")) .Qualify("Serialization") .Qualify("SerializationContext") .Qualify("Current"); body.Add( SF.ExpressionStatement( recordObject.Invoke(currentSerializationContext) .AddArgumentListArguments(SF.Argument(originalVariable), SF.Argument(boxedResultVariable)))); // Copy all members from the input to the result. foreach (var field in fields) { body.Add(SF.ExpressionStatement(field.GetSetter(boxedResultVariable, field.GetGetter(inputVariable)))); } body.Add(SF.ReturnStatement(boxedResultVariable)); } return (SF.MethodDeclaration(typeof(object).GetTypeSyntax(), "DeepCopier") .AddModifiers(SF.Token(SyntaxKind.PublicKeyword), SF.Token(SyntaxKind.StaticKeyword)) .AddParameterListParameters( SF.Parameter(SF.Identifier("original")).WithType(typeof(object).GetTypeSyntax())) .AddBodyStatements(body.ToArray()) .AddAttributeLists( SF.AttributeList().AddAttributes(SF.Attribute(typeof(CopierMethodAttribute).GetNameSyntax())))); }
public static InvocationExpressionSyntax OptionalGetValueOrDefault(ExpressionSyntax optionalOfTExpression, ExpressionSyntax defaultValue) { return(SF.InvocationExpression( SF.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, optionalOfTExpression, SF.IdentifierName(nameof(Option <int> .ValueOr))), SF.ArgumentList(SF.SingletonSeparatedList(SF.Argument(defaultValue))))); }
/// <summary> /// Generates syntax to invoke a method on a grain. /// </summary> /// <param name="grainType"> /// The grain type. /// </param> /// <param name="grain"> /// The grain instance expression. /// </param> /// <param name="method"> /// The method. /// </param> /// <param name="arguments"> /// The arguments expression. /// </param> /// <returns> /// Syntax to invoke a method on a grain. /// </returns> private static StatementSyntax[] GenerateInvokeForMethod( Type grainType, IdentifierNameSyntax grain, MethodInfo method, ExpressionSyntax arguments) { var castGrain = SF.ParenthesizedExpression(SF.CastExpression(grainType.GetTypeSyntax(), grain)); // Construct expressions to retrieve each of the method's parameters. var parameters = new List <ExpressionSyntax>(); var methodParameters = method.GetParameters().ToList(); for (var i = 0; i < methodParameters.Count; i++) { var parameter = methodParameters[i]; var parameterType = parameter.ParameterType.GetTypeSyntax(); var indexArg = SF.Argument(SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(i))); var arg = SF.CastExpression( parameterType, SF.ElementAccessExpression(arguments).AddArgumentListArguments(indexArg)); parameters.Add(arg); } // If the method is a generic method definition, use the generic method invoker field to invoke the method. if (method.IsGenericMethodDefinition) { var invokerFieldName = GetGenericMethodInvokerFieldName(method); var invokerCall = SF.InvocationExpression( SF.IdentifierName(invokerFieldName) .Member((GenericMethodInvoker invoker) => invoker.Invoke(null, null))) .AddArgumentListArguments(SF.Argument(grain), SF.Argument(arguments)); return(new StatementSyntax[] { SF.ReturnStatement(SF.AwaitExpression(invokerCall)) }); } // Invoke the method. var grainMethodCall = SF.InvocationExpression(castGrain.Member(method.Name)) .AddArgumentListArguments(parameters.Select(SF.Argument).ToArray()); // For void methods, invoke the method and return null. if (method.ReturnType == typeof(void)) { return(new StatementSyntax[] { SF.ExpressionStatement(grainMethodCall), SF.ReturnStatement(SF.LiteralExpression(SyntaxKind.NullLiteralExpression)) }); } // For methods which return non-generic Task, await the method and return null. if (method.ReturnType == typeof(Task)) { return(new StatementSyntax[] { SF.ExpressionStatement(SF.AwaitExpression(grainMethodCall)), SF.ReturnStatement(SF.LiteralExpression(SyntaxKind.NullLiteralExpression)) }); } if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition().FullName == "System.Threading.Tasks.ValueTask`1") { var convertToTaskResult = SF.IdentifierName("AsTask"); // Converting ValueTask method result to Task since "Invoke" method should return Task. // Temporary solution. Need to change when Orleans will be using ValueTask instead of Task. grainMethodCall = SF.InvocationExpression( SF.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SF.ExpressionStatement(grainMethodCall).Expression, convertToTaskResult)); } return(new StatementSyntax[] { SF.ReturnStatement(SF.AwaitExpression(grainMethodCall)) }); }
public ExpressionSyntax AddExplicitConvertTo(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, ITypeSymbol type) { var displayType = type.ToMinimalDisplayString(_semanticModel, vbNode.SpanStart); if (csNode is InvocationExpressionSyntax invoke && invoke.Expression is MemberAccessExpressionSyntax expr && expr.Expression is IdentifierNameSyntax name && name.Identifier.ValueText == "Conversions" && expr.Name.Identifier.ValueText == $"To{displayType}") { return(csNode); } var method = typeof(Conversions).GetMethod($"To{displayType}"); if (method == null) { throw new NotImplementedException($"Unimplemented conversion for {displayType}"); } // Need to use Conversions rather than Convert to match what VB does, eg. True -> -1 _extraUsingDirectives.Add("Microsoft.VisualBasic.CompilerServices"); var memberAccess = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName("Conversions"), SyntaxFactory.IdentifierName($"To{displayType}")); var arguments = SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(csNode))); return(SyntaxFactory.InvocationExpression(memberAccess, arguments)); }
/// <summary> /// Generates invoker methods. /// </summary> /// <param name="grainType">The grain type.</param> /// <param name="onEncounteredType"> /// The callback which is invoked when a type is encountered. /// </param> /// <returns>Invoker methods for the provided grain type.</returns> private static MemberDeclarationSyntax[] GenerateInvokeMethods(Type grainType, Action <Type> onEncounteredType) { var baseReference = SF.BaseExpression(); var methods = GrainInterfaceUtils.GetMethods(grainType); var members = new List <MemberDeclarationSyntax>(); foreach (var method in methods) { onEncounteredType(method.ReturnType); var methodId = GrainInterfaceUtils.ComputeMethodId(method); var methodIdArgument = SF.Argument(SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(methodId))); // Construct a new object array from all method arguments. var parameters = method.GetParameters(); var body = new List <StatementSyntax>(); foreach (var parameter in parameters) { onEncounteredType(parameter.ParameterType); if (typeof(IGrainObserver).GetTypeInfo().IsAssignableFrom(parameter.ParameterType)) { body.Add( SF.ExpressionStatement( CheckGrainObserverParamInternalExpression.Invoke() .AddArgumentListArguments(SF.Argument(parameter.Name.ToIdentifierName())))); } } // Get the parameters argument value. ExpressionSyntax args; if (method.IsGenericMethodDefinition) { // 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.GetGenericArguments()) { allParameters.Add(SF.TypeOfExpression(typeParameter.GetTypeSyntax())); } allParameters.AddRange(parameters.Select(GetParameterForInvocation)); args = SF.ArrayCreationExpression(typeof(object).GetArrayTypeSyntax()) .WithInitializer( SF.InitializerExpression(SyntaxKind.ArrayInitializerExpression) .AddExpressions(allParameters.ToArray())); } else if (parameters.Length == 0) { args = SF.LiteralExpression(SyntaxKind.NullLiteralExpression); } else { args = SF.ArrayCreationExpression(typeof(object).GetArrayTypeSyntax()) .WithInitializer( SF.InitializerExpression(SyntaxKind.ArrayInitializerExpression) .AddExpressions(parameters.Select(GetParameterForInvocation).ToArray())); } var options = GetInvokeOptions(method); // Construct the invocation call. var isOneWayTask = method.GetCustomAttribute <OneWayAttribute>() != null; if (method.ReturnType == typeof(void) || isOneWayTask) { var invocation = SF.InvocationExpression(baseReference.Member("InvokeOneWayMethod")) .AddArgumentListArguments(methodIdArgument) .AddArgumentListArguments(SF.Argument(args)); if (options != null) { invocation = invocation.AddArgumentListArguments(options); } body.Add(SF.ExpressionStatement(invocation)); if (isOneWayTask) { if (method.ReturnType != typeof(Task)) { throw new CodeGenerationException( $"Method {grainType.GetParseableName()}.{method.Name} is marked with [{nameof(OneWayAttribute)}], " + $"but has a return type which is not assignable from {typeof(Task)}"); } var done = typeof(Task).GetNameSyntax(true).Member((object _) => Task.CompletedTask); body.Add(SF.ReturnStatement(done)); } } else { var returnType = method.ReturnType == typeof(Task) ? typeof(object) : method.ReturnType.GenericTypeArguments[0]; var invocation = SF.InvocationExpression(baseReference.Member("InvokeMethodAsync", returnType)) .AddArgumentListArguments(methodIdArgument) .AddArgumentListArguments(SF.Argument(args)); if (options != null) { invocation = invocation.AddArgumentListArguments(options); } body.Add(SF.ReturnStatement(invocation)); } members.Add(method.GetDeclarationSyntax().AddBodyStatements(body.ToArray())); } return(members.ToArray()); }
/// <summary> /// Returns syntax for the static fields of the serializer class. /// </summary> /// <param name="fields">The fields.</param> /// <returns>Syntax for the static fields of the serializer class.</returns> private static MemberDeclarationSyntax[] GenerateStaticFields(List <FieldInfoMember> fields) { var result = new List <MemberDeclarationSyntax>(); // ReSharper disable once ReturnValueOfPureMethodIsNotUsed Expression <Action <TypeInfo> > getField = _ => _.GetField(string.Empty, BindingFlags.Default); Expression <Action <Type> > getTypeInfo = _ => _.GetTypeInfo(); Expression <Action> getGetter = () => FieldUtils.GetGetter(default(FieldInfo)); Expression <Action> getReferenceSetter = () => FieldUtils.GetReferenceSetter(default(FieldInfo)); Expression <Action> getValueSetter = () => FieldUtils.GetValueSetter(default(FieldInfo)); // Expressions for specifying binding flags. var bindingFlags = SyntaxFactoryExtensions.GetBindingFlagsParenthesizedExpressionSyntax( SyntaxKind.BitwiseOrExpression, BindingFlags.Instance, BindingFlags.NonPublic, BindingFlags.Public); // Add each field and initialize it. foreach (var field in fields) { var fieldInfo = getField.Invoke(getTypeInfo.Invoke(SF.TypeOfExpression(field.FieldInfo.DeclaringType.GetTypeSyntax()))) .AddArgumentListArguments( SF.Argument(field.FieldInfo.Name.GetLiteralExpression()), SF.Argument(bindingFlags)); var fieldInfoVariable = SF.VariableDeclarator(field.InfoFieldName).WithInitializer(SF.EqualsValueClause(fieldInfo)); var fieldInfoField = SF.IdentifierName(field.InfoFieldName); if (!field.IsGettableProperty || !field.IsSettableProperty) { result.Add( SF.FieldDeclaration( SF.VariableDeclaration(typeof(FieldInfo).GetTypeSyntax()).AddVariables(fieldInfoVariable)) .AddModifiers( SF.Token(SyntaxKind.PrivateKeyword), SF.Token(SyntaxKind.StaticKeyword), SF.Token(SyntaxKind.ReadOnlyKeyword))); } // Declare the getter for this field. if (!field.IsGettableProperty) { var getterType = typeof(Func <,>).MakeGenericType(field.FieldInfo.DeclaringType, field.FieldInfo.FieldType) .GetTypeSyntax(); var fieldGetterVariable = SF.VariableDeclarator(field.GetterFieldName) .WithInitializer( SF.EqualsValueClause( SF.CastExpression( getterType, getGetter.Invoke().AddArgumentListArguments(SF.Argument(fieldInfoField))))); result.Add( SF.FieldDeclaration(SF.VariableDeclaration(getterType).AddVariables(fieldGetterVariable)) .AddModifiers( SF.Token(SyntaxKind.PrivateKeyword), SF.Token(SyntaxKind.StaticKeyword), SF.Token(SyntaxKind.ReadOnlyKeyword))); } if (!field.IsSettableProperty) { if (field.FieldInfo.DeclaringType != null && field.FieldInfo.DeclaringType.GetTypeInfo().IsValueType) { var setterType = typeof(ValueTypeSetter <,>).MakeGenericType( field.FieldInfo.DeclaringType, field.FieldInfo.FieldType).GetTypeSyntax(); var fieldSetterVariable = SF.VariableDeclarator(field.SetterFieldName) .WithInitializer( SF.EqualsValueClause( SF.CastExpression( setterType, getValueSetter.Invoke() .AddArgumentListArguments(SF.Argument(fieldInfoField))))); result.Add( SF.FieldDeclaration(SF.VariableDeclaration(setterType).AddVariables(fieldSetterVariable)) .AddModifiers( SF.Token(SyntaxKind.PrivateKeyword), SF.Token(SyntaxKind.StaticKeyword), SF.Token(SyntaxKind.ReadOnlyKeyword))); } else { var setterType = typeof(Action <,>).MakeGenericType(field.FieldInfo.DeclaringType, field.FieldInfo.FieldType) .GetTypeSyntax(); var fieldSetterVariable = SF.VariableDeclarator(field.SetterFieldName) .WithInitializer( SF.EqualsValueClause( SF.CastExpression( setterType, getReferenceSetter.Invoke() .AddArgumentListArguments(SF.Argument(fieldInfoField))))); result.Add( SF.FieldDeclaration(SF.VariableDeclaration(setterType).AddVariables(fieldSetterVariable)) .AddModifiers( SF.Token(SyntaxKind.PrivateKeyword), SF.Token(SyntaxKind.StaticKeyword), SF.Token(SyntaxKind.ReadOnlyKeyword))); } } } return(result.ToArray()); }
public ExpressionSyntax GetSetter(ExpressionSyntax instance, ExpressionSyntax value, ExpressionSyntax boxedInstance = null) { Expression <Action> fieldSetter = () => this.FieldInfo.SetValue(default(object), default(object)); // If the field is the backing field for an auto-property, try to use the property directly. var propertyName = Regex.Match(this.FieldInfo.Name, "^<([^>]+)>.*$"); if (propertyName.Success && this.FieldInfo.DeclaringType != null) { var name = propertyName.Groups[1].Value; var property = this.FieldInfo.DeclaringType.GetProperty(name, BindingFlags.Instance | BindingFlags.Public); if (property != null && property.GetSetMethod() != null) { return(SF.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, instance.Member(property.Name), value)); } } return(fieldSetter.Invoke(this.FieldInfoExpression) .AddArgumentListArguments(SF.Argument(boxedInstance ?? instance), SF.Argument(value))); }
public ExpressionSyntax GetGetter(ExpressionSyntax instance, bool forceAvoidCopy = false) { Expression <Action> fieldGetter = () => this.FieldInfo.GetValue(default(object)); var getFieldExpression = fieldGetter.Invoke(this.FieldInfoExpression).AddArgumentListArguments(SF.Argument(instance)); // If the field is the backing field for an auto-property, try to use the property directly. var propertyName = Regex.Match(this.FieldInfo.Name, "^<([^>]+)>.*$"); if (propertyName.Success && this.FieldInfo.DeclaringType != null) { var name = propertyName.Groups[1].Value; var property = this.FieldInfo.DeclaringType.GetProperty(name, BindingFlags.Instance | BindingFlags.Public); if (property != null && property.GetGetMethod() != null) { return(instance.Member(property.Name)); } } if (forceAvoidCopy || this.FieldInfo.FieldType.IsOrleansShallowCopyable()) { // Shallow-copy the field. return(getFieldExpression); } // Deep-copy the field. Expression <Action> deepCopyInner = () => SerializationManager.DeepCopyInner(default(object)); return(SF.CastExpression( this.FieldInfo.FieldType.GetTypeSyntax(), deepCopyInner.Invoke().AddArgumentListArguments(SF.Argument(getFieldExpression)))); }
/// <summary> /// Returns syntax for the deserializer method. /// </summary> /// <param name="type">The type.</param> /// <param name="fields">The fields.</param> /// <returns>Syntax for the deserializer method.</returns> private static MemberDeclarationSyntax GenerateDeserializerMethod(Type type, List <FieldInfoMember> fields) { Expression <Action <IDeserializationContext> > deserializeInner = ctx => ctx.DeserializeInner(default(Type)); var contextParameter = SF.IdentifierName("context"); var resultDeclaration = SF.LocalDeclarationStatement( SF.VariableDeclaration(type.GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("result") .WithInitializer(SF.EqualsValueClause(GetObjectCreationExpressionSyntax(type))))); var resultVariable = SF.IdentifierName("result"); var body = new List <StatementSyntax> { resultDeclaration }; // Value types cannot be referenced, only copied, so there is no need to box & record instances of value types. if (!type.IsValueType) { // Record the result for cyclic deserialization. Expression <Action <IDeserializationContext> > recordObject = ctx => ctx.RecordObject(default(object)); var currentSerializationContext = contextParameter; body.Add( SF.ExpressionStatement( recordObject.Invoke(currentSerializationContext) .AddArgumentListArguments(SF.Argument(resultVariable)))); } // Deserialize all fields. foreach (var field in fields) { var deserialized = deserializeInner.Invoke(contextParameter) .AddArgumentListArguments( SF.Argument(SF.TypeOfExpression(field.Type))); body.Add( SF.ExpressionStatement( field.GetSetter( resultVariable, SF.CastExpression(field.Type, deserialized)))); } // If the type implements the internal IOnDeserialized lifecycle method, invoke it's method now. if (typeof(IOnDeserialized).IsAssignableFrom(type)) { Expression <Action <IOnDeserialized> > onDeserializedMethod = _ => _.OnDeserialized(default(ISerializerContext)); // C#: ((IOnDeserialized)result).OnDeserialized(context); var typedResult = SF.ParenthesizedExpression(SF.CastExpression(typeof(IOnDeserialized).GetTypeSyntax(), resultVariable)); var invokeOnDeserialized = onDeserializedMethod.Invoke(typedResult).AddArgumentListArguments(SF.Argument(contextParameter)); body.Add(SF.ExpressionStatement(invokeOnDeserialized)); } body.Add(SF.ReturnStatement(SF.CastExpression(type.GetTypeSyntax(), resultVariable))); return (SF.MethodDeclaration(typeof(object).GetTypeSyntax(), "Deserializer") .AddModifiers(SF.Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters( SF.Parameter(SF.Identifier("expected")).WithType(typeof(Type).GetTypeSyntax()), SF.Parameter(SF.Identifier("context")).WithType(typeof(IDeserializationContext).GetTypeSyntax())) .AddBodyStatements(body.ToArray()) .AddAttributeLists( SF.AttributeList() .AddAttributes(SF.Attribute(typeof(DeserializerMethodAttribute).GetNameSyntax())))); }
/// <summary> /// Generates syntax to invoke a method on a grain. /// </summary> /// <param name="grainType"> /// The grain type. /// </param> /// <param name="grain"> /// The grain instance expression. /// </param> /// <param name="method"> /// The method. /// </param> /// <param name="arguments"> /// The arguments expression. /// </param> /// <returns> /// Syntax to invoke a method on a grain. /// </returns> private static StatementSyntax[] GenerateInvokeForMethod( Type grainType, IdentifierNameSyntax grain, MethodInfo method, ExpressionSyntax arguments) { var castGrain = SF.ParenthesizedExpression(SF.CastExpression(grainType.GetTypeSyntax(), grain)); // Construct expressions to retrieve each of the method's parameters. var parameters = new List <ExpressionSyntax>(); var methodParameters = method.GetParameters().ToList(); for (var i = 0; i < methodParameters.Count; i++) { var parameter = methodParameters[i]; var parameterType = parameter.ParameterType.GetTypeSyntax(); var indexArg = SF.Argument(SF.LiteralExpression(SyntaxKind.NumericLiteralExpression, SF.Literal(i))); var arg = SF.CastExpression( parameterType, SF.ElementAccessExpression(arguments).AddArgumentListArguments(indexArg)); parameters.Add(arg); } // If the method is a generic method definition, use the generic method invoker field to invoke the method. if (method.IsGenericMethodDefinition) { var invokerFieldName = GetGenericMethodInvokerFieldName(method); var invokerCall = SF.InvocationExpression( SF.IdentifierName(invokerFieldName) .Member((GenericMethodInvoker invoker) => invoker.Invoke(null, null))) .AddArgumentListArguments(SF.Argument(grain), SF.Argument(arguments)); return(new StatementSyntax[] { SF.ReturnStatement(invokerCall) }); } // Invoke the method. var grainMethodCall = SF.InvocationExpression(castGrain.Member(method.Name)) .AddArgumentListArguments(parameters.Select(SF.Argument).ToArray()); // For void methods, invoke the method and return a completed task. if (method.ReturnType == typeof(void)) { var completed = (Expression <Func <Task <object> > >)(() => TaskUtility.Completed()); return(new StatementSyntax[] { SF.ExpressionStatement(grainMethodCall), SF.ReturnStatement(completed.Invoke()) }); } // For methods which return the expected type, Task<object>, simply return that. if (method.ReturnType == typeof(Task <object>)) { return(new StatementSyntax[] { SF.ReturnStatement(grainMethodCall) }); } // The invoke method expects a Task<object>, so we need to upcast the returned value. // For methods which do not return a value, the Box extension method returns a meaningless value. return(new StatementSyntax[] { SF.ReturnStatement(SF.InvocationExpression(grainMethodCall.Member((Task _) => _.Box()))) }); }
/// <summary> /// Returns syntax for the deep copier method. /// </summary> /// <param name="type">The type.</param> /// <param name="fields">The fields.</param> /// <returns>Syntax for the deep copier method.</returns> private static MemberDeclarationSyntax GenerateDeepCopierMethod(Type type, List <FieldInfoMember> fields) { var originalVariable = SF.IdentifierName("original"); var inputVariable = SF.IdentifierName("input"); var resultVariable = SF.IdentifierName("result"); var body = new List <StatementSyntax>(); if (type.GetCustomAttribute <ImmutableAttribute>() != null) { // Immutable types do not require copying. var typeName = type.GetParseableName(new TypeFormattingOptions(includeGlobal: false)); var comment = SF.Comment($"// No deep copy required since {typeName} is marked with the [Immutable] attribute."); body.Add(SF.ReturnStatement(originalVariable).WithLeadingTrivia(comment)); } else { body.Add( SF.LocalDeclarationStatement( SF.VariableDeclaration(type.GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("input") .WithInitializer( SF.EqualsValueClause( SF.ParenthesizedExpression( SF.CastExpression(type.GetTypeSyntax(), originalVariable))))))); body.Add( SF.LocalDeclarationStatement( SF.VariableDeclaration(type.GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("result") .WithInitializer(SF.EqualsValueClause(GetObjectCreationExpressionSyntax(type)))))); // Record this serialization. Expression <Action <ICopyContext> > recordObject = ctx => ctx.RecordCopy(default(object), default(object)); var context = SF.IdentifierName("context"); body.Add( SF.ExpressionStatement( recordObject.Invoke(context) .AddArgumentListArguments(SF.Argument(originalVariable), SF.Argument(resultVariable)))); // Copy all members from the input to the result. foreach (var field in fields) { body.Add(SF.ExpressionStatement(field.GetSetter(resultVariable, field.GetGetter(inputVariable, context)))); } body.Add(SF.ReturnStatement(resultVariable)); } return (SF.MethodDeclaration(typeof(object).GetTypeSyntax(), "DeepCopier") .AddModifiers(SF.Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters( SF.Parameter(SF.Identifier("original")).WithType(typeof(object).GetTypeSyntax()), SF.Parameter(SF.Identifier("context")).WithType(typeof(ICopyContext).GetTypeSyntax())) .AddBodyStatements(body.ToArray()) .AddAttributeLists( SF.AttributeList().AddAttributes(SF.Attribute(typeof(CopierMethodAttribute).GetNameSyntax())))); }
public (ExpressionSyntax csLeft, ExpressionSyntax csRight) AdjustForVbStringComparison(VBSyntax.ExpressionSyntax vbLeft, ExpressionSyntax csLeft, TypeInfo lhsTypeInfo, VBSyntax.ExpressionSyntax vbRight, ExpressionSyntax csRight, TypeInfo rhsTypeInfo) { if (OptionCompareTextCaseInsensitive) { _extraUsingDirectives.Add("System.Globalization"); var compareOptions = SyntaxFactory.Argument(GetCompareTextCaseInsensitiveCompareOptions()); var compareString = SyntaxFactory.InvocationExpression(ValidSyntaxFactory.MemberAccess(nameof(CultureInfo), nameof(CultureInfo.CurrentCulture), nameof(CultureInfo.CompareInfo), nameof(CompareInfo.Compare)), SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.Argument(csLeft), SyntaxFactory.Argument(csRight), compareOptions }))); csLeft = compareString; csRight = SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(0)); } else { (csLeft, csRight) = VbCoerceToString(vbLeft, csLeft, lhsTypeInfo, vbRight, csRight, rhsTypeInfo); } return(csLeft, csRight); }
public static ArgumentListSyntax ArgumentListWithOneArgument(ExpressionSyntax arg) { return(SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList <ArgumentSyntax>(SyntaxFactory.Argument(arg)))); }
private static MemberDeclarationSyntax GenerateDeserializerMethod(Type type, List <FieldInfoMember> fields) { Expression <Action> deserializeInner = () => SerializationManager.DeserializeInner(default(Type), default(BinaryTokenStreamReader)); var streamParameter = SF.IdentifierName("stream"); var resultDeclaration = SF.LocalDeclarationStatement( SF.VariableDeclaration(type.GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("result") .WithInitializer(SF.EqualsValueClause(GetObjectCreationExpressionSyntax(type))))); var resultVariable = SF.IdentifierName("result"); var boxedResultVariable = resultVariable; var body = new List <StatementSyntax> { resultDeclaration }; if (type.IsValueType) { // For value types, we need to box the result for reflection-based setters to work. body.Add(SF.LocalDeclarationStatement( SF.VariableDeclaration(typeof(object).GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("boxedResult").WithInitializer(SF.EqualsValueClause(resultVariable))))); boxedResultVariable = SF.IdentifierName("boxedResult"); } // Record the result for cyclic deserialization. Expression <Action> recordObject = () => DeserializationContext.Current.RecordObject(default(object)); var currentSerializationContext = SyntaxFactory.AliasQualifiedName( SF.IdentifierName(SF.Token(SyntaxKind.GlobalKeyword)), SF.IdentifierName("Orleans")) .Qualify("Serialization") .Qualify("DeserializationContext") .Qualify("Current"); body.Add( SF.ExpressionStatement( recordObject.Invoke(currentSerializationContext) .AddArgumentListArguments( SF.Argument(boxedResultVariable)))); // Deserialize all fields. foreach (var field in fields) { var deserialized = deserializeInner.Invoke() .AddArgumentListArguments( SF.Argument(SF.TypeOfExpression(field.Type)), SF.Argument(streamParameter)); body.Add( SF.ExpressionStatement( field.GetSetter( resultVariable, SF.CastExpression(field.Type, deserialized), boxedResultVariable))); } body.Add(SF.ReturnStatement(SF.CastExpression(type.GetTypeSyntax(), boxedResultVariable))); return (SF.MethodDeclaration(typeof(object).GetTypeSyntax(), "Deserializer") .AddModifiers(SF.Token(SyntaxKind.PublicKeyword), SF.Token(SyntaxKind.StaticKeyword)) .AddParameterListParameters( SF.Parameter(SF.Identifier("expected")).WithType(typeof(Type).GetTypeSyntax()), SF.Parameter(SF.Identifier("stream")).WithType(typeof(BinaryTokenStreamReader).GetTypeSyntax())) .AddBodyStatements(body.ToArray()) .AddAttributeLists( SF.AttributeList() .AddAttributes(SF.Attribute(typeof(DeserializerMethodAttribute).GetNameSyntax())))); }