欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

clang-tags--上下文关联的c++调用搜索工具及其vim脚本

程序员文章站 2024-03-01 12:16:58
...

实际上,用vim的一个很大的缺点,是没有一个好用的,能理解上下文的c++调用关系搜索工具以及代码补全工具。在IDE里面,鼠标右键查找引用,查找调用,出来的结果是经过语法分析的,补全也是根据上下文头文件弄的。但是vim里面没有这个东西,毕竟vim是编辑器,他不知道编译信息。这个问题从我开始工作,就困扰着我,一直是我没法愉快使用vim写cpp的原因,毕竟菜。

后来,有了clang,以及clang complete等vim插件,解决了cpp代码补全的问题。YouCompleteMe加入了转到定义的功能,部分解决了跳转到定义的问题(但是不是特别准,有点问题)。

但是,调用关系搜索,一直是个解决不了的问题。

Clang静态分析

前一阵子突然想到要解决这个问题,就想到了clang。clang可以做代码静态分析,那怎么就不能做调用关系分析呢?实际上编译的时候肯定是需要调用关系的一个数据库的,不然没法愉快分析链接过程。那么clang有暴露接口嘛?有的,于是想到了用暴露出来的调用关系接口,做一个简单的调用关系数据库,然后通过查询数据库,查找对应的调用栈等信息。

Clang-Tags

我能想到,自然也有网友能想到,于是我在git上找到了clang-tags。这个项目已经把我的大部分想法都实现了,虽然已经有些年头了,但是总的来说还是能正常运行,只不过它需要strace用于生成编译参数,在mac上不是特别友好(mac不支持strace,并且该脚本兼容性也不是特别好),我fork了一个自己clang-tags,将strace移除,修复了一些crash问题,并且加入了虚函数调用关系的搜索。

安装

这个东西的架构不复杂,就是一个c++后台加一个python前端,需要使用libclang应该是他最大的坑了。但是一个想用vim写cpp的码农,这点问题应该是难不倒他的。

原repo给出的安装指引已经很好地解释了如何安装了。基本上requrie的库有,就能直接cmake过去。如果使用我的repo,可以跳过strace依赖,其他都是一样的。并且原repo主人使用的是emacs,所以还带有emacs的相关脚本,由于我不用emacs,有兴趣的伙伴自行尝试。

直接使用clang-tags

使用方法可以参考愿文章的quck start,里面有详细的文档,这里简单介绍下其中一种使用。

以我写的hello.cpp为例:

➜  clang cat hello.cpp

class Hello
{
public:
    int hello(int a, int b)
    {
        return a + b;
    }
    int hello(int a)
    {
        return hello(a, 1);
    }

    Hello();
    virtual ~Hello();
};

int main(int argc, char *argv[])
{
    Hello hi;
    hi.hello(10);
    return 0;
}

clang-tags是一个backend+frontend的架构,所以每次启动的时候要在工作目录使用start命令将它起起来:

➜  clang clang-tags start
Starting server...

有时候上一次非法推出,就会有crash,需要执行clean

➜  clang clang-tags start
ERROR: socket already exists!
➜  clang clang-tags clean
➜  clang clang-tags start
Starting server...

之后使用scan扫描一次本地目录,生成需要索引的文件编译配置compile_commands.json:

➜  clang ➜  clang clang-tags scan .
➜  clang ls
compile_commands.json  hello.cpp
➜  clang cat compile_commands.json
[
    {
        "directory": ".",
        "command": "gcc /home/johnzeng/learning/clang/hello.cpp ",
        "file": "/home/johnzeng/learning/clang/hello.cpp"
    }
]%

scan后可以跟编译参数。

之后使用load将文件载入backend的文件列表,在使用index进行第一次索引:

➜  clang clang-tags load
Server response:
  /home/johnzeng/learning/clang/hello.cpp
➜  clang clang-tags index
Server response:

-- Indexing project
/home/johnzeng/learning/clang/hello.cpp:
  parsing...	0.002643s.
  indexing...
  indexing...	0.002183s.
0.007176s.
现在载入好了,只需要调用对应的命令进行查询即可,比如int hello(int a)这个函数,hello的h在文件中的偏移(也就是一个byte一个byte从头开始数,这个是第几个byte)是96,那么可以调用下列命令查找他的定义
➜  clang clang-tags find-def /home/johnzeng/learning/clang/hello.cpp 95 -m
Server response:
-- hello(int a) { return hello(a, 1); } -- CXXMethod hello
   hello.cpp:9-12:9-5: hello
   USR: c:@aaa@qq.com@aaa@qq.com#I#
   isVirtual: 0
可以看到他的函数签名是
c:@aaa@qq.com@aaa@qq.com#I#

定义在hello.cpp的第9行,不是虚函数,是一个普通的cxx方法。

然后就可以根据这个签名找调用了:

➜  clang clang-tags grep 'c:@aaa@qq.com@aaa@qq.com#I#'
Server response:
hello.cpp:9:    int hello(int a)
hello.cpp:21:    hi.hello(10);
hello.cpp:21:    hi.hello(10);
由于服务器没有做去重,第21行返回了两次。还是挺好用的。

Vim-Clang-Tags

同样,这样的好东西,也是有人已经弄了,在git找到 vim-clang-tags ,试用了下,嗯,还行。但是有些小问题,也fork了一个出来,自己改了一些功能来适应自己的需求,就有了我自己的vim-clang-tags。查找结果全部使用quickfix的窗口。效果如下:

clang-tags--上下文关联的c++调用搜索工具及其vim脚本

这里查的是Reader::ReadMessage的结果。效果非常赞。


相关标签: vim clang tags