Я хотел бы проанализировать обобщенные атрибуты функций-членов класса в следующем примере:
class Foo
{
public:
void foo [[interesting]] ();
void bar ();
};
Используя libclang C API, я бы хотел различать foo
а также bar
(и знаю, что foo
имеет interesting
атрибут) в источнике. Это возможно? Мне трудно найти примеры или документацию, которая объясняет концепции, используемые в API (я нашел ссылку, но это сложно использовать, когда концепции не объяснены).
Что-то вроде следующего first_attr
функция извлекает курсор первого атрибута переданного курсора, если он существует, или нулевой курсор, если его нет (непроверенный код … предупреждающий лектор)
CXChildVisitResult attr_visit(CXCursor cursor, CXCursor parent, CXClientData data) {
if (clang_isAttribute(cursor)) {
*data = cursor;
return CXChildVisit_Break;
}
return CXChildVisit_Continue;
}
CXCursor first_attr(const CXCursor& c) {
CXCursor attr;
unsigned visit_result = clang_visitChildren(c, attr_visit, &attr);
if (!visit_result) // attribute not found
attr = clang_getNullCursor();
return attr;
}
Что касается нахождения какого конкретного атрибута курсора a
представляет собой результат clang_getCursorKind(a)
может помочь, но доступны только следующие атрибуты:
CXCursor_IBActionAttr
CXCursor_IBOutletAttr
CXCursor_IBOutletCollectionAttr
CXCursor_CXXFinalAttr
CXCursor_CXXOverrideAttr
CXCursor_AnnotateAttr
CXCursor_AsmLabelAttr
Все остальное будет CXCursor_UnexposedAttr
и единственный способ, которым я могу придумать, чтобы получить текст этого, состоит в том, чтобы изучить clang_getCursorExtent(a)
(то есть прочитайте исходный код; ср. clang_tokenize
). В случае аннотаций конкретная аннотация используется через clang_getCursorDisplayName
,
Хотя мне не удалось найти обобщенные атрибуты в AST (кажется, они отбрасываются, когда или до создания AST, а не после него), я нашел обходной путь.
Есть annotate
атрибут clang в следующей форме:
__attribute__((annotate("something")))
С помощью макроса я мог получить разумный синтаксис и аннотацию, которая видна в AST:
#define INTERESTING __attribute__((annotate("interesting")))
class Foo
{
public:
INTERESTING void foo();
void bar();
};
Атрибут будет дочерним по отношению к узлу метода, а его display_name будет строкой аннотации. Возможный дамп AST:
<CursorKind.TRANSLATION_UNIT>
"test.h"{
__builtin_va_list <CursorKind.TYPEDEF_DECL>
"__builtin_va_list"type_info <CursorKind.CLASS_DECL>
"type_info"Foo <CursorKind.CLASS_DECL>
"Foo"{
<CursorKind.CXX_ACCESS_SPEC_DECL>
""foo <CursorKind.CXX_METHOD>
"foo()"{
<CursorKind.ANNOTATE_ATTR>
"interesting"}
bar <CursorKind.CXX_METHOD>
"bar()"}
}
Это дает тот же результат с void foo INTERESTING ();
тоже.