I would like to parse generalized attributes of class member functions in the following example:
class Foo
{
public:
void foo [[interesting]] ();
void bar ();
};
Using the libclang C API, I would like to distinguish between foo
and bar
(and know that foo
has the interesting
attribute) in the source. Is this possible? I have a hard time finding examples or documentation that explains the concepts used in the API (I've found a reference, but that's kind of hard to use when the concepts are not explained).
While I was unable to find the generalized attributes in the AST (it seems they are dropped when or before constructing the AST, not after it), I did find a workaround.
There is an annotate
clang attribute in the following form:
__attribute__((annotate("something")))
With a macro I could get a reasonable syntax and an annotation which is visible in the AST:
#define INTERESTING __attribute__((annotate("interesting")))
class Foo
{
public:
INTERESTING void foo();
void bar();
};
The attribute will be the child of the method node, with its display_name being the annotation string. A possible AST dump:
<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()"
}
}
It produces the same output with void foo INTERESTING ();
too.
Something like the following first_attr
function will fetch the cursor of the first attribute of the passed cursor if it exists, or a null cursor if it doesn't (untested code... caveat lector)
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;
}
As for finding which specific attribute a cursor a
represents, the result of clang_getCursorKind(a)
can help, but the only attributes exposed are:
CXCursor_IBActionAttr
CXCursor_IBOutletAttr
CXCursor_IBOutletCollectionAttr
CXCursor_CXXFinalAttr
CXCursor_CXXOverrideAttr
CXCursor_AnnotateAttr
CXCursor_AsmLabelAttr
Everything else will be a CXCursor_UnexposedAttr
and the only way I can think of to get the text of it is to examine clang_getCursorExtent(a)
(i.e., read the source code; cf. clang_tokenize
). In the case of annotations, the specific annotation used is available through clang_getCursorDisplayName
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With