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) { }
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]); }
/// <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()); }