python-clang:获取模板参数

python-clang: Getting Template Arguments

我正在尝试使用 python-clang 从 C++ 中的 class 实例中提取模板参数,即。 libclang 的 Python 绑定(clang 3.9)。例如,对于

template <typename T> class X {};
X<bool> x;

我希望能够弄清楚 X 是使用 bool 作为其模板参数实例化的。

首先,某些功能,例如 get_num_template_arguments,似乎一开始就没有通过 python-clang 公开,这正是 cymbal 似乎对猴子起作用的地方-补丁 python-clang.

有了这个,我能走到这一步:

#!/usr/bin/env python

import clang.cindex

clang.cindex.Config.set_library_file('/usr/lib/x86_64-linux-gnu/libclang-3.9.so.1')

index = clang.cindex.Index.create()

source = """
template <typename T> class X {};
X<bool> x;
"""

######### stolen from cymbal

from ctypes import c_uint, c_int

def find_libclang_function(function):
    return getattr(clang.cindex.conf.lib, function)

def monkeypatch_helper(classtype, name, library_function, args, result):
    if hasattr(classtype, name):
        raise ('failed to add method, %s is already available' % name) 
    f = find_libclang_function(library_function)
    f.argtypes = args
    f.restype = result
    def impl(*args):
        return f(*args)
    setattr(classtype, name, impl)

def monkeypatch_type(method_name, library_function, args, result):
    monkeypatch_helper(clang.cindex.Type, method_name, library_function, args, result)



monkeypatch_type('get_template_argument_type',
                        'clang_Type_getTemplateArgumentAsType',
                        [clang.cindex.Type, c_uint],
                        clang.cindex.Type)

monkeypatch_type('get_num_template_arguments',
                        'clang_Type_getNumTemplateArguments',
                        [clang.cindex.Type],
                        c_int)
######### /stolen from cymbal

# helpers for visiting the AST recursively
def visit(node, func):
    func(node)
    for c in node.get_children():
        visit(c, func)

def visit_depth(node, func, depth=0):
    func(node, depth)
    for c in node.get_children():
        visit_depth(c, func, depth+1)

# parse the TU
tu = clang.cindex.TranslationUnit.from_source('t.cpp', ['-std=c++11'], unsaved_files=[('t.cpp', source)])

# show the AST
def astprinter(node, depth):
    print " "*depth, node.kind, node.spelling
visit_depth(tu.cursor, astprinter)    

# find everything with a template and try to extract the template argument
def template_finder(node):
    if hasattr(node, 'type') and node.type.get_num_template_arguments() != -1:
        print node.type.get_num_template_arguments(), node.spelling, node.kind, node.get_template_argument_type(0).kind
visit(tu.cursor, template_finder)

这输出:

 CursorKind.TRANSLATION_UNIT t.cpp
  CursorKind.CLASS_TEMPLATE X
   CursorKind.TEMPLATE_TYPE_PARAMETER T
  CursorKind.VAR_DECL x
   CursorKind.TEMPLATE_REF X
   CursorKind.CALL_EXPR X
1 x CursorKind.VAR_DECL TypeKind.INVALID
1 X CursorKind.CALL_EXPR TypeKind.INVALID

我期待 template_finder 中的 node.get_template_argument_type(0).kind 到 return 可以引导我到 bool,但我找不到任何东西。这是正确的方法吗?是否有可能在 python-clang 的当前状态下获取模板参数?

我认为您真正缺少的只是模板查找器中几个地方的 .type,但作为参考,这对我有用,即使在 clang 3.7

时也是如此
import clang.cindex
from clang.cindex import *
import cymbal
from ctypes import *

cymbal.monkeypatch_type('get_template_argument_type',
                        'clang_Type_getTemplateArgumentAsType',
                        [Type, c_uint],
                        Type)

cymbal.monkeypatch_type('get_num_template_arguments',
                        'clang_Type_getNumTemplateArguments',
                        [Type],
                        c_int)


# check if the cursor's type is a template
def is_template(node):
    return hasattr(node, 'type') and node.type.get_num_template_arguments() != -1

index = clang.cindex.Index.create()

source = """
template <typename T> class X {};
X<bool> x;
"""
# parse the TU
tu = clang.cindex.TranslationUnit.from_source('t.cpp', ['-std=c++11'], unsaved_files=[('t.cpp', source)])

for c in tu.cursor.walk_preorder():
    if is_template(c):
        t = c.type
        print t.kind, t.spelling, t.get_num_template_arguments()
        print t.get_template_argument_type(0).spelling

给出:

TypeKind.UNEXPOSED X<bool> 1
bool
TypeKind.UNEXPOSED X<bool> 1
bool