示例#1
0
        private static MethodDeclarationSyntax GenerateGetHashCodeMethod(SyntaxGenerator generator, SemanticModel semanticModel, List <PropertyDeclarationSyntax> publicProperties)
        {
            var hashCodeVariable   = generator.IdentifierName("hashCode");
            var hasCodeDeclaration = generator.LocalDeclarationStatement("hashCode", generator.LiteralExpression(17));
            var newMethodName      = SyntaxFactory.IdentifierName("GetHashCode");

            var calculateHashCode = publicProperties.Select(x =>
            {
                var typeInfo = semanticModel.GetTypeInfo(x.Type);
                if (typeInfo.Type?.IsReferenceType == true)
                {
                    return(generator.AssignmentStatement(hashCodeVariable,
                                                         generator.AddExpression(
                                                             generator.MultiplyExpression(hashCodeVariable, generator.LiteralExpression(23)),
                                                             generator.CoalesceExpression(
                                                                 generator.InvocationExpression(
                                                                     SyntaxFactory.ConditionalAccessExpression(
                                                                         generator.IdentifierName(x.Identifier.Text) as ExpressionSyntax,
                                                                         SyntaxFactory.MemberBindingExpression(newMethodName))),
                                                                 generator.LiteralExpression(0)))));
                }

                return(generator.AssignmentStatement(hashCodeVariable,
                                                     generator.AddExpression(
                                                         generator.MultiplyExpression(hashCodeVariable, generator.LiteralExpression(23)),
                                                         generator.InvocationExpression(
                                                             generator.MemberAccessExpression(generator.IdentifierName(x.Identifier.Text), newMethodName)
                                                             ))));
            });
            var calculateHashCodeStms = new List <SyntaxNode>()
            {
                hasCodeDeclaration,
            };

            foreach (var node in calculateHashCode)
            {
                calculateHashCodeStms.Add(node);
            }

            calculateHashCodeStms.Add(generator.ReturnStatement(hashCodeVariable));

            var getHashCode = generator.MethodDeclaration("GetHashCode",
                                                          returnType: SyntaxFactory.ParseTypeName("int"), accessibility: Accessibility.Public,
                                                          statements: calculateHashCodeStms, modifiers: new DeclarationModifiers().WithIsOverride(true));

            return(getHashCode as MethodDeclarationSyntax);
        }
示例#2
0
        private static IList <SyntaxNode> CreateGetHashCodeMethodStatements(
            SyntaxGenerator factory,
            Compilation compilation,
            INamedTypeSymbol containingType,
            IList <ISymbol> members,
            CancellationToken cancellationToken)
        {
            const string HashCodeName = "hashCode";

            // -1521134295
            var permuteValue = factory.NegateExpression(
                factory.LiteralExpression(1521134295));

            var statements = new List <SyntaxNode>();

            var hashCodeNameExpression = factory.IdentifierName(HashCodeName);

            var firstHashValue = ComputeHashValue(factory, compilation, members[0]);

            if (members.Count == 1)
            {
#if false
                return(this.S1.GetHashCode());
#endif
                statements.Add(factory.ReturnStatement(firstHashValue));
            }
            else
            {
#if false
                var hashCode = this.S1.GetHashCode();
#endif
                statements.Add(factory.LocalDeclarationStatement(HashCodeName, firstHashValue));

                for (var i = 1; i < members.Count; i++)
                {
#if false
                    hashCode = hashCode * 0xA5555529 + value
#endif
                    statements.Add(factory.ExpressionStatement(
                                       factory.AssignmentStatement(hashCodeNameExpression,
                                                                   factory.AddExpression(
                                                                       factory.MultiplyExpression(hashCodeNameExpression, permuteValue),
                                                                       ComputeHashValue(factory, compilation, members[i])))));
                }

#if false
                return(hashCode);
#endif
                statements.Add(factory.ReturnStatement(hashCodeNameExpression));
            }

            return(statements);
        }
