叮当声:将函数的AST从原始文件写入新文件 [英] Clang: write a function's AST from original file to a new file

查看:61
本文介绍了叮当声:将函数的AST从原始文件写入新文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

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

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)

提前谢谢!

推荐答案

摘要:要获取源文本,请使用 SourceManager ;要从原始文件中删除该功能,请生成一个 Replacement ,然后将其与 RefactoringTool 一起应用.

Summary: to get the source text, work with the SourceManager; to remove the function from the original file, generate a Replacement and apply it with a RefactoringTool.

首先,这是一种获取函数定义源代码的方法,假设AST匹配器如下所示:

First, here's a way to get at the source code for a function definition, assuming an AST matcher that looks something like this:

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

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

The run method of the Callback would begin by getting access to the matched AST node, getting the source range covered by the function declaration, and getting a reference to the SouceManager, which relates the SourceLocation objects to the actual source:

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有一个陷阱:结束位置不是代码结束的位置;它是范围中最后一个标记的开始.因此,如果使用带有 decl_range.getEnd()的SourceManager进行函数定义,则不会得到右大括号. end_of_the_end()使用一个词法分析器来获取代码最后一位的位置:

What's with decl_start_end and decl_end_end? There is one catch to using a SourceRange: the ending location is not where the code ends; it is the beginning of the last token in the range. So if we go to the SourceManager with decl_range.getEnd() for a function definition, we won't get the closing curly bracket. end_of_the_end() uses a lexer to get the location of the last bit of the code:

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的字符缓冲区:

Back in run(), with accurate beginning and ending locations, you can get pointers into the SourceManager's character buffer:

    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具有函数的源代码;您可以写入新文件等.

func_string has the function's source code; you can write to new file etc.

要消除原始文件中函数的源代码,我们可以生成一个Replacement,然后让RefactoringTool为我们应用它.要创建替换项,我们需要在 run()中再添加两行代码:

To eliminate the function's source in the original file, we can generate a Replacement, and let the RefactoringTool apply that for us. To create a Replacement, we need to add two more lines of code to 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,在何处开始替换,覆盖多少以及覆盖内容.此替换内容将完全覆盖整个原始函数定义.

The Replacement ctor takes the SourceManager, where to begin replacing, how much to overwrite, and what to overwrite with. This Replacement overwrites the entire original function definition with nothing.

我们如何将替代品带到RefactoringTool?我们可以使用对RefactoringTool的Replacements成员的引用来构造回调类.然后在 run 中得出结论:

How do we get that Replacement to the RefactoringTool? We could construct the callback class with a reference to the RefactoringTool's Replacements member. In run, one would then conclude:

    repls_.insert(repl);

我在apps/FunctionMover.cc的 CoARCT(一个Clang重构示例集合)中添加了一个有效的示例应用程序.

I've added a working example application in apps/FunctionMover.cc in CoARCT, a collection of Clang refactoring examples.

这篇关于叮当声:将函数的AST从原始文件写入新文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