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"); } }
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); }
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); }
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)); }
private ExpressionSyntax GenCast(FuzzType type) { return(CastExpression(type.GenReferenceTo(), GenExpression(type))); }
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)); }
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))); }
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))); }