僕にそのコピペを直せというのか

  • 464
    いいね
  • 3
    コメント
この記事は最終更新日から1年以上が経過しています。

ソースコードをコピーアンドペーストで作成したコードクローンの方が信頼性がいいという言説もないことはないですが、多くの場合、コードクローンの存在は我々を土壇場で苦しめることが多いです。

担当者が逃げた、ソースコードを、夜遅くまで修正してリリースしたあとに、実は「コピペで作っているから別の所も全部なおしてテストしてね」とか言われて、作業をやり直すのは、とてもとても悲しいものです。

殆ど同じソースコードを間違い探しのように微妙に変更して、修正していくのは屈辱の極みです。

土壇場において、このような罰ゲームを避けるために、コピペの頻度というものは常時監視しておき、異常な頻度の場合はただちに是正すべきです。

ここでは、コピペの検出を行うツールについて説明します。

PMD-CPD

PMDはJavaで実装されたJavaのソースコードの潜在的問題を検出するツールです。
http://pmd.sourceforge.net/snapshot/

この機能の一部に重複したコードを検出するCPDコマンドが存在しており、次のプログラミング言語の重複を検出可能です。
・Java
・JSP
・C++
・Ruby
・Fortran
・PHP
・C#
・PLSQL
・Ecmascript

インストール方法

下記のいずれかのファイルをダウンロード、解凍して任意のフォルダに展開してください。
http://sourceforge.net/projects/pmd/files/pmd/

実行例

Windowsでの実行例

cpd --minimum-tokens 50 --language ecmascript --format text --encoding utf8 --files C:\tool\clonedigger\test\ > result.txt

Linuxでの実行例

bin/run.sh cpd --minimum-tokens 35 --format xml --language ruby --files /var/lib/redmine/app/ > result.xml

パラメータ

パラメータはwindowsとlinuxで共有です。

パラメータ 説明
--minimum-tokens 重複を検知するトークン数を指定します。
--format text,xml,csvが選択できます。xmlで出力した場合はjenkinsで使用できます。
--language プログラミング言語の種類を指定します.
--files 検査対象のソースコードのディレクトリを指定します。これは再帰的に検出します。
--encoding 検査対象のソースコードのエンコードを指定します

GUI

bin/cpdgui.batを実行することでGUIで動作することもできます。
clone.png

Clonedigger

ClonediggerはPythonとJavaで実装されたコピペ検出ツールです。
http://clonedigger.sourceforge.net/

検出可能なプログラミング言語は次の通りです。

・python
・java
・lua
・javascript

python以外のプログラミング言語の検出には、後述するコツがあります。

インストール方法

easy_install clonedigger

実行例

Pythonの検出例

ファイルを指定した場合

clonedigger -l python -o ./test.html C:\tool\clonedigger\test\test_utf8.py

フォルダを指定した場合

clonedigger -l python -o ./test.html C:\tool\clonedigger\test\test_utf8.py

フォルダを指定した場合は、サブフォルダも検出します。
-oで指定したファイルに以下のようなHTMLを作成します。

clone.png

もし、次のように--cpd-outputオプションを使用するとXML形式で出力されます。この出力形式はPMD/CPDと同じものになります。

clonedigger -l python --cpd-output -o test.xml C:\tool\clonedigger\test\python\

Javaの検出例

Python以外のソースコードを検出する場合、カレントディレクトリにjava_antlrが存在しないと動作しません。
Windows、Python2.7の場合は次のような操作が必要になります。

cd C:\Python27\Lib\site-packages\clonedigger-1.1.0-py2.7.egg\clonedigger
clonedigger -l java --cpd-output -o test.xml C:\tool\clonedigger\test\test.java

JavaScriptの検出例

JavaScriptを検出するときには、カレントディレクトリにjs_antlrが存在しないと動作しません。
Windows、Python2.7の場合は次のような操作が必要になります。

cd C:\Python27\Lib\site-packages\clonedigger-1.1.0-py2.7.egg\clonedigger
clonedigger -l js --cpd-output -o test.xml C:\tool\clonedigger\test\test.js

ブラウザで動作させるJavaScriptは次のようないい加減な実装でも動作します。

  // 最後のコンマが余分
  var questions = [
    {message: "ああああ", category: Category.emotionalExhaustion} ,
  ];

しかし、clonediggerではこのような不正な記述があると、解析が中断されエラーとなります。この時次のようなエラーメッセージが表示されるので、修正のヒントになるでしょう

line 14:2 rule arrayItem failed predicate: { input.LA(1) == COMMA }?

AIST CCFinderX

コメントで教えてもらった、AIST CCFinderXは下記のページからダウンロードできます。
http://www.ccfinder.net/ccfinderxos-j.html

動作させるに32ビットのJavaとPython2.6(上でも下でもダメ)が必要になります。
Windowsのバイナリをダウンロードした場合、32bitで動作させないと動かないので、gemx.batは以下のように修正する必要があります。

gemx.bat
set PATH=C:\Windows\SysWOW64;C:\TracLight\python;C:\TracLight\python\python\Scripts\;%~dp0\scripts
set CCFINDERX_PYTHON_INTERPRETER_PATH=C:\TracLight\python\python.exe

以下の画像はgemx.batで検知した画面の例になります。
無題.png

その他、散布図なども表示できます。これらのGUIは魅力的といえるでしょう。

コマンドラインから実行する場合は次のようになります。

ccfx p java -d c:\dev\java\

この時出力される、a.ccfxdはバイナリファイルでGemXで開くことが可能です。以下のコマンドでテキスト形式に変換できます。

>ccfx p a.ccfxd > test.txt

VisualBasicの対応

この手のツールとしてはめずらしくVisualBasicを対応しています。
VB6やVBAで作ったコードも解析しているようです。しかし、clsファイルは認識しないのでccfx_prep_scripts.iniを以下のように修正してください。

visualbasic=.vb;.bas;.frm;.cls

その他

・マルチバイトを扱っているソースに対する処理が失敗していることがあります。
・Jenkinsとの連携は調べた限り、簡単にはできそうもないです。
・更新履歴のページがデッドリンクになっていることから、現在はもうメンテナンスされていないようです。
 ソースコードがあるので、必要に応じて自分で治す必要があるでしょう。

Jenkinsによる監視

JenkinsのViolationsプラグインを用いることでコードクローンの遷移を監視できます。
https://wiki.jenkins-ci.org/display/JENKINS/Violations

  1. Jenkinsのスクリプト上にてワークスペース上にXMLを生成します。

  2. プロジェクトの設定のビルド後の処理でReportViolationsのcpdに1.のXMLを指定します。
    clone.png

  3. 各ビルドを行うことで以下のようなレポートが作成されます。
    clone.png