第12章 FindBugs™ によるデータ・マイニング

目次

1. コマンド
2. 例
3. Ant の例

バグデータベースへの高機能の問い合わせ機能、および、調査対象のコードの複数のバージョンにわたる警告の追跡記録機能を、 FindBugs は内蔵しています。これらを使って次のようなことができます。すなわち、いつバグが最初持ち込まれたかを捜し出すこと、最終リリース以後持ち込まれた警告の分析を行うこと、または、無限再起ループの数を時間軸でグラフにすることです。

これらの技術は、 FindBugs が警告の保存に使う XML 書式を使用します。これらの XML ファイルは、通常、特定の 1 分析に対する警告が入れられています。しかしそれらには、一連のソフトウェアのビルドやバージョンに対する分析結果を格納することもできます。

すべての FindBugs XML バグデータベースには、バージョン名とタイム・スタンプ が入れられています。FindBugs は分析が行われるファイルの更新時刻からタイム・スタンプを計算します (例えば、タイム・スタンプはクラスファイルの生成時刻になるようになっています。分析が行われた時刻ではありません) 。各々のバグデータベースには、バージョン名も入れられています。バージョン名とタイム・スタンプは、 setBugDatabaseInfo (「setBugDatabaseInfo」) コマンドを使用して手動で設定することもできます。

複数バージョンを格納するバグデータベースにおいては、分析されるコードの各バージョンごとにシーケンス番号が割り当てられます。これらのシーケンス番号は単に 0 から始まる連続する整数値です (例えば、 4 つのコードバージョンを格納するバグデータベースには、バージョン 0~3 が入れられます) 。バグデータベースにはまた、各バージョンの名前とタイム・スタンプがそれぞれ記録されます。filterBugs コマンドを使用すると、シーケンス番号、バージョン名またはタイム・スタンプからバージョンを参照することができます。

1 バージョンを格納するバグデータベースの集合から、 1 個の複数バージョンバグデータベースを作成することができます。また、複数バージョンバグデータベースに対して、それ以後に作成された 1 バージョンのバグデータベースを結合することができます。

これらのコマンドのいくつかは、 ant タスクとして実行することができます。コマンドの実行方法および属性・引数の詳細は、以下を参照してください。以下のすべての例においては、 findbugs.lib refid が正しく設定されていることを前提としています。設定方法の一例を次に示します :


   <!-- findbugs タスク定義 -->
   <property name="findbugs.home" value="/your/path/to/findbugs" />
   <path id="findbugs.lib">
      <fileset dir="${findbugs.home}/lib">
         <include name="findbugs-ant.jar"/>
      </fileset>
   </path>

1. コマンド

FindBugs データ・マイニング ツールはすべてコマンドラインから実行することができます。また、いくつかのより有用なコマンドは、 ant ビルドファイルから実行することができます。

コマンドラインツールについて簡単に説明します :

unionBugs

別のクラスに対する別個の分析結果を結合します。

computeBugHistory

複数バージョンから得られた複数のバグ警告を、マージして 1 個の複数バージョンバグデータベースにします。これを使って、既存の複数バージョンバグデータベースに更にバージョンを追加したり、 1 バージョンを格納するバグデータベースの集合から 1 個の複数バージョンバグデータベースを作成したり、できます。

setBugDatabaseInfo

リビジョン名やタイム・スタンプなどの情報を XML データベースに設定します。

listBugDatabaseInfo

XML データベースにあるリビジョン名やタイム・スタンプなどの情報を一覧表示します。

filterBugs

バグデータベースの部分集合を選択します。

mineBugHistory

複数バージョンバグデータベースの各バージョン毎の警告数を一覧にした表を作成します。

defectDensity

プロジェクト全体およびクラス毎・パッケージ毎の不良密度 (1000 NCSS 毎の警告数) に関する情報を一覧表示します。

convertXmlToText

XML 形式のバグ警告を、 1 行 1 バグのテキスト形式、または、HTML形式に変換します。

1.1. unionBugs

分析するのにアプリケーションの jar ファイルを分割している場合、このコマンドを使用することで、別個に生成された XML バグ警告ファイルをすべての警告を含んでいる 1 つの ファイルにすることができます。

同じファイルの異なるバージョンを分析した結果を結合する場合は、このコマンドを使用しないでください。代わりに computeBugHistory を使用してください。

XML ファイルは、コマンドラインで指定してください。結果は、標準出力に送られます。

1.2. computeBugHistory

このコマンドを使用することで、分析するソフトウェアの異なるビルドまたはバージョンの情報を含むバグデータベースを生成することができます入力として提供したファイルの 1 番目のファイルから履歴が取得されます。後に続くファイルは 1 バージョンのバグデータベースであるようにしてください (もし、履歴を持っていたとしても無視されます) 。

