You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用libclang获取AST字符串并借助CXUnsavedFile遍历AST?

实现libclang基于内存代码直接遍历AST的方案

不需要预先导出.ast文件,直接把待处理代码作为内存缓存传递给libclang的clang_parseTranslationUnit接口,配合CXUnsavedFile结构体即可完成内存中translationUnit的创建,全程无磁盘IO,实现逻辑如下:

1. 初始化libclang索引

索引是所有libclang操作的基础,先创建CXIndex实例:

// 第一个参数:是否排除本地声明,第二个参数:是否显示诊断信息,可按需调整
CXIndex index = clang_createIndex(0, 0);

2. 构造CXUnsavedFile实例

该结构体用于传递内存中未持久化到磁盘的代码内容:

CXUnsavedFile unsaved_file;
// 自定义文件名,后缀需要和代码语法规则匹配(比如.c/.cpp后缀对应C/C++代码)
unsaved_file.Filename = "demo.cpp";
// 内存中存储的待处理代码内容
unsaved_file.Contents = R"(
#include <iostream>
int main() {
    std::cout << "Hello World" << std::endl;
    return 0;
}
)";
// 代码内容的字节长度
unsaved_file.Length = strlen(unsaved_file.Contents);

如果需要同时处理多个内存文件,构造多个CXUnsavedFile组成数组传递即可。

3. 解析生成TranslationUnit

调用解析接口直接基于内存代码生成translationUnit:

// 编译选项,和clang/gcc编译参数完全一致,按需调整
const char* compile_args[] = {"-x", "c++", "-std=c++17"};
int num_args = sizeof(compile_args) / sizeof(compile_args[0]);

CXTranslationUnit tu = clang_parseTranslationUnit(
    index,
    unsaved_file.Filename, // 对应上一步定义的文件名
    compile_args, num_args, // 编译选项数组和数量
    &unsaved_file, 1, // 未保存文件数组和数量,单个文件填1即可
    CXTranslationUnit_None // 解析选项,可按需调整
);

如果解析返回空tu,可调用clang_getDiagnostic接口查看具体错误信息,常见原因是编译选项和代码类型不匹配、代码存在语法错误。

4. 遍历AST

拿到的translationUnit和基于.ast文件生成的tu用法完全一致,正常遍历即可:

CXCursor root_cursor = clang_getTranslationUnitCursor(tu);
clang_visitChildren(root_cursor, [](CXCursor cursor, CXCursor parent, CXClientData client_data) {
    // 自定义遍历逻辑,示例为打印节点类型和节点名称
    CXString kind_spelling = clang_getCursorKindSpelling(clang_getCursorKind(cursor));
    CXString cursor_spelling = clang_getCursorSpelling(cursor);
    printf("节点类型:%s,节点名称:%s\n", clang_getCString(kind_spelling), clang_getCString(cursor_spelling));
    clang_disposeString(kind_spelling);
    clang_disposeString(cursor_spelling);
    return CXChildVisit_Recurse;
}, nullptr);

5. 资源释放

操作完成后释放对应资源避免内存泄漏:

clang_disposeTranslationUnit(tu);
clang_disposeIndex(index);

常见说明

  • 如果代码依赖自定义头文件,可在编译选项中加-I指定头文件搜索路径,用法和正常编译参数完全一致
  • 针对不同语言的代码,修改编译选项中的-x参数即可,比如C代码改为-x c、Objective-C代码改为-x objective-c

内容的提问来源于stack exchange,提问作者Onkar Dahale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 14:36:04