モチベーションと結果
gitリポジトリを解析して、リビジョンAからリビジョンBの間でC++のどの関数が修正されたか特定したかったので、そもそも関数定義はどこの行で行われているかを特定するための方法を調査した。
ClangのPython bindingを使うことで、xxxという関数が何行目から何行目までで定義されているというような情報が取得できることが分かった。
元々がコンパイラなだけのことはあり、関数定義部だけでなく、変数定義部や二項演算子部やRETURN箇所等いろいろ取れるので、node.kind.nameの部分を適当に変えればいろいろできるだろう。
セットアップ
clangのpython bindingのインストール
Macな人は以下で良さそう。
http://asdm.hatenablog.com/entry/2015/01/08/170707
Ubuntuな人は、python bindingを使うためにはソースコードからビルドが必要のようだ。以下を参考にビルドする。
https://clang.llvm.org/get_started.html
https://blog.fenrir-inc.com/jp/2011/07/clang_syntax_analysis_interface_with_python.html
解析対象
ここのtest.cppを対象にさせてもった。
struct X{
int value;
void
func(){}
};
int
plus(int a, int b){
return a + b;
}
namespace hoge{
int
minus(int a, int b){
return a - b;
}
}
int
main(){
plus(1, 2);
hoge::minus(3, 5);
return 0;
}
解析コード
import clang.cindex
from clang.cindex import Index
from clang.cindex import Config
def print_method_area(node):
if (node.kind.name == 'FUNCTION_DECL'):
print "file : %s" % node.extent.start.file
print "function : %s" % node.displayname
print " from line:%s column:%s" % (node.extent.start.line, node.extent.start.column)
print " to line:%s column:%s" % (node.extent.end.line, node.extent.end.column)
for child in node.get_children():
print_method_area(child)
index = Index.create()
tu = index.parse("test.cpp")
print_method_area(tu.cursor)
出力
$ python analyze.py
file : test.cpp
function : plus(int, int)
from line:8 column:1
to line:11 column:2
file : test.cpp
function : minus(int, int)
from line:14 column:5
to line:17 column:6
file : test.cpp
function : main()
from line:20 column:1
to line:25 column:2
補足
include文なんかが入っていると、include先のファイルまで解析が実施される。include先を除去するには、node.extent.start.fileをチェックして解析対象ファイル以外はprintしないようにしてやれば良い。
そもそもの解析を止める方法もありそうだが。