Clang:将函数的AST从原始文件写入新文件

时间:2017-03-17 15:11:41

标签: clang libtooling

我是Clang的新手,他试图通过libtooling分析AST。 我想找到一个特定的函数,并将其AST从原始源文件移动到新文件。

我已经知道如何通过MatchFinder找到该功能。 现在,我想知道如何将其AST写入新文件(.c或.cpp)

提前致谢!

1 个答案:

答案 0 :(得分:4)

摘要:要获取源文本,请使用SourceManager;要从原始文件中删除该功能,请生成Replacement并将其应用于RefactoringTool

首先,这里有一种方法来获取函数定义的源代码,假设AST匹配器看起来像这样:

auto matcher(std::string const & fname) {
  return functionDecl(hasName(fname)).bind("f_decl");
}

回调的run方法将首先访问匹配的AST节点,获取函数声明所涵盖的源范围,并获取SouceManager的引用,该引用将SourceLocation对象与实际源相关联:

virtual void run(MatchResult_t const & result) override {
  using namespace clang;
  FunctionDecl * f_decl = const_cast<FunctionDecl *>(
      result.Nodes.getNodeAs<FunctionDecl>("f_decl"));
  if(f_decl) {
    SourceManager &sm(result.Context->getSourceManager());
    SourceRange decl_range(f_decl->getSourceRange());
    SourceLocation decl_begin(decl_range.getBegin());
    SourceLocation decl_start_end(decl_range.getEnd());
    SourceLocation decl_end_end( end_of_the_end( decl_start_end,sm));

decl_start_enddecl_end_end的内容是什么?使用SourceRange有一个问题:结束位置不是代码结束的位置;它是范围中最后一个标记的开头。因此,如果我们使用decl_range.getEnd()转到SourceManager进行函数定义,我们将无法获得结束大括号。 end_of_the_end()使用词法分析器来获取代码最后一位的位置:

SourceLocation
end_of_the_end(SourceLocation const & start_of_end, SourceManager & sm){
  LangOptions lopt;
  return Lexer::getLocForEndOfToken(start_of_end, 0, sm, lopt);
}

回到run(),使用准确的开始和结束位置,您可以获得指向SourceManager的字符缓冲区的指针:

    const char * buff_begin( sm.getCharacterData(decl_begin));
    const char * buff_end( sm.getCharacterData(decl_end_end));
    std::string const func_string(buff_begin,buff_end);

func_string具有该函数的源代码;你可以写新文件等。

要消除原始文件中的函数源,我们可以生成替换,让RefactoringTool为我们应用。要创建替换,我们需要向run()添加两行代码:

    uint32_t const decl_length =
      sm.getFileOffset(decl_end_end) - sm.getFileOffset(decl_begin);
    Replacement repl(sm,decl_begin,decl_length,"");

Replacement ctor获取SourceManager,开始替换的位置,覆盖的数量以及覆盖的内容。此替换用任何内容覆盖整个原始函数定义。

我们如何获得RefactoringTool的替换?我们可以通过引用RefactoringTool的Replacements成员来构造回调类。在run中,可以得出结论:

    repls_.insert(repl);

我已在CoARCT, a collection of Clang refactoring examples的apps / FunctionMover.cc中添加了一个有效的示例应用程序。

相关问题