• Clang教程之实现源源变化


    这篇博客是之前就写过的,因为最近在制作一个新的系列教程,又重新下载了最新的clang/llvm,因此准备更新一下,因此本篇中仅描述新(13.0)旧(4.0)的不同,原文地址:https://www.cnblogs.com/jourluohua/p/9526663.html

    基本可以这么说,实现思路没有变化,只有部分函数API发生了变化,我也会额外强调下。 从4.0到13.0,clang前端丰富了非常多,在现在的clang/tools下可以看到非常多的Tooling,因此整个文件夹被我提升到了clang/tools/extra下,没有了原来的loop-convert一层,现在的Cmake版本也需要3.10版本以上,同时现在的cmake要求文件夹名字和库名字不能相同,CMakeLists.txt文件也发生了变化,需要增加attr进行标识。关键的CMakeLists.txt变成了:

    set(LLVM_LINK_COMPONENTS support)
    
    add_clang_executable(loop-convert
      LoopConvert.cpp
      )
    target_link_libraries(loop-convert
      PRIVATE
      clangTooling
      clangBasic
      clangASTMatchers
      )
    

    同时,LoopConveret.cpp中代码变为了:

    //------------------------------------------------------------------------------
    // 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 VisitStmt(Stmt *s) {
        // Only care about If statements.
        if (isa<IfStmt>(s)) {
          IfStmt *IfStatement = cast<IfStmt>(s);
          Stmt *Then = IfStatement->getThen();
    
          TheRewriter.InsertText(Then->getBeginLoc(), "// the 'if' part
    ", true,
                                 true);
    
          Stmt *Else = IfStatement->getElse();
          if (Else)
            TheRewriter.InsertText(Else->getBeginLoc(), "// the 'else' part
    ",
                                   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();
          std::string TypeStr = QT.getAsString();
    
          // Function name
          DeclarationName DeclName = f->getNameInfo().getName();
          std::string FuncName = DeclName.getAsString();
    
          // Add comment before
          std::stringstream SSBefore;
          SSBefore << "// Begin function " << FuncName << " returning " << TypeStr
                   << "
    ";
          SourceLocation ST = f->getSourceRange().getBegin();
          TheRewriter.InsertText(ST, SSBefore.str(), true, true);
    
          // And after
          std::stringstream SSAfter;
          SSAfter << "
    // End function " << FuncName;
          ST = FuncBody->getEndLoc().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.
      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());
    }
    

    主要是原来是用getLocStart()->getBeginLoc()
    getLocEnd() ->getEndLoc()
    还有一个是新的llvm中添加了很多错误判断和状态控制的机制,返回值通常被包在Expected中,需要使用get()函数获取对象,也可以使用takeError()来获取错误返回值。

  • 相关阅读:
    NOI online2022题解
    【考试总结】20220331
    【考试总结】20220329
    【考试总结】20220327
    【考试总结】20220328
    【考试总结】20220326
    ElementUI使用vif控制tab标签显示遇到的Duplicate keys detected: 'xxx' 数据主键key重复
    ElementUI 的Tree Tree 菜单树形控件
    Element表格单元格的几种点击事件
    haproxy安装步骤及注意事项
  • 原文地址:https://www.cnblogs.com/jourluohua/p/14514274.html
Copyright © 2020-2023  润新知