Uncrustifyのセッティング (1) プリプロセッサ編

はじめに
--------
uncrustifyは、ソースコード整形のためのツール。
今回は、プリプロセッサに関する設定について、まとめて記載する。
これだけは、注意をしておこう。
uncrustifyでプリプロセッサをインデントさせるなら、「#pragma onceとインクルードガードは併用するな」

```cpp:foobar.hpp
#pragma once
#ifndef __FOO_BAR_HPP_INCLUDED__
#define __FOO_BAR_HPP_INCLUDED__

    #include <iostream> /* こんなふうにインデントされてしまうぞ */

#endif // __FOO_BAR_HPP_INCLUDED__

```

設定一覧
--------
|設定                   |説明                                                                                                                                     |
|:----------------------|:----------------------------------------------------------------------------------------------------------------------------------------|
| pp_indent             | #if、#ifdef、#ifndef〜#else〜#endifブロック内のプロプロセッサをインデントするかどうか。{ ignore, add, remove, force }                   |
| pp_indent_at_level    | ソースコードのインデントレベルに合わせてインデントするかどうか。{ true, false }                                                         |
| pp_indent_count       | pp_indent_at_level=falseの場合のインデント幅 { number }                                                                                 |
| pp_space              | #if、#ifdef、#ifndef〜#else〜#endifブロック内のプリプロセッサの#の後から半角空白でインデントするかどうか { ignore, add, remove, force } |
| pp_space_count        | #の後に加える半角空白数 { number }                                                                                                      |
| pp_indent_region      | #regionと#endregion (C#言語)、#pragmra region (C/C++) に対するインデント { number }                                                     |
| pp_region_indent_code | #regionと#endregionの間のコードをインデントするかどうか { true, false }                                                                 |
| pp_indent_if          | pp_indent_at_level=trueの場合: ファイルレベルにない'#if'、'#else'、'#endif'に対するインデント位置(N桁)を固定する { number }             |
| pp_if_indent_code     | ファイルレベルにない'#if'、'#else'、'#endif'の間のコードをインデントするかどうか { true, false }                                        |
| pp_define_at_level    | '#define'をブレースレベルに合わせてインデントするかどうか { true, false }                                                               |

僕の設定
--------
プリプロセッサ設定は、残念だが、自分のコーディングスタイルに合う設定を見つけるに至らなかった。
uncrustifyにおける僕なりの好みのセッティングについても書いておこう。

```bash:preprocessor.cfg
pp_indent             = add
pp_indent_at_level    = false
pp_indent_count       = 4
pp_space              = remove
pp_space_count        = 0
pp_indent_region      = 0
pp_region_indent_code = false
pp_indent_if          = 0
pp_if_indent_code     = false
pp_define_at_level    = false
```

- pp_indent設定 => add
  \#pragma onceのあるヘッダファイルはインデントが崩れるから、基本的にpp_indent=addする場合は、#pragma onceを付けないこと。

- pp_indent_at_level設定 => false
  pp_indent=ignoreが最良なので、後は書いても仕方がないが。
  ソースコードレベルに合わせてインデントするかどうかは、僕はしない。
  そもそもプリプロセッサはソースコードの行間に混在させたくない。
  ソースコードの行間に記述するとしても、これがマクロであり、ソースの実装と文脈が著しくずれている記述であることを意図的に強調させたい。

- pp_indent_count => 2 or 4
  プリプロセッサをインデントさせるなら、インデント幅は2もしくは4がいいかなと思う。どちらかというと4かな。

- pp_space => remove
  これは完全に好みだと思うけど、僕はプリプロセッサは#も含めてインデントする。
  理由は、キーボードの'TAB'キーを押しながら、インデントを入れていく時に#も含めた方が整形が楽だから。
  それに、「#だけは別」というインデントルールも増やしたくないし。(視認性は高いかもしれないけどね)

- pp_space_count => 0
  まあ、pp_space=removeだから、数値は関係ない。

- pp_indent_region
- pp_region_indent_code
  こういうpragmaは使わない。

- pp_indent_if
  pp_indent_at_level=falseだから、関係ない。

- pp_if_indent_code => false
  こんなことしたら、インデントしまくりで、ロジックが分かりづらくなる。
  そもそも、マクロとコードをミックスしないように最大限の努力を払うべきだし。