デフォルトでは、結果は標準出力に送られます。

この機能は、 ant からも使用することができます。まず次に示すように、ビルドファイルに computeBugHistory を taskdef で定義します :


<taskdef name="computeBugHistory" classname="edu.umd.cs.findbugs.anttask.ComputeBugHistoryTask">
    <classpath refid="findbugs.lib" />
</taskdef>

この ant タスクに指定できる属性を、下表に一覧で示します。入力ファイルを指定するには、 <datafile> 要素を入れ子にして入れてください。次に、例を示します:


<computeBugHistory home="${findbugs.home}" ...>
    <datafile name="analyze1.xml"/>
    <datafile name="analyze2.xml"/>
</computeBugHistory>

表12.1 computeBugHistory コマンドのオプション一覧

コマンドラインオプションAnt 属性目的
-output <file>output="<file>"出力結果を保存するファイル名を指定します。 (同時に入力ファイルにもなりえます)
-overrideRevisionNames[:truth]overrideRevisionNames="[true|false]"ファイル名から算出されるそれぞれのバージョン名を指定変更します。
-noPackageMoves[:truth]noPackageMoves="[true|false]"パッケージを移動したクラスがある場合、当該クラスの警告は別の存在として扱われます。
-preciseMatch[:truth]preciseMatch="[true|false]"バグパターンが正確に一致することを要求します。
-precisePriorityMatch[:truth]precisePriorityMatch="[true|false]"優先度が正確に一致した場合のみ警告が同一であると判断されます。
-quiet[:truth]quiet="[true|false]"エラーが発生しない限り、標準出力には何も表示されません。
-withMessages[:truth]withMessages="[true|false]"出力 XML に人間が読むことができるバグメッセージが含まれます。

1.3. filterBugs

このコマンドを使用することで、 FindBugs XML 警告ファイルから一部分を選び出して新規 FindBugs 警告ファイルに選択された部分を書き込むことができます。

このコマンドには、オプション群に続いて 0 個から 2 個の findbugs xml バグファイルを指定することができます。

ファイル名をひとつも指定しない場合は、標準入力から読んで標準出力に出力されます。ファイル名を 1 個 指定した場合は、指定したファイルから読んで標準出力に出力されます。ファイル名を 2 個 指定した場合は、 1 番目に指定したファイルから読んで 2 番目に指定したファイルに出力されます。

この機能は、 ant からも使用することができます。まず次に示すように、ビルドファイルに filterBugs を taskdef で定義します :


<taskdef name="filterBugs" classname="edu.umd.cs.findbugs.anttask.FilterBugsTask">
    <classpath refid="findbugs.lib" />
</taskdef>

この ant タスクに指定できる属性を、下表に一覧で示します。入力ファイルを指定するには、 input 属性を使用するか、 <datafile> 要素を入れ子にして入れてください。次に、例を示します:


<filterBugs home="${findbugs.home}" ...>
    <datafile name="analyze.xml"/>
</filterBugs>

表12.2 filterBugs コマンドのオプション一覧

コマンドラインオプションAnt 属性目的
 input="<file>"入力ファイルを指定します。
 output="<file>"出力ファイルを指定します。
-notnot="[true|false]"フィルターのスイッチを反転します。
-withSource[:truth]withSource="[true|false]"ソースが入手可能な警告のみ出力されます。
-exclude <filter file>exclude="<filter file>"フィルターに一致するバグが除外されます。
-include <filter file>include="<filter file>"フィルターに一致するバグのみを含まれます。
-annotation <text>annotation="<text>"手で入力した注釈に指定した文言を含む警告のみ出力されます。
-after <when>after="<when>"指定したバージョンより後に初めて出現した警告のみ出力されます。
-before <when>before="<when>"指定したバージョンより前に初めて出現した警告のみ出力されます。
-first <when>first="<when>"指定したバージョンに初めて出現した警告のみ出力されます。
-last <when>last="<when>"指定したバージョンが出現した最後である警告のみ出力されます。
-fixed <when>fixed="<when>"指定したバージョンの前回のバージョンが出現した最後である警告のみ出力されます。 (-last に優先します)。
-present <when>present="<when>"指定したバージョンに存在する警告のみ出力されます。
-absent <when>absent="<when>"指定したバージョンに存在しない警告のみ出力されます。
-active[:truth]active="[true|false]"最終通番に存在する警告のみ出力されます。
-introducedByChange[:truth]introducedByChange="[true|false]"存在するクラスの変更によってもたらされた警告のみ出力されます。
-removedByChange[:truth]removedByChange="[true|false]"存在するクラスの変更によって除去された警告のみ出力されます。
-newCode[:truth]newCode="[true|false]"新クラスの追加によってもたらされた警告のみ出力されます。
-removedCode[:truth]removedCode="[true|false]"クラスの削除によって除去された警告のみ出力されます。
-priority <level>priority="<level>"指定した優先度以上の優先度をもつ警告のみ出力されます。
-maxRank <rank>rank="[1..20]"allow only warnings with this rank or lower
-class <pattern>class="<class>"指定したパターンに一致する主クラスをもつ警告のみ出力されます。
-bugPattern <pattern>bugPattern="<pattern>"指定したパターンに一致するバグ種別をもつ警告のみ出力されます。
-category <category>category="<category>"指定した文字列で始まるカテゴリーの警告のみ出力されます。
-designation <designation>designation="<designation>"指定したバグ分類指定をもつ警告のみ出力されます。 (例、 -designation SHOULD_FIX)
-withMessages[:truth] withMessages="[true|false]"テキストメッセージを含んだ XML が生成されます。

