2016-03-12 34 views
1

LibClang公开了一个函数来“确定由给定方法覆盖的方法集”(解释为here)。然而这个函数似乎没有暴露在python绑定中。有人可以解释如何将这个函数添加到绑定或我没有找到它?LibClang Python绑定函数“getOverridden”

+0

我找到了自己的解决方案。稍后会在家发布。 – cwde

回答

0

通常,向libclang添加方法遵循库本身中使用的相同基本模式。

  1. 您可以使用ctypes来查找要包装的方法的句柄。
  2. 指定有关参数和返回类型的额外类型信息。
  3. 您可以将该ctypes函数封装在一个处理任何角落案例/缓存的python函数中。

对于简单的情况,您可以使用cymbal,这是一个新的Python模块,它出现在尝试回答此问题的一些实验中。 Cymbal允许您将方法固定到libclang类型和游标上。

但是,clang_getOverriddenCursors稍微比正常复杂,因为您需要处理通过调用clang_disposeOverriddenCursors返回的内存。

此外,libclang会做一些魔术,这意味着您从该函数获取的游标对于所有函数调用无效(它们省略了指向翻译单元的指针),因此您还需要生成更新的游标(基于翻译单位和地点)。

示例代码:

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 

假设要分析是这样的:

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

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

您可以找到树方法

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) 

然后,您可以看到超越

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) 

这对我来说会打印:

bar::f overrides foo::f