430 likes | 548 Views
プログラム変更支援を目的とした コードクローン情報付加ツール. 佐々木亨 ⁽¹⁾ 肥後芳樹 ⁽²⁾ 神谷年洋 ⁽³⁾ 楠本真二 ⁽²⁾ 井上克郎 ⁽²⁾ ⁽¹⁾ 大阪大学基礎工学部情報科学科 ⁽²⁾ 大阪大学大学院情報科学研究科 ⁽³⁾ 科学技術振興機構 さきがけ. 研究の背景 . コードクローンとは ソースコード中に存在するコード片で、同形のコード片が他に存在するもの コピー&ペーストによるプログラム再利用などで生じる ソフトウェア保守を困難にする あるコード片にバグがあると、そのコードクローン全てについて修正の検討をしなければならない
E N D
プログラム変更支援を目的としたコードクローン情報付加ツールプログラム変更支援を目的としたコードクローン情報付加ツール 佐々木亨⁽¹⁾ 肥後芳樹⁽²⁾ 神谷年洋⁽³⁾ 楠本真二⁽²⁾ 井上克郎⁽²⁾ ⁽¹⁾大阪大学基礎工学部情報科学科 ⁽²⁾大阪大学大学院情報科学研究科 ⁽³⁾科学技術振興機構 さきがけ 情報処理学会全国大会
研究の背景 • コードクローンとは • ソースコード中に存在するコード片で、同形のコード片が他に存在するもの • コピー&ペーストによるプログラム再利用などで生じる • ソフトウェア保守を困難にする • あるコード片にバグがあると、そのコードクローン全てについて修正の検討をしなければならない • 機能を追加する場合も同様のことが言える 情報処理学会全国大会
C1 C2 C3 C4 C5 クローンクラス • クローンクラス 同形のコードクローンの集合 • 例 クローンクラス1 {C1,C4,C5} クローンクラス2 {C2,C3} 情報処理学会全国大会
コードクローン検出ツールCCFinder • ソースコードを字句解析してトークンの列に分解してから、トークン単位で直接比較することによりクローンを検出 • 数百万行規模のシステムにも実用時間で解析可能 • 実用的に意味のないクローンを検出しない • さまざまな企業のソフトウェアにも適用している 情報処理学会全国大会
CCFinderの出力 #begin{file description} 0 1475 3429 /home/test/test1.c 1 3213 9669 /home/test/test2.c 2 3584 11420 /home/test/test3.c : #end{file description} #begin{clone} #begin{set} 0 1250,3,2811 1258,17,2853 0 1260,3,2861 1268,13,2903 1 2962,3,8913 2970,10,8955 #end{set} #begin{set} 149,1,66 55,41,120 262,1,93 68,39,147 275,1,15981,37,213 #end{set} : : #end{clone} 解析対象のファイル群の情報 ファイルのID・ファイル行数・ ファイルパスなどからなる クローンクラス情報 クローンクラス ID1のファイルの49行目から55行目 ID2のファイルの62行目から68行目 ID2のファイルの75行目から81行目 情報処理学会全国大会
クローン情報を用いてソースコードを修正する際の問題点クローン情報を用いてソースコードを修正する際の問題点 • コードクローンに対する機能追加・修正中にクローン情報とソースコードで行番号のずれが生じる • 対処法 • 行番号のずれを意識しながら作業する • 効率が悪い • 修正箇所を間違える可能性 情報処理学会全国大会
研究の目的 • コードクローンに対する機能追加・修正中に行番号のずれを意識せずに作業する • コードクローンの位置情報を、コメントとしてソースコードに埋め込む手法の提案とツールの実装を行う 情報処理学会全国大会
コードクローン情報の追加(コメントの利用)コードクローン情報の追加(コメントの利用) • 基本方針 • クローンクラスごとに割り付けたIDを利用する • クローンクラスに含まれる全行にコメントを追加する • コメントの形式 • クローンクラスの先頭行は“//@$クローンクラスのID@” • 先頭行以外は“//@クローンクラスのID@” • ある行が2つ以上のクローンクラスに属している場合はコンマで区切る 情報処理学会全国大会
コメント追加例 30: while(a>10){ 31: b=b+a; 32: a=a+1; 33: } 34: sum = a; 40: while(c>10){ 41: d=d+c; 42: c=c+1; 43: } 83: while(e>10){ 84: f=f+e; 85: e=e+1; 86: } 87: sum = e; //@$1@ //@1@ //@1@ //@1@ //@$1@ //@1@ //@1@ //@1@ //@$1@ //@1@ //@1@ //@1@ //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ //@$1@ //@1@ //@1@ //@1@ //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ クローンクラス1 #begin{set} 130,1,4533,1,52 140,1,5843,1,65 183,1,10286,1,109 #end{set} クローンクラス2 #begin{set} 130,1,4534,1,55 183,1,10287,1,112 #end{set} 情報処理学会全国大会
while(a < 10){ b=b+a; a=a+1; } Sum = a; : while(c > 10){ d=d+c; c=c+1; } : while(e > 10){ f=f+e; e=e+1; } Sum = e; //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ //@$1@ //@1@ //@1@ //@1@ //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ while(a < 10){ b=b+a; a=a+1; } Sum = a; : while(c < 10){ d=d+c; c=c+1; } : while(e < 10){ f=f+e; e=e+1; } Sum = e; //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ //@$1@ //@1@ //@1@ //@1@ //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ デバッグへの利用手順 while文の条件が間違っている while(a > 10){ b=b+a; a=a+1; } Sum = a; : while(c > 10){ d=d+c; c=c+1; } : while(e > 10){ f=f+e; e=e+1; } Sum = e; //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ //@$1@ //@1@ //@1@ //@1@ //@$1@,@$2@ //@1@,@2@ //@1@,@2@ //@1@,@2@ //@2@ while(a < 10){ b=b+a; a=a+1; } Sum = a; : while(c < 10){ d=d+c; c=c+1; } : while(e < 10){ f=f+e; e=e+1; } Sum = e; 1.あるバグを発見する 2.ソースコードにクローン情報の コメントを付加する 3.バグを修正する 4.修正部分のコメントを調べる 5.コメント中のクローンクラスのID を利用してクローンクラスの 先頭行を見つける 6.他の修正箇所を見つける 7.同様の修正を行う 8.不要になったコメントを除去する 情報処理学会全国大会
ツールの機能 • コメント追加機能 • コメントにはクローンクラスのIDを利用 • コメントはクローンクラスに含まれる全行に追加 • 追加はオリジナルファイルに行わず、編集用の一時的なファイルに行う • クローンクラス検索機能 • クローンクラスを指定し、そのコメントがあるファイル情報等を検索・表示 • 一時ファイル編集機能 • コメント追加後、ファイル編集のためにファイルを選択して開く • コメント除去機能 • 不要となったコメントを、クローンクラスのIDを指定して除去する • すべてのコメントを一括して除去する • 一時ファイル書き戻し機能 • 編集用の一時的なファイルの変更をオリジナルファイルに反映させる 情報処理学会全国大会
適用実験 • 日本語入力システム「かんな」(http://canna.sourceforge.jp)のバージョン3.6と3.6p1の間でのセキュリティ問題の修正に対して擬似的なデバッグを行うことで適用した • ソースコードはC言語で記述、92ファイル、約9万行 • この修正は、バッファのオーバーフローを調べる処理の追加で、全20箇所にほぼ同じ修正を行っている • 具体的な追加コードは if(Request.type7.datalen!=SIZEOFSHORT*3) return (-1); 等 • 実行環境 FreeBSDPentium4 1.5GHz 512MB 情報処理学会全国大会
具体例(修正前の「かんな」ソースコード) • 下図の2405行目の直前にオーバーフローの検査処理を追加する 2399 static 2400 ProcWideReq7(buf) 2401 BYTE *buf ; 2402 { 2403 ir_debug( Dmsg(10, "ProcWideReq7 start!!\n")); 2404 2405 buf += HEADER_SIZE; Request.type7.context = S2TOS(buf); 2406 buf += SIZEOFSHORT; Request.type7.number = S2TOS(buf); 2407 buf += SIZEOFSHORT; Request.type7.yomilen = (short)S2TOS(buf); 2408 ir_debug( Dmsg(10, "req->context =%d\n", Request.type7.context)); 2409 ir_debug( Dmsg(10, "req->number =%d\n", Request.type7.number)); 2410 ir_debug( Dmsg(10, "req->yomilen =%d\n", Request.type7.yomilen)); 2411 2412 return( 0 ) ; 2413 } 情報処理学会全国大会
赤い部分のずれは2行 青い部分のずれは4行 行番号の増減を意識しながら作業するのは困難 ツールを利用しない場合- コードクローン位置情報のずれ 「かんな」バージョン3.6のコードクローン情報 #begin{set} 0.912367,1,74522375,24,7483 0.912383,1,75192391,24,7550 0.912399,1,75862407,24,7617 0.912415,1,76572423,24,7688 0.912433,1,77392441,24,7770 : #end{set} #begin{set} 0.912376,5,74882381,2,7518 0.912392,5,75552397,2,7585 0.912408,5,76262413,2,7656 0.912426,5,77082431,2,7738 0.912444,5,77902449,2,7820 : #end{set} #begin{set} 0.912399,1,75862407,50,7619 0.912587,1,84102595,51,8443 : #end{set} #begin{set} 0.912367,1,74522375,24,7483 0.912383,1,75192391,24,7550 0.912399,1,75862407,24,7617 0.912415,1,76572423,24,7688 0.912433,1,77392441,24,7770 : #end{set} #begin{set} 0.912376,5,74882381,2,7518 0.912392,5,75552397,2,7585 0.912408,5,76262413,2,7656 0.912426,5,77082431,2,7738 0.912444,5,77902449,2,7820 : #end{set} #begin{set} 0.912399,1,75862407,50,7619 0.912587,1,84102595,51,8443 : #end{set} #begin{set} 0.912367,1,74522375,24,7483 0.912383,1,75192391,24,7550 0.912399,1,75862407,24,7617 0.912415,1,76572423,24,7688 0.912433,1,77392441,24,7770 : #end{set} #begin{set} 0.912376,5,74882381,2,7518 0.912392,5,75552397,2,7585 0.912408,5,76262413,2,7656 0.912426,5,77082431,2,7738 0.912444,5,77902449,2,7820 : #end{set} #begin{set} 0.912399,1,75862407,50,7619 0.912587,1,84102595,51,8443 : #end{set} この修正例において全部で20箇所101行もの処理を追加 2420行目に同様の2行分の修正を行ったとする 2405行目に追加したため ソースコードとコードクローン情報の間で行番号が2行ずつずれている 情報処理学会全国大会
追加処理 この部分のコメントを見ればクローンクラス1311と1318に関して同様の 修正の検討をすればいいとわかる(実際に1311に対して修正を行っていた) ツールを利用する場合- コメント付加後に追加 2399 static //@$1311@,@$1318@ 2400 ProcWideReq7(buf) //@1311@,@1318@ 2401 BYTE *buf ; //@1311@,@1318@ 2402 { //@1311@,@1318@ 2403 ir_debug( Dmsg(10, "ProcWideReq7 start!!\n")); //@1311@,@1318@ 2404 //@1311@,@1318@ 2405 if(Request.type7.datalen!=SIZEOFSHORT*3) 2406 return (-1); 2407 buf += HEADER_SIZE; Request.type7.context = S2TOS(buf); //@1311@,@1318@ 2408 buf += SIZEOFSHORT; Request.type7.number = S2TOS(buf); //@1311@,@1318@ 2409 buf += SIZEOFSHORT; Request.type7.yomilen = (short)S2TOS(buf); //@1311@,@1318@ 2410 ir_debug( Dmsg(10, "req->context =%d\n", Request.type7.context)); //@$1317@ 2411 ir_debug( Dmsg(10, “req->number =%d\n", Request.type7.number)); //@1317@ 2412 ir_debug( Dmsg(10, "req->yomilen =%d\n", Request.type7.yomilen)); //@1317@ 2413 //@1317@ 2414 return( 0 ) ; //@1317@ 2415 } //@1317@ 行番号のずれを意識することなく作業することができる 情報処理学会全国大会
まとめと今後の課題 • まとめ • プログラム変更作業を支援するための、コードクローン情報付加手法の提案、ツールの試作をし、「かんな」のバグ修正作業に適用した • 今後の課題 • 実際のソフトウェア開発・保守現場での評価 情報処理学会全国大会
終わり 情報処理学会全国大会
これ以降は発表に入れないスライド 情報処理学会全国大会
定義 • 完全性 • 修正が必要な箇所のうち実際に検出された割合 • 効率性 • 検出されたうち実際に修正箇所である割合 • 検出された • ある修正箇所を特定したときに、その箇所にあるコメント内のクローンクラスIDをたどってたどり着ける箇所 情報処理学会全国大会
評価内容 //CL1 総修正箇所は4箇所 検出された箇所は5箇所 検出された修正箇所は3箇所 完全性 (4箇所中3箇所)75% 効率性 (5箇所中3箇所)60% //CL1,2 //CL3 //CL2 //CL2,3 情報処理学会全国大会
評価結果 f値を見ると、本ツールはgrepより有効である 情報処理学会全国大会
CCFinderの最小一致トークン数を変化させた 補足実験 • コメント数 : 1修正箇所中のコメント数 情報処理学会全国大会
grepで検出されなかった唯一のクローン ・この部分を検索キーとすればgrepでも検出されるが、これだと他にも数多く検出される (135行一致する f値は0.26) static ProcWideReq1(buf) BYTE *buf ; /* ARGSUSED */ { ir_debug( Dmsg(10, "ProcWideReq1 start!!\n") ); return( 0 ) ; } このようにgrepなどのコード片を指定して検索する場合は利用者の能力によって検索結果に差が出る しかし、 本ツールではその必要がないためその心配がない 情報処理学会全国大会
1311は修正箇所で1318は修正しなくてよかったのはなぜ?1311は修正箇所で1318は修正しなくてよかったのはなぜ? クローンクラス1311 クローンクラス1312 クローンクラス1318 実際には1312に対して修正が行われていた つまり、1311に修正を行ったというより、 1312に対して修正を行っていた 情報処理学会全国大会
編集用の一時ファイルの作成方法 • ディレクトリAppend_Comment_Files中にディレクトリファイル階層を実現する 1 /Canna36/cmd/wtoc/wtoc.c 2 /Canna36/dic/ideo/pubdic/pod.c 3 /Canna36/doc/man/guide/tex/cannaindex.c 4 /Canna36/misc/is.c 5 /Canna36/sample/sample.c 1’ /Append_Comment_Files/Canna36/cmd/wtoc/wtoc.c 2’ /Append_Comment_Files/Canna36/dic/ideo/pubdic/pod.c 3’ /Append_Comment_Files/Canna36/man/guide/tex/cannaindex.c 4’ /Append_Comment_Files/Canna36/misc/is.c 5’ /Append_Comment_Files/Canna36/sample/sample.c 情報処理学会全国大会
既存のコードクローン検出手法(1/2) Bakerの手法 • 行単位でソースコードを比較してコードクローンを検出 Baxterらの手法 • C言語のソースファイルを入力,構文解析して,解析木(の部分木)を比較する [Baker1995] B. S. Baker: “On finding Duplication and Near-Duplication in Large Software System,” Proc. Second IEEE Working Conf. Reverse Eng., pp. 86-95, Tronto, Canada (Jul., 1995). [Baxter1998] I. D. Baxter, A. Yahin, L. Moura, M. Sant’Anna, and L. Bier: “Clone Detection Using Abstract Syntax Trees,” Proc. of ICSM ’98, pp. 368-377, Bethesda, Maryland (Nov., 1998). 情報処理学会全国大会
既存のコードクローン検出手法(2/2) • Merloらの手法 • 手続き(メソッドや関数)の特徴メトリクスを比較して,計測値が似ていればコードクローンであると判定する [Balazinska1999] M. Balazinska, E. Merlo, M. Dagenais, B. Lague, and K.A. Kontogiannis, "Measuring Clone Based Reengineering Opportunities", Proc. 6th IEEE Int'l Symposium on Software Metrics (METRICS '99), pp. 292-303, Boca Raton, Florida, Nov. 1999. 情報処理学会全国大会
CCFinder: コードクローン検出ツール ソースコードを字句解析してトークンの列に直してからコードクローン検出を行う • (浅い)文法知識に基づいたソースコード変形 • クラススコープや名前空間による複雑な名前の正規化を行う • 初期化テーブルを取り除く • モジュールの区切りを認識する • 言語依存部分を取り替えることで,さまざまなプログラミング言語に対応 情報処理学会全国大会
コードクローン検出手順 (1)ソースコードを入力し,トークンの列にする (2)変形ルールにより,トークン列を変形する (3)パラメータ置換を行う (4)マッチングアルゴリズムによりコードクローンを検出する (5)コードクローンの位置(ファイル,行, カラム)を出力する 情報処理学会全国大会
例題ソースコード 1. static void foo() throws RESyntaxException { 2. String a[] = new String [] { "123,400", "abc", "orange 100" }; 3. org.apache.regexp.RE pat = new org.apache.regexp.RE("[0-9,]+"); 4. int sum = 0; 5. for (int i = 0; i < a.length; ++i) 6. if (pat.match(a[i])) 7. sum += Sample.parseNumber(pat.getParen(0)); 8. System.out.println("sum = " + sum); 9. } 10. static void goo(String [] a) throws RESyntaxException { 11. RE exp = new RE("[0-9,]+"); 12. int sum = 0; 13. for (int i = 0; i < a.length; ++i) 14. if (exp.match(a[i])) 15. sum += parseNumber(exp.getParen(0)); 16. System.out.println("sum = " + sum); 17. } 情報処理学会全国大会
ステップ(1):ソースコードを入力し,トークンの列にするステップ(1):ソースコードを入力し,トークンの列にする 情報処理学会全国大会
ステップ(2):変形ルールにより,トークン列を変形するステップ(2):変形ルールにより,トークン列を変形する 情報処理学会全国大会
ステップ(3):パラメータ置換を行う 情報処理学会全国大会
ステップ(4): マッチングアルゴリズムにより,コードクローンを検出 情報処理学会全国大会
4-6行目と 13-15行目, 8-10行目と 17-19行目 1. static void foo() throws RESyntaxException { 2. String a[] = new String [] { "123,400", "abc", "orange 100" }; 3. org.apache.regexp.RE pat = new org.apache.regexp.RE("[0-9,]+"); 4. int sum = 0; 5. for (int i = 0; i < a.length; ++i) { 6. if (pat.match(a[i])) 7. sum += Sample.parseNumber(pat.getParen(0)); 8. } 9. System.out.println("sum = " + sum); 10. } 11. static void goo(String [] a) throws RESyntaxException { 12. RE exp = new RE("[0-9,]+"); 13. int sum = 0; 14. for (int i = 0; i < a.length; ++i) { 15. if (exp.match(a[i])) 16. sum += parseNumber(exp.getParen(0)); 17. } 18. System.out.println("sum = " + sum); 19. } 情報処理学会全国大会
1. static void foo() throws RESyntaxException { 2. String a[] = new String [] { "123,400", "abc", "orange 100" }; 3. org.apache.regexp.RE pat = new org.apache.regexp.RE("[0-9,]+"); 4. int sum = 0; 5. for (int i = 0; i < a.length; ++i) 6. if (pat.match(a[i])) 7. sum += Sample.parseNumber(pat.getParen(0)); 8. System.out.println("sum = " + sum); 9. } 10. static void goo(String [] a) throws RESyntaxException { 11. RE exp = new RE("[0-9,]+"); 12. int sum = 0; 13. for (int i = 0; i < a.length; ++i) 14. if (exp.match(a[i])) 15. sum += parseNumber(exp.getParen(0)); 16. System.out.println("sum = " + sum); 17. } 情報処理学会全国大会
Java向けの変形ルール RJ1:パッケージ名除去 ( PackageName ‘.’ )+ ClassName → ClassName RJ2:Callee挿入 NDotOrNew NClassName ‘(‘ → NDotOrNew CalleeIdentifier ‘.’ NClassName ‘(‘ RJ3:テーブル初期化除去 '=' '{' InitalizationList, '}' → '=' '{' UniqueIdentifier '}‘ ']' '{' InitalizationList, '}' → ']' '{' UniqueIdentifier '}’ RJ4:モジュールの分離 トップレベルの定義や宣言の終わりにUniqueIdentifier を挿入する RJ5:可視性キーワードの除去 protected, public,synchronizedなどのキーワードを取り除く RJ6:コンパウンド・ブロックの処理 if (…), else, while (…)の直後が単文なら{}を補う 情報処理学会全国大会
修正する 修正のたびにコードクローンの位置情報を更新すると‥ 検出されなくなる クローンペア クローンでなくなる 情報処理学会全国大会
メニューバー ステータスバー 実装 • Javaで実装 • 動作環境 FreeBSD 情報処理学会全国大会
先頭行から修正箇所を探し出す支援はないのか?先頭行から修正箇所を探し出す支援はないのか? • ありません • 一般的なプログラムテキストにおいて • コードクローンの大部分は大きさが20トークン程度(10行程度)であるといわれている 情報処理学会全国大会
本ツールの対応している言語 • CCFinderが対応していることが前提で、さらに行間のコメントで始まる言語 • CCFinderはC/C++,Java,COBOL,Fortran,EmacsLispに対応 • 現在、C/C++, Javaに対応 情報処理学会全国大会
CCFiderが実用時間とは?具体的には? • トークン列の比較にサフィックス木を利用しているため、高速 • 10MLOC(1千万行)ソースコードを68分(Pentium3 650MHz RAM 1GB)で解析 • 本適用例においては40秒で解析 情報処理学会全国大会
コードクローンはすべて悪いか? • そうとは限らない • 時間的制約のあるシステムでは、関数呼び出しのオーバーヘッドを抑えるためにわざと同様の処理を並べて書くことがある 情報処理学会全国大会