使用 python libclang 检索注释

Retrieving comments using python libclang

本文关键字:注释 检索 libclang python 使用      更新时间:2023-10-16

在下面的头文件中,我想获取类和成员变量的相应+reflect注释:

#ifndef __HEADER_FOO
#define __HEADER_FOO
//+reflect
class Foo
{
    public:
    private:
        int m_int; //+reflect
};
#endif

使用 libclang 的 python 绑定和以下脚本:

import sys
import clang.cindex
def dumpnode(node, indent):
    print ' ' * indent, node.kind, node.spelling
    for i in node.get_children():
        dumpnode(i, indent+2)
def main():
    index = clang.cindex.Index.create()
    tu = index.parse(sys.argv[1], args=['-x', 'c++'])
    dumpnode(tu.cursor, 0)
if __name__ == '__main__':
    main()

给我这个输出:

CursorKind.TRANSLATION_UNIT None
  CursorKind.TYPEDEF_DECL __builtin_va_list
  CursorKind.CLASS_DECL type_info
  CursorKind.CLASS_DECL Foo
    CursorKind.CXX_ACCESS_SPEC_DECL
    CursorKind.CXX_ACCESS_SPEC_DECL
    CursorKind.FIELD_DECL m_int

问题是缺少注释。它们是否被预处理器剥离?有什么办法可以防止这种情况吗?

为此,

您需要获取令牌,而不是游标。如果我在上面的文件上运行此脚本:

import sys
import clang.cindex
def srcrangestr(x):
    return '%s:%d:%d - %s:%d:%d' % (x.start.file, x.start.line, x.start.column, x.end.file, x.end.line, x.end.column)
def main():
    index = clang.cindex.Index.create()
    tu = index.parse(sys.argv[1], args=['-x', 'c++'])
    for x in tu.cursor.get_tokens():
        print x.kind
        print "  " + srcrangestr(x.extent)
        print "  '" + str(x.spelling) + "'"
if __name__ == '__main__':
    main()

我得到以下信息:

TokenKind.PUNCTUATION
  test2.h:1:1 - test2.h:1:2
  '#'
TokenKind.IDENTIFIER
  test2.h:1:2 - test2.h:1:8
  'ifndef'
TokenKind.IDENTIFIER
  test2.h:1:9 - test2.h:1:21
  '__HEADER_FOO'
TokenKind.PUNCTUATION
  test2.h:2:1 - test2.h:2:2
  '#'
TokenKind.IDENTIFIER
  test2.h:2:2 - test2.h:2:8
  'define'
TokenKind.IDENTIFIER
  test2.h:2:9 - test2.h:2:21
  '__HEADER_FOO'
TokenKind.COMMENT
  test2.h:4:1 - test2.h:4:11
  '//+reflect'
TokenKind.KEYWORD
  test2.h:5:1 - test2.h:5:6
  'class'
TokenKind.IDENTIFIER
  test2.h:5:7 - test2.h:5:10
  'Foo'
TokenKind.PUNCTUATION
  test2.h:6:1 - test2.h:6:2
  '{'
TokenKind.KEYWORD
  test2.h:7:5 - test2.h:7:11
  'public'
TokenKind.PUNCTUATION
  test2.h:7:11 - test2.h:7:12
  ':'
TokenKind.KEYWORD
  test2.h:8:5 - test2.h:8:12
  'private'
TokenKind.PUNCTUATION
  test2.h:8:12 - test2.h:8:13
  ':'
TokenKind.KEYWORD
  test2.h:9:9 - test2.h:9:12
  'int'
TokenKind.IDENTIFIER
  test2.h:9:13 - test2.h:9:18
  'm_int'
TokenKind.PUNCTUATION
  test2.h:9:18 - test2.h:9:19
  ';'
TokenKind.COMMENT
  test2.h:9:20 - test2.h:9:30
  '//+reflect'
TokenKind.PUNCTUATION
  test2.h:10:1 - test2.h:10:2
  '}'
TokenKind.PUNCTUATION
  test2.h:10:2 - test2.h:10:3
  ';'
TokenKind.PUNCTUATION
  test2.h:12:1 - test2.h:12:2
  '#'
TokenKind.IDENTIFIER
  test2.h:12:2 - test2.h:12:7
  'endif'

这对我来说应该足够了。

您需要修改 cindex.py 脚本并公开以下函数。

class Cursor(Structure):
   def getRawComment(self):
    return conf.lib.clang_Cursor_getRawCommentText(self)

还要将其添加到 cindex.py 中的正确位置

("clang_Cursor_getRawCommentText",
 [Cursor],
 _CXString,
 _CXString.from_result),

我不得不使用

 /*!
  * +reflect
  */

虽然

是的

,预处理器会删除所有注释。您可以通过执行 clang -E mycode.c > mycode.i 看到这一点,这将为您提供一个包含所有预处理但没有注释的mycode.i文件。

您可以使用 #pragma 或未剥离且被编译器忽略的内容执行某些操作。

您可以使用 PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION 并访问游标的 raw_comment 属性,以便在 AST 上下文中获取此信息。

请参阅此处 python 测试中的示例:https://github.com/llvm-mirror/clang/blob/master/bindings/python/tests/cindex/test_comment.py(在 linkrot 的情况下摘录到此处):

class TestComment(unittest.TestCase):
    def test_comment(self):
        files = [('fake.c', """
/// Aaa.
int test1;
/// Bbb.
/// x
void test2(void);
void f() {
}
""")]
        # make a comment-aware TU
        tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
                options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
        test1 = get_cursor(tu, 'test1')
        self.assertIsNotNone(test1, "Could not find test1.")
        self.assertTrue(test1.type.is_pod())
        raw = test1.raw_comment
        brief = test1.brief_comment
        self.assertEqual(raw, """/// Aaa.""")
        self.assertEqual(brief, """Aaa.""")

感谢@user408952对Mats Petersson的评论 - 这正是我所需要的。