示例#3
0
        /// <summary>
        /// Recursivelly builds C# code by traversing ast
        /// </summary>
        /// <param name="root">Root node of an AST tree for a statement</param>
        private SyntaxNode RecursiveVisit(Node root, ref List <SyntaxNode> declared)
        {
            switch (root)
            {
            case EmptyNode emptyNode:
                throw new NotImplementedException();

            case NumNode numNode:
                return(generator.LiteralExpression(numNode.Value));

            case FloatNode floatNode:
                return(generator.LiteralExpression(floatNode.Value));

            case VarNode varNode:
                return(this.generator.LocalDeclarationStatement(
                           generator.TypeExpression(SpecialType.System_Object),
                           varNode.Name
                           ));

            case AssignNode assignNode:
                if (assignNode.variable is VarNode)
                {
                    var variableDeclaration = RecursiveVisit(assignNode.variable, ref declared);
                    declared.Add(variableDeclaration);

                    var identifier = this.generator.IdentifierName((assignNode.variable as VarNode).Name);
                    return(generator.AssignmentStatement(identifier, RecursiveVisit(assignNode.expression, ref declared)));
                }
                else
                {
                    throw new Exception("Can't assign value to non variable.");
                }

            case InvocationNode mathFNode:
                //RecursiveVisit(mathFNode.arg);
                throw new NotImplementedException();

            case BinOpNode operatorNode:
                return(generator.AddExpression(
                           RecursiveVisit(operatorNode.left, ref declared),
                           RecursiveVisit(operatorNode.right, ref declared)
                           ));

            case SupNode supNode:
                //RecursiveVisit(supNode.baseEl);
                //RecursiveVisit(supNode.supEl);
                throw new NotImplementedException();

            default:
                throw new NotImplementedException("Node type not implemented yet.");
            }
        }
