citrun

watch C/C++ source code execute
Log | Files | Refs | LICENSE

commit 866fff20c320ccde33b9f38e7f31522994f9585a
parent f6816e0970e4abe3b5c9eb8c8ce328d7b73cf800
Author: kyle <kyle@getaddrinfo.net>
Date:   Sun, 25 Oct 2015 16:29:32 -0600

instrument: upgrade to latest source code rewriter example

- this also doesn't dump core anymore

Diffstat:
MMakefile | 4++--
Minstrument.cpp | 224+++++++++++++++++++++++++++++++++++--------------------------------------------
2 files changed, 100 insertions(+), 128 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,6 +1,6 @@ CXXFLAGS += -I/usr/local/include CXXFLAGS += -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -CXXFLAGS += -std=c++1y -fno-rtti +CXXFLAGS += -std=c++1y -fno-rtti -g CXX = eg++ LDLIBS += \ @@ -9,7 +9,7 @@ LDLIBS += \ -lclangSema -lclangStaticAnalyzerFrontend \ -lclangStaticAnalyzerCheckers -lclangStaticAnalyzerCore \ -lclangAnalysis -lclangARCMigrate -lclangRewriteCore -lclangRewriteFrontend \ - -lclangEdit -lclangAST -lclangLex -lclangBasic \ + -lclangEdit -lclangAST -lclangLex -lclangBasic -lclangTooling \ -lLLVMOption -lLLVMMCParser -lLLVMTransformUtils -lLLVMMC -lLLVMBitReader -lLLVMCore -lLLVMSupport \ -lpthread -lz diff --git a/instrument.cpp b/instrument.cpp @@ -1,172 +1,144 @@ -#include <cstdio> -#include <string> +//------------------------------------------------------------------------------ +// Tooling sample. Demonstrates: +// +// * How to write a simple source tool using libTooling. +// * How to use RecursiveASTVisitor to find interesting AST nodes. +// * How to use the Rewriter API to rewrite the source code. +// +// Eli Bendersky (eliben@gmail.com) +// This code is in the public domain +//------------------------------------------------------------------------------ #include <sstream> +#include <string> +#include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/RecursiveASTVisitor.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/TargetOptions.h" -#include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/CompilerInstance.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Parse/ParseAST.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Tooling.h" #include "clang/Rewrite/Core/Rewriter.h" -#include "clang/Rewrite/Frontend/Rewriters.h" -#include "llvm/Support/Host.h" #include "llvm/Support/raw_ostream.h" using namespace clang; -using namespace std; +using namespace clang::driver; +using namespace clang::tooling; +static llvm::cl::OptionCategory ToolingSampleCategory("Tooling Sample"); // By implementing RecursiveASTVisitor, we can specify which AST nodes // we're interested in by overriding relevant methods. -class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> -{ +class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> { public: - MyASTVisitor(Rewriter &R) - : TheRewriter(R) - {} + MyASTVisitor(Rewriter &R) : TheRewriter(R) {} bool VisitStmt(Stmt *s) { - - TheRewriter.InsertTextAfter(s->getLocEnd(), - "// <- statement here"); - // Only care about If statements. if (isa<IfStmt>(s)) { IfStmt *IfStatement = cast<IfStmt>(s); Stmt *Then = IfStatement->getThen(); - TheRewriter.InsertText(Then->getLocStart(), - "// the 'if' part\n", - true, true); + TheRewriter.InsertText(Then->getLocStart(), "// the 'if' part\n", true, + true); Stmt *Else = IfStatement->getElse(); if (Else) - TheRewriter.InsertText(Else->getLocStart(), - "// the 'else' part\n", + TheRewriter.InsertText(Else->getLocStart(), "// the 'else' part\n", true, true); } return true; } - bool VisitFunctionDecl(FunctionDecl *f) { - // Only function definitions (with bodies), not declarations. - if (f->hasBody()) { - Stmt *FuncBody = f->getBody(); - - // Type name as string - QualType QT = f->getReturnType(); - string TypeStr = QT.getAsString(); - - // Function name - DeclarationName DeclName = f->getNameInfo().getName(); - string FuncName = DeclName.getAsString(); - - // Add comment before - stringstream SSBefore; - SSBefore << "// Begin function " << FuncName << " returning " - << TypeStr << "\n"; - SourceLocation ST = f->getSourceRange().getBegin(); - TheRewriter.InsertText(ST, SSBefore.str(), true, true); - - // And after - stringstream SSAfter; - SSAfter << "\n// End function " << FuncName << "\n"; - ST = FuncBody->getLocEnd().getLocWithOffset(1); - TheRewriter.InsertText(ST, SSAfter.str(), true, true); - } + bool VisitFunctionDecl(FunctionDecl *f) { + // Only function definitions (with bodies), not declarations. + if (f->hasBody()) { + Stmt *FuncBody = f->getBody(); - return true; - } + // Type name as string + QualType QT = f->getReturnType(); + std::string TypeStr = QT.getAsString(); -private: - void AddBraces(Stmt *s); + // Function name + DeclarationName DeclName = f->getNameInfo().getName(); + std::string FuncName = DeclName.getAsString(); - Rewriter &TheRewriter; -}; + // Add comment before + std::stringstream SSBefore; + SSBefore << "// Begin function " << FuncName << " returning " << TypeStr + << "\n"; + SourceLocation ST = f->getSourceRange().getBegin(); + TheRewriter.InsertText(ST, SSBefore.str(), true, true); + // And after + std::stringstream SSAfter; + SSAfter << "\n// End function " << FuncName; + ST = FuncBody->getLocEnd().getLocWithOffset(1); + TheRewriter.InsertText(ST, SSAfter.str(), true, true); + } + + return true; + } + +private: + Rewriter &TheRewriter; +}; // Implementation of the ASTConsumer interface for reading an AST produced // by the Clang parser. -class MyASTConsumer : public ASTConsumer -{ - public: - MyASTConsumer(Rewriter &R) - : Visitor(R) - {} - - // Override the method that gets called for each parsed - // top-level declaration. - virtual bool HandleTopLevelDecl(DeclGroupRef DR) { - for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); - b != e; ++b) - // Traverse the declaration using our AST - // visitor. - Visitor.TraverseDecl(*b); - return true; +class MyASTConsumer : public ASTConsumer { +public: + MyASTConsumer(Rewriter &R) : Visitor(R) {} + + // Override the method that gets called for each parsed top-level + // declaration. + bool HandleTopLevelDecl(DeclGroupRef DR) override { + for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) { + // Traverse the declaration using our AST visitor. + Visitor.TraverseDecl(*b); + (*b)->dump(); } + return true; + } - private: - MyASTVisitor Visitor; +private: + MyASTVisitor Visitor; }; +// For each source file provided to the tool, a new FrontendAction is created. +class MyFrontendAction : public ASTFrontendAction { +public: + MyFrontendAction() {} + void EndSourceFileAction() override { + SourceManager &SM = TheRewriter.getSourceMgr(); + llvm::errs() << "** EndSourceFileAction for: " + << SM.getFileEntryForID(SM.getMainFileID())->getName() << "\n"; + + // Now emit the rewritten buffer. + TheRewriter.getEditBuffer(SM.getMainFileID()).write(llvm::outs()); + } -int main(int argc, char *argv[]) -{ - if (argc != 2) { - llvm::errs() << "Usage: rewritersample <filename>\n"; - return 1; + ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef file) override { + llvm::errs() << "** Creating AST consumer for: " << file << "\n"; + TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts()); + return new MyASTConsumer(TheRewriter); } - // CompilerInstance will hold the instance of the Clang compiler for us, - // managing the various objects needed to run the compiler. - CompilerInstance TheCompInst; - TheCompInst.createDiagnostics(NULL, false); - - // Initialize target info with the default triple for our platform. - TargetOptions TO; - TO.Triple = llvm::sys::getDefaultTargetTriple(); - // std::shared_ptr<TargetOptions> TO_shared (&TO); - TargetInfo *TI = TargetInfo::CreateTargetInfo( - TheCompInst.getDiagnostics(), &TO); - TheCompInst.setTarget(TI); - - TheCompInst.createFileManager(); - FileManager &FileMgr = TheCompInst.getFileManager(); - TheCompInst.createSourceManager(FileMgr); - SourceManager &SourceMgr = TheCompInst.getSourceManager(); - TheCompInst.createPreprocessor(); - TheCompInst.createASTContext(); - - // A Rewriter helps us manage the code rewriting task. +private: Rewriter TheRewriter; - TheRewriter.setSourceMgr(SourceMgr, TheCompInst.getLangOpts()); - - // Set the main file handled by the source manager to the input file. - const FileEntry *FileIn = FileMgr.getFile(argv[1]); - SourceMgr.createMainFileID(FileIn); - TheCompInst.getDiagnosticClient().BeginSourceFile( - TheCompInst.getLangOpts(), - &TheCompInst.getPreprocessor()); - - // Create an AST consumer instance which is going to get called by - // ParseAST. - MyASTConsumer TheConsumer(TheRewriter); - - // Parse the file to AST, registering our consumer as the AST consumer. - ParseAST(TheCompInst.getPreprocessor(), &TheConsumer, - TheCompInst.getASTContext()); - - // At this point the rewriter's buffer should be full with the rewritten - // file contents. - const RewriteBuffer *RewriteBuf = - TheRewriter.getRewriteBufferFor(SourceMgr.getMainFileID()); - llvm::outs() << string(RewriteBuf->begin(), RewriteBuf->end()); - - return 0; +}; + +int main(int argc, const char **argv) { + CommonOptionsParser op(argc, argv, ToolingSampleCategory); + ClangTool Tool(op.getCompilations(), op.getSourcePathList()); + + // ClangTool::run accepts a FrontendActionFactory, which is then used to + // create new objects implementing the FrontendAction interface. Here we use + // the helper newFrontendActionFactory to create a default factory that will + // return a new MyFrontendAction object every time. + // To further customize this, we could create our own factory class. + return Tool.run(newFrontendActionFactory<MyFrontendAction>()); }