예제 #1
0
    public static ExpressionSyntax GenLiteral(TypeManager types, Randomizer random, FuzzType type)
    {
        switch (type)
        {
        case PrimitiveType prim:
            return(GenPrimitiveLiteral(random, prim));

        case AggregateType agg:
            return
                (ObjectCreationExpression(type.GenReferenceTo())
                 .WithArgumentList(
                     ArgumentList(
                         SeparatedList(agg.Fields.Select(af => Argument(GenLiteral(types, random, af.Type)))))));

        case ArrayType arr:
            List <int> dims = GenArrayDimensions(random, arr);
            return(GenArrayCreation(types, random, arr, dims));

        case InterfaceType it:
            return(GenLiteral(types, random, random.NextElement(types.GetImplementingTypes(it))));

        default:
            throw new Exception("Unreachable");
        }
    }
예제 #2
0
    public ArrayTypeSyntax GenReferenceToArrayType()
    {
        if (_type != null)
        {
            return(_type);
        }

        List <int> ranks = new() { Rank };
        // int[][] => ArrayType(ArrayType(Int, 1), 1)
        // int[][,] => ArrayType(ArrayType(Int, 2), 1)
        FuzzType innerElem = ElementType;

        while (innerElem is ArrayType at)
        {
            ranks.Add(at.Rank);
            innerElem = at.ElementType;
        }

        _type = ArrayType(
            innerElem.GenReferenceTo(),
            ranks.Select(
                r =>
                ArrayRankSpecifier(
                    SeparatedList(
                        Enumerable.Repeat((ExpressionSyntax)OmittedArraySizeExpression(), r)))).ToSyntaxList());

        return(_type);
    }
예제 #3
0
        private ExpressionSyntax GenNewObject(FuzzType type)
        {
            if (!(type is AggregateType at))
            {
                return(null);
            }

            ObjectCreationExpressionSyntax creation =
                ObjectCreationExpression(type.GenReferenceTo())
                .WithArgumentList(
                    ArgumentList(
                        SeparatedList(
                            at.Fields.Select(f => Argument(GenExpression(f.Type))))));

            return(creation);
        }
예제 #4
0
        private ExpressionSyntax GenCall(FuzzType type, bool allowNew)
        {
            Debug.Assert(!(type is RefType), "Cannot GenCall to ref type -- use GenExistingLValue for that");

            FuncGenerator func;

            if (allowNew && Random.FlipCoin(Options.GenNewMethodProb))
            {
                type = type ?? Types.PickType(Options.ReturnTypeIsByRefProb);

                func = new FuncGenerator(_funcs, Random, Types, Statics, _genChecksumSiteId);
                func.Generate(type, true);
            }
            else
            {
                IEnumerable <FuncGenerator> funcs = _funcs.Skip(_funcIndex + 1);
                if (type != null)
                {
                    funcs = funcs.Where(f => f.ReturnType.IsCastableTo(type) || (f.ReturnType is RefType rt && rt.InnerType.IsCastableTo(type)));
                }

                List <FuncGenerator> list = funcs.ToList();
                if (list.Count == 0)
                {
                    return(null);
                }

                func = Random.NextElement(list);
                type = type ?? func.ReturnType;
            }

            ArgumentSyntax[]           args  = GenArgs(func, 0, out _);
            InvocationExpressionSyntax invoc =
                InvocationExpression(
                    IdentifierName(func.Name),
                    ArgumentList(
                        SeparatedList(args)));

            if (func.ReturnType == type || func.ReturnType is RefType retRt && retRt.InnerType == type)
            {
                return(invoc);
            }

            return(CastExpression(type.GenReferenceTo(), invoc));
        }
예제 #5
0
 private ExpressionSyntax GenCast(FuzzType type)
 {
     return(CastExpression(type.GenReferenceTo(), GenExpression(type)));
 }
