如何在 libclang c++ 中使用 RecursiveASTVisitor 提取注释并匹配声明?

Posted

技术标签:

【中文标题】如何在 libclang c++ 中使用 RecursiveASTVisitor 提取注释并匹配声明?【英文标题】:How to extract comments and match to declaration with RecursiveASTVisitor in libclang c++? 【发布时间】:2014-10-06 03:59:49 【问题描述】:

我正在编写一个实用程序,它应该解析 C++(和 C)头文件,提取结构、枚举、字段等,并根据提取的信息生成其他语言的代码。我决定为此使用 libclang。

我正在使用RecursiveASTVisitor,似乎我能够提取我需要的所有信息,除了 cmets。

我希望读取出现在每个声明(字段、结构、类、枚举)正上方的注释,并在生成其他语言的代码时添加其文本。

问题是我看到的所有使用 cmets 的示例都使用CxCursor 和clang 的C 接口,我不知道如何在我的上下文中获取CxCursor

那么 - 我如何在仍然使用 RecursiveASTVisitor 的同时提取 cmets?

【问题讨论】:

你可以研究一下clang-fmt的源码... 你的意思是你在写另一个 Doxygen? ;) [Yad, Yet another Doxygen - 或者“Yet Other Doxygen Again”, Yoda] 也许 Bison/Flex 是编写标记器/解析器的更好起点? @MatsPetersson - 我不想要单独的文档。我想在生成的代码中嵌入每个字段/结构的相关注释(这将是其他语言 - C#、Lua 等) @Tanuki - 我真的不知道这些,但是从一些谷歌搜索来看,它们似乎不是特定于 c++ 解析的,并且没有使用它们的规范 c++ 解析器实现。 libclang 的最大优势在于它实际上编译 代码,因此我得到了例如结构/字段/枚举的字节大小,甚至当我使用位域时的位大小。我没有提到目的是为了能够通过网络发送和接收这些数据结构,所以简单的解析在这里无济于事。 【参考方案1】:

经过更多的挖掘,我发现了这个:

对于任何相关的已访问 Decl (VisitXXXDecl),我可以这样做:

virtual bool VisitDecl(Decl* d)

    ASTContext& ctx = d->getASTContext();
    SourceManager& sm = ctx.getSourceManager();

    const RawComment* rc = d->getASTContext().getRawCommentForDeclNoCache(d);
    if (rc)
    
        //Found comment!
        SourceRange range = rc->getSourceRange();

        PresumedLoc startPos = sm.getPresumedLoc(range.getBegin());
        PresumedLoc endPos = sm.getPresumedLoc(range.getEnd());

        std::string raw = rc->getRawText(sm);
        std::string brief = rc->getBriefText(ctx);

        // ... Do something with positions or comments
    

    // ...

请注意,这标识(据我所见......)在代码中当前声明的上方(和相邻!)行中的 cmets,并且采用以下格式之一:

/// Comment /** Comment */ //! Comment

比如下面这种情况:

/// A field with a long long comment
/// A two-liner
long long LongLongData;

raw 将是:

/// A field with a long long comment
    /// A two-liner

brief 将是:

A field with a long long comment A two-liner

无论哪种方式,它都足以满足我的需求。

【讨论】:

【参考方案2】:

上面的答案是完美的。但是要使 API getRawCommentForDeclNoCache 返回像 // or /* 这样的普通 cmets,您需要在调用 clang 时提供选项 "-fparse-all-cmets"。因为默认情况下,clang 只解析 Doxygen 样式的 cmets。

【讨论】:

以上是关于如何在 libclang c++ 中使用 RecursiveASTVisitor 提取注释并匹配声明?的主要内容,如果未能解决你的问题,请参考以下文章

Cppy cmake 构建无法找到 LibClang

使用 libclang 解析 windows С++ 项目文件(带有 VC 代码库)

Cannot install ‘libclang-dev‘--Ubuntu20.04 安装 libclang-dev 插件

Cannot install ‘libclang-dev‘--Ubuntu20.04 安装 libclang-dev 插件

将 C++ 结构编组到 C# 类时出现 AccessViolationException

架构 i386 的未定义符号 - Lipo 错误?