2016-03-12 39 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