Using Libclang python bindings, how do you retrieve annotations added to C++ class/struct?

73 Views Asked by At

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.

1

There are 1 best solutions below

1
R2RT On BEST ANSWER

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)