// Matrix row C9: detector-side FixIt emission for UninitLocalRead + // DeprecatedApi. // // Pin: // 1. UninitLocalRead on `int x;` emits exactly one FixIt with // replacement ` = 0` inserted just before the `;`. // 2. UninitLocalRead on non-scalar locals (struct, array) emits // no FixIt — fold doesn't yet know the right zero-init form. // 3. DeprecatedApi with message containing `Use foo() instead` // emits a FixIt replacing the call expression with `foo()`. // 4. DeprecatedApi without a parseable replacement emits no // FixIt (silent skip, not a hallucinated rewrite). #include #include #include #include #include #include "fold/detect/deprecated_api.hpp" #include "fold/detect/uninit_local_read.hpp" #include "fold/report/finding.hpp" namespace { std::unique_ptr parse(const std::string& code) { return clang::tooling::buildASTFromCodeWithArgs(code, {"-std=c++20"}, "input.cpp"); } } // namespace TEST_CASE("c9 uninit-local-read: emits zero-init FixIt for int scalar", "[c9][uninit-local-read][int]") { auto unit = parse(R"( int leak() { int x; return x; } )"); REQUIRE(unit); auto findings = fold::detectUninitLocalReadInContext(unit->getASTContext()); REQUIRE(findings.size() >= 1); bool found_fix = false; for (const auto& f : findings) { for (const auto& fix : f.fix_its) { if (fix.replacement == " = 0") { found_fix = true; break; } } } REQUIRE(found_fix); } TEST_CASE("c9 uninit-local-read: no FixIt for non-scalar locals", "[c9][uninit-local-read][non-scalar]") { auto unit = parse(R"( struct S { int a; int b; }; int leak() { struct S s; return s.a; } )"); REQUIRE(unit); auto findings = fold::detectUninitLocalReadInContext(unit->getASTContext()); for (const auto& f : findings) REQUIRE(f.fix_its.empty()); } TEST_CASE("c9 deprecated-api: parses `Use foo() instead` from message", "[c9][deprecated-api][replace]") { auto unit = parse(R"( [[deprecated("Use foo() instead")]] int legacy(); int foo(); int caller() { return legacy(); } )"); REQUIRE(unit); auto findings = fold::detectDeprecatedApiInContext(unit->getASTContext()); REQUIRE(findings.size() == 1); REQUIRE(findings[0].fix_its.size() == 1); REQUIRE(findings[0].fix_its[0].replacement == "foo()"); } TEST_CASE("c9 deprecated-api: unparseable message yields no FixIt", "[c9][deprecated-api][no-replace]") { auto unit = parse(R"( [[deprecated("this is bad")]] int legacy(); int caller() { return legacy(); } )"); REQUIRE(unit); auto findings = fold::detectDeprecatedApiInContext(unit->getASTContext()); REQUIRE(findings.size() == 1); REQUIRE(findings[0].fix_its.empty()); }