private StatementSyntax GenerateScalarReferenceTypeHashCodeContribution(ExpressionSyntax expression)
 {
     return(SyntaxFactory.IfStatement(
                SyntaxHelper.IsNotNull(expression),
                SyntaxFactory.Block(GenerateScalarHashCodeContribution(expression))));
 }
        private IfStatementSyntax MakeDictionaryEqualsTest(
            string propertyInfoKey,
            ExpressionSyntax left,
            ExpressionSyntax right)
        {
            string dictionaryElementVariableName = _localVariableNameGenerator.GetNextCollectionElementVariableName();
            string otherPropertyVariableName     = _localVariableNameGenerator.GetNextCollectionElementVariableName();

            // Construct the key into the PropertyInfoDictionary so we can look up how
            // dictionary elements are to be compared.
            string     valuePropertyInfoKey = PropertyInfoDictionary.MakeDictionaryItemKeyName(propertyInfoKey);
            TypeSyntax dictionaryValueType  = _propertyInfoDictionary[valuePropertyInfoKey].Type;

            return(SyntaxFactory.IfStatement(
                       // if (!Object.ReferenceEquals(left, right))
                       SyntaxHelper.AreDifferentObjects(left, right),
                       SyntaxFactory.Block(
                           // if (left == null || right == null || left.Count != right.Count)
                           SyntaxFactory.IfStatement(
                               SyntaxFactory.BinaryExpression(
                                   SyntaxKind.LogicalOrExpression,
                                   SyntaxHelper.IsNull(left),
                                   SyntaxFactory.BinaryExpression(
                                       SyntaxKind.LogicalOrExpression,
                                       SyntaxHelper.IsNull(right),
                                       SyntaxFactory.BinaryExpression(
                                           SyntaxKind.NotEqualsExpression,
                                           SyntaxFactory.MemberAccessExpression(
                                               SyntaxKind.SimpleMemberAccessExpression,
                                               left,
                                               SyntaxFactory.IdentifierName(CountPropertyName)),
                                           SyntaxFactory.MemberAccessExpression(
                                               SyntaxKind.SimpleMemberAccessExpression,
                                               right,
                                               SyntaxFactory.IdentifierName(CountPropertyName))))),
                               // return false;
                               SyntaxFactory.Block(SyntaxHelper.Return(false))),
                           // foreach (var value_0 in left)
                           SyntaxFactory.ForEachStatement(
                               SyntaxHelper.Var(),
                               dictionaryElementVariableName,
                               left,
                               SyntaxFactory.Block(
                                   // var value_1;
                                   SyntaxFactory.LocalDeclarationStatement(
                                       default(SyntaxTokenList), // modifiers
                                       SyntaxFactory.VariableDeclaration(
                                           dictionaryValueType,
                                           SyntaxFactory.SingletonSeparatedList(
                                               SyntaxFactory.VariableDeclarator(otherPropertyVariableName)))),
                                   // if (!right.TryGetValue(value_0.Key, out value_1))
                                   SyntaxFactory.IfStatement(
                                       SyntaxFactory.PrefixUnaryExpression(
                                           SyntaxKind.LogicalNotExpression,
                                           SyntaxFactory.InvocationExpression(
                                               SyntaxFactory.MemberAccessExpression(
                                                   SyntaxKind.SimpleMemberAccessExpression,
                                                   right,
                                                   SyntaxFactory.IdentifierName("TryGetValue")),
                                               SyntaxFactory.ArgumentList(
                                                   SyntaxFactory.SeparatedList(
                                                       new ArgumentSyntax[]
            {
                SyntaxFactory.Argument(
                    SyntaxFactory.MemberAccessExpression(
                        SyntaxKind.SimpleMemberAccessExpression,
                        SyntaxFactory.IdentifierName(dictionaryElementVariableName),
                        SyntaxFactory.IdentifierName(KeyPropertyName))),
                SyntaxFactory.Argument(
                    default(NameColonSyntax),
                    SyntaxFactory.Token(SyntaxKind.OutKeyword),
                    SyntaxFactory.IdentifierName(otherPropertyVariableName))
            })))),
                                       // return false;
                                       SyntaxFactory.Block(SyntaxHelper.Return(false))),

                                   GeneratePropertyComparison(
                                       valuePropertyInfoKey,
                                       SyntaxFactory.MemberAccessExpression(
                                           SyntaxKind.SimpleMemberAccessExpression,
                                           SyntaxFactory.IdentifierName(dictionaryElementVariableName),
                                           SyntaxFactory.IdentifierName(ValuePropertyName)),
                                       SyntaxFactory.IdentifierName(otherPropertyVariableName)))))));
        }
Exemple #3
0
        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))))
            });
        }
Exemple #4
0
        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());
        }
Exemple #5
0
        /// <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());
        }