• 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接口来实现一个函数的新增?

  • 相关阅读:
    postgresql遇到的性能问题
    面试(三)
    Oracle的dmp文件的导入
    plsql的参数IN和OUT
    IT小说
    被关注应该也是一种强大-日经某文有感
    总结:安卓手机页面样式没问题,苹果手机样式错乱。
    前端开发人员要注意的css规范,css命名。
    水平,垂直居中的15种方法
    nuxt 的一些报错和插件推荐
  • 原文地址:https://www.cnblogs.com/jourluohua/p/14517145.html
Copyright © 2020-2023  润新知