在libclang(Python)中查找特定函数声明的所有引用
Find all references of specific function declaration in libclang (Python)
在Python中通过libclang解析C++源文件时,我试图查找(行和列位置)特定函数声明的所有引用。
例如:
#include <iostream>
using namespace std;
int addition (int a, int b)
{
int r;
r=a+b;
return r;
}
int main ()
{
int z, q;
z = addition (5,3);
q = addition (5,5);
cout << "The first result is " << z;
cout << "The second result is " << q;
}
因此,对于上面的源文件,我希望addition
在第5行的函数声明,find_all_function_decl_references
(见下文)在第15行和第16行返回对addition
的引用。
我试过这个(从这里改编)
import clang.cindex
import ccsyspath
index = clang.cindex.Index.create()
translation_unit = index.parse(filename, args=args)
for node in translation_unit.cursor.walk_preorder():
node_definition = node.get_definition()
if node.location.file is None:
continue
if node.location.file.name != sourcefile:
continue
if node_def is None:
pass
if node.kind.name == 'FUNCTION_DECL':
if node.kind.is_reference():
find_all_function_decl_references(node_definition.displayname) # TODO
另一种方法可以是存储列表中的所有函数声明,并在每个声明上运行find_all_function_decl_references
方法。
有人知道如何处理这个问题吗?这种find_all_function_decl_references
方法会如何?(我对libclang
和Python很陌生。)
我已经看到def find_typerefs
正在查找对某个类型的所有引用,但我不确定如何根据我的需要实现它。
理想情况下,我希望能够获取任何声明的所有引用;不仅是函数,还有变量声明、参数声明(例如上面第7行示例中的a
和b
)、类声明等。
编辑根据Andrew的评论,以下是关于我的设置规范的一些细节:
- LLVM 3.8.0-win64
- libclang-py3 3.8.1
- Python3.5.1(在Windows中,我假设是CPython)
- 对于
args
,我尝试了这里答案中建议的和另一个答案中的
*请注意,鉴于我的小编程经验,我很感激能给我一个简单解释它是如何工作的答案。
真正使这个问题具有挑战性的是C++的复杂性。
考虑一下C++中可调用的内容:函数、lambdas、函数调用运算符、成员函数、模板函数和成员模板函数。因此,在只匹配调用表达式的情况下,您需要能够消除这些情况的歧义。
此外,libclang并没有提供clang AST的完美视图(有些节点没有完全公开,尤其是与模板相关的一些节点)。因此,任意代码片段可能(甚至可能)包含一些构造,其中AST的libclangs视图不足以将调用表达式与声明相关联。
然而,如果您准备将自己限制在该语言的一个子集内,则可能会取得一些进展——例如,以下示例尝试将调用站点与函数声明关联起来。它通过在AST中的所有节点上执行一次调用表达式匹配函数声明来实现这一点。
from clang.cindex import *
def is_function_call(funcdecl, c):
""" Determine where a call-expression cursor refers to a particular function declaration
"""
defn = c.get_definition()
return (defn is not None) and (defn == funcdecl)
def fully_qualified(c):
""" Retrieve a fully qualified function name (with namespaces)
"""
res = c.spelling
c = c.semantic_parent
while c.kind != CursorKind.TRANSLATION_UNIT:
res = c.spelling + '::' + res
c = c.semantic_parent
return res
def find_funcs_and_calls(tu):
""" Retrieve lists of function declarations and call expressions in a translation unit
"""
filename = tu.cursor.spelling
calls = []
funcs = []
for c in tu.cursor.walk_preorder():
if c.location.file is None:
pass
elif c.location.file.name != filename:
pass
elif c.kind == CursorKind.CALL_EXPR:
calls.append(c)
elif c.kind == CursorKind.FUNCTION_DECL:
funcs.append(c)
return funcs, calls
idx = Index.create()
args = '-x c++ --std=c++11'.split()
tu = idx.parse('tmp.cpp', args=args)
funcs, calls = find_funcs_and_calls(tu)
for f in funcs:
print(fully_qualified(f), f.location)
for c in calls:
if is_function_call(f, c):
print('-', c)
print()
为了展示它的工作效果,您需要一个稍微更具挑战性的示例来解析:
// tmp.cpp
#include <iostream>
using namespace std;
namespace impl {
int addition(int x, int y) {
return x + y;
}
void f() {
addition(2, 3);
}
}
int addition (int a, int b) {
int r;
r=a+b;
return r;
}
int main () {
int z, q;
z = addition (5,3);
q = addition (5,5);
cout << "The first result is " << z;
cout << "The second result is " << q;
}
我得到了输出:
impl::addition
- <SourceLocation file 'tmp.cpp', line 10, column 9>
impl::f
addition
- <SourceLocation file 'tmp.cpp', line 22, column 7>
- <SourceLocation file 'tmp.cpp', line 23, column 7>
main
将其扩大到考虑更多类型的申报(IMO)将是一个不平凡的项目,也是一个有趣的项目。
处理意见
考虑到这个答案中的代码是否产生了我提供的结果,还有一些问题,我添加了代码的要点(再现了这个问题的内容)和一个非常小的流浪机器图像,你可以用来进行实验。一旦机器启动,你就可以克隆要点,并用命令重现答案:
git clone https://gist.github.com/AndrewWalker/daa2af23f34fe9a6acc2de579ec45535 find-func-decl-refs
cd find-func-decl-refs
export LD_LIBRARY_PATH=/usr/lib/llvm-3.8/lib/ && python3 main.py
- C++:为什么允许在另一个函数中声明函数,而不允许在函数定义中声明?
- 在c++中在类外声明函数有什么好处
- 使用 #define 声明函数
- 在静态库中声明函数,在使用该相同库的应用程序中定义它
- 如何强制编译器在 C/C++ 本身中声明函数?
- 如果您只需要在 .h 文件中声明函数.cpp是否需要在 .h 文件中声明函数?
- C++:<sys/sysctl.h> 无法声明函数CTL_HW和HW_NCPU
- 尝试声明函数的局部变量,但得到范围错误
- 如何在C++模板中声明函数
- 如何在另一个文件的类中声明函数
- 使用非类型模板参数正向声明函数模板
- 在此范围错误中未声明函数错误
- 当我们不能声明函数内联(GCC 编译器)时?
- 未在此作用域中声明函数,即使存在头文件也是如此
- 无法声明函数中的模板类型别名
- 单个CPP文件中多次声明函数声明可以吗?
- 编译一个支持VBA中声明函数的dll
- 使用从外部参数包中获取的参数类型声明函数
- 使用类成员正确地声明函数
- 在函数内重新声明函数