Модификация clang AST с помощью плагина - PullRequest
0 голосов
/ 13 января 2020

Я хотел бы изменить Clang AST с помощью плагина. У меня есть следующие предложения по использованию объекта Clang Rewriter. Я использую compiler.createDefaultOutputFile (), чтобы получить выходной поток для записи измененного файла в него. компиляция работает нормально, но сгенерированный объектный файл поврежден. Я получаю следующую ошибку компоновщика: «Формат файла не распознан».

Командная строка сборки: clang ++ - 8 -Xclang -load -Xclang libcashpp.so -Xclang -add-plugin -Xclang ca sh -pp test. cpp

Вывод сборки: /tmp/test-eb7d3d.o: файл не распознан: формат файла не распознан

Вопрос: - Возможно ли обновить AST с помощью лязгать плагин? - Может кто-нибудь указать мне пример программы, которая делает это?

Исходный код:

#include <clang/Frontend/FrontendPluginRegistry.h>
#include <clang/AST/AST.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include "clang/Rewrite/Core/Rewriter.h"
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Sema/Sema.h>
#include <llvm/Support/raw_ostream.h>
#include <string>
#include <sstream>

namespace {

class VarDeclVisitor : public clang::RecursiveASTVisitor<VarDeclVisitor> {
public:  
  VarDeclVisitor(clang::Rewriter& rewriter)
    : rewriter_(rewriter)
  {}

bool VisitCallExpr(clang::CallExpr *ce) {
    auto q = ce->getType();
    auto t = q.getTypePtrOrNull();
    if (t != NULL) {
      auto callee = ce->getDirectCallee();
      auto funcName = callee->getNameInfo().getAsString();      
      if (funcName == "getInstanceName") {        
        rewriter_.ReplaceText(ce->getBeginLoc(), callee->getIdentifier()->getName().size(), "getInstanceName2");
      }
    }
    return true;
  }
private:
  clang::Rewriter& rewriter_;
};

class MyASTConsumer : public clang::ASTConsumer {
  using Base = clang::ASTConsumer;
public:
  MyASTConsumer(std::unique_ptr<llvm::raw_pwrite_stream>&& os)
    : os_(std::move(os))
  {}

  void HandleTranslationUnit(clang::ASTContext &context) override {
    clang::Rewriter rewriter(context.getSourceManager(), context.getLangOpts());
    VarDeclVisitor visitor(rewriter);
    auto &source_manager = context.getSourceManager();
    const auto &mainFileID = source_manager.getMainFileID();
    const auto &decls = context.getTranslationUnitDecl()->decls();
    for (auto &decl : decls) {
      const auto &fileID = source_manager.getFileID(decl->getLocation());
      if (fileID != mainFileID)
        continue;
      visitor.TraverseDecl(decl);
    }   

    auto rwbuf = rewriter.getRewriteBufferFor(mainFileID);
    if (rwbuf) {
      *os_ << std::string(rwbuf->begin(), rwbuf->end());
    } else {
      *os_ << source_manager.getBufferData(mainFileID);
    }
  }

private:
  std::unique_ptr<llvm::raw_pwrite_stream> os_;
};

class MyPlugin : public clang::PluginASTAction {
public:
  std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance &compiler,
                                                        llvm::StringRef inFile) override {
    auto os = compiler.createDefaultOutputFile(false, inFile, "cpp");
    if (!os)
      return nullptr;
    return std::make_unique<MyASTConsumer>(std::move(os));
  }

  bool ParseArgs(const clang::CompilerInstance &compiler,
                 const std::vector<std::string> &args) override {
    return true;
  }

  void PrintHelp(llvm::raw_ostream &ros) {}
};

}

static clang::FrontendPluginRegistry::Add<MyPlugin>
    X("cash-pp", "My plugin");

Спасибо, -Blaise

...