1.4. mineBugHistory

このコマンドを使用することで、複数バージョンバグデータベースの各バージョン毎の警告数を一覧にした表を作成することができます。

この機能は、 ant からも使用することができます。まず次に示すように、ビルドファイルに mineBugHistory を taskdef で定義します :


<taskdef name="mineBugHistory" classname="edu.umd.cs.findbugs.anttask.MineBugHistoryTask">
    <classpath refid="findbugs.lib" />
</taskdef>

この ant タスクに指定できる属性を、下表に一覧で示します。入力ファイルを指定するには、 input 属性を使用するか、 <datafile> 要素を入れ子にして入れてください。次に、例を示します:


<mineBugHistory home="${findbugs.home}" ...>
    <datafile name="analyze.xml"/>
</mineBugHistory>

表12.3 mineBugHistory コマンドのオプション一覧

コマンドラインオプションAnt 属性目的
 input="<file>"入力ファイルを指定します。
 output="<file>"出力ファイルを指定します。
-formatDatesformatDates="[true|false]"データがテキスト形式で描画されます。
-noTabsnoTabs="[true|false]"タブの代わりに複数スペースでカラムが区切られます (下記参照)。
-summarysummary="[true|false]"最新 10 件の変更の要約が出力されます。

-noTabs 出力を使うことで、固定幅フォントのシェルで読み易くなります。数値カラムは右寄せされるので、スペースがカラム値の前に挿入されます。また、このオプションを使用した場合、 -formatDates を指定したときに要約の日付を描画するのに空白が埋め込まれなくなります。

出力される表は、 (-noTabs が無ければ) タブ区切りで次に示すカラムから成ります :

表12.4 mineBugHistory 出力のカラム一覧

表題目的
seqシーケンス番号 (0 始まりの連続した整数値)
versionバージョン名
timeリリースされた日時
classes分析されたクラス数
NCSSコメント文を除いた命令数 (Non Commenting Source Statements)
added前回のバージョンに存在したクラスにおける新規警告数
newCode前回のバージョンに存在しなかったクラスにおける新規警告数
fixed現在のバージョンに存在するクラスにおける除去された警告数
removed現在のバージョンに存在しないクラスの前回のバージョンにおける警告数
retained現在のバージョンと前回のバージョンの両方に存在する警告の数
dead以前のバージョンに存在したが現在のバージョンにも直前のバージョンにも存在しない警告の数
active現在のバージョンに存在する警告総数

1.5. defectDensity

このコマンドを使用することで、プロジェクト全体およびクラス毎・パッケージ毎の不良密度 (1000 NCSS 毎の警告数) に関する情報を一覧表示できます。標準入力から読み込む場合はファイル指定なしで、そうでなければ、コマンドラインでファイルを指定して、このコマンドを実行します。

出力される表は、次に示すカラムから成ります。また、プロジェクト全体情報の行、および、4 個以上の警告を含んでいる各パッケージ情報または各クラス情報の行も出力されます。

表12.5 defectDensity 出力のカラム一覧

表題目的
kindプロジェクト (project)、パッケージ (package) またはクラス (class)
nameプロジェクト、パッケージまたはクラスの名前
density 1000 NCSS 毎の警告数
bugs警告数
NCSSコメント文を除いた命令数 (Non Commenting Source Statements)

1.6. convertXmlToText

このコマンドを使用することで、XML 形式のバグ警告を、 1 行 1 バグのテキスト形式、または、HTML形式に変換することができます。

この機能は、 ant からも使用することができます。まず次に示すように、ビルドファイルに convertXmlToText を taskdef で定義します :


