| 569 | } // namespace |
| 570 | |
| 571 | ExpressionFuzzer::ExpressionFuzzer( |
| 572 | FunctionSignatureMap signatureMap, |
| 573 | size_t initialSeed, |
| 574 | const std::shared_ptr<VectorFuzzer>& vectorFuzzer, |
| 575 | const std::optional<ExpressionFuzzer::Options>& options) |
| 576 | : options_(options.value_or(Options())), |
| 577 | vectorFuzzer_(vectorFuzzer), |
| 578 | state{rng_, std::max(1, options_.maxLevelOfNesting)} { |
| 579 | BOLT_CHECK(vectorFuzzer, "Vector fuzzer must be provided"); |
| 580 | seed(initialSeed); |
| 581 | |
| 582 | appendSpecialForms(signatureMap, options_.specialForms); |
| 583 | filterSignatures( |
| 584 | signatureMap, options_.useOnlyFunctions, options_.skipFunctions); |
| 585 | |
| 586 | size_t totalFunctions = 0; |
| 587 | size_t totalFunctionSignatures = 0; |
| 588 | size_t supportedFunctionSignatures = 0; |
| 589 | // A local random number generator to be used just in ExpressionFuzzer |
| 590 | // constructor. We do not use rng_ in this function because code in this |
| 591 | // function may change rng_ and cause it to mismatch with the seed printed in |
| 592 | // the log. |
| 593 | FuzzerGenerator localRng{ |
| 594 | static_cast<FuzzerGenerator::result_type>(initialSeed)}; |
| 595 | // Process each available signature for every function. |
| 596 | for (const auto& function : signatureMap) { |
| 597 | ++totalFunctions; |
| 598 | bool atLeastOneSupported = false; |
| 599 | for (const auto& signature : function.second) { |
| 600 | ++totalFunctionSignatures; |
| 601 | |
| 602 | if (!isSupportedSignature(*signature, options_.enableComplexTypes)) { |
| 603 | continue; |
| 604 | } |
| 605 | if (!(signature->variables().empty() || options_.enableComplexTypes)) { |
| 606 | LOG(WARNING) << "Skipping unsupported signature: " << function.first |
| 607 | << signature->toString(); |
| 608 | continue; |
| 609 | } |
| 610 | if (signature->variableArity() && !options_.enableVariadicSignatures) { |
| 611 | LOG(WARNING) << "Skipping variadic function signature: " |
| 612 | << function.first << signature->toString(); |
| 613 | continue; |
| 614 | } |
| 615 | |
| 616 | // Determine a list of concrete argument types that can bind to the |
| 617 | // signature. For non-parameterized signatures, these argument types will |
| 618 | // be used to create a callable signature. For parameterized signatures, |
| 619 | // these argument types are only used to fetch the function instance to |
| 620 | // get their determinism. |
| 621 | std::vector<TypePtr> argTypes; |
| 622 | if (signature->variables().empty()) { |
| 623 | bool supportedSignature = true; |
| 624 | for (const auto& arg : signature->argumentTypes()) { |
| 625 | auto resolvedType = SignatureBinder::tryResolveType(arg, {}, {}); |
| 626 | if (!resolvedType) { |
| 627 | supportedSignature = false; |
| 628 | continue; |
nothing calls this directly
no test coverage detected