web-dev-qa-db-ja.com

レガシーC / C ++プロジェクトでのデッドコード検出

C/C++コードでデッドコードを検出する方法を教えてください。使用するコードベースはかなり大きく、少なくとも10〜15%がデッドコードです。この領域を識別するUnixベースのツールはありますか?一部のコードはまだ多くのプリプロセッサを使用していますが、自動化されたプロセスで処理できますか?

68
Nazgob

これにはコードカバレッジ分析ツールを使用し、コード内の未使用のスポットを探すことができます。

Gccツールチェーンの一般的なツールはgcovとグラフィカルフロントエンドlcovです( http://ltp.sourceforge.net/coverage/lcov.php )。

Gccを使用する場合は、gcovサポートを使用してコンパイルできます。これは、 '-coverage'フラグによって有効になります。次に、アプリケーションを実行するか、このgcov対応ビルドでテストスイートを実行します。

基本的に、gccはコンパイル中に余分なファイルをいくつか出力し、アプリケーションは実行中にカバレッジデータもいくつか出力します。これらすべて(.gcdoおよび.gcdaファイル)を収集する必要があります。ここでは詳しく説明しませんが、GCOV_PREFIXとGCOV_PREFIX_STRIPの2つの環境変数を設定して、適切な方法でカバレッジデータを収集する必要があります。

実行後、すべてのカバレッジデータをまとめて、lcov toolsuiteで実行できます。少し関係しますが、異なるテスト実行からすべてのカバレッジファイルをマージすることもできます。

とにかく、いくつかのカバレッジ情報を示すニースのWebページのセットがあり、カバレッジのないコードが使用されていないことを示しています。

もちろん、コードの一部がどのような状況でも使用されていないかどうか、そしてテストがコードベースをどの程度うまく実行しているかに大きく依存するかどうかを再確認する必要があります。しかし、少なくとも、これはデッドコード候補の可能性についてのアイデアを提供します...

30
Johan

-Wunreachable-codeを使用してgccでコンパイルします。

バージョンが新しいほど、より良い結果が得られると思いますが、彼らが積極的に取り組んでいるものであるという印象は間違っているかもしれません。これはフロー分析を行うことに注意してください。ただし、プリプロセッサを離れるまでにすでに無効になっている「コード」については、コンパイラによって解析されることはないので、信じられません。また、検出されません。呼び出されないエクスポートされた関数、またはそのパラメーターで関数を呼び出さないために偶然に発生する特別なケース処理コード-そのためのコードカバレッジが必要です(そして、ユニットテストではなく機能テストを実行します。ユニットテストはが100%のコードカバレッジを持ち、したがってアプリケーションに関する限り「デッド」なコードパスを実行することを想定しています)。それでも、これらの制限を念頭に置いて、コードベースで最も完全にボリックス化されたルーチンを簡単に見つけることができます。

このCERTアドバイザリは、静的デッドコード検出のための他のツールをいくつかリストしています

17
Steve Jessop

g ++ 4.01 -Wunreachable-codeは、関数内で到達できないコードについて警告しますが、未使用の関数については警告しません。

int foo() { 
    return 21; // point a
}

int bar() {
  int a = 7;
  return a;
  a += 9;  // point b
  return a;
}

int main(int, char **) {
    return bar();
}

g ++ 4.01は、ポイントbに関する警告を発行しますが、foo()(ポイントa)については何も言わず、このファイルでは到達できません。コンパイラーは、関数foo()が他のコンパイル単位でexternとして宣言され、そこから呼び出されないことを知ることができないため、期待はずれですが、この動作は正しいです。確実にできるのはリンカーのみです。

4

Cコードのみで、プロジェクト全体のソースコードが利用可能であると仮定して、オープンソースツール Frama-C を使用して分析を起動します。 GUIで赤を表示するプログラムのステートメントはすべてデッドコードです。

「デッドコード」の問題がある場合は、実行されるが最終結果には寄与しないコードである「スペアコード」を削除することもできます。これには、I/O関数の正確なモデル化を提供する必要があります(「スペア」と思われるが、printfへの引数として使用される計算を削除したくないでしょう)。 Frama-Cには、スペアコードを指定するオプションがあります。

4
Pascal Cuoq

アプローチは、可用性(自動化)テストに依存します。十分な量の機能をカバーすると信頼できるテストスイートがある場合は、以前の回答が既に示したように、カバレッジ分析を使用できます。

それほど幸運でない場合は、 SciTools 'などのソースコード分析ツールを検討することをお勧めします。多くの組み込み分析レポートを使用してコードを分析するのに役立つことを理解してください。このツールでの私の経験は2年前のものであるため、詳細を説明することはできませんが、覚えているのは、バグ修正と質問への回答が非常に高速であるという印象的なサポートがあったことです。

静的ソースコード分析 に他の多くのツールもリストされているページを見つけました。

それでも十分に役立たず、プリプロセッサ関連のデッドコードを見つけることに特に興味がある場合は、コードに関する詳細を投稿することをお勧めします。たとえば、主に#ifdef設定のさまざまな組み合わせに関連している場合は、設定(の組み合わせ)を決定し、実際に構築されない組み合わせを見つけるスクリプトなどを作成できます。

4
andreas buykx

MozillaOpen Office の両方に独自のソリューションがあります。

4
Max Lybbert

このようなデッドコード分析には、プロジェクト全体のグローバル分析が必要です。翻訳単位を個別に分析してこの情報を取得することはできません(まあ、完全に単一の翻訳単位内にある死んだエンティティを検出できますが、あなたが本当に探しているものとは思いません)。

DMS Software Reengineering Toolkitを使用して、Javaコードにこれを正確に実装しました。すべてのコンパイル単位を一度に解析し、すべてのシンボルテーブルを構築し、すべての参照を追跡します。参照も外部APIアイテムであるという主張もないトップレベルの定義はデッドです。このツールはデッドコードも自動的に除去し、最後に必要なものを選択できます:デッドエンティティのレポート、または除去されたコードそれらのエンティティ。

DMSは、さまざまな方言でC++を解析し(2014年2月の編集: C++ 14のMSおよびGCCバージョン[2017年11月の編集:現在C++ 17] )、必要なすべてのシンボルテーブルを構築します。デッドリファレンスの追跡は、その時点から簡単になります。 DMSを使用してそれらを除去することもできます。 http://www.semanticdesigns.com/Products/DMS/DMSToolkit.html を参照してください

3
Ira Baxter

ブルズアイ カバレッジツールが役立ちます。しかし、無料ではありません。

1
Ashwin