python + libclang; итерация вперед и назад: привязка комментариев поля к полю

Некоторое время я пытался найти достойный способ привязать поле в структуре C ++ к его комментариям, используя libclang 3.9.1, и python 3.5.2.

До сих пор я получил эту настройку и работает:
Предполагая, что у меня есть файл Foo.h:

typedef int arbType;

struct Foo {
//First bar comment
//Second bar comment
int Bar; //Third bar comment - after bar

/* First line baz comment - before baz
Second line baz comment - before baz
*/
arbType Baz; //Third line baz comment - after baz
};

Мой код на Python извлекает только встроенные комментарии:

#bind_comments.py
import clang.cindex

def get_cur_comments(cursor):
comment = ''
print ('\nGetting comment for:', cursor.spelling.decode())
parent_cur = cursor.lexical_parent
token_iter = parent_cur.get_tokens()
for token in token_iter:
if token.cursor == cursor:
while token.kind.name != 'PUNCTUATION':
token = next(token_iter)
token = next(token_iter)
if token.kind.name == 'COMMENT':
comment = token.spelling.decode().strip('/')
return comment

def main():
index = clang.cindex.Index.create()
tu = index.parse(b'Foo.h', [b'-x', b'c++'])
tu_iter = tu.cursor.get_children()
next(tu_iter)
root_cursor = next(tu_iter)

for cur in root_cursor.type.get_fields():
print(get_cur_comments(cur))

if __name__ == '__main__':
main()

И вывод:

C:\>bind_comments.py

Getting comment for: Bar
'Third bar comment - after bar'

Getting comment for: Baz
'Third line baz comment - after baz'

Теперь для моих задач, упорядоченных по важности, на нисходящем уровне:

  1. Как я могу связать комментарии до поля? Я посмотрел на многие «заглядывающие» решения в python, чтобы во время итерации токенов выяснить, является ли следующий курсором (полем), который меня интересует, но не нашел ничего, что я мог бы правильно реализовать в моем случае , Просто чтобы показать вам, насколько я серьезен, вот несколько решений, на которые я посмотрел:

  2. Концептуальный недостаток: я пока не знаю, как определить разницу между:

    struct Foo {
    int Bar; // This comment belong to bar
    // As well as this one
    
    // While this comment belong to baz already
    int Baz;
    };
    
  3. Проблемы с производительностью: обратите внимание, что для каждого поля я перебираю весь список токенов этой структуры. Если он большой, и у меня много токенов — думаю, это будет стоить мне. Я хотел бы найти несколько ярлыков .. Я думал о сохранении токенов в глобальном списке, но что тогда, если поле является объявлением другой структуры / класса? Добавить токены своих родителей в список? Это начинает становиться грязным …

Просто помощники для тех, кто еще не знает libclang:

>>> print(root_cursor.spelling.decode())
Foo
>>> root_cursor.type.get_fields()
<list_iterator object at 0x0177B770>
>>> list(root_cursor.type.get_fields())
[<clang.cindex.Cursor object at 0x0173B940>, <clang.cindex.Cursor object at 0x017443A0>]
>>> for cur in root_cursor.type.get_fields():
...   print (cur.spelling.decode())
...
Bar
Baz
>>> root_cursor.get_tokens()
<generator object TokenGroup.get_tokens at 0x01771180>

0

Решение

libclang обеспечивает прямую поддержку для извлечения комментариев в стиле javadoc с использованием Cursor свойства brief_comment а также raw_comment

С небольшой настройкой вашего входного кода:

s = '''
typedef int arbType;

struct Foo {
/// Brief comment about bar
///
/// Extra Text about bar
int Bar;

/** Brief comment about baz
*
* Extra Text about baz
*/
arbType Baz;

/// Brief only comment
int blah;
};
'''

import clang.cindex
from clang.cindex import CursorKind

idx = clang.cindex.Index.create()
tu = idx.parse('tmp.cpp', args=['-std=c++11'],  unsaved_files=[('tmp.cpp', s)],  options=0)
for c in tu.cursor.walk_preorder():
if c.kind == CursorKind.FIELD_DECL:
print c.brief_comment
print c.raw_comment
print

Производит:

Brief comment about bar
/// Brief comment about bar
///
/// Extra Text about bar

Brief comment about baz
/** Brief comment about baz
*
* Extra Text about baz
*/

Brief only comment
/// Brief only comment
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]