python-clang:获取模板参数
Posted
技术标签:
【中文标题】python-clang:获取模板参数【英文标题】:python-clang: Getting Template Arguments 【发布时间】:2016-12-26 15:21:24 【问题描述】:我正在尝试使用 python-clang
从 C++ 中的类实例化中提取模板参数,即。 libclang
的 Python 绑定(使用 clang
3.9)。例如,对于
template <typename T> class X ;
X<bool> x;
我希望能够弄清楚 X
是用 bool
作为其模板参数实例化的。
首先,似乎某些功能,例如get_num_template_arguments
,首先没有通过python-clang
公开,这就是cymbal 似乎对monkey-patch 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
返回一些东西来引导我到bool
,但我找不到任何东西。这是正确的方法吗?甚至可以在python-clang
的当前状态下获取模板参数吗?
【问题讨论】:
只是对 cymbal 的澄清——它在很大程度上是一个权宜之计,以防止任何人不得不复制和粘贴代码来使用 ctypes 注入函数。自发布以来,已经进行了一些重要的重构(例如,clang.cindex >= 3.9 现在有一个 register_function),这使得它变得不那么重要了。 还有关于 cymbal 的许可——它是在 MIT 许可下发布的,所以只要你做出适当的归属,就可以重复使用/回收你喜欢的任何代码 【参考方案1】:我认为您真正缺少的只是模板查找器中几个地方的.type
,但作为参考,这对我有用,即使在 3.7 年以前的 clang 上也是如此
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
【讨论】:
工作得很好,谢谢——还有关于钹的澄清,我会调查一下。以上是关于python-clang:获取模板参数的主要内容,如果未能解决你的问题,请参考以下文章