web-dev-qa-db-ja.com

使用されていないインクルードヘッダーを検索するツール

PC-Lint は、含まれているが使用されていないヘッダーについて通知できることを知っています。これを行うことができる他のツールはありますか、できればLinuxにありますか?

過去15年間に多くの機能が移動する大きなコードベースがありますが、機能が1つの実装ファイルから別のファイルに移動するときに残りの#includeディレクティブが削除されることはめったになく、この時点でかなりの混乱が残ります。私は明らかに、すべての#includeディレクティブを削除し、どのインクルードするものをコンパイラーに通知させるという骨の折れることをすることができますが、使用済みのリストを再構築するのではなく、逆に問題を解決します-未使用のものを見つけます。

70
Nick Bastin

免責事項:私の仕事は静的分析ツールを開発する会社で働いています。

ほとんどの(すべてではないにしても)静的解析ツールに何らかの形式のヘッダー使用チェックがない場合、私は驚くでしょう。 this wikipedia pageを使用して、利用可能なツールのリストを取得し、企業に電子メールで問い合わせることができます。

ツールを評価するときに考慮すべきいくつかのポイント:

関数のオーバーロードの場合、オーバーロード解決によって選択された関数を含むヘッダーだけでなく、オーバーロードを含むすべてのヘッダーを表示する必要があります。

// f1.h
void foo (char);

// f2.h
void foo (int);


// bar.cc
#include "f1.h"
#include "f2.h"

int main ()
{
  foo (0);  // Calls 'foo(int)' but all functions were in overload set
}

総当たり攻撃のアプローチをとる場合は、最初にすべてのヘッダーを削除してからコンパイルするまで追加し直します。「f1.h」を最初に追加すると、コードはコンパイルされますが、プログラムのセマンティクスは変更されています。

部分的な専門分野がある場合にも、同様の規則が適用されます。スペシャライゼーションが選択されているかどうかは関係ありません。すべてのスペシャライゼーションが表示されることを確認する必要があります。

// f1.h
template <typename T>
void foo (T);

// f2.h
template <>
void foo (int);

// bar.cc
#include "f1.h"
#include "f2.h"


int main ()
{
  foo (0);  // Calls specialization 'foo<int>(int)'
}

オーバーロードの例に関しては、ブルートフォースアプローチにより、プログラムはコンパイルされますが、動作は異なります。

注目できるもう1つの関連するタイプの分析は、型を前方宣言できるかどうかを確認することです。以下を考慮してください。

// A.h
class A { };

// foo.h
#include "A.h"
void foo (A const &);

// bar.cc
#include "foo.h"

void bar (A const & a)
{
  foo (a);
}

上記の例では、「A」の定義は不要であるため、ヘッダーファイル「foo.h」を変更して、「A」のみの前方宣言を行うことができます。

// foo.h
class A;
void foo (A const &);

この種類のチェックは、ヘッダーの依存関係も減らします。

30
Richard Corden

これを行うスクリプトを次に示します。

#!/bin/bash
# Prune include files one at a time, recompile, and put them back if it doesn't compile
# arguments are list of files to check
removeinclude() {
    file=$1
    header=$2
    Perl -i -p -e 's+([ \t]*#include[ \t][ \t]*[\"\<]'$2'[\"\>])+//REMOVEINCLUDE $1+' $1
}
replaceinclude() {
   file=$1
   Perl -i -p -e 's+//REMOVEINCLUDE ++' $1
}

for file in $*
do
    includes=`grep "^[ \t]*#include" $file | awk '{print $2;}' | sed 's/[\"\<\>]//g'`
    echo $includes
    for i in $includes
    do
        touch $file # just to be sure it recompiles
        removeinclude $file $i
        if make -j10 >/dev/null  2>&1;
        then
            grep -v REMOVEINCLUDE $file > tmp && mv tmp $file
            echo removed $i from $file
        else
            replaceinclude $file
            echo $i was needed in $file
        fi
    done
done
22
Andy C

Dehydra をご覧ください。

ウェブサイトから:

Dehydraは、C++コードのアプリケーション固有の分析が可能な、軽量でスクリプト可能な汎用の静的分析ツールです。最も単純な意味では、Dehydraはセマンティックgrepツールと考えることができます。

未使用の#includeファイルをチェックするスクリプトを考え出すことができるはずです。

5

Googleの cppclean は、未使用のヘッダーファイルを見つけるというまともな仕事をしているようです。使い始めたばかりです。いくつかの誤検知が発生します。多くの場合、ヘッダーファイルに不要なインクルードがありますが、関連するクラスの前方宣言が必要であり、インクルードを関連するソースファイルに移動する必要があるということはわかりません。

4
Chance

Eclipse CDTを使用している場合は、 Includator を試すことができます。これは(この記事の執筆時点で)ベータテスターに​​無料で、不要な#includeを自動的に削除するか、欠落しているものを追加します。

免責事項:私はIncludatorを開発している会社で働いており、過去数か月間それを使用しています。それは私にとって非常にうまくいくので、試してみてください:-)

3
Mirko Stocker

私の知る限り、これはPCリントではありませんが、これは恥ずべきことであり、驚くべきことです。私は、このちょっとした擬似コードを実行する提案を見てきました(これは基本的に「苦労するプロセス」を自動化するものです:

すべてのcppファイルについて
すべてのヘッダーに含める
インクルードをコメントアウト
cppファイルをコンパイルします
if(compile_errors)
ヘッダーのコメントを外します
そうしないと
ヘッダーインクルードをcppから削除

それを夜間のcronに入れて、問題のプロジェクトに未使用のヘッダーを残さないようにします(明らかに手動で実行できますが、実行には時間がかかります)。唯一の問題は、ヘッダーを含めないことがエラーを生成しないが、それでもコードを生成する場合です。

1
Cinder6

私はこれを手動で行いましたが、コンパイル時間の短縮により、短期(ああ、それは長期ですか?-長い時間がかかります)で価値があります:

  1. 各cppファイルで解析するヘッダーが少なくなります。
  2. 依存性が少ない-1つのヘッダーを変更した後、全世界で再コンパイルする必要はありません。

また、再帰的なプロセス-残っている各ヘッダーファイルは、ヘッダーファイルitが含まれているかどうかを確認するために調べる必要があります。さらに、ヘッダーインクルードの代わりに前方宣言を使用できる場合があります。

その後、残りのヘッダーを常に把握するために、プロセス全体を年に数か月ごとに繰り返す必要があります。

実際、私はC++コンパイラに少しイライラしています。彼らは不要なものを教えてくれるはずです-コンパイル中にヘッダーファイルへの変更を安全に無視できる場合、Microsoftコンパイラはあなたに伝えることができます。

1
quamrana

誰かが興味を持っているなら、sourceforgeに小さなJavaまさにそれを行うためのコマンドラインツールを置いた。Javaで書かれているように、明らかにLinux上で実行可能である。

プロジェクトのリンクは https://sourceforge.net/projects/chksem/files/chksem-1.0/ です

0
Arctica