Search code examples
pythonc++llvmabstract-syntax-treelibclang

A templated constructor cursor and a templated member cursor have kind FUNCTION_TEMPLATE in libclang


Some context

I am not that familiar with libclang. I am just modifying a vim plugin which uses the python bindings to libclang.

There is a python function which receives a cursor parameter. This is called for almost every node in the AST of the current C++ buffer.

The problem

cursor.kind is used to get the kind of the cursor. All is ok, except that

  • templated free function declarations,
  • templated constructor declarations and
  • templated method declarations

all have the same kind: FUNCTION_TEMPLATE. I need to differentiate between them.

More insight

For instance, the non-templated versions of the above have the kinds:

  • FUNCTION_DECL
  • CXX_METHOD and
  • CONSTRUCTOR.

I have search the source of cindex.py and there are no CXX_METHOD_TEMPLATE or CONSTRUCTOR_TEMPLATE or similar.

I have tried without success to somehow get the information I need, e.g. with cursor.get_definition() and cursor.underlying_typedef_type.get_declaration().

The only partial success I got is that for a method and a constructor the semantic and lexical parent is a STRUCT_DECL.

I don't really care if it's templated or not. All I care if it's a constructor, member or free function.

To sum it up

Given a cursor, how I can tell if it's a method (even templated), a constructor (even templated) or a free function declaration?


Solution

  • tl;dr

    cindex.CursorKind.from_id(cindex.conf.lib.clang_getTemplateCursorKind(cursor))
    

    Browsing the C libclang online doxygen documentation we find in the C++ AST introspection the function clang_getTemplateCursorKind

    CINDEX_LINKAGE enum CXCursorKind  clang_getTemplateCursorKind (CXCursor C)
    

    Given a cursor that represents a template, determine the cursor kind of the specializations would be generated by instantiating the template.

    Which is exactly what I want. Unfortunately, calling it in Python is not as simple.

    By looking around, this is how we call the C functions not implemented explicitly in Python:

    tk = cindex.conf.lib.clang_getTemplateCursorKind(cursor)
    

    Don't ask, black magic.

    The next bump in the road is that this function returns a long. If we really want the CursorKind object, we need this:

    cindex.CursorKind.from_id(tk)