冬休み到来! clang-tidy で安心安全な C/C++ コーディングを極めよう!

漢なら C/C++ ですね! clang-tidy で安心安全な C/C++ コーディングを極めましょう!

https://clang.llvm.org/extra/clang-tidy/index.html

clang-tidy は, LibTooling をベースとした, コーディングをチェックしたりするツールです. ちょっとしたワーニングなら自動でリライトする機能もあって便利だよ. 


clang 単体でも, `-Weverything` で結構見つかるけど([C++コードのデトックス](http://qiita.com/MitsutakaTakeda/items/6b9966f890cc9b944d75) 参照), clang-tidy だと MPI 関数のチェックとか(なんという俺得機能)あって, もっと色々解析してくれるよ.

### tidy(タイディ) とは

テディベアの Teddy とはスペルが違います.

片付けるとか, 整理するという意味合いです. つまりは konmari(こんまり)ですね.


## 準備する.

clang-tidy では, C/C++ コードがどのようにコンパイルされたかの情報が必要になります.

https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html

cmake とか ninja とかだと, 自動で生成する機能があるようです.

とりあえず今回は手動で作ります.
ちなみに, こういう時, ヘッダオンリーだったりシングルファイルな C/C++ コードだとセットアップが楽で新しいツールをすぐ試せて便利ですね! [シングルファイル C/C++ ライブラリが便利すぎてやばい](http://qiita.com/syoyo/items/e9d4aff56f691f5b783b)

以下のようなコンパイルデータベースを用意します.
ファイル名は `compile_commands.json` でないとダメのようです.

```json
[
  { "directory": "/Users/syoyo/work/tidy-test/",
    "command": "/usr/bin/clang++ -Weverything file.cc",
    "file": "file.cc"
  }
]
```

適当に `file.cc` をでっちあげます.

```cpp
int main(int argc, char **argv)
{
  const char *cpc;
  const char *cpc2 = (const char*)cpc;
  short b = argc;
  return b;
}
```

以下のようにして `file.cc` をチェックします. `compile_commands.json` は同じディレクトリにあると仮定していますが, 別ディレクトリにある場合は `-p` コマンドでディレクトリの場所を指定できます.

```
$ clang-tidy file.cc

7 warnings generated.
file.cc:1:27: warning: unused parameter 'argv' [clang-diagnostic-unused-parameter]
int main(int argc, char **argv)
                          ^
file.cc:4:3: warning: Assigned value is garbage or undefined [clang-analyzer-core.uninitialized.Assign]
  const char *cpc2 = (const char*)cpc;
  ^
file.cc:3:3: note: 'cpc' declared without an initial value
  const char *cpc;
  ^
file.cc:4:3: note: Assigned value is garbage or undefined
  const char *cpc2 = (const char*)cpc;
  ^
file.cc:4:15: warning: Value stored to 'cpc2' during its initialization is never read [clang-analyzer-deadcode.DeadStores]
  const char *cpc2 = (const char*)cpc;
              ^
file.cc:4:15: note: Value stored to 'cpc2' during its initialization is never read
  const char *cpc2 = (const char*)cpc;
              ^
file.cc:4:15: warning: unused variable 'cpc2' [clang-diagnostic-unused-variable]
  const char *cpc2 = (const char*)cpc;
              ^
file.cc:4:22: warning: use of old-style cast [clang-diagnostic-old-style-cast]
  const char *cpc2 = (const char*)cpc;
                     ^
/Users/syoyo/work/tidy-test/file.cc:4:35: warning: variable 'cpc' is uninitialized when used here [clang-diagnostic-uninitialized]
  const char *cpc2 = (const char*)cpc;
                                  ^
/Users/syoyo/work/tidy-test/file.cc:3:18: note: initialize the variable 'cpc' to silence this warning
  const char *cpc;
                 ^
/Users/syoyo/work/tidy-test/file.cc:5:13: warning: implicit conversion loses integer precision: 'int' to 'short' [clang-diagnostic-conversion]
  short b = argc;
            ^
```

おお〜!

`-checks` でどのチェックを行うか指定できます. 

`-checks=* -list-checks` で, どのチェックが利用可能かわかります.

```
$ clang-tidy -checks=* -list-checks
Enabled checks:
    boost-use-to-string
    cert-dcl03-c
    cert-dcl50-cpp
    cert-dcl54-cpp
    cert-dcl59-cpp
    cert-env33-c
    cert-err34-c
    cert-err52-cpp
    cert-err58-cpp
    cert-err60-cpp
    cert-err61-cpp
    cert-fio38-c
    cert-flp30-c
    cert-oop11-cpp
    clang-analyzer-alpha.core.BoolAssignment
    clang-analyzer-alpha.core.CallAndMessageUnInitRefArg
    clang-analyzer-alpha.core.CastSize
    clang-analyzer-alpha.core.CastToStruct
    clang-analyzer-alpha.core.DynamicTypeChecker
    clang-analyzer-alpha.core.FixedAddr
    clang-analyzer-alpha.core.IdenticalExpr
    clang-analyzer-alpha.core.PointerArithm
    clang-analyzer-alpha.core.PointerSub
    clang-analyzer-alpha.core.SizeofPtr
    clang-analyzer-alpha.core.TestAfterDivZero
    clang-analyzer-alpha.cplusplus.VirtualCall
    clang-analyzer-alpha.deadcode.UnreachableCode
    clang-analyzer-alpha.osx.cocoa.DirectIvarAssignment
    clang-analyzer-alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions
    clang-analyzer-alpha.osx.cocoa.InstanceVariableInvalidation
    clang-analyzer-alpha.osx.cocoa.MissingInvalidationMethod
    clang-analyzer-alpha.osx.cocoa.localizability.PluralMisuseChecker
    clang-analyzer-alpha.security.ArrayBound
    clang-analyzer-alpha.security.ArrayBoundV2
    clang-analyzer-alpha.security.MallocOverflow
    clang-analyzer-alpha.security.ReturnPtrRange
    clang-analyzer-alpha.security.taint.TaintPropagation
    clang-analyzer-alpha.unix.Chroot
    clang-analyzer-alpha.unix.PthreadLock
    clang-analyzer-alpha.unix.SimpleStream
    clang-analyzer-alpha.unix.Stream
    clang-analyzer-alpha.unix.cstring.BufferOverlap
    clang-analyzer-alpha.unix.cstring.NotNullTerminated
    clang-analyzer-alpha.unix.cstring.OutOfBounds
    clang-analyzer-core.CallAndMessage
    clang-analyzer-core.DivideZero
    clang-analyzer-core.DynamicTypePropagation
    clang-analyzer-core.NonNullParamChecker
    clang-analyzer-core.NullDereference
    clang-analyzer-core.StackAddressEscape
    clang-analyzer-core.UndefinedBinaryOperatorResult
    clang-analyzer-core.VLASize
    clang-analyzer-core.builtin.BuiltinFunctions
    clang-analyzer-core.builtin.NoReturnFunctions
    clang-analyzer-core.uninitialized.ArraySubscript
    clang-analyzer-core.uninitialized.Assign
    clang-analyzer-core.uninitialized.Branch
    clang-analyzer-core.uninitialized.CapturedBlockVariable
    clang-analyzer-core.uninitialized.UndefReturn
    clang-analyzer-cplusplus.NewDelete
    clang-analyzer-cplusplus.NewDeleteLeaks
    clang-analyzer-deadcode.DeadStores
    clang-analyzer-llvm.Conventions
    clang-analyzer-nullability.NullPassedToNonnull
    clang-analyzer-nullability.NullReturnedFromNonnull
    clang-analyzer-nullability.NullableDereferenced
    clang-analyzer-nullability.NullablePassedToNonnull
    clang-analyzer-nullability.NullablePassedToNonnull
    clang-analyzer-optin.mpi.MPI-Checker
    clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker
    clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker
    clang-analyzer-optin.performance.Padding
    clang-analyzer-osx.API
    clang-analyzer-osx.SecKeychainAPI
    clang-analyzer-osx.cocoa.AtSync
    clang-analyzer-osx.cocoa.ClassRelease
    clang-analyzer-osx.cocoa.Dealloc
    clang-analyzer-osx.cocoa.IncompatibleMethodTypes
    clang-analyzer-osx.cocoa.Loops
    clang-analyzer-osx.cocoa.MissingSuperCall
    clang-analyzer-osx.cocoa.NSAutoreleasePool
    clang-analyzer-osx.cocoa.NSError
    clang-analyzer-osx.cocoa.NilArg
    clang-analyzer-osx.cocoa.NonNilReturnValue
    clang-analyzer-osx.cocoa.ObjCGenerics
    clang-analyzer-osx.cocoa.RetainCount
    clang-analyzer-osx.cocoa.SelfInit
    clang-analyzer-osx.cocoa.SuperDealloc
    clang-analyzer-osx.cocoa.UnusedIvars
    clang-analyzer-osx.cocoa.VariadicMethodTypes
    clang-analyzer-osx.coreFoundation.CFError
    clang-analyzer-osx.coreFoundation.CFNumber
    clang-analyzer-osx.coreFoundation.CFRetainRelease
    clang-analyzer-osx.coreFoundation.containers.OutOfBounds
    clang-analyzer-osx.coreFoundation.containers.PointerSizedValues
    clang-analyzer-security.FloatLoopCounter
    clang-analyzer-security.insecureAPI.UncheckedReturn
    clang-analyzer-security.insecureAPI.getpw
    clang-analyzer-security.insecureAPI.gets
    clang-analyzer-security.insecureAPI.mkstemp
    clang-analyzer-security.insecureAPI.mktemp
    clang-analyzer-security.insecureAPI.rand
    clang-analyzer-security.insecureAPI.strcpy
    clang-analyzer-security.insecureAPI.vfork
    clang-analyzer-unix.API
    clang-analyzer-unix.Malloc
    clang-analyzer-unix.MallocSizeof
    clang-analyzer-unix.MismatchedDeallocator
    clang-analyzer-unix.Vfork
    clang-analyzer-unix.cstring.BadSizeArg
    clang-analyzer-unix.cstring.NullArg
    cppcoreguidelines-c-copy-assignment-signature
    cppcoreguidelines-interfaces-global-init
    cppcoreguidelines-pro-bounds-array-to-pointer-decay
    cppcoreguidelines-pro-bounds-constant-array-index
    cppcoreguidelines-pro-bounds-pointer-arithmetic
    cppcoreguidelines-pro-type-const-cast
    cppcoreguidelines-pro-type-cstyle-cast
    cppcoreguidelines-pro-type-member-init
    cppcoreguidelines-pro-type-reinterpret-cast
    cppcoreguidelines-pro-type-static-cast-downcast
    cppcoreguidelines-pro-type-union-access
    cppcoreguidelines-pro-type-vararg
    google-build-explicit-make-pair
    google-build-namespaces
    google-build-using-namespace
    google-default-arguments
    google-explicit-constructor
    google-global-names-in-headers
    google-readability-braces-around-statements
    google-readability-casting
    google-readability-function-size
    google-readability-namespace-comments
    google-readability-redundant-smartptr-get
    google-readability-todo
    google-runtime-int
    google-runtime-member-string-references
    google-runtime-memset
    google-runtime-operator
    google-runtime-references
    llvm-header-guard
    llvm-include-order
    llvm-namespace-comment
    llvm-twine-local
    misc-argument-comment
    misc-assert-side-effect
    misc-bool-pointer-implicit-conversion
    misc-dangling-handle
    misc-definitions-in-headers
    misc-fold-init-type
    misc-forward-declaration-namespace
    misc-inaccurate-erase
    misc-incorrect-roundings
    misc-inefficient-algorithm
    misc-macro-parentheses
    misc-macro-repeated-side-effects
    misc-misplaced-const
    misc-misplaced-widening-cast
    misc-move-const-arg
    misc-move-constructor-init
    misc-multiple-statement-macro
    misc-new-delete-overloads
    misc-noexcept-move-constructor
    misc-non-copyable-objects
    misc-pointer-and-integral-operation
    misc-redundant-expression
    misc-sizeof-container
    misc-sizeof-expression
    misc-static-assert
    misc-string-constructor
    misc-string-integer-assignment
    misc-string-literal-with-embedded-nul
    misc-suspicious-missing-comma
    misc-suspicious-semicolon
    misc-suspicious-string-compare
    misc-swapped-arguments
    misc-throw-by-value-catch-by-reference
    misc-unconventional-assign-operator
    misc-undelegated-constructor
    misc-uniqueptr-reset-release
    misc-unused-alias-decls
    misc-unused-parameters
    misc-unused-raii
    misc-unused-using-decls
    misc-virtual-near-miss
    modernize-avoid-bind
    modernize-deprecated-headers
    modernize-loop-convert
    modernize-make-shared
    modernize-make-unique
    modernize-pass-by-value
    modernize-raw-string-literal
    modernize-redundant-void-arg
    modernize-replace-auto-ptr
    modernize-shrink-to-fit
    modernize-use-auto
    modernize-use-bool-literals
    modernize-use-default
    modernize-use-emplace
    modernize-use-nullptr
    modernize-use-override
    modernize-use-using
    performance-faster-string-find
    performance-for-range-copy
    performance-implicit-cast-in-loop
    performance-unnecessary-copy-initialization
    performance-unnecessary-value-param
    readability-avoid-const-params-in-decls
    readability-braces-around-statements
    readability-container-size-empty
    readability-deleted-default
    readability-else-after-return
    readability-function-size
    readability-identifier-naming
    readability-implicit-bool-cast
    readability-inconsistent-declaration-parameter-name
    readability-named-parameter
    readability-redundant-control-flow
    readability-redundant-smartptr-get
    readability-redundant-string-cstr
    readability-redundant-string-init
    readability-simplify-boolean-expr
    readability-static-definition-in-anonymous-namespace
    readability-uniqueptr-delete-release
```

## チェックの例

readability-braces-around-statements

https://clang.llvm.org/extra/clang-tidy/checks/readability-braces-around-statements.html

括弧のない if 文などをチェックしてくれます.

筆者は常に括弧つけたい派なので, このオプションを活用していきたいですね.

## clang-tidy で自動でソースコードを fix する.

clang-tidy には `-fix`(及び `-fix-error`) で, 自動で修正してくれる機能があります.

ただ, どのチェックでも利用可能なわけでないようです. 

少なくとも, clang-tidy(clang-tools)のテストコードを見て, `CHECK-FIXES` があるのは自動で fix してくれると想像できます. 今回は `google-readability-casting` に注目してみましょう.

https://github.com/llvm-mirror/clang-tools-extra/blob/master/test/clang-tidy/google-readability-casting.cpp

特定のチェックにフォーカスするために, `-checks=-*,google-readability-casting` とすることで, `-*` でまずはすべてのチェックを無効にし, その後 `google-readability-casting` だけを有効にすることができます. カンマで区切ることで複数指定できます. `*` でワイルドカードも使えます.

```
$ clang-tidy file.cc -checks=-*,google-readability-casting 
6 warnings generated.
/Users/syoyo/work/tidy-test/file.cc:4:22: warning: redundant cast to the same type [google-readability-casting]
  const char *cpc2 = (const char*)cpc;
                     ^
Suppressed 5 warnings (5 with check filters).
```

```
$ clang-tidy file.cc -checks=-*,google-readability-casting -fix
6 warnings generated.
/Users/syoyo/work/tidy-test/file.cc:4:22: warning: redundant cast to the same type [google-readability-casting]
  const char *cpc2 = (const char*)cpc;
                     ^
/Users/syoyo/work/tidy-test/file.cc:4:22: note: FIX-IT applied suggested code changes
  const char *cpc2 = (const char*)cpc;
                     ^
clang-tidy applied 1 of 1 suggested fixes.
Suppressed 5 warnings (5 with check filters).

$ cat file.cc
int main(int argc, char **argv)
{
  const char *cpc;
  const char *cpc2 = cpc;
  short b = argc;
  return b;
}
```

Voala! 冗長なキャストのコードが消えました!

clang-tidy は, ソースコードのフォーマットはしないので, あとで [clang-format](https://clang.llvm.org/docs/ClangFormat.html) で整形しておきましょう.

clang-tidy で Happy C/C++ コーディング!

## TODO

* `(type)a` を `static_cast<type>(a)` に自動で fix してくれるプラグインを作りたい.
* **優秀な C/C++ 若人が, clang-tidy(と clang-tools)を極め, 安心安全で平和な C/C++ コーディングを日々切磋琢磨し極めてくれるスキームを確立したい.**