示例#4
0
        public static ImmutableArray <SyntaxNode> CreateGetHashCodeMethodStatements(
            this SyntaxGenerator factory,
            SyntaxGeneratorInternal generatorInternal,
            Compilation compilation,
            INamedTypeSymbol containingType,
            ImmutableArray <ISymbol> members,
            bool useInt64)
        {
            var components = GetGetHashCodeComponents(
                factory, compilation, containingType, members, justMemberReference: false);

            if (components.Length == 0)
            {
                return(ImmutableArray.Create(factory.ReturnStatement(factory.LiteralExpression(0))));
            }

            const int hashFactor = -1521134295;

            var initHash     = 0;
            var baseHashCode = GetBaseGetHashCodeMethod(containingType);

            if (baseHashCode != null)
            {
                initHash = initHash * hashFactor + Hash.GetFNVHashCode(baseHashCode.Name);
            }

            foreach (var symbol in members)
            {
                initHash = initHash * hashFactor + Hash.GetFNVHashCode(symbol.Name);
            }

            if (components.Length == 1 && !useInt64)
            {
                // If there's just one value to hash, then we can compute and directly
                // return it.  i.e.  The full computation is:
                //
                //      return initHash * hashfactor + ...
                //
                // But as we know the values of initHash and hashFactor we can just compute
                // is here and directly inject the result value, producing:
                //
                //      return someHash + this.S1.GetHashCode();    // or

                var multiplyResult = initHash * hashFactor;
                return(ImmutableArray.Create(factory.ReturnStatement(
                                                 factory.AddExpression(
                                                     CreateLiteralExpression(factory, multiplyResult),
                                                     components[0]))));
            }

            var statements = ArrayBuilder <SyntaxNode> .GetInstance();

            // initialize the initial hashCode:
            //
            //      var hashCode = initialHashCode;

            const string HashCodeName = "hashCode";

            statements.Add(!useInt64
                ? factory.SimpleLocalDeclarationStatement(generatorInternal, compilation.GetSpecialType(SpecialType.System_Int32), HashCodeName, CreateLiteralExpression(factory, initHash))
                : factory.LocalDeclarationStatement(compilation.GetSpecialType(SpecialType.System_Int64), HashCodeName, CreateLiteralExpression(factory, initHash)));

            var hashCodeNameExpression = factory.IdentifierName(HashCodeName);

            // -1521134295
            var permuteValue = CreateLiteralExpression(factory, hashFactor);

            foreach (var component in components)
            {
                // hashCode = hashCode * -1521134295 + this.S.GetHashCode();
                var rightSide =
                    factory.AddExpression(
                        factory.MultiplyExpression(hashCodeNameExpression, permuteValue),
                        component);

                if (useInt64)
                {
                    rightSide = factory.InvocationExpression(
                        factory.MemberAccessExpression(rightSide, GetHashCodeName));
                }

                statements.Add(factory.ExpressionStatement(
                                   factory.AssignmentStatement(hashCodeNameExpression, rightSide)));
            }

            // And finally, the "return hashCode;" statement.
            statements.Add(!useInt64
                ? factory.ReturnStatement(hashCodeNameExpression)
                : factory.ReturnStatement(
                               factory.ConvertExpression(
                                   compilation.GetSpecialType(SpecialType.System_Int32),
                                   hashCodeNameExpression)));

            return(statements.ToImmutableAndFree());
        }
        /// <summary>
        /// Generates an override of <see cref="object.Equals(object)"/> similar to the one
        /// generated for anonymous types.
        /// </summary>
        private static ImmutableArray <SyntaxNode> CreateGetHashCodeMethodStatements(
            SyntaxGenerator factory,
            Compilation compilation,
            INamedTypeSymbol containingType,
            ImmutableArray <ISymbol> members,
            CancellationToken cancellationToken)
        {
            var hasBaseGetHashCode = HasExistingBaseGetHashCodeMethod(containingType, cancellationToken);
            var baseHashCode       = factory.InvocationExpression(
                factory.MemberAccessExpression(factory.BaseExpression(), GetHashCodeName));

            if (members.Length == 0)
            {
                // Trivial case.  Just directly:
                //
                //      return 0; or
                //      return base.GetHashCode();

                return(ImmutableArray.Create(factory.ReturnStatement(
                                                 hasBaseGetHashCode ? baseHashCode : factory.LiteralExpression(0))));
            }

            const int hashFactor = -1521134295;

            var initHash = 0;

            foreach (var symbol in members)
            {
                initHash = initHash * hashFactor + Hash.GetFNVHashCode(symbol.Name);
            }

            if (members.Length == 1 && !hasBaseGetHashCode)
            {
                // If there's just one value to hash, then we can compute and directly
                // return it.  i.e.  The full computation is:
                //
                //      return initHash * hashfactor + ...
                //
                // But as we know the values of initHash and hashFactor we can just compute
                // is here and directly inject the result value, producing:
                //
                //      return someHash + this.S1.GetHashCode();    // or

                var multiplyResult = initHash * hashFactor;
                return(ImmutableArray.Create(factory.ReturnStatement(
                                                 factory.AddExpression(
                                                     CreateLiteralExpression(factory, multiplyResult),
                                                     ComputeHashValue(factory, compilation, members[0])))));
            }

            var statements = ArrayBuilder <SyntaxNode> .GetInstance();

            // initialize the initial hashCode:
            //
            //      var hashCode = initialHashCode;
            const string HashCodeName = "hashCode";

            statements.Add(factory.LocalDeclarationStatement(HashCodeName, CreateLiteralExpression(factory, initHash)));

            var hashCodeNameExpression = factory.IdentifierName(HashCodeName);

            // -1521134295
            var permuteValue = CreateLiteralExpression(factory, hashFactor);

            // If our base type overrode GetHashCode, then include it's value in our hashCode
            // as well.
            if (hasBaseGetHashCode)
            {
                //  hashCode = hashCode * -1521134295 + base.GetHashCode();
                statements.Add(factory.ExpressionStatement(
                                   factory.AssignmentStatement(hashCodeNameExpression,
                                                               factory.AddExpression(
                                                                   factory.MultiplyExpression(hashCodeNameExpression, permuteValue),
                                                                   baseHashCode))));
            }

            foreach (var member in members)
            {
                // hashCode = hashCode * -1521134295 + this.S.GetHashCode();
                statements.Add(factory.ExpressionStatement(
                                   factory.AssignmentStatement(hashCodeNameExpression,
                                                               factory.AddExpression(
                                                                   factory.MultiplyExpression(hashCodeNameExpression, permuteValue),
                                                                   ComputeHashValue(factory, compilation, member)))));
            }

            // And finally, the "return hashCode;" statement.
            statements.Add(factory.ReturnStatement(hashCodeNameExpression));

            return(statements.ToImmutableAndFree());
        }