call graphなるintellijのpluginについて

# 概要

[コールグラフ](https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%BC%E3%83%AB%E3%82%B0%E3%83%A9%E3%83%95)を簡易に出すために[call graph](https://github.com/Chentai-Kao/call-graph-plugin)というintellijのpluginを利用して感じたことのメモ。
結論としては、有用そうだったが、Spring等DIを用いているソースコードの解析には今ひとつ足りないように感じた。

# モチベーション

なぜcall graphを利用しようと思ったのか？

ソースコードの改修を行うとき、このコードは一体にどこに影響があるのだろう、と悩むことは多い。
そんな時に私は修正箇所のメソッドを呼び出している箇所を洗いだして、影響箇所を確認している。

このような作業をする替わりに、スパッと一瞬で下記のようなコールグラフが図示できたら素敵だな、というのがモチベーションである。

![method.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441085/506fd2e3-200e-1bcc-dedd-b3d01704cf45.png)

# call graph

[call graph](https://github.com/Chentai-Kao/call-graph-plugin)は、コールグラフを出力することができるintellijのpluginである。
サポート対象の言語はJavaのみである。

試しに[HikariCP](https://github.com/brettwooldridge/HikariCP)で解析を実行してみたところ、下記のようになった。
![スクリーンショット 2022-08-14 20.09.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441085/01dd323f-e0b4-4782-9825-520f7c7dd4fc.png)

上記図では細かいところは分からないが、もちろんズームすることができる。
メソッドをクリックすると繋がりの線が光るようになり、繋がりを追いやすくする工夫が凝らされている。

![スクリーンショット 2022-08-14 20.11.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441085/f0102c60-aaf9-4d1f-0a82-8f43c963b7eb.png)

## 物足りなかったところ

DIによってインスタンス生成が行われている場合、コールグラフが期待した形にならない。
例として、下記のようなController、Service、Repositoryを利用した構成になっている場合を考える。

```java:Controller
package com.example.tryjpa;

import java.util.List;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Controller {

    private final Service service;

    public Controller(Service service) {
        this.service = service;
    }

    @GetMapping("test")
    public List<MyEntity> get() {
        return service.findAll();
    }
}
```

```java:Service
package com.example.tryjpa;

import java.util.List;

public interface Service {
    List<MyEntity> findAll();
}
```

```java:ServiceImpl
package com.example.tryjpa;

import java.util.List;

@org.springframework.stereotype.Service
public class ServiceImpl implements Service {
    private final MyRepository myRepository;

    public ServiceImpl(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    @Override
    public List<MyEntity> findAll() {
        return myRepository.findAll();
    }
}
```

```java:Repository
package com.example.tryjpa;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface MyRepository extends JpaRepository<MyEntity, Long> {
}
```

上記のようなコードの場合、call graphによる解析は下記のようになる。

![スクリーンショット 2022-08-14 20.29.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441085/4dbed6d0-afaa-2dd4-4241-61605f58c70e.png)

ここで特に物足りないと感じるのは、`Service.java`の`findAll`メソッドと`ServiceImpl.java`の`findAll`メソッドが別々に扱われてしまう点だ。
`Controller#get` -> `Service#findAll` -> `MyRepository#findAll`
の流れを見ることができれば最高なのだが、それは叶わない。

# その他雑感

[2020年発表の論文](https://mugdhak30.github.io/assets/MugdhaMasterThesis.pdf)で、Webフレームワークのコールグラフ構築領域が未開拓であることが言及されている。
今、Springのコールグラフを出力できるツールがあったら是非知りたい。

```
正確なコールグラフを構築することは、健全で正確な静的解析を行うための重要な前提条件です。
多くの研究が健全なコールグラフ構築アルゴリズムの開発に費やされている一方で、Webフレームワークのコールグラフ構築の領域はほとんど未開拓のままである。
本論文の最初の貢献は、Springフレームワークのコールグラフ構築アルゴリズムの不健全さが、反射呼び出しの存在にのみ起因するという観察である。
これは第3章に記述されており、我々の問題を静的解析におけるリフレクションの処理に絞り込んでいる。
本論文のもう一つの貢献は、4章で説明するように、ハイブリッド解析アルゴリズムを提示することである。
このアルゴリズムは、Javaで書かれた入力Springプログラムの単純で、反射しないバージョンを生成する。このアルゴリズムは入力されたプログラムをSpringコンテナの初期化まで実行する。この実行からいくつかのBean情報を取得し、それを使って入力プログラムを単純な非反射型プログラムに変換します。
このアルゴリズムはSpringフレームワークの上で設計されたWebフレームワークで書かれたプログラムに対して動作し、これらのプログラムに対して構築されるコールグラフは必要に応じて健全かつ正確なものとなる。
このアルゴリズムのアイデアが、将来、プログラム解析者やウェブ開発者がコールグラフ構築アルゴリズムの健全性と結果のコールグラフの精度を研究し、（できれば）改善するのに役立つことを期待する。
```