3

I'm a novice for Clang who is trying to analyze AST via libtooling. I want to find a particular function, and move its AST from original source file to a new file.

I've known how to find the function by MatchFinder. Now, I was wondering how to write its AST to a new file(.c or .cpp)

Thanks in advance!

4

1 回答 1

6

摘要:要获取源文本,请使用SourceManager; 要从原始文件中删除该函数,请生成 aReplacement并将其与 a 一起应用RefactoringTool

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

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

Callback 的 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_end和有什么关系decl_end_end?使用 SourceRange 有一个问题:结束位置不是代码结束的地方;它是范围内最后一个标记的开始。因此,如果我们使用 SourceManagerdecl_range.getEnd()进行函数定义,我们将不会得到右花括号。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 有函数的源代码;您可以写入新文件等。

为了消除原始文件中的函数源,我们可以生成一个替换,并让重构工具为我们应用它。要创建替换,我们需要再添加两行代码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 的 apps/FunctionMover.cc 中添加了一个工作示例应用程序,这是 Clang 重构示例的集合

于 2017-03-19T19:30:06.507 回答