C++のautoの誤用を検出したい

# はじめに
C++に型推論`auto`が追加されて10年あまり, 間違った使い方をたくさん見てきました.
`auto`の使用に関しては, Epicの[コーディング規約](https://docs.unrealengine.com/4.27/ja/ProductionPipelines/DevelopmentSetup/CodingStandard/)に, ~~私にしてはめずらしく~~ 完全に同意します. 要約するほどの分量ではないですが, リンクを踏みたくない人のために

- コードの読み手へ型を明らかにすること
    - この理由は書かれていません
        - 私は型はプログラムを説明するものだと思っています
    - "IDEに推論結果のポップアップ表示があるから", という言い訳は認められません. VCS, merge, diff, レビューツールなどでサポートされないからです.
- `auto`の使用が認められる例外
    - 型名が冗長になりがちなiterator
    - lambda, templateでの, 使用が避けられない場合
- `auto`を使用する場合, 常に正しく`const`, `&`, または`*`を使うこと

# テストコード
もっと複雑でないと検証にならないと思いますが, コンパイル単位を分けるぐらいはやってみます.

<details><summary>SugoiDekai.h</summary><div>

```cpp
#ifndef INC_SUGOIDEKAI_H_
#define INC_SUGOIDEKAI_H_
#include <cstdint>

namespace check
{
struct SugoiDekai
{
    static constexpr uint32_t Size = 1024;
    void zeros();
    void fill();
    void print();

    uint8_t data_[Size];
};

void print(SugoiDekai data);
} // namespace check
#endif // INC_SUGOIDEKAI_H_

```
</div></details>

<details><summary>SugoiDekai.cpp</summary><div>

```cpp
#include "SugoiDekai.h"
#include <chrono>
#include <cstring>
#include <iostream>
#include <random>

namespace check
{
void SugoiDekai::zeros()
{
    ::memset(data_, 0, sizeof(uint8_t) * Size);
}

void SugoiDekai::fill()
{
    std::random_device device;
    std::minstd_rand engine(device());
    for(uint32_t i = 0; i < Size; ++i) {
        data_[i] = static_cast<uint8_t>(engine());
    }
}

void SugoiDekai::print()
{
    for(uint32_t i = 0; i < Size; ++i) {
        if(0 == (i % 1024)) {
            std::cout << static_cast<uint32_t>(data_[i]);
        }
    }
    std::cout << std::endl;
}

void print(SugoiDekai data)
{
    data.print();
}
} // namespace check
```
</div></details>

型名を明示した場合も含めて, 人が見ると明らかな論理的不具合を２パターン, パフォーマンス的によろしくない１パターン（`auto`と関係ないですが）を用意しました.

```cpp
#include "SugoiDekai.h"
#include <vector>

int main(void)
{
    using namespace check;
    static constexpr uint32_t NumSamples = 1000;
    std::vector<SugoiDekai> data;
    data.resize(NumSamples);
    { // Initialize
        for(auto& d: data) {
            d.zeros();
        }
    }

    { // Bad usage 1 --- case 1
        for(auto d: data) {
            d.fill();
        }
    }

    { // Bad usage 2 --- case 2
        for(size_t i = 0; i < data.size(); ++i) {
            auto d = data[i];
            d.fill();
        }
    }

    { // Bad usage 3 --- case 3
        for(const auto& d: data) {
            print(d);
        }
    }

    { // Bad usage 4 --- case 4
        for(SugoiDekai d: data) {
            d.fill();
        }
    }

    { // Bad usage 5 --- case 5
        for(size_t i = 0; i < data.size(); ++i) {
            SugoiDekai d = data[i];
            d.fill();
        }
    }

    { // Bad usage 6 --- case 6
        for(const SugoiDekai& d: data) {
            print(d);
        }
    }
    return 0;
}
```

コンパイルオプションは次のCMakeLists.txtを参照のこと.

<details><summary>CMakeLists.txt</summary><div>

```cmake
cmake_minimum_required(VERSION 3.16)
set(PROJECT_NAME check)
project(${PROJECT_NAME})
set(PROJECT_VERSION 1.0.0)
set(PROJECT_ROOT ${CMAKE_CURRENT_SOURCE_DIR})

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

include_directories(AFTER ${PROJECT_ROOT})

set(HEADERS "SugoiDekai.h")
set(SOURCES "SugoiDekai.cpp;main.cpp")

source_group("include" FILES ${HEADERS})
source_group("src" FILES ${SOURCES})

add_executable(${PROJECT_NAME} ${HEADERS} ${SOURCES})
set_target_properties(${PROJECT_NAME} PROPERTIES
    OUTPUT_NAME_DEBUG "${PROJECT_NAME}d" OUTPUT_NAME_RELEASE "${PROJECT_NAME}")

if(MSVC)
    set(DEFAULT_CXX_FLAGS "/DWIN32 /D_WINDOWS /D_UNICODE /DUNICODE /W4 /WX- /nologo /fp:precise /arch:AVX /Oi /Zc:wchar_t /TP /Gd")

    if(MSVC_VERSION VERSION_LESS_EQUAL "1900")
        set(DEFAULT_CXX_FLAGS "${DEFAULT_CXX_FLAGS} /Zc:__cplusplus /std:c++latest")
    else()
        set(DEFAULT_CXX_FLAGS "${DEFAULT_CXX_FLAGS} /Zc:__cplusplus /std:c++17")
    endif()

    set(CMAKE_CXX_FLAGS "${DEFAULT_CXX_FLAGS}")
    set(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Zi /Ob0 /Od /RTC1 /Gy /GR- /GS /Gm- /EHsc")
    set(CMAKE_CXX_FLAGS_RELEASE "/MD /O2 /Oi /GL /GR- /DNDEBUG /EHsc-")

elseif(UNIX)
    set(DEFAULT_CXX_FLAGS "-Wall -Wextra -O2 -std=c++17 -march=x86-64-v3 -fno-exceptions")
elseif(XCODE)
endif()
```
</div></details>

# 解析ツール
## Visual Studio 静的解析
何も検出されませんでした.

## clang-tidy
`performance-for-range-copy`が仕事をしてくれそうだったのですが, 何も検出されませんでした.

## cppcheck
何も検出されませんでした.

## Coverity
WIP 
[オンラインスキャン](https://scan.coverity.com/)がうまくいっていないため.

```
Error details: invalid literal for int() with base 10: "tail: cannot open '/opt/workspace/username_projectname/cov-int/build-log.txt' for reading: No such file or directory"
```

case 3, 6で警告が出ることは分かっています.

# まとめ
静的解析での検出は期待できないかもと思います. 全文検索のパターンマッチの方がよさそうな気がしてきました.
`auto`をどうしても使わなければならない人はC++初心者以上でしょうし, 通常のプロジェクトでは禁止にしてしまってもいいと思います.