- pp_define_at_level => false
  これとpp_if_indent_codeと同じ理由だ。

PP_INDENT
---------
```cpp:pp_indent.cpp
// pp_indent=add
// #if、#ifdef、#ifndef〜#endifブロック内のプリプロセッサにインデントを挿入する。
#ifdef FOO
    #define BAR 1
#endif

// pp_indent=remove
// #if、#ifdef、#ifndef〜#endifブロック内のプリプロセッサからインデントを削除する。
#ifdef FOO
#define BAR 1
#endif
```

PP_INDENT_AT_LEVEL
------------------
```cpp:pp_indent_at_level.cpp
// pp_indent_at_level=true
// プリプロセッサのインデントレベルをコードのインデントレベルに合わせる。
class foo
{
    #ifdef FOO
    #define BAR 1
    #endif
    ...
}

// pp_indent_at_level=false
// プリプロセッサのインデントレベルをコードのインデントレベルに合わせない。
class foo
{
#ifdef FOO
#define BAR 1
#endif
    ...
}
```

PP_INDENT_COUNT
----------------
```cpp:pp_indent_count.cpp
// pp_indent_count=4
// インデント幅は半角空白4個
#ifdef FOO
    #ifdef BAR
        #define SOMETHING
    #endif
#endif

// pp_indent_count=8
// インデント幅は半角空白8個
#ifdef FOO
        #ifdef BAR
                #define SOMETHING
        #endif
#endif
```

PP_SPACE
--------
```cpp:pp_space.cpp
// pp_space=add
// #の後にスペースを挿入する
#ifdef FOO
# ifdef BAR
#  define SOMETHING
# endif
#endif

// pp_space=remove
// #の後にあるスペースを削除する
#ifdef FOO
#ifdef BAR
#define SOMETHING
#endif
#endif
```

PP_SPACE_COUNT
---------------
```cpp:pp_space_count.cpp
// pp_space_count=1
// #の後のインデント幅は1
#ifdef FOO
# ifdef BAR
#  define SOMETHING
# endif
#endif

// pp_space_count=2
// #の後のインデント幅は2
#ifdef FOO
#  ifdef BAR
#    define SOMETHING
#  endif
#endif
```

PP_INDENT_REGION
----------------
```cpp:pp_indent_region.cpp
```

PP_REGION_INDENT_CODE
----------------------
```cpp:pp_region_indent_code.cpp
```

PP_INDENT_IF
-----------
```cpp:pp_indent_if.cpp
// pp_indent_if=0
// インデント幅は固定されない。その他の整形オプションに応じてインデントされる。
namespace foo
{
    namespace bar
    {
        #ifdef FOO
            #ifdef BAR
                #define SOMETHING
            #endif
        #endif
    };
};

// pp_indent_if=2
// #ifxxx、#else、#endifのインデント幅は常に1(プリプロセッサは2桁目から開始)。#defineは影響されない。
namespace foo
{
    namespace bar
    {
 #ifdef FOO
 #ifdef BAR
                #define SOMETHING
 #endif
 #endif
    };
};
```

PP_IF_INDENT_CODE
----------------
```cpp:pp_if_indent_code.cpp
// pp_if_indent_code=true
// プリプロセッサレベル (#if〜#endifブロック) でインデントする。C/C++のコードもインデントされる。
struct foo
{
    struct bar
    {
        #ifdef FOO
            #ifdef BAR
                int foo;
            #else
                int bar;
            #endif
        #endif
    };
};

// pp_if_indent_code=false
// プリプロセッサレベル (#if〜#endifブロック) でインデントされない。
struct foo
{
    struct bar
    {
        #ifdef FOO
        #ifdef BAR
        int foo;
        #else
        int bar;
        #endif
        #endif
    };
};

```

PP_DEFINE_AT_LEVEL
-----------------
```cpp:pp_define_at_level.cpp
// pp_define_at_level=true
// #defineがソースコード(struct bar)のインデントレベルでインデントされる。
struct foo
{
    struct bar
    {
#ifdef FOO
        #define SOMETHING
#endif
    };
};

// pp_define_at_level=false
// #defineがソースコード(struct bar)のインデントレベルにはインデントされない。その他の整形オプションに応じてインデントされる。
struct foo
{
    struct bar
    {
#ifdef FOO
    #define SOMETHING
#endif
    };
};
```