Path: blob/main/contrib/llvm-project/lldb/tools/lldb-instr/Instrument.cpp
34879 views
#include "clang/AST/AST.h"1#include "clang/AST/ASTConsumer.h"2#include "clang/AST/RecursiveASTVisitor.h"3#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"4#include "clang/Frontend/ASTConsumers.h"5#include "clang/Frontend/CompilerInstance.h"6#include "clang/Frontend/FrontendActions.h"7#include "clang/Rewrite/Core/Rewriter.h"8#include "clang/Tooling/CommonOptionsParser.h"9#include "clang/Tooling/Tooling.h"1011#include "llvm/ADT/StringExtras.h"12#include "llvm/ADT/StringRef.h"13#include "llvm/Support/raw_ostream.h"1415#include <sstream>16#include <string>1718using namespace clang;19using namespace clang::driver;20using namespace clang::tooling;2122static llvm::cl::OptionCategory InstrCategory("LLDB Instrumentation Generator");2324class SBVisitor : public RecursiveASTVisitor<SBVisitor> {25public:26SBVisitor(Rewriter &R, ASTContext &Context)27: MyRewriter(R), Context(Context) {}2829bool VisitCXXMethodDecl(CXXMethodDecl *Decl) {30// Not all decls should be registered. Please refer to that method's31// comment for details.32if (ShouldSkip(Decl))33return false;3435// Print 'bool' instead of '_Bool'.36PrintingPolicy Policy(Context.getLangOpts());37Policy.Bool = true;3839// Collect the functions parameter types and names.40std::vector<std::string> ParamNames;41if (!Decl->isStatic())42ParamNames.push_back("this");43for (auto *P : Decl->parameters())44ParamNames.push_back(P->getNameAsString());4546// Construct the macros.47std::string Buffer;48llvm::raw_string_ostream Macro(Buffer);49if (ParamNames.empty()) {50Macro << "LLDB_INSTRUMENT()";51} else {52Macro << "LLDB_INSTRUMENT_VA(" << llvm::join(ParamNames, ", ") << ")";53}5455Stmt *Body = Decl->getBody();56for (auto &C : Body->children()) {57if (C->getBeginLoc().isMacroID()) {58CharSourceRange Range =59MyRewriter.getSourceMgr().getExpansionRange(C->getSourceRange());60MyRewriter.ReplaceText(Range, Macro.str());61} else {62Macro << ";";63SourceLocation InsertLoc = Lexer::getLocForEndOfToken(64Body->getBeginLoc(), 0, MyRewriter.getSourceMgr(),65MyRewriter.getLangOpts());66MyRewriter.InsertTextAfter(InsertLoc, Macro.str());67}68break;69}7071return true;72}7374private:75/// Determine whether we need to consider the given CXXMethodDecl.76///77/// Currently we skip the following cases:78/// 1. Decls outside the main source file,79/// 2. Decls that are only present in the source file,80/// 3. Decls that are not definitions,81/// 4. Non-public methods,82/// 5. Variadic methods.83/// 6. Destructors.84bool ShouldSkip(CXXMethodDecl *Decl) {85// Skip anything outside the main file.86if (!MyRewriter.getSourceMgr().isInMainFile(Decl->getBeginLoc()))87return true;8889// Skip if the canonical decl in the current decl. It means that the method90// is declared in the implementation and is therefore not exposed as part91// of the API.92if (Decl == Decl->getCanonicalDecl())93return true;9495// Skip decls that have no body, i.e. are just declarations.96Stmt *Body = Decl->getBody();97if (!Body)98return true;99100// Skip non-public methods.101AccessSpecifier AS = Decl->getAccess();102if (AS != AccessSpecifier::AS_public)103return true;104105// Skip variadic methods.106if (Decl->isVariadic())107return true;108109// Skip destructors.110if (isa<CXXDestructorDecl>(Decl))111return true;112113return false;114}115116Rewriter &MyRewriter;117ASTContext &Context;118};119120class SBConsumer : public ASTConsumer {121public:122SBConsumer(Rewriter &R, ASTContext &Context) : Visitor(R, Context) {}123124// Override the method that gets called for each parsed top-level125// declaration.126bool HandleTopLevelDecl(DeclGroupRef DR) override {127for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {128Visitor.TraverseDecl(*b);129}130return true;131}132133private:134SBVisitor Visitor;135};136137class SBAction : public ASTFrontendAction {138public:139SBAction() = default;140141bool BeginSourceFileAction(CompilerInstance &CI) override { return true; }142143void EndSourceFileAction() override { MyRewriter.overwriteChangedFiles(); }144145std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,146StringRef File) override {147MyRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());148return std::make_unique<SBConsumer>(MyRewriter, CI.getASTContext());149}150151private:152Rewriter MyRewriter;153};154155int main(int argc, const char **argv) {156auto ExpectedParser = CommonOptionsParser::create(157argc, argv, InstrCategory, llvm::cl::OneOrMore,158"Utility for generating the macros for LLDB's "159"instrumentation framework.");160if (!ExpectedParser) {161llvm::errs() << ExpectedParser.takeError();162return 1;163}164CommonOptionsParser &OP = ExpectedParser.get();165166auto PCHOpts = std::make_shared<PCHContainerOperations>();167PCHOpts->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());168PCHOpts->registerReader(std::make_unique<ObjectFilePCHContainerReader>());169170ClangTool T(OP.getCompilations(), OP.getSourcePathList(), PCHOpts);171return T.run(newFrontendActionFactory<SBAction>().get());172}173174175