<br>Hi,<br><br>I'm new to libclang and looking to do some refactoring type work using it. After reading the "Thinking Beyond The Compiler" slides, and the very nice blog post at<br><br><a href="http://eli.thegreenplace.net/2011/07/03/parsing-c-in-python-with-clang/">http://eli.thegreenplace.net/2011/07/03/parsing-c-in-python-with-clang/</a><br>
<br>I've run into a difficulty that seems to be associated with templates.<br><br>I have a python script which walks the AST and finds a declaration node associated with a C++ method. Then, I walk the tree again and looks for references to the desired method (there are multiple classes which have this method name, which is why this is very difficult to do textually and why clang looks like the right tool.)<br>
<br>This works great when the class is not a templated class:<br><br><br>struct A { void foo() {} };<br><br>struct B { void foo() {} };<br><br>int main()<br>{<br> A a;<br> a.foo();<br><br> B b;<br> b.foo();<br>}<br>
<br>My python script produces the following expected output:<br><br>./reference-test.py test1.cxx<br>Parsing source into AST...<br>Finding target declaration...<br>Finding references...<br>found foo of kind CursorKind.CALL_EXPR<br>
Is this foo a ref to the target declaration? YES<br>found foo of kind CursorKind.MEMBER_REF_EXPR<br>Is this foo a ref to the target declaration? YES<br>found foo of kind CursorKind.CALL_EXPR<br>Is this foo a ref to the target declaration? NO<br>
found foo of kind CursorKind.MEMBER_REF_EXPR<br>Is this foo a ref to the target declaration? NO<br><br>That is all expected behavior. The target declaration is A::foo().<br><br>However, when class A is a templated class:<br>
<br>template <class T><br>struct A { void foo() {} };<br><br>struct B { void foo() {} };<br> <br>int main()<br>{<br> A<int> a;<br> a.foo();<br><br> B b;<br> b.foo();<br>}<br><br>The behavior changes, and none of the references seem to point back to the declaration node this time. The output is now:<br>
<br>./reference-test.py test2.cxx<br>Parsing source into AST...<br>Finding target declaration...<br>Finding references...<br>found foo of kind CursorKind.CALL_EXPR<br>Is this foo a ref to the target declaration? NO<br>found foo of kind CursorKind.MEMBER_REF_EXPR<br>
Is this foo a ref to the target declaration? NO<br>found foo of kind CursorKind.CALL_EXPR<br>Is this foo a ref to the target declaration? NO<br>found foo of kind CursorKind.MEMBER_REF_EXPR<br>Is this foo a ref to the target declaration? NO<br>
<br>When I print out the full AST as text, I cannot find any other node in the AST which corresponds to the declaration of A::foo(). There is only one, and it is the one I am finding in my first pass through the tree.<br>
<br>I'm stumped as to why I seem to be unable to resolve to the declaration of A::foo() when A is a templated class.<br><br>Help?<br><br>My python script is as follows (apologies for most likely awful python, I don't use it much at all):<br>
<br>#!/usr/bin/env python<br>""" Usage: call with <filename><br>"""<br><br>import sys<br>import clang.cindex<br><br>target_decl_node = None<br><br>def find_target_method(node):<br> global target_decl_node<br>
<br> # When we get here, we know we're in the target declaration, so<br> # look for the desired method<br> if node.spelling == "foo":<br> target_decl_node = node<br><br> for child in node.get_children():<br>
find_target_method(child)<br> <br>def find_target_decl(node):<br><br> # Find class declaration subtree<br> if node.kind.is_declaration():<br> if node.spelling == "A":<br> find_target_method(node)<br>
<br> for child in node.get_children():<br> find_target_decl(child)<br><br>def find_target_refs(node):<br> if node.kind.is_expression():<br> if node.displayname == "foo":<br> print "found foo of kind %s" % (node.kind)<br>
refnode = clang.cindex.Cursor_ref(node)<br> print "Is this foo a ref to the target declaration?",<br> if refnode == target_decl_node:<br> print "YES"<br> else:<br>
print "NO"<br><br> for child in node.get_children():<br> find_target_refs(child)<br><br>cxx_args = []<br>cxx_args.append("-I/usr/local/include")<br><br>print "Parsing source into AST..."<br>
index = clang.cindex.Index.create()<br>tu = index.parse(sys.argv[1], cxx_args)<br><br>print "Finding target declaration..."<br>find_target_decl(tu.cursor)<br><br>print "Finding references..."<br>find_target_refs(tu.cursor)<br>
<br>