예제 #6
0
        private ExpressionSyntax GenCall(FuzzType type, bool allowNew)
        {
            Debug.Assert(!(type is RefType), "Cannot GenCall to ref type -- use GenExistingLValue for that");

            FuncGenerator func;

            if (allowNew && Random.FlipCoin(Options.GenNewFunctionProb) && !Options.FuncGenRejection.Reject(_funcs.Count, Random.Rng))
            {
                type = type ?? Types.PickType(Options.ReturnTypeIsByRefProb);

                func = new FuncGenerator(_funcs, Random, Types, Statics, _genChecksumSiteId);
                func.Generate(type, true);
            }
            else
            {
                IEnumerable <FuncGenerator> funcs =
                    _funcs
                    .Skip(_funcIndex + 1)
                    .Where(candidate =>
                {
                    // Make sure we do not get too many leaf calls. Here we compute what the new transitive
                    // number of calls would be to each function, and if it's too much, reject this candidate.
                    // Note that we will never reject calling a leaf function directly, even if the +1 puts
                    // us over the cap. That is intentional. We only want to limit the exponential growth
                    // which happens when functions call functions multiple times, and those functions also
                    // call functions multiple times.
                    foreach (var(transFunc, transNumCall) in candidate._callCountMap)
                    {
                        _callCountMap.TryGetValue(transFunc, out long curNumCalls);
                        if (curNumCalls + transNumCall > Options.SingleFunctionMaxTotalCalls)
                        {
                            return(false);
                        }
                    }

                    return(true);
                });

                if (type != null)
                {
                    funcs = funcs.Where(f => f.ReturnType.IsCastableTo(type) || (f.ReturnType is RefType rt && rt.InnerType.IsCastableTo(type)));
                }

                List <FuncGenerator> list = funcs.ToList();
                if (list.Count == 0)
                {
                    return(null);
                }

                func = Random.NextElement(list);
                type = type ?? func.ReturnType;
            }

            // Update transitive call counts before generating args, so we decrease chance of
            // calling the same methods in the arg expressions.
            _callCountMap.TryGetValue(func._funcIndex, out long numCalls);
            _callCountMap[func._funcIndex] = numCalls + 1;

            foreach (var(transFunc, transNumCalls) in func._callCountMap)
            {
                _callCountMap.TryGetValue(transFunc, out long curNumCalls);
                _callCountMap[transFunc] = curNumCalls + transNumCalls;
            }

            ArgumentSyntax[]           args  = GenArgs(func, 0, out _);
            InvocationExpressionSyntax invoc =
                InvocationExpression(
                    IdentifierName(func.Name),
                    ArgumentList(
                        SeparatedList(args)));

            if (func.ReturnType == type || func.ReturnType is RefType retRt && retRt.InnerType == type)
            {
                return(invoc);
            }

            return(CastExpression(type.GenReferenceTo(), invoc));
        }
예제 #7
0
        private StatementSyntax GenAssignmentStatement()
        {
            LValueInfo lvalue = null;

            if (!Random.FlipCoin(Options.AssignToNewVarProb))
            {
                lvalue = GenExistingLValue(null, int.MinValue);
            }

            if (lvalue == null)
            {
                FuzzType newType = Types.PickType(Options.LocalIsByRefProb);
                // Determine if we should create a new local. We do this with a certain probabilty,
                // or always if the new type is a by-ref type (we cannot have static by-refs).
                if (newType is RefType || Random.FlipCoin(Options.NewVarIsLocalProb))
                {
                    VariableIdentifier variable;
                    string             varName = $"var{_varCounter++}";
                    ExpressionSyntax   rhs;
                    if (newType is RefType newRt)
                    {
                        LValueInfo rhsLV = GenLValue(newRt.InnerType, int.MinValue);
                        variable = new VariableIdentifier(newType, varName, rhsLV.RefEscapeScope);
                        rhs      = RefExpression(rhsLV.Expression);
                    }
                    else
                    {
                        rhs      = GenExpression(newType);
                        variable = new VariableIdentifier(newType, varName, -(_scope.Count - 1));
                    }

                    LocalDeclarationStatementSyntax decl =
                        LocalDeclarationStatement(
                            VariableDeclaration(
                                variable.Type.GenReferenceTo(),
                                SingletonSeparatedList(
                                    VariableDeclarator(variable.Name)
                                    .WithInitializer(
                                        EqualsValueClause(rhs)))));

                    _scope.Last().Variables.Add(variable);

                    return(decl);
                }

                StaticField newStatic = Statics.GenerateNewField(newType);
                lvalue = new LValueInfo(IdentifierName(newStatic.Var.Name), newType, int.MaxValue);
            }

            // Determine if we should generate a ref-reassignment. In that case we cannot do anything
            // clever, like generate compound assignments.
            FuzzType rhsType = lvalue.Type;

            if (lvalue.Type is RefType rt)
            {
                if (Random.FlipCoin(Options.AssignGenRefReassignProb))
                {
                    RefExpressionSyntax refRhs = RefExpression(GenLValue(rt.InnerType, lvalue.RefEscapeScope).Expression);
                    return
                        (ExpressionStatement(
                             AssignmentExpression(
                                 SyntaxKind.SimpleAssignmentExpression,
                                 lvalue.Expression,
                                 refRhs)));
                }

                // We have a ref-type, but are not generating a ref-reassign, so lift the type and make a normal assignment.
                rhsType = rt.InnerType;
            }

            SyntaxKind assignmentKind = SyntaxKind.SimpleAssignmentExpression;

            // Determine if we should generate compound assignment.
            if (rhsType.AllowedAdditionalAssignmentKinds.Length > 0 && Random.FlipCoin(Options.CompoundAssignmentProb))
            {
                assignmentKind = Random.NextElement(rhsType.AllowedAdditionalAssignmentKinds);
            }

            // Early our for simple cases.
            if (assignmentKind == SyntaxKind.PreIncrementExpression ||
                assignmentKind == SyntaxKind.PreDecrementExpression)
            {
                return(ExpressionStatement(PrefixUnaryExpression(assignmentKind, lvalue.Expression)));
            }

            if (assignmentKind == SyntaxKind.PostIncrementExpression ||
                assignmentKind == SyntaxKind.PostDecrementExpression)
            {
                return(ExpressionStatement(PostfixUnaryExpression(assignmentKind, lvalue.Expression)));
            }

            // Right operand of shifts are always ints.
            if (assignmentKind == SyntaxKind.LeftShiftAssignmentExpression ||
                assignmentKind == SyntaxKind.RightShiftAssignmentExpression)
            {
                rhsType = Types.GetPrimitiveType(SyntaxKind.IntKeyword);
            }

            ExpressionSyntax right = GenExpression(rhsType);

            // For modulo and division we don't want to throw divide-by-zero exceptions,
            // so always or right-hand-side with 1.
            if (assignmentKind == SyntaxKind.ModuloAssignmentExpression ||
                assignmentKind == SyntaxKind.DivideAssignmentExpression)
            {
                right =
                    CastExpression(
                        rhsType.GenReferenceTo(),
                        ParenthesizedExpression(
                            BinaryExpression(
                                SyntaxKind.BitwiseOrExpression,
                                ParenthesizeIfNecessary(right),
                                LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(1)))));
            }

            return(ExpressionStatement(AssignmentExpression(assignmentKind, lvalue.Expression, right)));
        }
