Using the following C++ struct as an example:
__attribute__((annotate("MyAttribute")))
struct TestComponent
{
__attribute__((annotate("MyAttribute")))
int32_t testInt;
__attribute__((annotate("MyAttribute")))
bool testBool;
__attribute__((annotate("MyAttribute")))
char testChar;
};
Given a node (cursor) from clang using (clang module's cindex) while parsing the AST, using the following I can get the annotations on the class members when node is pointing to TestComponent and has a kind equal to CursorKind.STRUCT_DECL:
def get_annotations(node):
annotations = [c.displayname for c in node.get_children()
if c.kind == clang.cindex.CursorKind.ANNOTATE_ATTR]
return annotations
But class/struct annotations never show up as children of a struct/class. Is there a way to get to those? Even in the C bindings - I can try Monkeypatching it, but couldn't find anything.
tl;dr: attribute should be placed between struct
and TestComponent
struct __attribute__((annotate("MyAttribute"))) TestComponent
If you print tu.diagnostics
, clang
does issue a -Wignored-attributes
warning:
test.cpp:2:17: warning: attribute 'annotate' is ignored, place it after "struct" to apply attribute to type declaration [-Wignored-attributes]
Once fixed, ANNOTATE_ATTR
is visible in AST:
test.cpp CursorKind.TRANSLATION_UNIT
TestComponent CursorKind.STRUCT_DECL
MyStruct CursorKind.ANNOTATE_ATTR
testInt CursorKind.FIELD_DECL
MyInt CursorKind.ANNOTATE_ATTR
testBool CursorKind.FIELD_DECL
MyBool CursorKind.ANNOTATE_ATTR
testChar CursorKind.FIELD_DECL
MyChar CursorKind.ANNOTATE_ATTR
My test code for reference:
code = """
__attribute__((annotate("InvalidAttribute")))
struct __attribute__((annotate("MyStruct"))) TestComponent
{
__attribute__((annotate("MyInt")))
int testInt;
__attribute__((annotate("MyBool")))
bool testBool;
__attribute__((annotate("MyChar")))
char testChar;
};
"""
from clang.cindex import Cursor, Index, Config
Config.set_library_file('C:/llvm-16/bin/libclang.dll')
index = Index.create()
args = ['-x', 'c++', '-std=c++20', 'test.cpp']
tu = index.parse(None, args,
unsaved_files=[('test.cpp', code)])
for d in tu.diagnostics:
print(d)
def recurse(c: Cursor, indent=0):
print(' ' * indent, c.spelling, c.kind)
for n in c.get_children():
recurse(n, indent + 2)
recurse(tu.cursor)