pycparserを用いたCコードレビューツール

# 背景・目的

普段C言語のソフト開発していて、
コードレビューを依頼する前に自分の書いたコードがコーディングルールに沿って書かれているかセルフチェックするツールが欲しいと考えていました。

コードの構文解析処理から作るのは大変なので何か良いライブラリはないか探したところ、
pycparserというライブラリが使えそうだったので、これを使ったコードレビューツール、「pycreviewer」を作りました。
https://github.com/dromar-soft/Pycreviewer
 
# 実行環境
 
* Python 3.8.2. 
* pycparser 2.2.0(https://github.com/eliben/pycparser)

# pycparserについて

pycparserはeliben氏によって開発されたC言語の構文解析ライブラリです。
https://github.com/eliben/pycparser

# 設計

![](https://raw.githubusercontent.com/dromar-soft/Pycreviewer/images/architecture.png)
 
# 機能

## 対応するコーディングルール一覧

### Static variable name prefix

static変数名に特定の接頭辞（例えば'm_'）がついているかを確認します。

```c
#inclide <stdio.h>
static int m_var;
```

### Global variable name prefix

global変数名に特定の接頭辞(例えば'g_')がついているかを確認します。

```c
#inclide <stdio.h>
int g_var;
```

### Too short variable name

短すぎる変数名を検出します。

```c
int i;
```

### Recursive call

関数の再起呼び出しを検出します。

### Function blacklist

使用禁止の関数呼び出しを検出します。
(使用禁止の関数は後述のJSONファイルで設定）

### No break statement in the switch-case statement

switch-case文中にbreak()文が入っていない箇所を検出します。

```c
    switch(flag){
        case 0:
            break;
        case 1:
            //No Break
        default:
            break;
    }
```

### No default statement in switch statement

switch文中にdefault文が定義されていない箇所を検出します。

```c
        switch(f){
            case 0:
                break;
            case 1:
                break;
            //No Default
        }
```


## JSONファイルによる詳細条件の設定

```json
{
    "version": "0.1.0",
    "conditions":{
        "static_variable_prefix":{
            "id":"R001",
            "param":"m_",
            "level":"SHOULD"
        },
        "global_variable_prefix":{
            "id":"R002",
            "param":"g_",
            "level":"SHOULD"
        },
        "variable_short_name":{
            "id":"R003",
            "param":2,
            "level":"MUST"
        },
        "recursive_call":{
            "id":"R004",
            "param":true,
            "level":"MUST"
        },
        "function_blacklist":{
            "id":"R005",
            "param":[
                "malloc",
                "free"
            ],
            "level":"WANT"
        },
        "no_break_in_switch":{
            "id":"R006",
            "param":true,
            "level":"SHOULD"
        },
        "no_default_in_switch":{
            "id":"R007",
            "param":true,
            "level":"SHOULD"
        }
    }
}

```
 
# インストール

```bash 
git clone https://github.com/dromar-soft/Pycreviewer.git
```

# 使い方
 
## コンソールアプリケーションとして利用

```bash
python -m pycreviewer
input source folder >> 'your sourcecode directory'
{'id': 'R006', 'level': 'SHOULD', 'msg': 'No break statement in switch-case statement.', 'file': '/xxx/xxx/xxx.c', 'line': X, 'column': X}
{'id': 'R007', 'level': 'SHOULD', 'msg': 'No default statement in switch-case statement.', 'file': '/xxx/xxx/xxx.c', 'line': X, 'column': Y}
...
...
...
X files codereview completed. Please enter esc key.
```

## ライブラリとしての利用

pycreviewer.review_file()を呼び出すことで、単一のソースファイルに対してコードレビューを実行することができます。

```python
def review_file(sourcefile: str, cpp_args=['-E', r'-Ipycreviewer/utils/fake_libc_include'], jsonfile='./default.json') ->list:
    """
    Perform code review on a single source file.
    The result of the code review is returned in the form of List<CheckResult>.
    sourcefile:
        the target source file path.
    cppargs:
        a list of command line arguments for the preprocessor execution of C compiler.
        Normally, specifies the preprocessor execution option '-E' and the include option '-Ixxxxx'.
    jsonfile:
        JSON file path describing the checking conditions for coding rules.
    """
```    
# 注意事項
 
* C言語のソースコードを解析するために、本ライブラリはCコンパイラのプリプロセッサ(gcc -E)を実行します。
そのため、ターゲットソースコードのコンパイルエラーを事前に除去しておく必要があります。

# 最後に

* 自分の書いたコードがコーディングルールに沿って書かれているかセルフチェックするツールを開発しました。
* 2020/5/31時点ではいくつかの簡単なルールのみ実装していますが、必要に応じて追加のルールを実装していきます。