예제 #8
0
        private StatementSyntax GenAssignmentStatement()
        {
            ExpressionSyntax lhs  = null;
            FuzzType         type = null;

            if (!Random.FlipCoin(Options.AssignToNewVarProb))
            {
                (lhs, type) = GenMemberAccess(ft => true);
            }

            if (lhs == null)
            {
                type = Types.PickType();
                if (Random.FlipCoin(Options.NewVarIsLocalProb))
                {
                    VariableIdentifier variable = new VariableIdentifier(type, $"var{_varCounter++}");

                    LocalDeclarationStatementSyntax decl =
                        LocalDeclarationStatement(
                            VariableDeclaration(
                                variable.Type.GenReferenceTo(),
                                SingletonSeparatedList(
                                    VariableDeclarator(variable.Name)
                                    .WithInitializer(
                                        EqualsValueClause(
                                            GenExpression(variable.Type))))));

                    _scope.Last().Variables.Add(variable);

                    return(decl);
                }

                StaticField newStatic = Statics.GenerateNewField(type);
                lhs = IdentifierName(newStatic.Var.Name);
            }

            SyntaxKind assignmentKind = SyntaxKind.SimpleAssignmentExpression;

            if (type.AllowedAdditionalAssignmentKinds.Length > 0 && Random.FlipCoin(Options.FancyAssignmentProb))
            {
                assignmentKind = Random.NextElement(type.AllowedAdditionalAssignmentKinds);
            }

            if (assignmentKind == SyntaxKind.PreIncrementExpression ||
                assignmentKind == SyntaxKind.PreDecrementExpression)
            {
                return(ExpressionStatement(PrefixUnaryExpression(assignmentKind, lhs)));
            }

            if (assignmentKind == SyntaxKind.PostIncrementExpression ||
                assignmentKind == SyntaxKind.PostDecrementExpression)
            {
                return(ExpressionStatement(PostfixUnaryExpression(assignmentKind, lhs)));
            }

            if (assignmentKind == SyntaxKind.LeftShiftAssignmentExpression ||
                assignmentKind == SyntaxKind.RightShiftAssignmentExpression)
            {
                type = Types.GetPrimitiveType(SyntaxKind.IntKeyword);
            }

            ExpressionSyntax right = GenExpression(type);

            if (assignmentKind == SyntaxKind.ModuloAssignmentExpression ||
                assignmentKind == SyntaxKind.DivideAssignmentExpression)
            {
                right =
                    CastExpression(
                        type.GenReferenceTo(),
                        ParenthesizedExpression(
                            BinaryExpression(
                                SyntaxKind.BitwiseOrExpression,
                                ParenthesizeIfNecessary(right),
                                LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(1)))));
            }

            return(ExpressionStatement(AssignmentExpression(assignmentKind, lhs, right)));
        }