[cfe-dev] libclang type resolution problem (python bindings)

Robert Anderson rwa at alumni.princeton.edu
Wed Jan 4 12:20:39 PST 2012


Hi,

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

http://eli.thegreenplace.net/2011/07/03/parsing-c-in-python-with-clang/

I've run into a difficulty that seems to be associated with templates.

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.)

This works great when the class is not a templated class:


struct A { void foo() {} };

struct B { void foo() {} };

int main()
{
   A a;
   a.foo();

   B b;
   b.foo();
}

My python script produces the following expected output:

./reference-test.py test1.cxx
Parsing source into AST...
Finding target declaration...
Finding references...
found foo of kind CursorKind.CALL_EXPR
Is this foo a ref to the target declaration? YES
found foo of kind CursorKind.MEMBER_REF_EXPR
Is this foo a ref to the target declaration? YES
found foo of kind CursorKind.CALL_EXPR
Is this foo a ref to the target declaration? NO
found foo of kind CursorKind.MEMBER_REF_EXPR
Is this foo a ref to the target declaration? NO

That is all expected behavior.  The target declaration is A::foo().

However, when class A is a templated class:

template <class T>
struct A { void foo() {} };

struct B { void foo() {} };

int main()
{
   A<int> a;
   a.foo();

   B b;
   b.foo();
}

The behavior changes, and none of the references seem to point back to the
declaration node this time.  The output is now:

./reference-test.py test2.cxx
Parsing source into AST...
Finding target declaration...
Finding references...
found foo of kind CursorKind.CALL_EXPR
Is this foo a ref to the target declaration? NO
found foo of kind CursorKind.MEMBER_REF_EXPR
Is this foo a ref to the target declaration? NO
found foo of kind CursorKind.CALL_EXPR
Is this foo a ref to the target declaration? NO
found foo of kind CursorKind.MEMBER_REF_EXPR
Is this foo a ref to the target declaration? NO

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.

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.

Help?

My python script is as follows (apologies for most likely awful python, I
don't use it much at all):

#!/usr/bin/env python
""" Usage: call with <filename>
"""

import sys
import clang.cindex

target_decl_node = None

def find_target_method(node):
   global target_decl_node

   # When we get here, we know we're in the target declaration, so
   # look for the desired method
   if node.spelling == "foo":
      target_decl_node = node

   for child in node.get_children():
      find_target_method(child)

def find_target_decl(node):

   # Find class declaration subtree
   if node.kind.is_declaration():
      if node.spelling == "A":
         find_target_method(node)

   for child in node.get_children():
      find_target_decl(child)

def find_target_refs(node):
   if node.kind.is_expression():
      if node.displayname == "foo":
         print "found foo of kind %s" % (node.kind)
         refnode = clang.cindex.Cursor_ref(node)
         print "Is this foo a ref to the target declaration?",
         if refnode == target_decl_node:
            print "YES"
         else:
            print "NO"

   for child in node.get_children():
      find_target_refs(child)

cxx_args = []
cxx_args.append("-I/usr/local/include")

print "Parsing source into AST..."
index = clang.cindex.Index.create()
tu = index.parse(sys.argv[1], cxx_args)

print "Finding target declaration..."
find_target_decl(tu.cursor)

print "Finding references..."
find_target_refs(tu.cursor)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20120104/693d06d6/attachment.html>


More information about the cfe-dev mailing list