/// <summary> /// Returns syntax for initializing a new instance of the provided type. /// </summary> /// <param name="type">The type.</param> /// <returns>Syntax for initializing a new instance of the provided type.</returns> private static ExpressionSyntax GetObjectCreationExpressionSyntax(Type type) { ExpressionSyntax result; var typeInfo = type.GetTypeInfo(); if (typeInfo.IsValueType) { // Use the default value. result = SF.DefaultExpression(typeInfo.AsType().GetTypeSyntax()); } else if (GetEmptyConstructor(typeInfo) != null) { // Use the default constructor. result = SF.ObjectCreationExpression(typeInfo.AsType().GetTypeSyntax()).AddArgumentListArguments(); } else { // Create an unformatted object. Expression <Func <object> > getUninitializedObject = () => FormatterServices.GetUninitializedObject(default(Type)); result = SF.CastExpression( type.GetTypeSyntax(), getUninitializedObject.Invoke() .AddArgumentListArguments( SF.Argument(SF.TypeOfExpression(typeInfo.AsType().GetTypeSyntax())))); } return(result); }
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> /// 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); } // Invoke the method. var grainMethodCall = SF.InvocationExpression(castGrain.Member(method.Name)) .AddArgumentListArguments(parameters.Select(SF.Argument).ToArray()); if (method.ReturnType == typeof(void)) { var completed = (Expression <Func <Task <object> > >)(() => TaskUtility.Completed()); return(new StatementSyntax[] { SF.ExpressionStatement(grainMethodCall), SF.ReturnStatement(completed.Invoke()) }); } //// Generate a Task wrapper for a query method //if (GrainInterfaceUtils.IsQueryType(method.ReturnType)) //{ // var TaskFromResult = SF.InvocationExpression( // SF.MemberAccessExpression( // SyntaxKind.SimpleMemberAccessExpression, // SF.IdentifierName("global::System.Threading.Tasks.Task"), // SF.IdentifierName("FromResult")), // SF.ArgumentList(SF.SeparatedList(new[] { SF.Argument(grainMethodCall) }))); // return new StatementSyntax[] //{ // SF.ReturnStatement(SF.InvocationExpression(TaskFromResult.Member((Task _) => _.Box()))) //}; //} // 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 retrieving the value of this field, deep copying it if necessary. /// </summary> /// <param name="instance">The instance of the containing type.</param> /// <param name="serializationContextExpression">The expression used to retrieve the serialization context.</param> /// <param name="forceAvoidCopy">Whether or not to ensure that no copy of the field is made.</param> /// <returns>Syntax for retrieving the value of this field.</returns> public ExpressionSyntax GetGetter(ExpressionSyntax instance, ExpressionSyntax serializationContextExpression = null, bool forceAvoidCopy = false) { // Retrieve the value of the field. var getValueExpression = this.GetValueExpression(instance); // Avoid deep-copying the field if possible. if (forceAvoidCopy || this.FieldInfo.FieldType.IsOrleansShallowCopyable()) { // Return the value without deep-copying it. return(getValueExpression); } // Addressable arguments must be converted to references before passing. // IGrainObserver instances cannot be directly converted to references, therefore they are not included. ExpressionSyntax deepCopyValueExpression; if (typeof(IAddressable).IsAssignableFrom(this.FieldInfo.FieldType) && this.FieldInfo.FieldType.GetTypeInfo().IsInterface && !typeof(IGrainObserver).IsAssignableFrom(this.FieldInfo.FieldType)) { var getAsReference = getValueExpression.Member( (IAddressable grain) => grain.AsReference <IGrain>(), this.FieldInfo.FieldType); // If the value is not a GrainReference, convert it to a strongly-typed GrainReference. // C#: (value == null || value is GrainReference) ? value : value.AsReference<TInterface>() deepCopyValueExpression = SF.ConditionalExpression( SF.ParenthesizedExpression( SF.BinaryExpression( SyntaxKind.LogicalOrExpression, SF.BinaryExpression( SyntaxKind.EqualsExpression, getValueExpression, SF.LiteralExpression(SyntaxKind.NullLiteralExpression)), SF.BinaryExpression( SyntaxKind.IsExpression, getValueExpression, typeof(GrainReference).GetTypeSyntax()))), getValueExpression, SF.InvocationExpression(getAsReference)); } else { deepCopyValueExpression = getValueExpression; } // Deep-copy the value. Expression <Action> deepCopyInner = () => SerializationManager.DeepCopyInner(default(object), default(ICopyContext)); var typeSyntax = this.FieldInfo.FieldType.GetTypeSyntax(); return(SF.CastExpression( typeSyntax, deepCopyInner.Invoke() .AddArgumentListArguments( SF.Argument(deepCopyValueExpression), SF.Argument(serializationContextExpression)))); }
/// <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> deserializeInner = () => SerializationManager.DeserializeInner(default(Type), default(IDeserializationContext)); 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.GetTypeInfo().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() .AddArgumentListArguments( SF.Argument(SF.TypeOfExpression(field.Type)), SF.Argument(contextParameter)); body.Add( SF.ExpressionStatement( field.GetSetter( resultVariable, SF.CastExpression(field.Type, deserialized)))); } body.Add(SF.ReturnStatement(SF.CastExpression(type.GetTypeSyntax(), resultVariable))); 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("context")).WithType(typeof(IDeserializationContext).GetTypeSyntax())) .AddBodyStatements(body.ToArray()) .AddAttributeLists( SF.AttributeList() .AddAttributes(SF.Attribute(typeof(DeserializerMethodAttribute).GetNameSyntax())))); }
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"); } // 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())))); }
/// <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); } // 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()))) }); }
private static MemberDeclarationSyntax GenerateSerializerMethod(Type type, List <FieldInfoMember> fields) { Expression <Action> serializeInner = () => SerializationManager.SerializeInner(default(object), default(ISerializationContext), default(Type)); var contextParameter = SF.IdentifierName("context"); var body = new List <StatementSyntax> { SF.LocalDeclarationStatement( SF.VariableDeclaration(type.GetTypeSyntax()) .AddVariables( SF.VariableDeclarator("input") .WithInitializer( SF.EqualsValueClause( SF.CastExpression(type.GetTypeSyntax(), SF.IdentifierName("untypedInput")))))) }; var inputExpression = SF.IdentifierName("input"); // Serialize all members. foreach (var field in fields) { body.Add( SF.ExpressionStatement( serializeInner.Invoke() .AddArgumentListArguments( SF.Argument(field.GetGetter(inputExpression, forceAvoidCopy: true)), SF.Argument(contextParameter), SF.Argument(SF.TypeOfExpression(field.FieldInfo.FieldType.GetTypeSyntax()))))); } return (SF.MethodDeclaration(typeof(void).GetTypeSyntax(), "Serializer") .AddModifiers(SF.Token(SyntaxKind.PublicKeyword), SF.Token(SyntaxKind.StaticKeyword)) .AddParameterListParameters( SF.Parameter(SF.Identifier("untypedInput")).WithType(typeof(object).GetTypeSyntax()), SF.Parameter(SF.Identifier("context")).WithType(typeof(ISerializationContext).GetTypeSyntax()), SF.Parameter(SF.Identifier("expected")).WithType(typeof(Type).GetTypeSyntax())) .AddBodyStatements(body.ToArray()) .AddAttributeLists( SF.AttributeList() .AddAttributes(SF.Attribute(typeof(SerializerMethodAttribute).GetNameSyntax())))); }
/// <summary> /// Generates a method. /// </summary> /// <param name="methodDescription"> /// The method description. /// </param> /// <returns> /// The generated method. /// </returns> /// <exception cref="ArgumentException"> /// The return type of the provided method is not supported. /// </exception> private static MethodDeclarationSyntax GenerateMethod(ActorMethodDescription methodDescription) { // Types var method = methodDescription.MethodInfo; Type asyncReturnType; if (!method.ReturnType.IsGenericType && (method.ReturnType == typeof(Task))) { asyncReturnType = typeof(void); } else if (method.ReturnType.GetGenericTypeDefinition() == typeof(Task <>)) { asyncReturnType = method.ReturnType.GenericTypeArguments[0]; } else { throw new ArgumentException("Method return type is not Task or Task<T>."); } // Body statements var parameterReferences = method.GetParameters() .Select( p => SF.Argument(SF.CastExpression(typeof(object).GetTypeSyntax(), SF.IdentifierName(p.Name)))) .ToArray(); var writeEventMethod = SF.ThisExpression().Member((EventProducerBase <object> _) => _.WriteEvent(default(string), default(object), default(object))); var writeEvent = SF.ExpressionStatement( SF.AwaitExpression( SF.InvocationExpression(writeEventMethod) .AddArgumentListArguments(SF.Argument(methodDescription.Name.GetLiteralExpression())) .AddArgumentListArguments(parameterReferences))); var returnValue = asyncReturnType == typeof(void) ? null : SF.DefaultExpression(asyncReturnType.GetTypeSyntax()); // Build and return the method. return (SF.MethodDeclaration(method.ReturnType.GetTypeSyntax(), methodDescription.MethodInfo.Name) .AddModifiers(SF.Token(SyntaxKind.PublicKeyword), SF.Token(SyntaxKind.AsyncKeyword)) .AddParameterListParameters(method.GetParameterListSyntax()) .AddBodyStatements(writeEvent, SF.ReturnStatement(returnValue))); }
/// <summary> /// Returns syntax for retrieving the value of this field, deep copying it if neccessary. /// </summary> /// <param name="instance">The instance of the containing type.</param> /// <param name="forceAvoidCopy">Whether or not to ensure that no copy of the field is made.</param> /// <returns>Syntax for retrieving the value of this field.</returns> public ExpressionSyntax GetGetter(ExpressionSyntax instance, bool forceAvoidCopy = false) { // Retrieve the value of the field. var getValueExpression = this.GetValueExpression(instance); // Avoid deep-copying the field if possible. if (forceAvoidCopy || this.FieldInfo.FieldType.IsOrleansShallowCopyable()) { // Return the value without deep-copying it. return getValueExpression; } // Deep-copy the value. Expression<Action> deepCopyInner = () => SerializationManager.DeepCopyInner(default(object)); var typeSyntax = this.FieldInfo.FieldType.GetTypeSyntax(); return SF.CastExpression( typeSyntax, deepCopyInner.Invoke().AddArgumentListArguments(SF.Argument(getValueExpression))); }
private MemberDeclarationSyntax MockProviderMethod() { var m = F.MethodDeclaration(MockMemberType, F.Identifier(MemberMockName)).WithTypeParameterList(TypeParameterList()); m = m.WithModifiers(F.TokenList(F.Token(SyntaxKind.PublicKeyword))); var keyCreation = F.LocalDeclarationStatement(F.VariableDeclaration(F.IdentifierName("var")).WithVariables(F.SingletonSeparatedList(F .VariableDeclarator(F.Identifier("key")).WithInitializer(F.EqualsValueClause(TypesOfTypeParameters()))))); var mockCreation = F.SimpleLambdaExpression(F.Parameter(F.Identifier("keyString")), F.ObjectCreationExpression(MockMemberType) .WithExpressionsAsArgumentList( F.ThisExpression(), F.LiteralExpression(SyntaxKind.StringLiteralExpression, F.Literal(ClassSymbol.Name)), F.LiteralExpression(SyntaxKind.StringLiteralExpression, F.Literal(InterfaceSymbol.Name)), F.BinaryExpression(SyntaxKind.AddExpression, F.LiteralExpression(SyntaxKind.StringLiteralExpression, F.Literal(Symbol.Name)), F.IdentifierName("keyString")), F.BinaryExpression(SyntaxKind.AddExpression, F.BinaryExpression(SyntaxKind.AddExpression, F.LiteralExpression(SyntaxKind.StringLiteralExpression, F.Literal(MemberMockName)), F.IdentifierName("keyString")), F.LiteralExpression( SyntaxKind.StringLiteralExpression, F.Literal("()"))), StrictnessExpression() )); var returnStatement = F.ReturnStatement(F.CastExpression(MockMemberType, F.InvocationExpression( F.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, F.IdentifierName(MockProviderName), F.IdentifierName("GetOrAdd"))) .WithArgumentList( F.ArgumentList(F.SeparatedList(new[] { F.Argument(F.IdentifierName("key")), F.Argument(mockCreation) }))))); m = m.WithBody(F.Block(keyCreation, returnStatement)); var constraints = TypesForSymbols.AsConstraintClauses(Symbol.TypeParameters); if (constraints.Any()) { m = m.AddConstraintClauses(constraints); } return(m); }
public ExpressionSyntax VisitExpression(ExpressionSyntax node) { if (node is BinaryExpressionSyntax binaryExpression) { var left = VisitExpression(binaryExpression.Left); var right = VisitExpression(binaryExpression.Right); return(SF.BinaryExpression(node.Kind(), left, right)); } if (node is IdentifierNameSyntax identifierName) { return(SMS.Variables[identifierName.Identifier.Text]); } if (node is CastExpressionSyntax castExpression) { return(SF.CastExpression(castExpression.Type, VisitExpression(castExpression.Expression))); } if (node is InvocationExpressionSyntax invocationExpression) { var arguments = SF.ArgumentList(); foreach (var a in invocationExpression.ArgumentList.Arguments) { arguments = arguments.AddArguments(VisitArgument(a)); } return(SF.InvocationExpression(invocationExpression.Expression, arguments)); } if (node is PrefixUnaryExpressionSyntax prefixUnaryExpression) { return(SF.PrefixUnaryExpression(node.Kind(), VisitExpression(prefixUnaryExpression.Operand))); } if (node is ParenthesizedExpressionSyntax parenthesizedExpressionSyntax) { return(SF.ParenthesizedExpression(VisitExpression(parenthesizedExpressionSyntax.Expression))); } if (node is LiteralExpressionSyntax || node is MemberAccessExpressionSyntax) { return(node); } throw new NotImplementedException(node.GetType().Name); }
public override SyntaxList <StatementSyntax> VisitAssignmentStatement(VBSyntax.AssignmentStatementSyntax node) { var lhs = (ExpressionSyntax)node.Left.Accept(_nodesVisitor); var rhs = (ExpressionSyntax)node.Right.Accept(_nodesVisitor); // e.g. VB DivideAssignmentExpression "/=" is always on doubles unless you use the "\=" IntegerDivideAssignmentExpression, so need to cast in C# // Need the unconverted type, since the whole point is that it gets converted to a double by the operator if (node.IsKind(VBasic.SyntaxKind.DivideAssignmentStatement) && !node.HasOperandOfUnconvertedType("System.Double", _semanticModel)) { var doubleType = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.DoubleKeyword)); rhs = SyntaxFactory.CastExpression(doubleType, rhs); } if (node.IsKind(VBasic.SyntaxKind.ExponentiateAssignmentStatement)) { rhs = SyntaxFactory.InvocationExpression( SyntaxFactory.ParseExpression($"{nameof(Math)}.{nameof(Math.Pow)}"), ExpressionSyntaxExtensions.CreateArgList(lhs, rhs)); } var kind = node.Kind().ConvertToken(TokenContext.Local); return(SingleStatement(SyntaxFactory.AssignmentExpression(kind, lhs, rhs))); }
/// <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 = () => SerializationManager.GetGetter(default(FieldInfo)); Expression <Action> getReferenceSetter = () => SerializationManager.GetReferenceSetter(default(FieldInfo)); Expression <Action> getValueSetter = () => SerializationManager.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.IsValueType) { var setterType = typeof(SerializationManager.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()); }
/// <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. 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)))))); // Copy all members from the input to the result. foreach (var field in fields) { body.Add(SF.ExpressionStatement(field.GetSetter(resultVariable, field.GetGetter(inputVariable)))); } // 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(resultVariable)))); body.Add(SF.ReturnStatement(resultVariable)); } 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())))); }
/// <summary> /// Returns syntax for initializing a new instance of the provided type. /// </summary> /// <param name="type">The type.</param> /// <returns>Syntax for initializing a new instance of the provided type.</returns> private static ExpressionSyntax GetObjectCreationExpressionSyntax(Type type) { ExpressionSyntax result; var typeInfo = type.GetTypeInfo(); if (typeInfo.IsValueType) { // Use the default value. result = SF.DefaultExpression(typeInfo.GetTypeSyntax()); } else if (type.GetConstructor(Type.EmptyTypes) != null) { // Use the default constructor. result = SF.ObjectCreationExpression(typeInfo.GetTypeSyntax()).AddArgumentListArguments(); } else { // Create an unformatted object. #if DNXCORE50 var bindingFlags = SyntaxFactoryExtensions.GetBindingFlagsParenthesizedExpressionSyntax( SyntaxKind.BitwiseOrExpression, BindingFlags.Instance, BindingFlags.NonPublic, BindingFlags.Public); var nullLiteralExpressionArgument = SF.Argument(SF.LiteralExpression(SyntaxKind.NullLiteralExpression)); var typeArg = SF.Argument(SF.TypeOfExpression(typeInfo.GetTypeSyntax())); var bindingFlagsArg = SF.Argument(bindingFlags); var binderArg = nullLiteralExpressionArgument; ArgumentSyntax ctorArgumentsArg; var cons = typeInfo.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .OrderBy(p => p.GetParameters().Count()).FirstOrDefault(); var consParameters = cons != null?cons.GetParameters().Select(p => p.ParameterType).ToArray() : null; if (consParameters != null && consParameters.Length > 0) { var separatedSyntaxList = new SeparatedSyntaxList <ExpressionSyntax>(); separatedSyntaxList = consParameters .Aggregate(separatedSyntaxList, (current, t) => current.Add(SF.DefaultExpression(t.GetTypeInfo().GetTypeSyntax()))); ctorArgumentsArg = SF.Argument(separatedSyntaxList.GetArrayCreationWithInitializerSyntax( SF.PredefinedType(SF.Token(SyntaxKind.ObjectKeyword)))); } else { ctorArgumentsArg = nullLiteralExpressionArgument; } var cultureInfoArg = SF.Argument( SF.IdentifierName("System").Member("Globalization").Member("CultureInfo").Member("InvariantCulture")); var createInstanceArguments = new [] { typeArg, bindingFlagsArg, binderArg, ctorArgumentsArg, cultureInfoArg }; Expression <Func <object> > getUninitializedObject = () => Activator.CreateInstance( default(Type), BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, null, System.Globalization.CultureInfo.InvariantCulture); result = SF.CastExpression( type.GetTypeSyntax(), getUninitializedObject.Invoke() .AddArgumentListArguments(createInstanceArguments)); #else Expression <Func <object> > getUninitializedObject = () => FormatterServices.GetUninitializedObject(default(Type)); result = SF.CastExpression( type.GetTypeSyntax(), getUninitializedObject.Invoke() .AddArgumentListArguments( SF.Argument(SF.TypeOfExpression(typeInfo.GetTypeSyntax())))); #endif } return(result); }
/// <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> /// 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.GetTypeInfo().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), SF.Token(SyntaxKind.StaticKeyword)) .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())))); }
private static MemberDeclarationSyntax GenerateConstructor(string className, List <FieldInfoMember> fields) { var body = new List <StatementSyntax>(); Expression <Action <TypeInfo> > getField = _ => _.GetField(string.Empty, BindingFlags.Default); Expression <Action <Type> > getTypeInfo = _ => _.GetTypeInfo(); 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(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)); 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.GetTypeInfo().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)) }); } 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)) }); }