<taskdef name="convertXmlToText" classname="edu.umd.cs.findbugs.anttask.ConvertXmlToTextTask">
    <classpath refid="findbugs.lib" />
</taskdef>

この ant タスクに指定できる属性を、下表に一覧で示します。

表12.6 convertXmlToText コマンドのオプション一覧

コマンドラインオプションAnt 属性目的
 input="<filename>"入力ファイルを指定します。
 output="<filename>"出力ファイルを指定します。
-longBugCodeslongBugCodes="[true|false]"2 文字のバグ略称の代わりに、省略なしのバグパターンコードを使用します。
 format="text"プレーンテキストの出力が作成されます。1 行につき 1 つのバグが出力されます。コマンドライン時のデフォルトです。
-html[:stylesheet]format="html:<stylesheet>"指定されたスタイルシートを使用して出力が作成されます (下記参照) 。省略した場合は、 default.xsl が使用されます。

-html/format オプションには、plain.xsl 、 default.xsl 、 fancy.xsl 、 fancy-hist.xsl または ユーザ自身が作成した XSL スタイルシートのいずれかを指定することができます。オプション名をよそに、 html 以外の形式を出力するスタイルシートを指定することもできます。FindBugs に含まれているスタイルシート(上述)以外のスタイルシートを使用する場合は、オプション -html/format で当該スタイルシートへのパスまたは URL を指定してください。

1.7. setBugDatabaseInfo

このコマンドを使用することで、指定したバグ警告にメタ情報を設定することができます。このコマンドには次に示すオプションがあります:

この機能は、 ant からも使用することができます。まず次に示すように、ビルドファイルに setBugDatabaseInfo を taskdef で定義します :


<taskdef name="setBugDatabaseInfo" classname="edu.umd.cs.findbugs.anttask.SetBugDatabaseInfoTask">
    <classpath refid="findbugs.lib" />
</taskdef>

この ant タスクに指定できる属性を、下表に一覧で示します。入力ファイルを指定するには、 input 属性を使用するか、 <datafile> 要素を入れ子にして入れてください。次に、例を示します:


<setBugDatabaseInfo home="${findbugs.home}" ...>
    <datafile name="analyze.xml"/>
</setBugDatabaseInfo>

表12.7 setBugDatabaseInfo オプション一覧

コマンドラインオプションAnt 属性目的
 input="<file>"入力ファイルを指定します。
 output="<file>"出力ファイルを指定します。
-name <name>name="<name>"最新リビジョンの名前を設定します。
-timestamp <when>timestamp="<when>"最新リビジョンのタイム・スタンプを設定します。
-source <directory>source="<directory>"ソースを検索するディレクトリーを追加指定します。
-findSource <directory>findSource="<directory>"指定したディレクトリー内を検索して関連するソースの場所を追加します。
-suppress <filter file>suppress="<filter file>"指定したファイルに一致する警告を抑止します (以前に指定した抑止設定は置き換えられます)。
-withMessageswithMessages="[true|false]"XMLにテキストメッセージを追加します。
-resetSourceresetSource="[true|false]"ソース検索パスをすべて削除します。

1.8. listBugDatabaseInfo

このコマンドの実行においては、コマンドラインで 0 個以上の xml バグデータベースファイル名を指定します。ファイル名を1つも指定しなければ、標準出力から読み込みを行いテーブルのヘッダーは生成されません。

このコマンドには 1 つだけオプションがあります : -formatDates を指定するとテキスト形式でデータが描画されます。

出力される表は、各バグデータベースごとに行を持ち、次に示すカラムから成ります :

表12.8 listBugDatabaseInfo カラム一覧

カラム目的
versionバージョン名
timeリリースされた日時
classes分析されたクラス数
NCSSコメント文を除いた命令数 (Non Commenting Source Statements)
total全警告数
high優先度(高)の警告の総数
medium優先度(中)の警告の総数
low優先度(低)の警告の総数
filenameデータベースのファイル名

2. 例

2.1. 提供されたシェル・スクリプトを使用しての履歴マイニング

以下はすべて、 jdk1.6.0-b12, jdk1.6.0-b13, ..., jdk1.6.0-b60 のディレクトリに対してコマンドを実行しています。

以下のコマンドを実行してみます :

computeBugHistory jdk1.6.0-b* | filterBugs -bugPattern IL_ | mineBugHistory -formatDates

すると、次のような出力が行われます :

