Parsing C++ template parameters using cindex.py

Hi,

I am parsing a C++ file using cindex.py and want to get the template
parameters to a specific node. However, the tree seems to be different
depending on if the template parameter is a struct/class or a simple
type such as int or float. In the first case the template type is
appended as a child to the VAR_DECL node (the TYPE_REF node seen in
the example below), but this is not the case with for example int. Any
hint on where the template type is located for int/float/etc?

/joel de vahl

Example code:

template
class Test
{
T test;
};

struct S
{
};

Test test_int;
Test test_struct;

Tree dump script:

def DeepPrintType(node, depth = 0):
tabs = " " * depth
print tabs + “type”
print tabs + " kind", node.kind

def DeepPrint(node, depth = 0):
tabs = " " * depth
print tabs + “cursor”, node.spelling
print tabs + " location", node.location
node_type_res = node.type.get_result()

print tabs + " result", node_type_res.kind
print tabs + " kind", node.kind
DeepPrintType(node.type, depth + 1)
print tabs + " xdata", node.xdata
print tabs + " data", node.data[0], node.data[1], node.data[2]

print tabs + " children"
children = [c for c in node.get_children()]
for c in children:
DeepPrint(c, depth + 2)

index = Index.create()
tu = index.parse(None, [‘testfile.cpp’])
children = [c for c in tu.cursor.get_children() if c.kind ==
CursorKind.VAR_DECL]
for c in children:
DeepPrint(c)

Dump output:

cursor test_int
location <SourceLocation file ‘testfile.cpp’, line 11, column 11>
result TypeKind.INVALID
kind CursorKind.VAR_DECL
type
kind TypeKind.UNEXPOSED
xdata 0
data 48356112 1 4106544
children
cursor None
location <SourceLocation file ‘testfile.cpp’, line 11, column 1>
result TypeKind.INVALID
kind CursorKind.TEMPLATE_REF
type
kind TypeKind.INVALID
xdata 0
data 48201424 75 4106544
children
cursor None
location <SourceLocation file ‘testfile.cpp’, line 11, column 11>
result TypeKind.INVALID
kind CursorKind.CALL_EXPR
type
kind TypeKind.UNEXPOSED
xdata 0
data 48356112 48357480 4106544
children

cursor test_struct
location <SourceLocation file ‘testfile.cpp’, line 12, column 9>
result TypeKind.INVALID
kind CursorKind.VAR_DECL
type
kind TypeKind.UNEXPOSED
xdata 0
data 48358032 1 4106544
children
cursor None
location <SourceLocation file ‘testfile.cpp’, line 12, column 1>
result TypeKind.INVALID
kind CursorKind.TEMPLATE_REF
type
kind TypeKind.INVALID
xdata 0
data 48201424 96 4106544
children
cursor None
location <SourceLocation file ‘testfile.cpp’, line 12, column 6>
result TypeKind.INVALID
kind CursorKind.TYPE_REF
type
kind TypeKind.RECORD
xdata 0
data 48355056 101 4106544
children
cursor None
location <SourceLocation file ‘testfile.cpp’, line 12, column 9>
result TypeKind.INVALID
kind CursorKind.CALL_EXPR
type
kind TypeKind.UNEXPOSED
xdata 0
data 48358032 48415208 4106544
children

I don't have the answer (sorry) but have you tried using ipython to
experiment interactively with each member of the Cursor you're
interested in? For example see:
http://lists.cs.uiuc.edu/pipermail/cfe-dev/2012-August/023449.html

With ipython and your example C++ code I found that
c.type.get_declaration().displayname (where c is the cursor for
test_int) is "Test<int>" -- so it clearly *knows* the information, but I
couldn't find a way of getting at an explicit list of the type
parameters. It wouldn't surprise me if either libclang or its python
bindings is missing this functionality.

After giving up with ipython, the next thing I checked was the libclang
C headers. Index.h[1] is the public API; I searched all functions taking
a "CXCursor" or a "CXType" but didn't see anything that would return
type parameters for a template instantiation.

CXCursor.h[2], which is part of libclang's private implementation, does
have:

    std::pair<TemplateDecl *, SourceLocation>
    getCursorTemplateRef(CXCursor C);

and TemplateDecl "stores the list of template parameters"[3].

So it seems you'd have to expose the information you want in Index.h,
then add the corresponding python bindings[4].

(Or, I could be entirely wrong and have missed something obvious. I'm
far from an expert on clang or libclang.)

[1] https://github.com/llvm-mirror/clang/blob/master/include/clang-c/Index.h
[2] https://github.com/llvm-mirror/clang/blob/bbf66ca1/tools/libclang/CXCursor.h#L102
[3] https://github.com/llvm-mirror/clang/blob/b43d87b0/include/clang/AST/DeclTemplate.h#L213
[4] https://github.com/llvm-mirror/clang/blob/master/bindings/python/clang/cindex.py