1111#include < clang/ASTMatchers/ASTMatchFinder.h>
1212#include < clang/ASTMatchers/ASTMatchers.h>
1313#include < clang/Frontend/FrontendActions.h>
14+ #include < clang/Lex/Lexer.h>
1415#include < clang/Sema/Initialization.h>
1516#include < clang/Sema/Lookup.h>
1617#include < clang/Sema/Overload.h>
1920#include < clang/Tooling/CompilationDatabase.h>
2021#include < clang/Tooling/Tooling.h>
2122
23+ #include < string>
24+ #include < unordered_map>
25+
2226#include " compat/platform_flags.h"
2327#include " converter/mapper.h"
2428
@@ -69,7 +73,9 @@ struct LookupInfo {
6973
7074class Callback : public clang ::ast_matchers::MatchFinder::MatchCallback {
7175public:
72- explicit Callback (llvm::json::Object &out) : out_(out) {}
76+ Callback (llvm::json::Object &out,
77+ std::unordered_map<std::string, std::string> &expected_funcs)
78+ : out_(out), expected_funcs_(expected_funcs) {}
7379
7480 void init (clang::Sema &sema) {
7581 sema_ = &sema;
@@ -80,6 +86,22 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
8086 void run (const clang::ast_matchers::MatchFinder::MatchResult &R) override {
8187 assert (sema_);
8288 Mapper::PushASTContext scoped (*R.Context );
89+
90+ if (auto efunc = R.Nodes .getNodeAs <clang::FunctionDecl>(" expected_func" )) {
91+ std::string body_src;
92+ if (auto *body = efunc->getBody ()) {
93+ auto &sm = R.Context ->getSourceManager ();
94+ auto &lo = R.Context ->getLangOpts ();
95+ body_src =
96+ clang::Lexer::getSourceText (
97+ clang::CharSourceRange::getTokenRange (body->getSourceRange ()),
98+ sm, lo)
99+ .str ();
100+ }
101+ expected_funcs_[efunc->getQualifiedNameAsString ()] = std::move (body_src);
102+ return ;
103+ }
104+
83105 if (auto var = R.Nodes .getNodeAs <clang::TypeAliasDecl>(" tvar" )) {
84106 clang::QualType type;
85107 if (auto *tdecl = var->getDescribedAliasTemplate ()) {
@@ -171,6 +193,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
171193
172194private:
173195 llvm::json::Object &out_;
196+ std::unordered_map<std::string, std::string> &expected_funcs_;
174197 clang::Sema *sema_ = nullptr ;
175198 clang::SourceLocation loc_;
176199
@@ -646,7 +669,9 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
646669
647670class ActionFactory : public clang ::tooling::FrontendActionFactory {
648671public:
649- explicit ActionFactory (llvm::json::Object &out) : cb_(out) {
672+ ActionFactory (llvm::json::Object &out,
673+ std::unordered_map<std::string, std::string> &expected_funcs)
674+ : cb_(out, expected_funcs) {
650675 using namespace clang ::ast_matchers;
651676 finder_.addMatcher (
652677 returnStmt (
@@ -675,6 +700,13 @@ class ActionFactory : public clang::tooling::FrontendActionFactory {
675700 typeAliasDecl (matchesName (" (^|::)t[0-9]+$" ), isExpansionInMainFile ())
676701 .bind (" tvar" ),
677702 &cb_);
703+
704+ // Collect every f<n> for the post-run diff against bound bodies.
705+ finder_.addMatcher (functionDecl (isDefinition (),
706+ matchesName (" (^|::)f[0-9]+$" ),
707+ isExpansionInMainFile ())
708+ .bind (" expected_func" ),
709+ &cb_);
678710 }
679711
680712 std::unique_ptr<clang::FrontendAction> create () override {
@@ -721,14 +753,28 @@ class ActionFactory : public clang::tooling::FrontendActionFactory {
721753
722754} // namespace
723755
724- void Extract (const std::filesystem::path &src_path, llvm::json::Object &out) {
756+ bool Extract (const std::filesystem::path &src_path, llvm::json::Object &out) {
725757 auto flags = getPlatformClangBeginFlags ();
726758 auto end_flags = getPlatformClangEndFlags ();
727759 flags.insert (flags.end (), end_flags.begin (), end_flags.end ());
728760 clang::tooling::FixedCompilationDatabase compilations (" ." , flags);
729- ActionFactory factory (out);
761+ std::unordered_map<std::string, std::string> expected_funcs;
762+ ActionFactory factory (out, expected_funcs);
730763 clang::tooling::ClangTool tool (compilations, {src_path.string ()});
731- tool.run (&factory);
764+ bool ok = (tool.run (&factory) == 0 );
765+
766+ for (const auto &[name, body_src] : expected_funcs) {
767+ if (out.find (name) == out.end ()) {
768+ llvm::errs () << src_path.string () << " : " << name
769+ << " : matcher did not bind to the function body.\n "
770+ << " body: " << body_src << ' \n '
771+ << " Likely cause: return expression shape not handled by "
772+ " rule_src_parser.cpp's ActionFactory matcher (e.g. a "
773+ " literal from a macro expansion).\n " ;
774+ ok = false ;
775+ }
776+ }
777+ return ok;
732778}
733779
734780} // namespace cpp2rust::RuleSrcParser
0 commit comments