// Matrix row C7 — deprecated-API detector. Flags call sites whose // target decl is marked `[[deprecated]]`, `__attribute__((deprecated))`, // or `__attribute__((availability(...,deprecated=...)))`. Uses // clang::Decl::isDeprecated under the hood. #include #include #include #include #include #include "fold/detect/deprecated_api.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("deprecated-api: [[deprecated]] call site is flagged", "[deprecated-api][cxx-attribute]") { auto unit = parse(R"( [[deprecated]] int legacy(); int caller() { return legacy(); } )"); REQUIRE(unit); auto findings = fold::detectDeprecatedApiInContext(unit->getASTContext()); REQUIRE(findings.size() == 1); REQUIRE(findings[0].kind == fold::FindingKind::DeprecatedApi); } TEST_CASE("deprecated-api: __attribute__((deprecated)) call site is flagged", "[deprecated-api][gnu-attribute]") { auto unit = parse(R"( __attribute__((deprecated)) int legacy(); int caller() { return legacy(); } )"); REQUIRE(unit); auto findings = fold::detectDeprecatedApiInContext(unit->getASTContext()); REQUIRE(findings.size() == 1); REQUIRE(findings[0].kind == fold::FindingKind::DeprecatedApi); } TEST_CASE("deprecated-api: deprecation message is carried into the finding", "[deprecated-api][message]") { auto unit = parse(R"( [[deprecated("use modern_api() instead")]] int legacy(); int caller() { return legacy(); } )"); REQUIRE(unit); auto findings = fold::detectDeprecatedApiInContext(unit->getASTContext()); REQUIRE(findings.size() == 1); REQUIRE(findings[0].message.find("use modern_api() instead") != std::string::npos); } TEST_CASE("deprecated-api: non-deprecated calls do not fire", "[deprecated-api][negative]") { auto unit = parse(R"( int modern(); int caller() { return modern(); } )"); REQUIRE(unit); auto findings = fold::detectDeprecatedApiInContext(unit->getASTContext()); REQUIRE(findings.empty()); } TEST_CASE("deprecated-api: declaration alone is not flagged (only call sites)", "[deprecated-api][decl-only]") { // A deprecated declaration without any call sites should produce // zero findings — the detector flags USE, not definition. auto unit = parse(R"( [[deprecated]] int legacy(); // no caller )"); REQUIRE(unit); auto findings = fold::detectDeprecatedApiInContext(unit->getASTContext()); REQUIRE(findings.empty()); } TEST_CASE("deprecated-api: multiple call sites produce multiple findings", "[deprecated-api][repeat]") { auto unit = parse(R"( [[deprecated]] int legacy(); int caller() { return legacy() + legacy(); } )"); REQUIRE(unit); auto findings = fold::detectDeprecatedApiInContext(unit->getASTContext()); REQUIRE(findings.size() == 2); } TEST_CASE("deprecated-api: deprecated method on a class is flagged", "[deprecated-api][method]") { auto unit = parse(R"( struct S { [[deprecated]] int legacy(); int modern(); }; int caller(S* s) { return s->legacy() + s->modern(); } )"); REQUIRE(unit); auto findings = fold::detectDeprecatedApiInContext(unit->getASTContext()); REQUIRE(findings.size() == 1); }