seq	version	time	classes	NCSS	added	newCode	fixed	removed	retained	dead	active
0	jdk1.6.0-b12	"Thu Nov 11 09:07:20 EST 2004"	13128	811569	0	4	0	0	0	0	4
1	jdk1.6.0-b13	"Thu Nov 18 06:02:06 EST 2004"	13128	811570	0	0	0	0	4	0	4
2	jdk1.6.0-b14	"Thu Dec 02 06:12:26 EST 2004"	13145	811786	0	0	2	0	2	0	2
3	jdk1.6.0-b15	"Thu Dec 09 06:07:04 EST 2004"	13174	811693	0	0	1	0	1	2	1
4	jdk1.6.0-b16	"Thu Dec 16 06:21:28 EST 2004"	13175	811715	0	0	0	0	1	3	1
5	jdk1.6.0-b17	"Thu Dec 23 06:27:22 EST 2004"	13176	811974	0	0	0	0	1	3	1
6	jdk1.6.0-b19	"Thu Jan 13 06:41:16 EST 2005"	13176	812011	0	0	0	0	1	3	1
7	jdk1.6.0-b21	"Thu Jan 27 05:57:52 EST 2005"	13177	812173	0	0	0	0	1	3	1
8	jdk1.6.0-b23	"Thu Feb 10 05:44:36 EST 2005"	13179	812188	0	0	0	0	1	3	1
9	jdk1.6.0-b26	"Thu Mar 03 06:04:02 EST 2005"	13199	811770	0	0	0	0	1	3	1
10	jdk1.6.0-b27	"Thu Mar 10 04:48:38 EST 2005"	13189	812440	0	0	0	0	1	3	1
11	jdk1.6.0-b28	"Thu Mar 17 02:54:22 EST 2005"	13185	812056	0	0	0	0	1	3	1
12	jdk1.6.0-b29	"Thu Mar 24 03:09:20 EST 2005"	13117	809468	0	0	0	0	1	3	1
13	jdk1.6.0-b30	"Thu Mar 31 02:53:32 EST 2005"	13118	809501	0	0	0	0	1	3	1
14	jdk1.6.0-b31	"Thu Apr 07 03:00:14 EDT 2005"	13117	809572	0	0	0	0	1	3	1
15	jdk1.6.0-b32	"Thu Apr 14 02:56:56 EDT 2005"	13169	811096	0	0	0	0	1	3	1
16	jdk1.6.0-b33	"Thu Apr 21 02:46:22 EDT 2005"	13187	811942	0	0	0	0	1	3	1
17	jdk1.6.0-b34	"Thu Apr 28 02:49:00 EDT 2005"	13195	813488	0	1	0	0	1	3	2
18	jdk1.6.0-b35	"Thu May 05 02:49:04 EDT 2005"	13457	829837	0	0	0	0	2	3	2
19	jdk1.6.0-b36	"Thu May 12 02:59:46 EDT 2005"	13462	831278	0	0	0	0	2	3	2
20	jdk1.6.0-b37	"Thu May 19 02:55:08 EDT 2005"	13464	831971	0	0	0	0	2	3	2
21	jdk1.6.0-b38	"Thu May 26 03:08:16 EDT 2005"	13564	836565	0	0	0	0	2	3	2
22	jdk1.6.0-b39	"Fri Jun 03 03:10:48 EDT 2005"	13856	849992	0	1	0	0	2	3	3
23	jdk1.6.0-b40	"Thu Jun 09 03:30:28 EDT 2005"	15972	959619	0	2	0	0	3	3	5
24	jdk1.6.0-b41	"Thu Jun 16 03:19:22 EDT 2005"	15972	959619	0	0	0	0	5	3	5
25	jdk1.6.0-b42	"Fri Jun 24 03:38:54 EDT 2005"	15966	958581	0	0	0	0	5	3	5
26	jdk1.6.0-b43	"Thu Jul 14 03:09:34 EDT 2005"	16041	960544	0	0	0	0	5	3	5
27	jdk1.6.0-b44	"Thu Jul 21 03:05:54 EDT 2005"	16041	960547	0	0	0	0	5	3	5
28	jdk1.6.0-b45	"Thu Jul 28 03:26:10 EDT 2005"	16037	960606	0	0	1	0	4	3	4
29	jdk1.6.0-b46	"Thu Aug 04 03:02:48 EDT 2005"	15936	951355	0	0	0	0	4	4	4
30	jdk1.6.0-b47	"Thu Aug 11 03:18:56 EDT 2005"	15964	952387	0	0	1	0	3	4	3
31	jdk1.6.0-b48	"Thu Aug 18 08:10:40 EDT 2005"	15970	953421	0	0	0	0	3	5	3
32	jdk1.6.0-b49	"Thu Aug 25 03:24:38 EDT 2005"	16048	958940	0	0	0	0	3	5	3
33	jdk1.6.0-b50	"Thu Sep 01 01:52:40 EDT 2005"	16287	974937	1	0	0	0	3	5	4
34	jdk1.6.0-b51	"Thu Sep 08 01:55:36 EDT 2005"	16362	979377	0	0	0	0	4	5	4
35	jdk1.6.0-b52	"Thu Sep 15 02:04:08 EDT 2005"	16477	979399	0	0	0	0	4	5	4
36	jdk1.6.0-b53	"Thu Sep 22 02:00:28 EDT 2005"	16019	957900	0	0	1	0	3	5	3
37	jdk1.6.0-b54	"Thu Sep 29 01:54:34 EDT 2005"	16019	957900	0	0	0	0	3	6	3
38	jdk1.6.0-b55	"Thu Oct 06 01:54:14 EDT 2005"	16051	959014	0	0	0	0	3	6	3
39	jdk1.6.0-b56	"Thu Oct 13 01:54:12 EDT 2005"	16211	970835	0	0	0	0	3	6	3
40	jdk1.6.0-b57	"Thu Oct 20 01:55:26 EDT 2005"	16279	971627	0	0	0	0	3	6	3
41	jdk1.6.0-b58	"Thu Oct 27 01:56:30 EDT 2005"	16283	971945	0	0	0	0	3	6	3
42	jdk1.6.0-b59	"Thu Nov 03 01:56:58 EST 2005"	16232	972193	0	0	0	0	3	6	3
43	jdk1.6.0-b60	"Thu Nov 10 01:54:18 EST 2005"	16235	972346	0	0	0	0	3	6	3

