如何使用 clang python 绑定获取 class 方法定义?
How to get class method definitions using clang python bindings?
给定以下 C++ 文件:
class Foo
{
public:
Foo();
void bar(int input);
void another(int input, double & output);
};
void
Foo::bar(int input)
{
input += 1;
}
void
Foo::another(int input, double & output)
{
input += 1;
output = input * 1.2345;
}
如何利用 clang python 绑定来提取这两种方法的定义。我可以使用下面的 python 脚本获得 class 声明,但我似乎无法弄清楚如何提取完整的方法。例如,我想要这个信息:
void
Foo::another(int input, double & output)
{
input += 1;
output = input * 1.2345;
}
Python 脚本:
#!/usr/bin/env python
import clang.cindex
clang.cindex.Config.set_library_path('/opt/moose/llvm-3.7.0/lib')
def getCursors(cursor, output, kind):
"""
Recursively extract all the cursors of the given kind.
"""
for c in cursor.get_children():
if c.kind == kind:
output.append(c)
getCursors(c, output, kind)
if __name__ == '__main__':
# Parse the test file
index = clang.cindex.Index.create()
tu = index.parse('method.C', ['-x', 'c++'])
# Extract the parsers
output = []
getCursors(tu.cursor, output, clang.cindex.CursorKind.CXX_METHOD)
# Print the method declarations (How to I get the definitions?)
for c in output:
defn = c.get_definition() # Gives nothing
print defn
print c.extent.start.file, c.extent.start.line, c.extent.end.line # Gives decleration
跟进:
建议使用以下函数作为解决方案,但它不适用于 clang 3.7。在它发布之前我无法更新到 3.9,我需要支持最新的两个版本的 clang(3.7 和 3.8)。如果您添加打印语句,结果表明未找到定义。
def method_definitions(cursor):
for i in cursor.walk_preorder():
print i.kind, i.is_definition() # Added this
if i.kind != CursorKind.CXX_METHOD:
continue
if not i.is_definition():
continue
yield i
运行 该方法产生以下结果,有人知道 clang 3.7 和 3.9 之间发生了什么变化吗?
CursorKind.TRANSLATION_UNIT False
CursorKind.CLASS_DECL True
CursorKind.CXX_ACCESS_SPEC_DECL True
CursorKind.CONSTRUCTOR False
CursorKind.CXX_METHOD False
CursorKind.PARM_DECL True
CursorKind.CXX_METHOD False
CursorKind.PARM_DECL True
CursorKind.PARM_DECL True
您非常接近 - 诀窍是使用光标偏移量而不是行/列,而且据我所知,libclang 不会公开源的字节,因此您需要自己读出文本。
以下是测试:
- Clang 由 Xcode 7.3(7D175) 提供 - OSX Apple LLVM 版本 7.3.0 (clang-703.0.29) 和来自 pypi (
pip install 'clang==3.7'
) 的 pip 安装绑定
- Ubuntu clang 版本 3.7.1-svn253742-1~exp1 (branches/release_37)(基于 LLVM 3.7.1)
- Ubuntu clang 版本 3.6.2-svn240577-1~exp1 (branches/release_36) (基于 LLVM 3.6.2)
- clang 版本 3.9.0-svn267343-1~exp1(主干)
唯一需要注意的是,对于使用宏的更复杂的情况/headers YMMV。
import clang.cindex
from clang.cindex import *
def method_definitions(cursor):
for i in cursor.walk_preorder():
if i.kind != CursorKind.CXX_METHOD:
continue
if not i.is_definition():
continue
yield i
def extract_definition(cursor):
filename = cursor.location.file.name
with open(filename, 'r') as fh:
contents = fh.read()
return contents[cursor.extent.start.offset: cursor.extent.end.offset]
idx = Index.create()
tu = idx.parse('method.C', ['-x', 'c++'])
defns = method_definitions(tu.cursor)
for defn in defns:
print extract_definition(defn)
给出:
void
Foo::bar(int input)
{
input += 1;
}
void
Foo::another(int input, double & output)
{
input += 1;
output = input * 1.2345;
}
给定以下 C++ 文件:
class Foo
{
public:
Foo();
void bar(int input);
void another(int input, double & output);
};
void
Foo::bar(int input)
{
input += 1;
}
void
Foo::another(int input, double & output)
{
input += 1;
output = input * 1.2345;
}
如何利用 clang python 绑定来提取这两种方法的定义。我可以使用下面的 python 脚本获得 class 声明,但我似乎无法弄清楚如何提取完整的方法。例如,我想要这个信息:
void
Foo::another(int input, double & output)
{
input += 1;
output = input * 1.2345;
}
Python 脚本:
#!/usr/bin/env python
import clang.cindex
clang.cindex.Config.set_library_path('/opt/moose/llvm-3.7.0/lib')
def getCursors(cursor, output, kind):
"""
Recursively extract all the cursors of the given kind.
"""
for c in cursor.get_children():
if c.kind == kind:
output.append(c)
getCursors(c, output, kind)
if __name__ == '__main__':
# Parse the test file
index = clang.cindex.Index.create()
tu = index.parse('method.C', ['-x', 'c++'])
# Extract the parsers
output = []
getCursors(tu.cursor, output, clang.cindex.CursorKind.CXX_METHOD)
# Print the method declarations (How to I get the definitions?)
for c in output:
defn = c.get_definition() # Gives nothing
print defn
print c.extent.start.file, c.extent.start.line, c.extent.end.line # Gives decleration
跟进:
建议使用以下函数作为解决方案,但它不适用于 clang 3.7。在它发布之前我无法更新到 3.9,我需要支持最新的两个版本的 clang(3.7 和 3.8)。如果您添加打印语句,结果表明未找到定义。
def method_definitions(cursor):
for i in cursor.walk_preorder():
print i.kind, i.is_definition() # Added this
if i.kind != CursorKind.CXX_METHOD:
continue
if not i.is_definition():
continue
yield i
运行 该方法产生以下结果,有人知道 clang 3.7 和 3.9 之间发生了什么变化吗?
CursorKind.TRANSLATION_UNIT False
CursorKind.CLASS_DECL True
CursorKind.CXX_ACCESS_SPEC_DECL True
CursorKind.CONSTRUCTOR False
CursorKind.CXX_METHOD False
CursorKind.PARM_DECL True
CursorKind.CXX_METHOD False
CursorKind.PARM_DECL True
CursorKind.PARM_DECL True
您非常接近 - 诀窍是使用光标偏移量而不是行/列,而且据我所知,libclang 不会公开源的字节,因此您需要自己读出文本。
以下是测试:
- Clang 由 Xcode 7.3(7D175) 提供 - OSX Apple LLVM 版本 7.3.0 (clang-703.0.29) 和来自 pypi (
pip install 'clang==3.7'
) 的 pip 安装绑定 - Ubuntu clang 版本 3.7.1-svn253742-1~exp1 (branches/release_37)(基于 LLVM 3.7.1)
- Ubuntu clang 版本 3.6.2-svn240577-1~exp1 (branches/release_36) (基于 LLVM 3.6.2)
- clang 版本 3.9.0-svn267343-1~exp1(主干)
唯一需要注意的是,对于使用宏的更复杂的情况/headers YMMV。
import clang.cindex
from clang.cindex import *
def method_definitions(cursor):
for i in cursor.walk_preorder():
if i.kind != CursorKind.CXX_METHOD:
continue
if not i.is_definition():
continue
yield i
def extract_definition(cursor):
filename = cursor.location.file.name
with open(filename, 'r') as fh:
contents = fh.read()
return contents[cursor.extent.start.offset: cursor.extent.end.offset]
idx = Index.create()
tu = idx.parse('method.C', ['-x', 'c++'])
defns = method_definitions(tu.cursor)
for defn in defns:
print extract_definition(defn)
给出:
void
Foo::bar(int input)
{
input += 1;
}
void
Foo::another(int input, double & output)
{
input += 1;
output = input * 1.2345;
}