private StatementSyntax GenerateObjectModelTypeHashCodeContribution(ExpressionSyntax expression) { // if (x != null) // { // result = (result * 31) + x.ValueGetHashCode(); // } return(SyntaxFactory.IfStatement( SyntaxHelper.IsNotNull(expression), SyntaxFactory.Block( SyntaxFactory.ExpressionStatement( SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName(GetHashCodeResultVariableName), SyntaxFactory.BinaryExpression( SyntaxKind.AddExpression, SyntaxFactory.ParenthesizedExpression( SyntaxFactory.BinaryExpression( SyntaxKind.MultiplyExpression, SyntaxFactory.IdentifierName(GetHashCodeResultVariableName), SyntaxFactory.LiteralExpression( SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(GetHashCodeCombiningValue)))), SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, expression, SyntaxFactory.IdentifierName(GetValueHashCodeMethodName))))))))); }
private StatementSyntax GenerateCollectionHashCodeContribution( string hashKindKey, ExpressionSyntax expression) { string collectionElementVariableName = _localVariableNameGenerator.GetNextCollectionElementVariableName(); // From the type of the element (primitive, object, list, or dictionary), create // the appropriate hash generation code. string elementHashTypeKey = PropertyInfoDictionary.MakeElementKeyName(hashKindKey); StatementSyntax hashCodeContribution = GeneratePropertyHashCodeContribution( elementHashTypeKey, SyntaxFactory.IdentifierName(collectionElementVariableName)); return(SyntaxFactory.IfStatement( SyntaxHelper.IsNotNull(expression), SyntaxFactory.Block( SyntaxFactory.ForEachStatement( SyntaxHelper.Var(), collectionElementVariableName, expression, SyntaxFactory.Block( SyntaxFactory.ExpressionStatement( SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName(GetHashCodeResultVariableName), SyntaxFactory.BinaryExpression( SyntaxKind.MultiplyExpression, SyntaxFactory.IdentifierName(GetHashCodeResultVariableName), SyntaxFactory.LiteralExpression( SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(GetHashCodeCombiningValue))))), hashCodeContribution))))); }
private StatementSyntax GenerateDictionaryHashCodeContribution(ExpressionSyntax expression) { string xorValueVariableName = _localVariableNameGenerator.GetNextXorVariableName(); string collectionElementVariableName = _localVariableNameGenerator.GetNextCollectionElementVariableName(); return(SyntaxFactory.IfStatement( SyntaxHelper.IsNotNull(expression), SyntaxFactory.Block( // int xor_0 = 0; SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.VariableDeclaration( SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntKeyword)), SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator( SyntaxFactory.Identifier(xorValueVariableName), default(BracketedArgumentListSyntax), SyntaxFactory.EqualsValueClause( SyntaxFactory.LiteralExpression( SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(0))))))) .WithLeadingTrivia( SyntaxFactory.ParseLeadingTrivia(Resources.XorDictionaryComment)), SyntaxFactory.ForEachStatement( SyntaxHelper.Var(), collectionElementVariableName, expression, SyntaxFactory.Block( // xor_0 ^= value_0.Key.GetHashCode(); Xor(xorValueVariableName, collectionElementVariableName, KeyPropertyName), SyntaxFactory.IfStatement( SyntaxHelper.IsNotNull( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(collectionElementVariableName), SyntaxFactory.IdentifierName(ValuePropertyName))), SyntaxFactory.Block( Xor(xorValueVariableName, collectionElementVariableName, ValuePropertyName))))), SyntaxFactory.ExpressionStatement( SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.IdentifierName(GetHashCodeResultVariableName), SyntaxFactory.BinaryExpression( SyntaxKind.AddExpression, SyntaxFactory.ParenthesizedExpression( SyntaxFactory.BinaryExpression( SyntaxKind.MultiplyExpression, SyntaxFactory.IdentifierName(GetHashCodeResultVariableName), SyntaxFactory.LiteralExpression( SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(GetHashCodeCombiningValue)))), SyntaxFactory.IdentifierName(xorValueVariableName))))))); }
/// <summary> /// Generate the visitor method for one of the classes defined by the schema. /// </summary> /// <param name="className"> /// The name of the class for which a visitor method is to be generated. /// </param> /// <returns> /// A method declaration for the vistor method. /// </returns> /// <example> /// <code> /// public virtual VisitLocation(Location node) /// { /// if (node != null) /// { /// // GenerateVisitClassBodyStatements() /// } /// /// return node; /// } /// </code> /// </example> private MethodDeclarationSyntax GenerateVisitClassMethod(string className) { string methodName = MakeVisitClassMethodName(className); TypeSyntax generatedClassType = SyntaxFactory.ParseTypeName(className); return(SyntaxFactory.MethodDeclaration(generatedClassType, methodName) .AddModifiers( SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.VirtualKeyword)) .AddParameterListParameters( SyntaxFactory.Parameter(SyntaxFactory.Identifier(NodeParameterName)) .WithType(generatedClassType)) .AddBodyStatements( SyntaxFactory.IfStatement( SyntaxHelper.IsNotNull(NodeParameterName), SyntaxFactory.Block( GeneratePropertyVisits(className))), SyntaxFactory.ReturnStatement( SyntaxFactory.IdentifierName(NodeParameterName)))); }
private StatementSyntax GenerateScalarReferenceTypeHashCodeContribution(ExpressionSyntax expression) { return(SyntaxFactory.IfStatement( SyntaxHelper.IsNotNull(expression), SyntaxFactory.Block(GenerateScalarHashCodeContribution(expression)))); }
private StatementSyntax[] GenerateArrayVisit( int arrayRank, int nestingLevel, ExpressionSyntax arrayValuedExpression) { ExpressionSyntax loopLimitExpression; if (nestingLevel == 0) { // node.Locations.Count loopLimitExpression = SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, arrayValuedExpression, SyntaxFactory.IdentifierName(CountPropertyName)); } else { // value_0.Count loopLimitExpression = SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName( LocalVariableNameGenerator.GetCollectionElementVariableName(nestingLevel - 1)), SyntaxFactory.IdentifierName(CountPropertyName)); } var statements = new List <StatementSyntax>(); if (nestingLevel < arrayRank) { // We're not yet at the innermost level, so we need another for loop. string loopVariableName = LocalVariableNameGenerator.GetLoopIndexVariableName(nestingLevel); string outerLoopVariableName = LocalVariableNameGenerator.GetLoopIndexVariableName(nestingLevel - 1); string arrayElementVariableName = LocalVariableNameGenerator.GetCollectionElementVariableName(nestingLevel - 1); // For every level except the outermost, we need to get an array element and test whether // it's null. if (nestingLevel > 0) { // var value_0 = node.Locations[index_0]; statements.Add( SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.VariableDeclaration( SyntaxHelper.Var(), SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator( SyntaxFactory.Identifier(arrayElementVariableName), default(BracketedArgumentListSyntax), SyntaxFactory.EqualsValueClause( SyntaxFactory.ElementAccessExpression( arrayValuedExpression, SyntaxFactory.BracketedArgumentList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Argument( SyntaxFactory.IdentifierName(outerLoopVariableName))))))))))); } // for ForStatementSyntax forStatement = SyntaxFactory.ForStatement( // (index_0 = 0; SyntaxFactory.VariableDeclaration( SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntKeyword)), SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator(loopVariableName) .WithInitializer( SyntaxFactory.EqualsValueClause(SyntaxFactory.LiteralExpression( SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(0)))))), default(SeparatedSyntaxList <ExpressionSyntax>), // index_0 < value_0.Count; SyntaxFactory.BinaryExpression( SyntaxKind.LessThanExpression, SyntaxFactory.IdentifierName(loopVariableName), loopLimitExpression), // ++index_0) SyntaxFactory.SingletonSeparatedList <ExpressionSyntax>( SyntaxFactory.PrefixUnaryExpression( SyntaxKind.PreIncrementExpression, SyntaxFactory.IdentifierName(loopVariableName))), // { ... } SyntaxFactory.Block( GenerateArrayVisit(arrayRank, nestingLevel + 1, arrayValuedExpression))); if (nestingLevel > 0) { statements.Add( SyntaxFactory.IfStatement( SyntaxHelper.IsNotNull(arrayElementVariableName), SyntaxFactory.Block( forStatement))); } else { statements.Add(forStatement); } } else { string loopVariableName = LocalVariableNameGenerator.GetLoopIndexVariableName(nestingLevel - 1); // We're in the body of the innermost loop over array elements. This is // where we do the assignment. For arrays of rank 1, the assignment is // to an element of the property itself. For arrays of rank > 1, the // assignment is to an array element of a temporary variable representing // one of the elements of the property. ElementAccessExpressionSyntax elementAccessExpression; if (arrayRank == 1) { // node.Location[index_0] elementAccessExpression = SyntaxFactory.ElementAccessExpression( arrayValuedExpression, SyntaxFactory.BracketedArgumentList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Argument( SyntaxFactory.IdentifierName(loopVariableName))))); } else { string arrayElementVariableName = LocalVariableNameGenerator.GetCollectionElementVariableName(nestingLevel - 2); // value_0[index_1] elementAccessExpression = SyntaxFactory.ElementAccessExpression( SyntaxFactory.IdentifierName(arrayElementVariableName), SyntaxFactory.BracketedArgumentList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Argument( SyntaxFactory.IdentifierName(loopVariableName))))); } statements.Add( SyntaxFactory.ExpressionStatement( SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, elementAccessExpression, SyntaxFactory.InvocationExpression( SyntaxFactory.IdentifierName(VisitNullCheckedMethodName), SyntaxHelper.ArgumentList(elementAccessExpression))))); } return(statements.ToArray()); }
private StatementSyntax[] GenerateDictionaryVisit(int arrayRank, string propertyName) { const string KeyVariableName = "key"; const string KeysVariableName = "keys"; const string KeysPropertyName = "Keys"; const string ValueVariableName = "value"; ExpressionSyntax dictionaryValue = SyntaxFactory.ElementAccessExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(NodeParameterName), SyntaxFactory.IdentifierName(propertyName)), SyntaxFactory.BracketedArgumentList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Argument( SyntaxFactory.IdentifierName(KeyVariableName))))); // The code to visit an individual dictionary element depends on whether the // elements are scalar values or arrays. StatementSyntax[] dictionaryElementVisitStatements; if (arrayRank == 0) { dictionaryElementVisitStatements = new StatementSyntax[] { GenerateScalarVisit(dictionaryValue, SyntaxFactory.IdentifierName(ValueVariableName)) }; } else { ExpressionSyntax arrayValuedExpression = SyntaxFactory.ElementAccessExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(NodeParameterName), SyntaxFactory.IdentifierName(propertyName)), SyntaxFactory.BracketedArgumentList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Argument( SyntaxFactory.IdentifierName(KeyVariableName))))); dictionaryElementVisitStatements = GenerateArrayVisit( arrayRank, nestingLevel: 0, arrayValuedExpression: arrayValuedExpression); } return(new StatementSyntax[] { // var keys = node.PropertyName.Keys.ToArray(); SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.VariableDeclaration( SyntaxHelper.Var(), SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator( SyntaxFactory.Identifier(KeysVariableName), default(BracketedArgumentListSyntax), SyntaxFactory.EqualsValueClause( SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(NodeParameterName), SyntaxFactory.IdentifierName(propertyName)), SyntaxFactory.IdentifierName(KeysPropertyName)), SyntaxFactory.IdentifierName(ToArrayMethodName)), SyntaxHelper.ArgumentList())))))), // foreach (var key in keys) SyntaxFactory.ForEachStatement( SyntaxHelper.Var(), KeyVariableName, SyntaxFactory.IdentifierName(KeysVariableName), SyntaxFactory.Block( SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.VariableDeclaration( SyntaxHelper.Var(), SyntaxFactory.SingletonSeparatedList( SyntaxFactory.VariableDeclarator( SyntaxFactory.Identifier(ValueVariableName), default(BracketedArgumentListSyntax), SyntaxFactory.EqualsValueClause(dictionaryValue))))), SyntaxFactory.IfStatement( SyntaxHelper.IsNotNull(ValueVariableName), SyntaxFactory.Block(dictionaryElementVisitStatements)))) }); }
/// <summary> /// Generate the code necessary to visit each property. /// </summary> /// <param name="className"> /// The name of the class for which the visitor method is being generated. /// </param> /// <returns> /// The statements necessary to visit each property in the class. /// </returns> /// <remarks> /// It is only necessary to visit those properties which are themselves of a /// schema-defined type. Scalar properties can be visited directly. For properties /// of array type, each element must be visited. /// </remarks> /// <example> /// Visiting a class with one scalar-valued property and one array-valued property: /// <code> /// node.MessageDescriptor = VisitNullChecked(node.MessageDescriptor); /// /// if (node.Locations != null) /// { /// // GenerateArrayVisit() /// } /// </code> /// </example> private StatementSyntax[] GeneratePropertyVisits(string className) { var statements = new List <StatementSyntax>(); PropertyInfoDictionary propertyInfoDictionary = _classInfoDictionary[className]; foreach (KeyValuePair <string, PropertyInfo> entry in propertyInfoDictionary.OrderBy(kvp => kvp.Value.DeclarationOrder)) { string propertyNameWithRank = entry.Key; PropertyInfo propertyInfo = entry.Value; // We only need to visit properties whose type is one of the classes // defined by the schema. if (!propertyInfo.IsOfSchemaDefinedType) { continue; } string propertyName = propertyNameWithRank.BasePropertyName(out int arrayRank, out bool isDictionary); TypeSyntax collectionType = propertyInfoDictionary.GetConcreteListType(propertyName); TypeSyntax elementType = propertyInfoDictionary[propertyNameWithRank].Type; ExpressionSyntax propertyAccessExpression = SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(NodeParameterName), SyntaxFactory.IdentifierName(propertyName)); if (arrayRank == 0 && !isDictionary) { // This is a simple scalar assignment. statements.Add(GenerateScalarVisit(propertyAccessExpression)); } else { _localVariableNameGenerator.Reset(); StatementSyntax[] nullTestedStatements = null; if (isDictionary) { nullTestedStatements = GenerateDictionaryVisit(arrayRank, propertyName); } else { nullTestedStatements = GenerateArrayVisit( arrayRank, nestingLevel: 0, arrayValuedExpression: propertyAccessExpression); } statements.Add( SyntaxFactory.IfStatement( SyntaxHelper.IsNotNull( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(NodeParameterName), SyntaxFactory.IdentifierName(propertyName))), SyntaxFactory.Block(nullTestedStatements))); } } return(statements.ToArray()); }