// Phase 3 (int-truncation recall): explicit narrowing casts ((char)x, // static_cast(x)) carry the truncation in an inner ImplicitCast flagged // part_of_explicit_cast that no use site observes. The encoder now fires the // truncation hook for exactly those nodes — without double-counting ordinary // implicit narrowings, which are still observed at their use sites. #include #include #include #include #include #include #include "fold/detect/int_truncation.hpp" #include "fold/report/finding.hpp" #include "fold/symbolic/budget.hpp" namespace { std::size_t runTrunc(const std::string& body) { const std::string code = "extern int RAND32();\nvoid sink(char);\n" + body; auto unit = clang::tooling::buildASTFromCodeWithArgs(code, {"-std=c++17"}, "input.cpp"); REQUIRE(unit); fold::SolverBudget b; fold::SolverStats s; auto fs = fold::detectIntTruncationInContext(unit->getASTContext(), b, s); std::size_t n = 0; for (const auto& f : fs) if (f.kind == fold::FindingKind::IntTruncation) ++n; return n; } } // namespace TEST_CASE("explicit C-style narrowing cast is flagged", "[int-truncation][cast]") { REQUIRE(runTrunc("void f(short data){ char c = (char)data; sink(c); }") >= 1); } TEST_CASE("explicit static_cast narrowing is flagged", "[int-truncation][cast]") { REQUIRE(runTrunc("void f(short data){ char c = static_cast(data); sink(c); }") >= 1); } TEST_CASE("explicit narrowing cast in a call argument is flagged", "[int-truncation][cast]") { REQUIRE(runTrunc("void f(short data){ sink((char)data); }") >= 1); } TEST_CASE("implicit narrowing is still flagged exactly once", "[int-truncation][cast]") { // Must NOT double-count: the implicit cast is observed at the init use site, // not at the cast node. REQUIRE(runTrunc("void f(short data){ char c = data; sink(c); }") == 1); } TEST_CASE("explicit widening cast is not flagged", "[int-truncation][cast]") { REQUIRE(runTrunc("void f(char data){ int w = (int)data; sink((char)w); (void)w; }") == 1); // ^ exactly one: the (char)w narrowing fires; the (int)data widening does not. } TEST_CASE("same-width explicit cast is not flagged", "[int-truncation][cast]") { REQUIRE(runTrunc("void f(char data){ char c = (char)data; sink(c); }") == 0); }