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

2024-01-22

我是 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 的 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 and 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);
}

Back in 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);

我在 apps/FunctionMover.cc 中添加了一个工作示例应用程序CoARCT,Clang 重构示例集合 https://github.com/lanl/CoARCT.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • JavaFX 2:使 ScrollPane 在添加内容后自动滚动到边缘

    使用 JavaFX 2 我有一个基本示例ScrollPane其中包含一个HBox of Labels 我希望能够添加一个Label to the HBox 同时滚动到右侧边缘ScrollPane以便新添加的Label是可见的 我当前的方法使
  • 有没有办法确定应用程序在 iOS 中使用的磁盘空间量?

    我看过很多关于如何获取iOS设备有多少可用空间 或者iOS设备有多少可用空间的帖子 但是有没有办法确定应用程序本身使用了多少空间 包括应用程序本身及其所有资源 文档 缓存 等 这与在 设置 gt 常规 gt iPhone 存储 中看到的值相
  • 在Python中解析JSON MSG

    我正在尝试将 json MSG 解析为 python 字典 作为参考 该消息是使用 python MQTT 处理程序从物联网接收的 这是我打印对象时收到的格式 msg MSG variable group MSG data0 0 data1
  • 路线 [登录] 未定义

    今天第一次尝试玩 Laravel 当我尝试访问 localhost project public 时收到以下错误 无效参数异常路线 登录 未定义 应用程序 routes php
  • TypeCasting:下面两行代码有什么区别?

    下面两行代码有什么区别 两者都试图获取路径 其中一个正在工作 另一个正在抛出错误 我正在开发 Delphi 7 Path FFormOwner as TForm Designer as IDesigner GetPrivateDirecto
  • 如何在实体框架中执行SqlCommand而不将其包含在事务中

    我需要使用实体框架执行存储过程 通常我这样称呼它 this Context Database ExecuteSqlCommand EXEC edi UploadTransmission 然而 这个特定的存储过程包括访问链接服务器 由于 EF
  • 强类型 DataContext 如何工作?

    这是一个深入的延续我今天早上早些时候提出的问题 https stackoverflow com questions 2178090 is this a spurious warning when using linq to sql 我仍然对
  • 如何使用 mongoose 连接到 mongoDB Atlas

    我正在尝试通过 Mongoose connect 连接到 mongoDB Atlas 上的集群 但每次尝试连接时都会收到异常 MongoError 身份验证失败 我知道 MongoDB Atlas 是新的 mongo 即服务 mongoos
  • 谷歌浏览器错误?

    此消息始终出现在 Chrome 开发人员工具控制台中 Port error Could not establish connection Receiving end does not exist miscellaneous bindings
  • 如何在 Mac OS 上开发 Blackberry 应用程序?

    我正在 Apple MacBook 上开发 iPhone 和 Android 应用程序 我想开发黑莓应用程序 我现在正在使用Windows来学习 是否有任何软件或 Eclipse 插件可以在 Mac OS 而不是 Windows 上开发 B
  • 如何将毕加索与列表视图一起使用?

    我想向 ListView 添加有关小部件的信息 public class Widget String w type String title String desc String img 如果 img 字段不为空 我想在列表视图中显示图像
  • 如何获取数组中同一键的最大值

    如何获取数组中同一键的最大值 E x 我有这个数组 Array id gt 1 amount gt 4 Array id gt 1 amount gt 3 Array id gt 2 amount gt 3 我想要以下结果 意味着我想要相同
  • 递归:幕后[关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 虽然众所周知 递归是 一种调用自身的方法 但我倾向于想知道到底发生了什么 举个经典的阶乘例子 public static int fact
  • 以角度显示时间/时钟

    我正在使用以下方法在我的应用程序中显示时间 constructor private datePipe DatePipe ngOnInit this getTime this date this datePipe transform new
  • 为什么指定模式名称时 PostgreSQL SELECT 查询会返回不同的结果?

    我有一个 PostgreSQL 数据库表 有 4 列 标记为 column a column b 等 我想使用简单的选择查询来查询该表 select from table name 我得到一些结果 如下所示 column a column
  • GCE - 如果我使用 SSH 或从终端登录,用户名会不同吗?

    我创建了一个新项目 里面什么都没有 当我创建第一个微实例时 我执行了以下操作 使用浏览器窗口 SSH 连接到它 我懂了 用户名 instance 1 如果我使用 gcloud 命令进行连接 gcloud 计算 project project
  • C 中 Union 的示例 [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我正在寻找一些工会的例子 不是为了了
  • Flutter:使用导航器推送到新屏幕时保留 BottomNavigationBar

    在iOS中 我们有一个UITabBar控制器 https developer apple com documentation uikit uitabbarcontroller当我们推送到新的 ViewController 时 它会永久保留在
  • 如何使用 Google Cloud Pub/Sub 进行 Junit 测试

    我在我的系统中使用Google Cloud Pub Sub的push pub sub 我想构建我的CI测试代码 但我不知道如何去做 例如 一些代码是这样的 final Pubsub pubsub PubsubUtils getClient
  • Clang:将函数的 AST 从原始文件写入新文件

    我是 Clang 的新手 正在尝试通过 libtooling 分析 AST 我想找到一个特定的函数 并将其 AST 从原始源文件移动到新文件 我已经知道如何通过 MatchFinder 找到该函数 现在 我想知道如何将其 AST 写入新文件