今、話題の人工知能(AI)などで人気のPython。初心者に優しいとか言われていますが、全然優しくない! という事を、つらつら、愚痴っていきます

356.spotbugs

»

初回:2024/03/20

 今回は、Javaのコード内のバグを探す『SpotBugs』をご紹介したいと思います。

P子「前回までの PMD と何が違うの?」※1

 PMDは、ソースコードを解析して問題のある個所を指摘します。SpotBugsは、コンパイルされたバイナリを解析して問題のある個所を検出してくれます。どちらかというと、PMDでは必要なチェックを追加していくという感じですが、SpotBugsではバグと思われる個所をピックアップするので、出来るだけすべての項目を修正する方向で検討するのが良いでしょう。

1.SpotBugs とは

P子「聞くまでもないと思うけど、一応説明して」

 まずは、解説文を見てみましょう。

《参考資料1》
  https://spotbugs.github.io/
  Find bugs in Java Programs

SpotBugs は、静的分析を使用して Java コード内のバグを探すプログラムです。 これはフリー ソフトウェアであり、GNU Lesser General Public License の条件に基づいて配布されます。

SpotBugs は FindBugs (現在は放棄されたプロジェクト) から分岐したもので、コミュニティのサポートを受けて中断した時点から継続しています。 詳細は公式マニュアルをご確認ください。

SpotBugs を実行するには、JRE (または JDK) 1.8.0 以降が必要です。 ただし、Java の任意のバージョン用にコンパイルされたプログラムを分析できます。
《google翻訳》

 昔は、FindBugs と呼ばれていましたが、開発が停止されたため、後継としてSpotBugsが開発を継続しているみたいです。そのあたりの紆余曲折はよく知りませんが、オープンソース系では色々と思想の相違が起こるのでしょう。

P子「OpenOfficeとLibreOfficeみたいなものね」

2.ダウンロードと設定

 まずは、入手方法から。

 先の《参考資料1》の github へのリンクから入ります。右の About の欄の下の方に、Releases という文字がありますので、その下に最新版へのリンクがあります。今日現在は、『SpotBugs 4.8.3』でしょう。

 それをクリックすると、SpotBugs 4.8.3 のページが表示されるので、下の方にある Assets から、spotbugs-4.8.3.zip のリンクをクリックしてダウンロードします。

《参考資料1》
  https://github.com/spotbugs/spotbugs/releases/tag/4.8.3
  SpotBugs 4.8.3
  spotbugs-4.8.3.zip
  https://github.com/spotbugs/spotbugs/releases/download/4.8.3/spotbugs-4.8.3.zip

 このツールも、Ant や Maven に組み込んで使用することができますが、前回同様、単独で使用することにします。

 ダウンロードした zip を展開して、java へのパスを通して、bin\spotbugs.bat を実行します。すると、GUI の画面が立ち上がりますので、新規プロジェクトから各種設定をしていきます。設定後、プロジェクトを保存しておくと、次回起動時に読み込ませることができます。
 例えば、test.xml というファイルにセーブした場合、

 call bin\spotbugs.bat -project test.xml

 で、起動できます。

 もちろん、GUI で起動するのは分かりやすくて便利ですが、普段から、テキストエディターで編集している私としては、結果をテキストで出力しておきたいと思います。

call Javaのパスを通す

set SRCPATH="SRC=チェック対象のソースのフォルダ\"

call bin\spotbugs.bat -textui -effort:max -property %SRCPATH% -project test.xml -low: -progress: -sortByClass -output error.txt

 -textui で、テキスト出力されます。

3.出力形式の変更カスタマイズ

 さて、先ほどのテキスト出力形式では、秀丸君でのF10タグジャンプ機能が使えません。そこで、ソースコードを修正して形式をカスタマイズしてみましょう。

P子「必要あるの?」

 必要ありません。あくまで、やってみたいな~という好奇心だけです。

 まず、-textui でテキスト出力しているソースは、TextUIBugReporter.java です。これを入手します。

 先ほどの spotbugs-4.8.3.zip をダウンロードした箇所から、spotbugs-4.8.3-source.zip を取得して展開してください。その中の

C:\spotbugs-4.8.3-source.zip\spotbugs-4.8.3\src\main\java\edu\umd\cs\findbugs\TextUIBugReporter.java を取り出します。

 または、git-hub のリンクから直接取得しても良いでしょう。

https://github.com/spotbugs/spotbugs/blob/master/spotbugs/src/main/java/edu/umd/cs/findbugs/TextUIBugReporter.java

 このソースから、protected void printBug(BugInstance bugInstance) メソッド部分を変更します。

    protected void printBug(BugInstance bugInstance) {
        SourceLineAnnotation line = bugInstance.getPrimarySourceLineAnnotation();
        // 1.ジャンプ用の行番号を作成します。『:[line 1101]』 → 『(1101):』に変換します。
        String srcname = line.toString().replace(":[line ","(").replace("]","):");
        // 2.後ろから最初のスペースを見つけて、それ以降を残す。
        final int idx1 = srcname.lastIndexOf(' ');
        srcname = srcname.substring( idx1+1 );
        // 3.クラス名を取得
        final String clsname = line.getClassName();
        // 4.srcname の 『.java』以降を削除して、clsname のクラス名の位置を見つけます。
        final int idx2 = srcname.indexOf('.');
        int idx3 = -1;
        if( idx2 < 0 ) {
            idx3 = clsname.lastIndexOf('.');
        }
        else {
            idx3 = clsname.indexOf(srcname.substring(0,idx2));
            // 5.該当のクラス名が見つからない場合は、強制的に最後の『.』を見つけてパッケージ名を作ります。
            if( idx3 < 0 ) {
                idx3 = clsname.lastIndexOf('.');
            }
        }

        // 7.ソースのフルパスを先頭に追加します。(システムパラメータで指定)
        final String srcpath = System.getProperty("SRC");
        outputStream.print( srcpath );

        // 6.クラス名のパッケージ部分と、ソース名+行番号 の文字列を連結し、ファイルパスに変換します。
        final String fullname = clsname.substring(0,idx3).replace('.','\\') + srcname;
        outputStream.print( fullname );
        outputStream.print( "\t" );

        // 8. LongBugCodes を取り出します。
        final String bugcode = bugInstance.getType();
        outputStream.print( bugcode );
        outputStream.print( "\t" );

        // 9. メッセージを取り出します。(改行コードは、スペースに置換)
        final String message = bugInstance.getMessage().replace('\n', ' ');
        outputStream.println( message );
    }

形式的には、PMD の出力と同じ感じの形式にしています。

4.まとめ

 ソースコードチェックは、自動でついついやりがちなミスを見つけてくれます。それにばかり頼るのはまずいのですが、ソースの品質を一定に保つためには、非常にお手軽に実行できるので非常に強力なツールになると思います。

 上手に活用したいと思います。

 ほな、さいなら

======= <<注釈>>=======

※1 P子「前回までの PMD と何が違うの?」
 P子とは、私があこがれているツンデレPythonの仮想女性の心の声です。

Comment(0)

コメント

コメントを投稿する