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)))));
        }
 public InterfaceGenerator(
     PropertyInfoDictionary propertyInfoDictionary,
     JsonSchema schema,
     string typeNameSuffix,
     HintDictionary hintDictionary)
     : base(propertyInfoDictionary, schema, typeNameSuffix, hintDictionary)
 {
 }
Beispiel #3
0
 public ClassOrInterfaceGenerator(
     PropertyInfoDictionary propertyInfoDictionary,
     JsonSchema schema,
     string typeNameSuffix,
     HintDictionary hintDictionary)
     : base(schema, typeNameSuffix, hintDictionary)
 {
     PropInfoDictionary = propertyInfoDictionary;
 }
        private ForStatementSyntax CollectionIndexLoop(
            string comparisonKindKey,
            ExpressionSyntax left,
            ExpressionSyntax right)
        {
            // The name of the index variable used in the loop over elements.
            string indexVarName = _localVariableNameGenerator.GetNextLoopIndexVariableName();

            // The two elements that will be compared each time through the loop.
            ExpressionSyntax leftElement =
                SyntaxFactory.ElementAccessExpression(
                    left,
                    SyntaxHelper.BracketedArgumentList(
                        SyntaxFactory.IdentifierName(indexVarName)));

            ExpressionSyntax rightElement =
                SyntaxFactory.ElementAccessExpression(
                    right,
                    SyntaxHelper.BracketedArgumentList(
                        SyntaxFactory.IdentifierName(indexVarName)));

            // From the type of the element (primitive, object, list, or dictionary), create
            // the appropriate comparison, for example, "a == b", or "Object.Equals(a, b)".
            string elmentComparisonTypeKey = PropertyInfoDictionary.MakeElementKeyName(comparisonKindKey);

            StatementSyntax comparisonStatement = GeneratePropertyComparison(elmentComparisonTypeKey, leftElement, rightElement);

            return(SyntaxFactory.ForStatement(
                       SyntaxFactory.VariableDeclaration(
                           SyntaxFactory.ParseTypeName(WellKnownTypeNames.Int),
                           SyntaxFactory.SingletonSeparatedList(
                               SyntaxFactory.VariableDeclarator(
                                   SyntaxFactory.Identifier(indexVarName),
                                   default(BracketedArgumentListSyntax),
                                   SyntaxFactory.EqualsValueClause(
                                       SyntaxFactory.LiteralExpression(
                                           SyntaxKind.NumericLiteralExpression,
                                           SyntaxFactory.Literal(0)))))),
                       SyntaxFactory.SeparatedList <ExpressionSyntax>(),
                       SyntaxFactory.BinaryExpression(
                           SyntaxKind.LessThanExpression,
                           SyntaxFactory.IdentifierName(indexVarName),
                           SyntaxFactory.MemberAccessExpression(
                               SyntaxKind.SimpleMemberAccessExpression,
                               left,
                               SyntaxFactory.IdentifierName(CountPropertyName))),
                       SyntaxFactory.SingletonSeparatedList <ExpressionSyntax>(
                           SyntaxFactory.PrefixUnaryExpression(
                               SyntaxKind.PreIncrementExpression,
                               SyntaxFactory.IdentifierName(indexVarName))),
                       SyntaxFactory.Block(comparisonStatement)));
        }
        /// <summary>
        /// Generates a class that implements <see cref="System.Collections.Generic.IEqualityComparer{T}"/>
        /// for the specified class.
        /// </summary>
        /// <param name="className">
        /// The name of the class whose equality comparer class is to be generated.
        /// </param>
        /// <param name="propertyInfoDictionary">
        /// An object containing information about each property in the class specified by <paramref name="className"/>.
        /// </param>
        /// <returns>
        /// A string containing the text of the generated equality comparer class.
        /// </returns>
        internal string Generate(string className, PropertyInfoDictionary propertyInfoDictionary)
        {
            _className = className;
            _propertyInfoDictionary = propertyInfoDictionary;

            _classType = SyntaxFactory.ParseTypeName(_className);
            _localVariableNameGenerator.Reset();

            string comparerClassName = GetEqualityComparerClassName(_className);

            var comparerInterface = GetComparerBaseType(_className);

            ClassDeclarationSyntax classDeclaration =
                SyntaxFactory.ClassDeclaration(comparerClassName)
                .AddModifiers(
                    SyntaxFactory.Token(SyntaxKind.InternalKeyword),
                    SyntaxFactory.Token(SyntaxKind.SealedKeyword))
                .AddBaseListTypes(comparerInterface)
                .AddMembers(
                    GenerateInstanceProperty(),
                    GenerateEqualsMethod(),
                    GenerateGetHashCodeMethod());

            var usings = new HashSet <string>
            {
                "System",                       // For Object.
                "System.Collections.Generic"    // For IEqualityComparer<T>
            };

            IEnumerable <string> namespaceNames = _propertyInfoDictionary
                                                  .Values
                                                  .Select(propertyInfo => propertyInfo.NamespaceName)
                                                  .Where(namespaceName => !string.IsNullOrWhiteSpace(namespaceName));

            foreach (string namespaceName in namespaceNames)
            {
                usings.Add(namespaceName);
            }

            return(classDeclaration.Format(
                       _copyrightNotice,
                       usings,
                       _namespaceName,
                       MakeSummaryComment()));
        }
        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)))))));
        }
        internal string GenerateClass(
            string className,
            JsonSchema schema,
            bool sealClasses,
            string classNameSuffix)
        {
            className = GetHintedClassName(className).ToPascalCase();
            string suffixedClassName = className + classNameSuffix;

            var propertyInfoDictionary = new PropertyInfoDictionary(
                className,
                _settings.TypeNameSuffix,
                schema,
                _settings.HintDictionary,
                OnAdditionalTypeRequired);

            _classInfoDictionary.Add(suffixedClassName, propertyInfoDictionary);

            EnumHint      enumHint      = null;
            InterfaceHint interfaceHint = null;

            if (_settings.HintDictionary != null)
            {
                string key = className.ToCamelCase();
                enumHint      = _settings.HintDictionary.GetHint <EnumHint>(key);
                interfaceHint = _settings.HintDictionary.GetHint <InterfaceHint>(key);
            }

            string baseInterfaceName = null;

            if (interfaceHint != null)
            {
                baseInterfaceName = "I" + suffixedClassName;
            }

            TypeGenerator typeGenerator;

            if (enumHint == null)
            {
                typeGenerator = new ClassGenerator(
                    propertyInfoDictionary,
                    schema,
                    _settings.HintDictionary,
                    baseInterfaceName,
                    _settings.GenerateEqualityComparers,
                    _settings.GenerateCloningCode,
                    _settings.SealClasses,
                    _nodeInterfaceName,
                    _kindEnumName,
                    _settings.TypeNameSuffix);

                if (_settings.GenerateCloningCode)
                {
                    // The cloning code includes an enumeration with one member for each
                    // generated class, so keep track of the class names.
                    _generatedClassNames.Add(suffixedClassName);
                }
            }
            else
            {
                typeGenerator = new EnumGenerator(schema, _settings.TypeNameSuffix, _settings.HintDictionary);
            }

            _pathToFileContentsDictionary[suffixedClassName] = typeGenerator.Generate(
                _settings.SuffixedNamespaceName,
                className,
                _settings.CopyrightNotice,
                schema.Description);

            if (interfaceHint != null)
            {
                typeGenerator = new InterfaceGenerator(
                    propertyInfoDictionary,
                    schema,
                    _settings.TypeNameSuffix,
                    _settings.HintDictionary);
                string description = interfaceHint.Description ?? schema.Description;

                _pathToFileContentsDictionary[baseInterfaceName + _settings.TypeNameSuffix] = typeGenerator.Generate(
                    _settings.SuffixedNamespaceName,
                    baseInterfaceName,
                    _settings.CopyrightNotice,
                    description);
            }

            return(_pathToFileContentsDictionary[suffixedClassName]);
        }
Beispiel #8
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());
        }