このブログシリーズでは、Clang/LLVMプロジェクトのclang-tidyユーティリティを紹介し、それを使用してC++ソースコードを自動的にリファクタリングし、ビルドシステムと統合する方法と、Unices以外のプラットフォームでツールを使用する方法を示します。
動機:レガシーコードベースの喜び
C++11は、今日までまだ完全には使用されていないかなりの量の新しいC++言語機能を追加しました。 最も視覚的なものは確かにauto
、override
、ラムダ式、範囲ベースのfor
、統一された初期化構文です。 C++11はすでに数年前ですが、管理からのポリシーや、開発者側からの移植作業を避けるための純粋な怠惰など、新しい言語機能を使用しないコードベース LLVM compiler infrastructureプロジェクトのClang-Tidyは、少なくとも後者を克服し、ソースコードの自動リファクタリングを可能にして、新しい言語機能を使用するためにここにあ
オーバーライドを使用する、誰か?
さて、まだC++03モードでコンパイルされているかなり大きなコードベースをすでに維持しているが、将来的にはC++11を使用したい場合はどうなりますか? これに似たコードがたくさんある可能性があります:
struct Base { virtual void reimplementMe(int a) {}};struct Derived : public Base { virtual void reimplementMe(int a) {}};
これまでのところ、あなたはユニットテストを介してコードを広範囲にテストしたので、正しい基本クラスメソッドを常に再実装しました! もちろんそうだった したがって、コードは問題ありませんが、あなたは今、上に移動したいと思います。 コードベースのすべての再実装されたメソッドにoverride
指定子を追加したいのですが、もちろん、コードを1行ずつ実行して手動で追加する研修生を雇うこと
override
を追加することが実際に目的を果たすことを強調するために、Qt3Dで正しい基本クラスメソッドをオーバーロードしていないバグを最近修正しました。 以前に追加された指定子では、再コンパイル後にすぐに気づいていたでしょう。
missing-overrideの例をさらに取り上げて、clang-tidyの基本的な使い方を説明します。
Clang-TidyはclangベースのC++linterツールで、clang-tidyと呼ばれるシェル実行可能ファイルをメインエントリポイントとして提供します。 これは、典型的なプログラミングエラー、またはスタイルの問題—一般的にコードの静的分析中に検出できるものを診断するための拡張可能なフレームワーク このツールの本当の利点は、個々の問題が提供するfixitを適用することによって、ソースコードを自動的にリファクタリングできることです。 それは重くプラグインベースであり、我々は次の段落で議論するつもりだ箱から出してプラグインの便利なセットが付属しています。
Clang-TidyはClang/LLVMコミュニティによって開発され、維持されているツールです。
Setup
Linuxを実行しているとき、clang-tidyは通常、ディストリビューションのパッケージマネージャーを介して簡単に取得できます。 たとえば、Ubuntu Linuxでは、次のコマンドを実行するのと同じくらい簡単にインストールできます:
% sudo apt-get install clang-tidy
今後のブログ記事では、Linux以外のプラットフォームにこのツールをインストールすることについて説明します。
注: 利用可能なプラグイン/チェッカーの数はバージョンごとに大きく異なり、絶えず増加するため、常に最新バージョンをインストールすることをお勧めします(執筆時点では、Clang/LLVM3.9に基づくバージョンが推奨されています)。
はじめに
注:このブログ記事では、clang-tidy-3.9が使用されました
コマンドラインツールの典型的な呼び出しは次のようになります:
% clang-tidy test.cpp -- -Imy_project/include -DMY_DEFINES ...
このように実行すると、Clang/GCCが診断を提供するのとまったく同じ方法で、ツールは警告とメモの束(該当する場合)を出力します。
Clang-Tidyは、利用可能なチェッカーがたくさんある便利な静的解析ツールですが、これはこのブログ記事の焦点ではありません。 むしろ、このツールの強力なリファクタリング機能を活用してソースコードを近代化したいと考えています。
利用可能なチェッカーの一覧
特定のコマンドラインパラメータなしでツールを実行すると、ユーティリティによって有効になっているデフォルトのチェ 他のチェッカーが提供しなければならないことを確認しましょう(–checks=’*’を渡してすべてを表示します)、具体的には名前にmodernizeを持つものをgrepします。 これらのチェッカーは、現代の言語構造の使用を提唱しています:
$ clang-tidy --list-checks -checks='*' | grep "modernize" 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
すでにオプションの印象的なリストは、そうではありませんか? Clang-Tidyは実際に(Clang/LLVM3.9の時点で)いくつかの興味深いチェッカーを箱から出して出荷し、リストはリリースからリリースまで絶えず成長しています。
チェッカーの名前はかなり自明です(例えば、modernize-use-autoは該当する場合はautoを使用します)が、それぞれが何を意味するのかを調べたい場合は、clang-tidyホームページのチェ:
ツールがどのように使用されているかを示すために、modernize-use-overrideチェッカーに焦点を当てましょう。
単一のファイルをリファクタリングする
オーバーライドの例をもう一度:
struct Base { virtual void reimplementMe(int a) {}};struct Derived : public Base { virtual void reimplementMe(int a) {}};
例でclang-tidyを実行しています(今回はmodernize-use-overrideチェッカーを有効にしています):
% clang-tidy-3.9 -checks='modernize-use-override' test.cpp -- -std=c++111 warning generated./home/kfunk/test.cpp:5:18: warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' virtual void reimplementMe(int a) {} ^ override
よし そのため、Derived::reimplementMe(int)
は基本クラスのメソッドをオーバーライドしますが、override
指定子がないことに気付きました! 今、私たちはそれを手動で追加することができます…または単にツールが渡すことによって私たちのためにそれをやらせてください-fix!
例で実行しています(modernize-use-override checker&fix-itsを有効にしています):
% clang-tidy-3.9 -checks='modernize-use-override' -fix test.cpp -- -std=c++111 warning generated./home/kfunk/test.cpp:5:18: warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' virtual void reimplementMe(int a) {} ^ override/home/kfunk/test.cpp:5:5: note: FIX-IT applied suggested code changes virtual void reimplementMe(int a) {} ^/home/kfunk/test.cpp:5:38: note: FIX-IT applied suggested code changes virtual void reimplementMe(int a) {} ^clang-tidy applied 2 of 2 suggested fixes.
Clang-tidyはfix-itを適用し、5行目のメソッド宣言の後にoverride
を挿入しました。 終わった!
いくつかのノート
言及する価値があるいくつかのことがあります:
- clang-tidyのすべてのチェッカーが実際にfix-itsを運ぶわけではありませんが、modernizeで始まるものはすべてそうです。
- 複数のチェッカーからfix-itsを同時に使用できます(consider-checks=’modernize-use-override,modernize-use-auto’-fix)
- clang-tidyを実行すると、完全なClangコンパイラのフロントエンドが呼び出されるため、
- Clang-tidyからのリファクタリング結果は完全に正確です。
- clang-tidyからのリファクタリング結果は、完全なc++パーサーによってバックアップされているため、完全に正確です。
- Clang-tidyからのリファクタリング結果は完全に正確です。
- Clang-tidyからのリファクタリング結果は完全に正確です。
完全なプロジェクトのリファクタリング(cmakeベース)
これまでのところ、単一のスタンドアロンファイルでのみclang-tidyを実行しました。 多くのファイルがあり、すべてカスタムコンパイルフラグがある、より複雑なプロジェクト設定がある場合はどうなりますか? Clang-tidyは、常に単一のファイル、またはむしろ翻訳単位で動作します。 このツールは、プロジェクトでコンパイルする各翻訳単位の正しいコンパイルフラグを把握するのに役立ちます。 これを実行する最も便利な方法は、compileコマンドデータベースを使用することです。 CMakeは自動的に1つを生成し、一度compile_commandsすることができます。jsonが配置されており、clang-tidyの動作バージョンがパスにあり、コードベース全体をrun-clang-tidyで分析できます。pyスクリプト(通常はインストールの一部として出荷されます)。 そうでない場合は、単にここでそれをダウンロードすることができます。
注:使用することを強くお勧めしますrun-clang-tidy.py プロジェクト全体でclang-tidyを実行するには、ツールを複数回並列に実行し、同時実行が互いに干渉しないようにします(たとえば、共有ヘッダーを並列に変更し、壊れたコードを生成しないようにします)。
compile_commandsを生成します。compile_commandsを生成するためのjsonファイル
。CMakeベースのプロジェクトでjsonファイルを実行するだけです:
% cd my-cmake-based-project% mkdir build% cd build% cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
スクリプトを使用してclang-tidyを実行
プロジェクト内の各翻訳単位のデフォルトチェックでツールを実行するには、compile_commandsを使用してディレクトリ内のrun-clang-tidyスクリプトを呼び出すだけです。jsonファイル:
% run-clang-tidy.py
前に見たように、デフォルトのチェックだけを有効にしてclang-tidyを実行したので、これはこれまでのところ何も変更しません。 たとえば、すべての翻訳単位でmodernize-use-overrideチェックを実行し、実際にすべてのコードをリファクタリングするには、この呼び出しが必要です:
% run-clang-tidy.py -header-filter='.*' -checks='-*,modernize-use-override' -fix
それだけです。 プロジェクト内の各翻訳単位でclang-tidyが呼び出され、欠落している部分に上書きが追加されます。 パラメータ-header-filter=’。*’は、clang-tidyが翻訳単位で消費されるヘッダー内のコードを実際にリファクタリングすることを確認します。 パラメータchecks=’-*,…’は、すべての既定のチェックが無効になっていることを確認します。
修正はrun-clang-tidyが終了した後にのみ適用されることに注意してください! スクリプトは、実行される変更のみを記録し、最後に一度にすべてを適用します。
他のチェッカーを実行する
ここでも、modernize-use-overrideは単なる例ですが、clang-tidyには便利な他のチェッカーがたくさんあります。 もう1つの非常に便利なものは、0
またはNULL
リテラルを現代のC++11nullptr
バージョンに変換するmodernize-use-nullptrチェッカーです。 プロジェクト内の古いスタイルのリテラルのすべての使用をリファクタリングするには、次のように実行します:
% run-clang-tidy.py -header-filter='.*' -checks='-*,modernize-use-nullptr' -fix
中間結果(”C++11nullptrへのポート”、”C++11overrideへのポート”、…)をバージョン管理システムにコミットして、チェッカーを次々に実行することをお勧めします。
いくつかの現実世界の例
私は個人的にclang-tidyをすでに多くの異なるプロジェクトで使用してきましたが、肯定的な結果が得られました。 覚えておいてください、このツールはあなたのコードの完全な知識を持っています(実際にはClangコンパイラのフロントエンドを使用しているので)。
:
- このパッチは、kdeのすべてのフレームワークライブラリをC++11nullptrに移植し、約9000の異なるコードの場所に触れることによって
- このパッチは、KDE MarbleコードベースをC++11オーバライドに移植し、約2300の異なるコードの場所に触れることによって
結論
Clang-Tidyは、Clang-Tidyをc++11オーバーライドに移植する強力なツールです。レガシーコードベースをC++11に移植することは、ワンライナーを実行することの問題になります。 これは、デフォルトのチェッカーの偉大なセットが付属しており、追加のもののリストは常に成長します。 Modernize-checkersは、新しいC++言語機能を使用するためにソースコードを近代化/リファクタリングするために使用できます。
このシリーズの次の部分では、他のビルドシステムでclang-tidyプロジェクト全体を使用する方法について説明します。
助けが必要ですか?
KDABは、Clangツールを日常的に使用しているいくつかのエンジニアを雇用しています。 プロジェクト固有のコードチェックを実装したり、コードベースで自動リファクタリングツールを実行したりすることで、プロジェクトでClangツールを使用して問題が発生した場合や、それを最大限に活用したい場合に備えて、私たちは喜んでお手伝いします。 私たちは、クライアントがツールを使用して非常に大規模なコードベースを正常に近代化するのを助けました。
お問い合わせ
カテゴリ:C++/機能安全/How to/KDAB Blogs/KDAB on Qt/Tooling
タグ:自動リファクタリング/C++/C++11/C++14/Clang/LLVM