zoukankan      html  css  js  c++  java
  • Clang教程之实现源源变化(2)

    前边的一个随笔里边就写了使用Clang来进行源源变化的一个case,其实还有很多有趣的可以进行的操作。比如,我们可以用添加宏的方式,实现对函数体的修改。

    主要代码如下:

    //------------------------------------------------------------------------------
    // 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/Frontend/ASTConsumers.h"
    #include "clang/Frontend/CompilerInstance.h"
    #include "clang/Frontend/FrontendActions.h"
    #include "clang/Rewrite/Core/Rewriter.h"
    #include "clang/Tooling/CommonOptionsParser.h"
    #include "clang/Tooling/Tooling.h"
    #include "llvm/Support/raw_ostream.h"
    
    using namespace clang;
    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> {
    public:
      MyASTVisitor(Rewriter &R) : TheRewriter(R) {}
    
    
      bool VisitFunctionDecl(FunctionDecl *f) {
        // Only function definitions (with bodies), not declarations.
        if (f->hasBody()) {
          Stmt *FuncBody = f->getBody();
    
          SourceLocation slStart = FuncBody->getBeginLoc();
          SourceLocation slEnd   = FuncBody->getEndLoc();
          
          std::stringstream fbBefore ;
          fbBefore <<";
    #if 0
    
    ";
          TheRewriter.InsertText(slStart, fbBefore.str(), true, true);
    
          std::stringstream fbEnd;
          fbEnd <<"}
    #endif
    ";
          TheRewriter.ReplaceText(slEnd, fbEnd.str());
          
        }
    
        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.
      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;
    };
    
    // 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() << "
    ";
    
        // Now emit the rewritten buffer.
        TheRewriter.getEditBuffer(SM.getMainFileID()).write(llvm::outs());
      }
    
      std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
                                                     StringRef file) override {
        llvm::errs() << "** Creating AST consumer for: " << file << "
    ";
        TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
        return std::make_unique<MyASTConsumer>(TheRewriter);
      }
    
    private:
      Rewriter TheRewriter;
    };
    
    int main(int argc, const char **argv) {
      llvm::Expected<CommonOptionsParser> op=CommonOptionsParser::create(argc, argv, ToolingSampleCategory);
      
      ClangTool Tool(op.get().getCompilations(), op.get().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>().get());
    }

    我在这里使用的case叫test.cpp,内容如下:

    void foo(int* a, int *b)
    {
        if (a[0] > 1)
        {
            b[0] = 2;
        }
    }
    
    int main(){
    
        return 0;
    }

    结果截图如下:

     或许后边会考虑做一个直接使用Clang的AST接口来实现一个函数的新增?

  • 相关阅读:
    POJ 2236 Wireless Network(并查集)
    POJ 2010 Moo University
    POJ 3614 Sunscreen(贪心,区间单点匹配)
    POJ 2184 Cow Exhibition(背包)
    POJ 1631 Bridging signals(LIS的等价表述)
    POJ 3181 Dollar Dayz(递推,两个long long)
    POJ 3046 Ant Counting(递推,和号优化)
    POJ 3280 Cheapest Palindrome(区间dp)
    POJ 3616 Milking Time(dp)
    POJ 2385 Apple Catching(01背包)
  • 原文地址:https://www.cnblogs.com/jourluohua/p/14517145.html
Copyright © 2011-2022 走看看