任何基于 libclang 的 C/C++ 重构工具?(即使是最简单的"toy example")



正如我在这里指出的那样,clang的libclang应该非常适合实现C/c++代码分析和修改这一艰巨任务(查看视频演示和幻灯片)。

你知道任何基于libclang的 C/c++重构工具吗?

"Any"甚至包括简单的alpha状态项目,支持一种重构技术。它可以不支持预处理器。举一个我所谈论的功能的例子:更改方法名,无论它一次支持多个文件还是只支持一个文件。您可能会想知道,即使是小的工作示例的目的是什么。我的想法是,创建一个代码示例和小工具的列表放在一个地方,将提供一个更好的资源来学习如何实现重构与libclang。我相信从简单的项目可以发展成更大的项目——以适当的开源方式:)。

Clang包含一个名为"CIndex"的库,我相信它是为了在ide中完成代码补全而开发的。它也可以用于解析c++和遍历AST,但没有任何重构的方式。参见Eli Bendersky的文章。

我最近开始了这样一个项目:cmonster。它是一个基于python的API,用于解析c++(使用libclang),分析AST,具有"重写"接口(即插入/删除/修改源范围)。目前还没有很好的方法来修改函数名并将其转换为源代码修改,但这样做并不会非常困难。

我还没有创建一个具有此功能的版本(尽管它在github repo中),因为我正在等待llvm/clang 3.0发布。

还有,我应该指出几件事:

  • 代码非常粗糙,称之为alpha可能会很慷慨。
  • 我绝不是这方面的专家(不像那边的Ira Baxter博士)。

适当调整期望

更新: cmonster 0.2已经发布,其中包括所描述的功能。在Github上查看。

Google一直在为Clang开发工具库。从3.2版本开始。它包含一个ASTMatchers库,因此您可以构建一个查询,而不必遍历AST。

关于这个主题有一个很好的视频演讲,其中介绍了一个简单的重命名示例。(这和上面发布的MapReduce演讲来自同一个人,但是更新,更多的是关于一个简单的实际实现,而不是谷歌正在进行的内部设计和企业规模的东西)。

在工具分支中可以找到重命名方法的示例的源代码。它可能在后备箱的某个地方,但我找不到。另外,将getDeclAs函数重命名为getNodesAs,因为另一个函数显然已被弃用。)有一个更高级的例子,可以删除重复的c_str调用(在trunk中,有人在上面发布)。

LibASTMatchers和libtools的文档

编辑:一些更好的ASTMatcher文档。这里和这里

编辑:Google现在正在做一个叫做Clangd的东西,它的目标是成为某种用于重构的Clang服务器。

Google为他们的c++代码库开发了一个基于Clang的重构工具,并计划发布它。我不知道项目的当前状态,但是您可以在2011年LLVM开发人员会议上看到这个演示:https://www.youtube.com/watch?v=mVbDzTM21BQ.

此外,XCode的(4+)内置自动补全和重构功能是基于libclang的。

这可能有点"元",但有一个例子是在clang中编写的,作为在clang上运行的工具(尽管,还有更多的事情要做。

RemoveCStrCalls.cpp

//  This file implements a tool that prints replacements that remove redundant
//  calls of c_str() on strings.
//
//  Usage:
//  remove-cstr-calls <cmake-output-dir> <file1> <file2> ...
//
//  Where <cmake-output-dir> is a CMake build directory in which a file named
//  compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
//  CMake to get this output).
//
//  <file1> ... specify the paths of files in the CMake source tree. This path
//  is looked up in the compile command database. If the path of a file is
//  absolute, it needs to point into CMake's source tree. If the path is
//  relative, the current working directory needs to be in the CMake source
//  tree and the file must be in a subdirectory of the current working
//  directory. "./" prefixes in the relative files will be automatically
//  removed, but the rest of a relative path must be a suffix of a path in
//  the compile command line database.
//
//  For example, to use remove-cstr-calls on all files in a subtree of the
//  source tree, use:
//
//    /path/in/subtree $ find . -name '*.cpp'|
//        xargs remove-cstr-calls /path/to/source

不是开源的,但已经被用来对c++程序进行非常非玩具的大规模自动重构:我们的DMS软件再造工具包。DMS是一个"库"(我们称它为"工具箱")的工具,可以组成来实现分析和/或自动翻译。

与c++相关,DMS在此时提供:

    完整的c++ 11解析器,构建AST并能够准确地重新生成源代码包括注释,带有完整的预处理器
  • 完整的c++解析器,包含c++的名称和类型解析(ANSI, GNU, MS Visual c++)
  • c++控制流程分析<<li> Source-to-source转换/gh>
  • 部分完成"重命名"机器(见下文讨论)

从我的经验来看,c++是一门很难转换的语言。

我们继续致力于此,并正在完成一个可靠的重命名工具。即使这样也很难;一个关键问题是名字的阴影问题。你有一个局部变量X,在这个作用域中有一个对Y的引用;您尝试将Y重命名为X,并发现局部变量"捕获"了访问。在c++中需要考虑的命名空间和捕获类型之多令人惊讶。这是许多其他重构的基础。

编辑2014年2月:完整的c++ 14解析器,控制流分析,本地数据流分析

https://github.com/lukhnos/refactorial是基于clang和claims

提供

变换

Accessor:合成指定成员的getter和setter变量

MethodMove:将内联成员函数体移动到实现中文件

ExtractParameter:将一个函数变量提升为该函数的参数函数

TypeRename:重命名类型,包括标签类型(enum、struct、union、类),模板类,Objective-C类型(类和协议),类型定义,甚至内置类型(例如unsigned to uint32_t)

RecordFieldRename:重命名记录(结构体,联合)字段,包括c++成员变量

FunctionRename:重命名函数,包括c++成员函数

通过YAML配置文件中的规范工作。我还没有试过。

另一种可能性是为GCC开发自己的插件,或者开发一个GCC MELT扩展来完成您的任务。但是扩展GCC(或Clang)需要理解这些编译器的内部表示(Gimple &Tree),这需要一些工作。MELT是扩展GCC的高级领域特定语言。

这不是重构,而是完成,但可能有用:

  • clang complete:使用clang完成C、c++、Objective-C和objective - c++

相关内容

最新更新