次に示すコマンドを実行すると、db.xml 中間ファイルを生成することなく直接同じ情報を作成できます。

computeBugHistory  jdk1.6.0-b*/jre/lib/rt.xml | filterBugs -bugPattern IL_ db.xml | mineBugHistory -formatDates

この情報を使って、 Sun JDK1.6.0 の各ビルドにおいて FindBugs によって発見された無限再起ループの数を表すグラフを表示します。青色の領域は、当該ビルドにおける無限再起ループの数を表しています。その上に描かれている赤色の領域は、以前のバージョンには存在したが当該バージョンでは除去された無限再起ループの数を表しています。 (したがって、赤色の領域と青色の領域を足し合わせた高さは決して減少しないことが保証されています。そして、新たに無限再起ループのバグが持ち込まれた時点で増加します) 。赤色の領域の高さは、当該バージョンにおいて修正または削除されたバグ数の合計で算出されます。バージョン 13 および 14 において見られる減少は、 FindBugs を使用して見つかった JDK のバグの報告を Sun が受け取ったことによるものです。

db.xml ファイルは、 jdk1.6.0 のすべてのビルドに対する検索結果を保持しています。したがって、次に示すコマンドを実行することで、優先度(高)または優先度(低)の正確性に関する警告の履歴が表示されます :

filterBugs -priority M -category C db.xml | mineBugHistory -formatDates

作成される表の例 :

