#include "clang/AST/ASTConsumer.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/CommandLine.h" #include using namespace clang; using namespace clang::tooling; using namespace llvm; // Apply a custom category to all command-line options so that they are the // only ones displayed. static cl::OptionCategory MyToolCategory("my-tool options"); // CommonOptionsParser declares HelpMessage with a description of the common // command-line options related to the compilation database and input files. // It's nice to have this help message in all tools. static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); // A help message for this specific tool can be added afterwards. static cl::extrahelp MoreHelp("\nMore help text...\n"); class FunctionVisitor : public RecursiveASTVisitor { private: ASTContext *Context; public: explicit FunctionVisitor(ASTContext *Context) : Context(Context) {} bool VisitFunctionDecl(FunctionDecl *Declaration) { if (Declaration->hasBody()) { SourceManager &SM = Context->getSourceManager(); SourceLocation Loc = Declaration->getLocation(); if (SM.isInMainFile(Loc)) { std::string FuncName = Declaration->getNameInfo().getName().getAsString(); unsigned Line = SM.getExpansionLineNumber(Loc); spdlog::info("Found function '{}' at line {}", FuncName, Line); // Count parameters unsigned ParamCount = Declaration->getNumParams(); spdlog::debug(" - Function '{}' has {} parameters", FuncName, ParamCount); // Check if it's a main function if (FuncName == "main") { spdlog::warn("Found main function at line {}", Line); } } } return true; } bool VisitVarDecl(VarDecl *Declaration) { SourceManager &SM = Context->getSourceManager(); SourceLocation Loc = Declaration->getLocation(); if (SM.isInMainFile(Loc)) { std::string VarName = Declaration->getNameAsString(); unsigned Line = SM.getExpansionLineNumber(Loc); spdlog::debug("Found variable '{}' at line {}", VarName, Line); } return true; } }; class FunctionConsumer : public ASTConsumer { private: FunctionVisitor Visitor; public: explicit FunctionConsumer(ASTContext *Context) : Visitor(Context) {} void HandleTranslationUnit(ASTContext &Context) override { spdlog::info("Starting AST traversal..."); Visitor.TraverseDecl(Context.getTranslationUnitDecl()); spdlog::info("AST traversal completed"); } }; class FunctionAction : public ASTFrontendAction { public: std::unique_ptr CreateASTConsumer(CompilerInstance &Compiler, StringRef InFile) override { spdlog::info("Processing file: {}", InFile.str()); return std::make_unique(&Compiler.getASTContext()); } }; int main(int argc, const char **argv) { // Set up logging spdlog::set_level(spdlog::level::debug); spdlog::info("Starting clang tooling example"); auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory); if (!ExpectedParser) { // Fail gracefully for unsupported options. llvm::errs() << ExpectedParser.takeError(); return 1; } CommonOptionsParser &OptionsParser = ExpectedParser.get(); ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList()); spdlog::info("Running tool on {} source files", OptionsParser.getSourcePathList().size()); int Result = Tool.run(newFrontendActionFactory().get()); if (Result == 0) { spdlog::info("Tool completed successfully"); } else { spdlog::error("Tool failed with exit code {}", Result); } return Result; }