Clang:将函数的 AST 从原始文件写入新文件
Clang: write a function's AST from original file to a new file
我是 Clang 的新手,正在尝试通过 libtooling 分析 AST。
我想找到一个特定的函数,并将其 AST 从原始源文件移动到新文件。
我知道如何通过 MatchFinder 找到函数。
现在,我想知道如何将其 AST 写入新文件(.c 或 .cpp)
提前致谢!
总结:要获取源文本,请使用 SourceManager
;要从原始文件中删除该函数,请生成 Replacement
并将其与 RefactoringTool
.
一起应用
首先,这是一种获取函数定义源代码的方法,假设 AST 匹配器看起来像这样:
auto matcher(std::string const & fname) {
return functionDecl(hasName(fname)).bind("f_decl");
}
Callback 的 运行 方法首先访问匹配的 AST 节点,获取函数声明涵盖的源范围,并获取对 SourceManager 的引用,它将 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 有一个问题:结束位置不是代码结束的地方;它是范围内最后一个标记的开始。因此,如果我们使用 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 成员来构造回调 class。在 run
中,人们会得出结论:
repls_.insert(repl);
中的 apps/FunctionMover.cc 中添加了一个工作示例应用程序
我是 Clang 的新手,正在尝试通过 libtooling 分析 AST。 我想找到一个特定的函数,并将其 AST 从原始源文件移动到新文件。
我知道如何通过 MatchFinder 找到函数。 现在,我想知道如何将其 AST 写入新文件(.c 或 .cpp)
提前致谢!
总结:要获取源文本,请使用 SourceManager
;要从原始文件中删除该函数,请生成 Replacement
并将其与 RefactoringTool
.
首先,这是一种获取函数定义源代码的方法,假设 AST 匹配器看起来像这样:
auto matcher(std::string const & fname) {
return functionDecl(hasName(fname)).bind("f_decl");
}
Callback 的 运行 方法首先访问匹配的 AST 节点,获取函数声明涵盖的源范围,并获取对 SourceManager 的引用,它将 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 有一个问题:结束位置不是代码结束的地方;它是范围内最后一个标记的开始。因此,如果我们使用 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 成员来构造回调 class。在 run
中,人们会得出结论:
repls_.insert(repl);
中的 apps/FunctionMover.cc 中添加了一个工作示例应用程序