seq	version	time	classes	NCSS	added	newCode	fixed	removed	retained	dead	active
0	jdk1.6.0-b12	"Thu Nov 11 09:07:20 EST 2004"	13128	811569	0	1075	0	0	0	0	1075
1	jdk1.6.0-b13	"Thu Nov 18 06:02:06 EST 2004"	13128	811570	0	0	0	0	1075	0	1075
2	jdk1.6.0-b14	"Thu Dec 02 06:12:26 EST 2004"	13145	811786	3	0	6	0	1069	0	1072
3	jdk1.6.0-b15	"Thu Dec 09 06:07:04 EST 2004"	13174	811693	2	1	3	0	1069	6	1072
4	jdk1.6.0-b16	"Thu Dec 16 06:21:28 EST 2004"	13175	811715	0	0	1	0	1071	9	1071
5	jdk1.6.0-b17	"Thu Dec 23 06:27:22 EST 2004"	13176	811974	0	0	1	0	1070	10	1070
6	jdk1.6.0-b19	"Thu Jan 13 06:41:16 EST 2005"	13176	812011	0	0	0	0	1070	11	1070
7	jdk1.6.0-b21	"Thu Jan 27 05:57:52 EST 2005"	13177	812173	0	0	1	0	1069	11	1069
8	jdk1.6.0-b23	"Thu Feb 10 05:44:36 EST 2005"	13179	812188	0	0	0	0	1069	12	1069
9	jdk1.6.0-b26	"Thu Mar 03 06:04:02 EST 2005"	13199	811770	0	0	2	1	1066	12	1066
10	jdk1.6.0-b27	"Thu Mar 10 04:48:38 EST 2005"	13189	812440	1	0	1	1	1064	15	1065
11	jdk1.6.0-b28	"Thu Mar 17 02:54:22 EST 2005"	13185	812056	0	0	0	0	1065	17	1065
12	jdk1.6.0-b29	"Thu Mar 24 03:09:20 EST 2005"	13117	809468	3	0	8	26	1031	17	1034
13	jdk1.6.0-b30	"Thu Mar 31 02:53:32 EST 2005"	13118	809501	0	0	0	0	1034	51	1034
14	jdk1.6.0-b31	"Thu Apr 07 03:00:14 EDT 2005"	13117	809572	0	0	0	0	1034	51	1034
15	jdk1.6.0-b32	"Thu Apr 14 02:56:56 EDT 2005"	13169	811096	1	1	0	1	1033	51	1035
16	jdk1.6.0-b33	"Thu Apr 21 02:46:22 EDT 2005"	13187	811942	3	0	2	1	1032	52	1035
17	jdk1.6.0-b34	"Thu Apr 28 02:49:00 EDT 2005"	13195	813488	0	1	0	0	1035	55	1036
18	jdk1.6.0-b35	"Thu May 05 02:49:04 EDT 2005"	13457	829837	0	36	2	0	1034	55	1070
19	jdk1.6.0-b36	"Thu May 12 02:59:46 EDT 2005"	13462	831278	0	0	0	0	1070	57	1070
20	jdk1.6.0-b37	"Thu May 19 02:55:08 EDT 2005"	13464	831971	0	1	1	0	1069	57	1070
21	jdk1.6.0-b38	"Thu May 26 03:08:16 EDT 2005"	13564	836565	1	7	2	6	1062	58	1070
22	jdk1.6.0-b39	"Fri Jun 03 03:10:48 EDT 2005"	13856	849992	6	39	5	0	1065	66	1110
23	jdk1.6.0-b40	"Thu Jun 09 03:30:28 EDT 2005"	15972	959619	7	147	11	0	1099	71	1253
24	jdk1.6.0-b41	"Thu Jun 16 03:19:22 EDT 2005"	15972	959619	0	0	0	0	1253	82	1253
25	jdk1.6.0-b42	"Fri Jun 24 03:38:54 EDT 2005"	15966	958581	3	0	1	2	1250	82	1253
26	jdk1.6.0-b43	"Thu Jul 14 03:09:34 EDT 2005"	16041	960544	5	11	15	8	1230	85	1246
27	jdk1.6.0-b44	"Thu Jul 21 03:05:54 EDT 2005"	16041	960547	0	0	0	0	1246	108	1246
28	jdk1.6.0-b45	"Thu Jul 28 03:26:10 EDT 2005"	16037	960606	19	0	2	0	1244	108	1263
29	jdk1.6.0-b46	"Thu Aug 04 03:02:48 EDT 2005"	15936	951355	13	1	1	32	1230	110	1244
30	jdk1.6.0-b47	"Thu Aug 11 03:18:56 EDT 2005"	15964	952387	163	8	7	20	1217	143	1388
31	jdk1.6.0-b48	"Thu Aug 18 08:10:40 EDT 2005"	15970	953421	0	0	0	0	1388	170	1388
32	jdk1.6.0-b49	"Thu Aug 25 03:24:38 EDT 2005"	16048	958940	1	11	1	0	1387	170	1399
33	jdk1.6.0-b50	"Thu Sep 01 01:52:40 EDT 2005"	16287	974937	19	27	16	7	1376	171	1422
34	jdk1.6.0-b51	"Thu Sep 08 01:55:36 EDT 2005"	16362	979377	1	15	3	0	1419	194	1435
35	jdk1.6.0-b52	"Thu Sep 15 02:04:08 EDT 2005"	16477	979399	0	0	1	1	1433	197	1433
36	jdk1.6.0-b53	"Thu Sep 22 02:00:28 EDT 2005"	16019	957900	13	12	16	20	1397	199	1422
37	jdk1.6.0-b54	"Thu Sep 29 01:54:34 EDT 2005"	16019	957900	0	0	0	0	1422	235	1422
38	jdk1.6.0-b55	"Thu Oct 06 01:54:14 EDT 2005"	16051	959014	1	4	7	0	1415	235	1420
39	jdk1.6.0-b56	"Thu Oct 13 01:54:12 EDT 2005"	16211	970835	6	8	37	0	1383	242	1397
40	jdk1.6.0-b57	"Thu Oct 20 01:55:26 EDT 2005"	16279	971627	0	0	0	0	1397	279	1397
41	jdk1.6.0-b58	"Thu Oct 27 01:56:30 EDT 2005"	16283	971945	0	1	1	0	1396	279	1397
42	jdk1.6.0-b59	"Thu Nov 03 01:56:58 EST 2005"	16232	972193	6	0	5	0	1392	280	1398
43	jdk1.6.0-b60	"Thu Nov 10 01:54:18 EST 2005"	16235	972346	0	0	0	0	1398	285	1398
44	jdk1.6.0-b61	"Thu Nov 17 01:58:42 EST 2005"	16202	971134	2	0	4	0	1394	285	1396

