1

LibClang exposes a function to "determine the set of methods that are overridden by the given method" (explained here). However this function does not seem to be exposed in the python bindings. Could someone explain how to add this function to the bindings or did I just not find it?

cwde
  • 214
  • 1
  • 10

1 Answers1

0

In general, adding methods to libclang follows the same basic pattern used in the library itself.

  1. You use ctypes to find a handle to the method you want to wrap.
  2. You specify the extra type information about arguments and return types.
  3. You wrap that ctypes function in a python function that deals with any corner cases / caching.

For simple cases, you can use cymbal, a new Python module that came out of some experiments trying to answer this question. Cymbal lets you tack methods onto libclang types and cursors.

However, clang_getOverriddenCursors is slightly more complex than normal because you need to dispose of the memory returned by calling clang_disposeOverriddenCursors.

Additionally, libclang does some magic that means the cursors you get back from that function aren't valid for all function calls (they omit a pointer to the translation unit), So you also need to generate updated cursors (based on the translation unit and location).

Sample code:

import clang.cindex
from clang.cindex import *

clang_getOverriddenCursors = clang.cindex.conf.lib.clang_getOverriddenCursors
clang_getOverriddenCursors.restype = None
clang_getOverriddenCursors.argtypes = [Cursor, POINTER(POINTER(Cursor)), POINTER(c_uint)]

clang_disposeOverriddenCursors = clang.cindex.conf.lib.clang_disposeOverriddenCursors
clang_disposeOverriddenCursors.restype = None
clang_disposeOverriddenCursors.argtypes = [ POINTER(Cursor) ]

def get_overriden_cursors(self):
    cursors = POINTER(Cursor)()
    num = c_uint()
    clang_getOverriddenCursors(self, byref(cursors), byref(num))

    updcursors = []
    for i in xrange(int(num.value)):
        c = cursors[i]
        updcursor = Cursor.from_location(self._tu, c.location)
        updcursors.append( updcursor )

    clang_disposeOverriddenCursors(cursors)

    return updcursors

Assuming that you want to parse something like this:

// sample.cpp
class foo {
public:
    virtual void f();
};

class bar : public foo {
public:
    virtual void f();
};

You can find methods in the tree

idx = Index.create()
tu = idx.parse('sample.cpp', args = '-x c++'.split())
methods = []
for c in tu.cursor.walk_preorder():
    if c.kind == CursorKind.CXX_METHOD:
        methods.append(c)

You can then see the overrides

def show_method(method):
    return method.semantic_parent.spelling + '::' + method.spelling

for m in methods:
    for override in get_overriden_cursors(m):
        print show_method(m), 'overrides', show_method(override)

Which for me prints:

bar::f overrides foo::f
Andrew Walker
  • 40,984
  • 8
  • 62
  • 84