2.2. 増分履歴メンテナンス

仮に、 db.xml がビルド b12 - b60 に対する findbugs 実行結果を保持している場合、次に示すコマンドを実行することで、 db.xml に b61 に対する実行結果を追加することができます :

computeBugHistory -output db.xml db.xml jdk1.6.0-b61/jre/lib/rt.xml

3. Ant の例

findbugs の実行とその後のデータ・マイニングツールの活用の両方を実行している ant スクリプトの完全な例を以下に示します :


<project name="analyze_asm_util" default="findbugs">
   <!-- findbugs タスク定義 -->
   <property name="findbugs.home" value="/Users/ben/Documents/workspace/findbugs/findbugs" />
   <property name="jvmargs" value="-server -Xss1m -Xmx800m -Duser.language=en -Duser.region=EN -Dfindbugs.home=${findbugs.home}" />

    <path id="findbugs.lib">
      <fileset dir="${findbugs.home}/lib">
         <include name="findbugs-ant.jar"/>
      </fileset>
   </path>

   <taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask">
      <classpath refid="findbugs.lib" />
   </taskdef>

   <taskdef name="computeBugHistory" classname="edu.umd.cs.findbugs.anttask.ComputeBugHistoryTask">
      <classpath refid="findbugs.lib" />
   </taskdef>

   <taskdef name="setBugDatabaseInfo" classname="edu.umd.cs.findbugs.anttask.SetBugDatabaseInfoTask">
      <classpath refid="findbugs.lib" />
   </taskdef>

   <taskdef name="mineBugHistory" classname="edu.umd.cs.findbugs.anttask.MineBugHistoryTask">
      <classpath refid="findbugs.lib" />
   </taskdef>

   <!-- findbugs タスク定義 -->
   <target name="findbugs">
      <antcall target="analyze" />
      <antcall target="mine" />
   </target>

   <!-- 分析を行うタスク-->
   <target name="analyze">
      <!-- asm-util に対して findbugs を実行する -->
      <findbugs home="${findbugs.home}"
                output="xml:withMessages"
                timeout="90000000"
                reportLevel="experimental"
                workHard="true"
                effort="max"
                adjustExperimental="true"
                jvmargs="${jvmargs}"
                failOnError="true"
                outputFile="out.xml"
                projectName="Findbugs"
                debug="false">
         <class location="asm-util-3.0.jar" />
      </findbugs>
   </target>

   <target name="mine">

      <!-- 最新の分析結果に情報を設定する -->
      <setBugDatabaseInfo home="${findbugs.home}"
                            withMessages="true"
                            name="asm-util-3.0.jar"
                            input="out.xml"
                            output="out-rel.xml"/>

      <!-- 履歴ファイル (out-hist.xml) が既に存在するかどうかを確認する -->
      <condition property="mining.historyfile.available">
         <available file="out-hist.xml"/>
      </condition>
      <condition property="mining.historyfile.notavailable">
         <not>
            <available file="out-hist.xml"/>
         </not>
      </condition>

      <!-- このターゲットは、履歴ファイルが存在しないとき (初回) だけ実行されます -->
      <antcall target="history-init">
        <param name="data.file" value="out-rel.xml" />
        <param name="hist.file" value="out-hist.xml" />
      </antcall>
      <!-- 上記以外の場合に実行されます -->
      <antcall target="history">
        <param name="data.file"         value="out-rel.xml" />
        <param name="hist.file"         value="out-hist.xml" />
        <param name="hist.summary.file" value="out-hist.txt" />
      </antcall>
   </target>

   <!-- 履歴ファイルを初期化します -->
   <target name="history-init" if="mining.historyfile.notavailable">
      <copy file="${data.file}" tofile="${hist.file}" />
   </target>

   <!-- バグ履歴を算出します -->
   <target name="history" if="mining.historyfile.available">
      <!-- ${data.file} を ${hist.file} にマージします -->
      <computeBugHistory home="${findbugs.home}"
                           withMessages="true"
                           output="${hist.file}">
            <dataFile name="${hist.file}"/>
            <dataFile name="${data.file}"/>
      </computeBugHistory>

      <!-- 履歴を算出して ${hist.summary.file} に出力します -->
      <mineBugHistory home="${findbugs.home}"
                        formatDates="true"
                      noTabs="true"
                        input="${hist.file}"
                        output="${hist.summary.file}"/>
   </target>

</project>