コードクローン研究 ふりかえり ~ストロング・スタイルで行こう~

57
コードクローン研究 ふりかえり ~ストロング・スタイルで行こう~ 神谷年洋 [email protected] 島根大学大学院総合理工学研究科 (前世紀からの) 2017.03.08 19回プログラミングおよびプログラミング言語ワークショップ(PPL2017) 山形県笛吹市石和温泉

Upload: kamiya-toshihiro

Post on 12-Apr-2017

211 views

Category:

Software


0 download

TRANSCRIPT

コードクローン研究ふりかえり

~ストロング・スタイルで行こう~

神谷年洋[email protected]

島根大学大学院総合理工学研究科

(前世紀からの)

2017.03.08第19回プログラミングおよびプログラミング言語ワークショップ(PPL2017)

於 山形県笛吹市石和温泉

「ストロング・スタイルで行こう」▶ もしあなたが● 研究時間をたっぷり持っていて● 好きに(な)研究対象(ネタ)を選べて● 研究用ツールを自作できて● 実験する手間が惜しくないなら

▶ 目の前にブルー・オーシャンが広がっています

「ストロング・スタイルで行こう」▶ もしあなたが● 研究時間をたっぷり持っていて● 好きに(な)研究対象(ネタ)を選べて● 研究用ツールを自作できて● 実験する手間が惜しくないなら

▶ 目の前にブルー・オーシャンが広がっています

好きなドメインなら何が問題か知っているはず

自由度アップ!独自の実装/実験実験すればアイデア見つかる

解くべき問題がわかっている+アプローチのためのアイデアがある+自分たちのグループしか実験できない→ ブルー・オーシャン �

職歴神谷年洋(KAMIYA Toshihiro) 2015.10 島根大学大学院総合理工学研究科 教授(松江市) 文部科学大臣表彰 (井上, 楠本, 神谷) ��2010.04 はこだて未来大学 准教授(函館市) マイクロソフトリサーチ日本情報学研究賞 ��2005.04 産総研 研究員(秋葉原)2004.11〜2005.10未踏ソフトウェア開発者 天才プログラマー/スーパークリエータ ��2001.12 科技団さきがけ研究21「機能と構成」研究者(豊中)2001.04 科技団さきがけ研究21「協調と制御」領域 中小路グループメンバ(奈良先)

教授になったのは割と最近

教員

研究員

興味(研究に限らず)● ソフトウェア開発技術

– プログラミング言語– 開発ツール

● ソフトウェア工学– プログラム解析

● 静的解析/動的解析– 可視化– プロダクトメトリクス

どうすればソフトウェア開発という

やっかいな問題に対処できるのか

ソフトウェア(開発)の特殊性● 大規模: 「1ビットから数百メガバイトという9桁もの違いを、1個

の知性で橋渡ししなければならない唯一の専門職」(Edsger Dijkstra 1989)– 抽象化 → 「漏れ」(Joel Spolsky 2005)

● 一点もの: 開発:製造 = 10:0。手作業● デザインが必要:

– ヒトとモノ(コト)の両方を扱う– やっかいな問題(wicked problem): 解決するまで定義できない

● 解決 → 理解 → 効果的な解法(本質的に繰り返しを含む)

つまりソフトウェアとは大規模なのにうまく抽象化しきれない

試行錯誤なしに作れないほど複雑しかも、人が手作業で作る一点もの

����������������

�� � �日々問題が発生 ����

����������������

「ソフトウェア開発は自動化されるのでは?」

● 弱問題)ソフトウェア開発は開発技術の発達で自動化できる– 規則的な部分は徐々に自動化されてきている– 特殊な応用分野(ex. 帳票のような画面遷移)向けの、パラメー

タで簡単に表現できる部分は自動化されてきた– → 開発者の仕事はそれ以外(より不規則・曖昧な問題を解く)に

● 強問題)ソフトウェア開発は人工知能で自動化できる– ソフトウェア開発が広汎に自動化できるのは他の多くの仕事より

も後に– 部分的に実現すれば、人工知能に指示を与える仕事が新たに発生

● 指示を与えるためにより高度な知識・技術が必要に

興味(研究に限らず)(再)● ソフトウェア開発技術

– プログラミング言語– 開発ツール

● ソフトウェア工学– プログラム解析

● 静的解析/動的解析– 可視化– プロダクトメトリクス

開発者はプロダクトをどう理解するのか

どう扱っているのかどうすれば

ソフトウェア開発というやっかいな問題に

対処できるのか

コードクローン● 直感的には、コピー&ペーストで複製された

コードのこと● 「重複したロジックを持つプログラムは修正が困難である」(Kent Beck 1999)

● オリジナルの修正に伴ってコピペコードを修正する(判断を行う)必要– 「バグを修正したはずなのに直っていない」– オリジナルとコピペコード間の明示的に記述

されない関係(結合)● 商用プログラムには半分以上のコードがコピー

(ソースファイルまるごとコピーを含む)のものも

コピペ

コピペ

コードクローン● 直感的には、コピー&ペーストで複製された

コードのこと● 「重複したロジックを持つプログラムは修正が困難である」(Kent Beck 1999)

● オリジナルの修正に伴ってコピペコードを修正する(判断を行う)必要– 「バグを修正したはずなのに直っていない」– オリジナルとコピペコード間の明示的に記述

されない関係(結合)● 商用プログラムには半分以上のコードがコピー

(ソースファイルまるごとコピーを含む)のものも

バグバグ?

バグ??

コードクローン● 直感的には、コピー&ペーストで複製された

コードのこと● 「重複したロジックを持つプログラムは修正が困難である」(Kent Beck 1999)

● オリジナルの修正に伴ってコピペコードを修正する(判断を行う)必要– 「バグを修正したはずなのに直っていない」– オリジナルとコピペコード間の明示的に記述

されない関係(結合)● 商用プログラムには半分以上のコードがコピー

(ソースファイルまるごとコピーを含む)のものも

通常のプログラム解析手法では見えない☹

コードクローン研究/応用の広がり 概念・技術・応用タイプ

I, II, III, IV解析対象

クローンの進化

検出手法・アルゴリズム

視覚化クローン

メトリクス

クローン追跡

クローン管理

プロダクトの品質評価コードの剽窃

検出ライセンス違反検出

コード(バグ)パターン検索

リファクタリング編集のサポート

vs. 開発プロセス

vs. 設計/アーキテクチャ

コードクラス階層

Code decay

バージョン管理システム

トリアージ良いクローン・悪いクローン

vs. バグ

散布図

多言語対応

コードクローン研究/応用の広がり (1999年当時)タイプ

I, II, III, IV解析対象

クローンの進化

検出手法・アルゴリズム

視覚化クローン

メトリクス

クローン追跡

クローン管理

プロダクトの品質評価コードの剽窃

検出ライセンス違反検出

コード(バグ)パターン検索

リファクタリング編集のサポート

vs. 開発プロセス

vs. 設計/アーキテクチャ

コードクラス階層

Code decay

バージョン管理システム

トリアージ良いクローン・悪いクローン

vs. バグ

散布図

多言語対応

コードクローン研究のきっかけ● 当時D。論文の本数も足りて「好きなことやってて」な状況● 研究室が共同研究している某社で長年保守されているソフト

の話を小耳に– 「昔は新機能リクエストしたらすぐに付けてくれたのに、

最近はすごく時間がかかる」と顧客– 数多くの派生バージョンがあるらしい

⇩● そういえばそういう研究あったな→読んでみる→なんか面白そう。自分でも作ってみよう

まずいことになってるのは想像がつく

CCFinder [Kamiya 2002]● コードクローン検出ツールの一実装● 大規模な実験に耐える実装

– 実行時性能– 不正なデータ(ソースコード)への耐性 ⇦

– 複数のプログラミング言語(C/C++, Java, COBOL某方言)に対応 ⇦● 検出精度を上げるための工夫

– 識別子の区別(予約語、名前)– 構文上の正規化ルール({}やインデントの差異などを吸収)⇦ – 正規化ルールに基づく枝刈り ⇦

● 分析手法の確立– コードクローンを用いたプロダクトの解析

「⇦」 ツールを自作することで可能(容易)になった点

クローン検出のステップ(1)ソースコードを入力し、トークンの列にする(2)構文上の正規化ルールによりトークン列を変形する(3)同一の部分トークン列(クローン)を検出する(4)クローンの位置(ファイル、行)を出力する

例)☐ (1)ソースコードを入力し、トークンの列にする☐ (2)構文上の正規化ルールによりトークン列を変形する☐ (3)同一の部分トークン列(クローン)を検出する☐ (4)クローンの位置(ファイル、行)を出力する

AFG::AFG(JaObject* obj) {  objname = “afg";  object = obj;}AFG::~AFG() {  for(unsigned int i = 0; i < children.size(); i++)    if(children[i] != NULL)      delete children[i];  for(unsigned int i = 0; i < nodes.size(); i++)    if(nodes[i] != NULL)      delete nodes[i];}

例)☑ (1)ソースコードを入力し、トークンの列にする☐ (2)構文上の正規化ルールによりトークン列を変形する☐ (3)同一の部分トークン列(クローン)を検出する☐ (4)クローンの位置(ファイル、行)を出力する

AFG :: AFG ( JaObject * obj ) {

objname = "afg" ;

object = obj ;

}

AFG :: AFG (~ ) {

for ( unsigned int i

)

= 0 ; i < children . size ( ) ; i ++ )

if ( children [ i ] != NULL

delete children [ i ] ;

for ( unsigned int i

)

= 0 ; i < node . size ( ) ; i ++ )

if ( node [ i ] != NULL

delete node [ i ] ;

}

例)

:: ( * ) {

= ;

}

:: (~ ) {

for ( unsigned int

)

= ; < . ( ) ; ++ )

if ( [ ] !=

delete [ ] ;

for ( unsigned int

)

= ; < . ( ) ; ++ )

if ( [ ] !=

delete [ ] ;

}

$ $ $ $

$ $

= ;$ $

$ $

$ $ $ $ $ $

$ $ $

$ $

$ $ $ $ $ $

$ $ $

$ $

☑ (1)ソースコードを入力し、トークンの列にする☑ (2)構文上の正規化ルールによりトークン列を変形する☐ (3)同一の部分トークン列(クローン)を検出する☐ (4)クローンの位置(ファイル、行)を出力する

識別子(変数名、関数名)を「$」に

$ :: $ ( $ * $ ) { $ = $ ; $ = $ ; } $ :: ~ $ (

$ ● ● ● ● ● ● ● ● ● ●:: ● ●$ ● ● ● ● ● ● ● ● ● ●( ● ●$ ● ● ● ● ● ● ● ● ● ●* ●$ ● ● ● ● ● ● ● ● ● ●) ●{ ●$ ● ● ● ● ● ● ● ● ● ●= ● ●$ ● ● ● ● ● ● ● ● ● ●; ● ●$ ● ● ● ● ● ● ● ● ● ●= ● ●$ ● ● ● ● ● ● ● ● ● ●; ● ●} ●$ ● ● ● ● ● ● ● ● ● ●:: ● ●~ ●$ ● ● ● ● ● ● ● ● ● ●( ● ●

例)☑ (1)ソースコードを入力し、トークンの列にする☑ (2)構文上の正規化ルールによりトークン列を変形する☐ (3)同一の部分トークン列(クローン)を検出する☐ (4)クローンの位置(ファイル、行)を出力する

例)☑ (1)ソースコードを入力し、トークンの列にする☑ (2)構文上の正規化ルールによりトークン列を変形する☐ (3)同一の部分トークン列(クローン)を検出する☐ (4)クローンの位置(ファイル、行)を出力する

$ :: $ ( $ * $ ) { $ = $ ; $ = $ ; } $ :: ~ $ ( ) { for

( unsigned

int

$ = $ ; $ < $ . $ ( ) ; $ ++

) if ( $ [ $ ] != $ ) delete

$ [ $ ] ; for

( unsigned

int

$ = $ ; $ < $ . $ ( ) ; $ ++

) if ( $ [ $ ] != $ ) delete

$ [ $ ] ; }

$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●:: ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●( ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●* ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●{ ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●= ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●= ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●} ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●:: ● ●~ ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●( ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●{ ● ●for ● ●( ● ● ● ● ● ● ● ●unsigned ● ●int ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●= ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●< ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●. ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●( ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●++ ● ●) ● ● ● ● ● ● ● ●if ● ●( ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●[ ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●] ● ● ● ●!= ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●delete ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●[ ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●] ● ● ● ●; ● ● ● ● ● ● ● ●for ● ●( ● ● ● ● ● ● ● ●unsigned ● ●int ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●= ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●< ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●. ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●( ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●++ ● ●) ● ● ● ● ● ● ● ●if ● ●( ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●[ ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●] ● ● ● ●!= ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●delete ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●[ ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●] ● ● ● ●; ● ● ● ● ● ● ● ●} ● ●

$ :: $ ( $ * $ ) { $ = $ ; $ = $ ; } $ :: ~ $ ( ) { for

( unsign

edint

$ = $ ; $ < $ . $ ( ) ; $ ++

) if ( $ [ $ ] != $ ) delete

$ [ $ ] ; for

( unsign

edint

$ = $ ; $ < $ . $ ( ) ; $ ++

) if ( $ [ $ ] != $ ) delete

$ [ $ ] ; }

$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●:: ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●( ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●* ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●{ ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●= ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●= ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●} ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●:: ● ●~ ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●( ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●{ ● ●for ● ●( ● ● ● ● ● ● ● ●unsigned ● ●int ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●= ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●< ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●. ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●( ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●++ ● ●) ● ● ● ● ● ● ● ●if ● ●( ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●[ ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●] ● ● ● ●!= ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●delete ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●[ ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●] ● ● ● ●; ● ● ● ● ● ● ● ●for ● ●( ● ● ● ● ● ● ● ●unsigned ● ●int ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●= ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●< ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●. ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●( ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●++ ● ●) ● ● ● ● ● ● ● ●if ● ●( ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●[ ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●] ● ● ● ●!= ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●delete ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●[ ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●] ● ● ● ●; ● ● ● ● ● ● ● ●} ● ●

例)☑ (1)ソースコードを入力し、トークンの列にする☑ (2)構文上の正規化ルールによりトークン列を変形する☑ (3)同一の部分トークン列(クローン)を検出する☐ (4)クローンの位置(ファイル、行)を出力する

$ :: $ ( $ * $ ) { $ = $ ; $ = $ ; } $ :: ~ $ ( ) { for

( unsign

edint

$ = $ ; $ < $ . $ ( ) ; $ ++

) if ( $ [ $ ] != $ ) delete

$ [ $ ] ; for

( unsign

edint

$ = $ ; $ < $ . $ ( ) ; $ ++

) if ( $ [ $ ] != $ ) delete

$ [ $ ] ; }

$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●:: ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●( ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●* ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●{ ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●= ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●= ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●} ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●:: ● ●~ ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●( ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●{ ● ●for ● ●( ● ● ● ● ● ● ● ●unsigned ● ●int ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●= ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●< ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●. ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●( ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●++ ● ●) ● ● ● ● ● ● ● ●if ● ●( ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●[ ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●] ● ● ● ●!= ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●delete ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●[ ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●] ● ● ● ●; ● ● ● ● ● ● ● ●for ● ●( ● ● ● ● ● ● ● ●unsigned ● ●int ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●= ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●< ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●. ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●( ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●; ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●++ ● ●) ● ● ● ● ● ● ● ●if ● ●( ● ● ● ● ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●[ ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●] ● ● ● ●!= ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●) ● ● ● ● ● ● ● ●delete ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●[ ● ● ● ●$ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●] ● ● ● ●; ● ● ● ● ● ● ● ●} ● ●

例)☑ (1)ソースコードを入力し、トークンの列にする☑ (2)構文上の正規化ルールによりトークン列を変形する☑ (3)同一の部分トークン列(クローン)を検出する☐ (4)クローンの位置(ファイル、行)を出力する

例)☑ (1)ソースコードを入力し、トークンの列にする☑ (2)構文上の正規化ルールによりトークン列を変形する☑ (3)同一の部分トークン列(クローン)を検出する☑ (4)クローンの位置(ファイル、行)を出力する

AFG::AFG(JaObject* obj) {  objname = “afg";  object = obj;}AFG::~AFG() {  for(unsigned int i = 0; i < children.size(); i++)    if(children[i] != NULL)      delete children[i];  for(unsigned int i = 0; i < nodes.size(); i++)    if(nodes[i] != NULL)      delete nodes[i];}

実装では● 構文上の正規化ルール

– 識別子(変数名、関数名)の$への置き換え– リテラルの並び「int[] a = { 11, 23, 54……. };」を取り除

く– プリフィックスの除去– 文や関数の区切りを認識

● アルゴリズム– 接辞尾木を利用– 枝刈り: 区切りをまたぐコード辺は取り除く

解析対象の知識を利用した発見的手法

適用例) FreeBSD vs Linux vs NetBSD● FreeBSD, Linux, NetBSDの間の

コードクローン– それぞれ100万行以上

● 2つのBSDの間からはコードクローンが多数

● LinuxとBSD(のいずれか)の間にはそれほどコードクローンはない

● それぞれのOS内にはコードクローンがある

適用例) 剽窃検出● 某大学コンパイラ作成演習

– 教科書のサンプルとの一致– 学生のプログラム間の類似

● 訴訟での利用

P1 P2 P3 P4 P5

P1

P2

P3

P4

P5

「grep/diffで簡単にできるでしょ?」

● 検出: (接辞尾木, 接辞尾配列)などにより類似部分を見つけ出すまで– O(m + n)– 出力する処理は別

● 最悪値はO(mn)● 検索: (線形検索) アルゴリズムをその

まま適用すると– O(n) × m = O(mn)

検索 O(n)

n

検出 O(m + n)

n

m

● ただし、最近の全文検索(lucene等)+うまい正規化なら、ひょっとして??

CCFinderX● 対話的環境● コードクローン検出 + 視覚化 + 分析

– 散布図による視覚化(対話的なズーム)– Diff + アラインメント– クローンメトリクス(対話的な絞り込み)

● クローン検出アルゴリズムの強化– 接辞尾木 → 平方分割(的なもの) + 独自アルゴリズム

● 構文の正規化ルールをDSLにより記述– 耐性を保ちつつ、正規化ルールの修正が容易に

CCFinderX● 対話的環境● コードクローン検出 + 視覚化 + 分析

– 散布図による視覚化(対話的なズーム)– Diff + アラインメント– クローンメトリクス(対話的な絞り込み)

● クローン検出アルゴリズムの強化– 接辞尾木 → 平方分割(的なもの) + 独自アルゴリズム

● 構文の正規化ルールをDSLにより記述– 耐性を保ちつつ、正規化ルールの修正が容易に

CCFinderX● 対話的環境● コードクローン検出 + 視覚化 + 分析

– 散布図による視覚化(対話的なズーム)– Diff + アラインメント– クローンメトリクス(対話的な絞り込み)

● クローン検出アルゴリズムの強化– 接辞尾木 → 平方分割(的なもの) + 独自アルゴリズム

● 構文の正規化ルールをDSLにより記述– 耐性を保ちつつ、正規化ルールの修正が容易に

移動やコピーを視覚化

CCFinderX● 対話的環境● コードクローン検出 + 視覚化 + 分析

– 散布図による視覚化(対話的なズーム)– Diff + アラインメント– クローンメトリクス(対話的な絞り込み)

● クローン検出アルゴリズムの強化– 接辞尾木 → 平方分割(的なもの) + 独自アルゴリズム

● 構文の正規化ルールをDSLにより記述– 耐性を保ちつつ、正規化ルールの修正が容易に

ツールの公開● ツール公開/オープンソースのライセンス

– ツールを利用して研究した人が引用してくれた– ベンチマーク(比較対象)として使われるように

なった– 企業でも利用してもらった(もらっている)– 開発者の知らない間にGitHubにプロジェクトがで

きていた

ツールを利用した研究● ソフトウェアの品質分析[Monden2002]● 対話的分析環境 + ギャップトクローンの検出[Ueda2002]● コード検索への応用[Izumida2003]● リファクタリング支援[Higo2004]

– → クラス階層とクローンの関係[Yoshida2005]● バージョン間の変遷の分析(版管理システム)[Kawaguchi2005]

● BSD OSの系統樹の復元 [Yamamoto2005]● 分散処理による検出 D-CCFinder [Livieri2007]

ふりかえり(裏。後悔ともいう)

● CCFinderXの新しい検出アルゴリズムや、DSLについて論文にしていない– 「引用できる文献ないの?」との問い合わせ�

– 車輪の再発明の危機�

● ツールを維持できていない(研究ツールにありがち)– 業務として認められない�

ブルー・オーシャンだった理由● きっかけは「◯ その問題に興味があった」「× 研究分野として確立して

いた/有望だった」● 研究分野として確立する前にスタートした

– 国際会議のセッションにもなれないくらいのコミュニティ– 研究用のツールも未整備

● 指導教授、指導教員からの強力なバックアップ– 「今使ってるのPCではメモリ積めない 」→ 「面白そうやから� 金つ

ぎ込んで。新しいマシン買えばええよ」● ビッグデータ?のはしり(たまたま)

– ドメイン知識+浅い分析+大きなデータ● (今のデータ分析の人からは当たり前かも)

コードクローン研究/応用の広がり (1999年当時) 再掲タイプ

I, II, III, IV解析対象

クローンの進化

検出手法・アルゴリズム

視覚化クローン

メトリクス

クローン追跡

クローン管理

プロダクトの品質評価コードの剽窃

検出ライセンス違反検出

コード(バグ)パターン検索

リファクタリング編集のサポート

vs. 開発プロセス

vs. 設計/アーキテクチャ

コードクラス階層

Code decay

バージョン管理システム

トリアージ良いクローン・悪いクローン

vs. バグ

散布図

多言語対応

このあたりから、現在の研究トピックに

踏み込みます。

話のまとまりが良くないと思いますが

ご容赦ください。

状況の変化● CCFinder(X)は本当に「開発者」向けか?

– クローン率による開発プロセスの品質管理– 「クローン率が高いとコミットさせない」を実現したかったの?�

● コードクローン研究の進歩– 良いクローンvs悪いクローン ��

– クローン検出&除去 → クローン(が入ったままソースコードを)管理● 開発技術の進歩

– 複数言語による開発が当たり前– リファクタリングが行われるように– 関数型プログラミングの普及(MapReduceなども含め)

試行錯誤は続く● 識別子の差異の分析[Kamiya2008]● プロジェクトの設定(configuration)とコードクロー

ンの関係[Kamiya2010]● 様々なクローン検出アルゴリズムを比較してみる● 呼び出し関係でクローンをまとめてみる[Kamiya2012]

– コードの文脈と内容

リファクタリングとは● 「コードの外部的な振る舞いを変えずに、内部構造を改善する」(Fowler 1999)– 実際のコードの修正は様々。デザインパターンを導入するような修正も

● リファクタリングは「動いているコードは触るな」に反する行為– (自動化)テストによって外部的な振る舞いが変更さ

れていないことが確認できることが前提● 修正 → テスト(確認) → 修正 → テスト → …

コードクローンの除去とは● コードクローンの除去はリファクタリングの一種● コードクローンを除去することを目的としたデザイン

パターンも存在する– メソッドやクラスへの引き上げ

新しい方針(2013〜)● リファクタリング耐性

「同じコードを見つける」から→ 「おおよそ同じコードを見つけて、それらの違っている部分を見る」 or→ 「(一方が修正され)違うコードになったが動作は同じものを見つける」

● 関数型プログラミングのコードの特性– 制御構造を自由に作ることができる– 機能がより細かく刻まれる

● 計算資源はもっと使って良い

● 構文上の等価性 → 動作の等価性?

動作の等価性のためのモデル● ソースコードは実行トレースを折りたたんだもの

⇩● アーキテクチャ(設計)の違い → 折りたたみ方の違い● リファクタリング → ある折りたたみ方から別の折りたたみ方への変更

⇩● 外部的に同じ振る舞い = 同じ実行トレース● 〃に相当する異なったコード = 〃の異なった折りたたみ方

ソースコードを実行トレースに展開して解析?

実行トレースを折りたたんでから

解析?

⇩ ⇩

実行トレースのn-gramを生成してクローン検出 [Kamiya2013]● 目的: メソッド呼び出しの階層にまたがるクローンの検出● ソースコード(Java)を解析して可能なメソッド呼び出し系列

のn-gramを生成

c

d

モジュールm ab

e

f

mmd

e

実行トレースのn-gramを生成してクローン検出 [Kamiya2013]● 目的: メソッド呼び出しの階層にまたがるクローンの検出● ソースコード(Java)を解析して可能なメソッド呼び出し系列

のn-gramを生成

c

d

モジュールm ab

e

f

mmd

e

4-gramabde, bdefabmf ⇒ abcd, bcdfamef ⇒ acde, cdef

実行トレースのn-gramを生成してクローン検出 [Kamiya2013]● 目的: メソッド呼び出しの階層にまたがるクローンの検出● ソースコード(Java)を解析して可能なメソッド呼び出し系列

のn-gramを生成

c

d

モジュールm ab

e

f

mmd

e

4-gramabde, bdefabmf ⇒ abcd, bcdfamef ⇒ acde, cdef

メソッドの抽出によって異なったコードになったものもコードクローンとして検出可能

実行トレースからのクローン検出[Kamiya2015][Kamiya2016]● 目的: 型情報が利用できないPLでも、関数型によって切り刻まれたコードか

らでも、クローンを検出● プログラム(Python)の実行トレース→コールツリー→関数間の(呼び出しによる)到達関係+α

…call __main__//<module> runpy//_run_code 69:load_const __main__//<module> 0load_const __main__//<module> 12load_const __main__//<module> 21load_const __main__//<module> 30load_const __main__//<module> 39call __main__//main __main__//<module> 63:call __main__//print_extensions_w_for_stmt __main__//main 24: <list>call posixpath//splitext __main__//print_extensions_w_for_stmt 25: 'about.txt'call genericpath//_splitext posixpath//splitext 18: 'about.txt' '/' None '.'load_const genericpath//_splitext 0return genericpath//_splitext 139: * 'about' '.txt'return posixpath//splitext 21: * 'about' '.txt'call pygoat.hook/Out/write __main__//print_extensions_w_for_stmt 32: '.txt'return pygoat.hook/Out/write 15call pygoat.hook/Out/write __main__//print_extensions_w_for_stmt 33: '\n'return pygoat.hook/Out/write 15call posixpath//splitext __main__//print_extensions_w_for_stmt 25: 'pygoat.data'call genericpath//_splitext posixpath//splitext 18: 'pygoat.data' '/' None '.'load_const genericpath//_splitext 0return genericpath//_splitext 139: * 'pygoat' '.data'return posixpath//splitext 21: * 'pygoat' '.data'call pygoat.hook/Out/write __main__//print_extensions_w_for_stmt 32: '.data'return pygoat.hook/Out/write 15call pygoat.hook/Out/write __main__//print_extensions_w_for_stmt 33: '\n'return pygoat.hook/Out/write 15call posixpath//splitext __main__//print_extensions_w_for_stmt 25: 'greeting.md'call genericpath//_splitext posixpath//splitext 18: 'greeting.md' '/' None '.'load_const genericpath//_splitext 0return genericpath//_splitext 139: * 'greeting' '.md'return posixpath//splitext 21: * 'greeting' '.md'call pygoat.hook/Out/write __main__//print_extensions_w_for_stmt 32: '.md'return pygoat.hook/Out/write 15call pygoat.hook/Out/write __main__//print_extensions_w_for_stmt 33

Program

Execution trace

main()

os.listdir()print_extensions_w_for_stmt()

print_extensions_w_map_func()

os.path.splitext() print str.join()get_extensions() print

map()

lambda() at line 8

os.path.splitext()

Call tree

main()

get_extensions(),map(),lambda() at line 8,os.listdir(),os.path.split(),print,print_extensions_w_for_stmt(),print_extensions_w_map_func(),str.join()

print_extensions_w_map_func()

main()

get_extensions(),map(),lambda() at line 8,os.path.split(),print,str.join()

print_extensions_w_for_stmt()

main()

os.path.split()print

検出例● print_dataとformat_body

– https://github.com/chrislongo/HttpShell– https://pypi.python.org/pypi/httpie

検出例● print_dataとformat_body

– https://github.com/chrislongo/HttpShell– https://pypi.python.org/pypi/httpie

検出例.. .

.

.

2../ColorFormatter/get_lexer

.

.. pygments.util//get_bool_opt

1.pygments.formatters.terminal/TerminalFormatter/__init__ .

.

StringIO/StringIO/writepygments.lexer//streamer

.

.

.

pygments.lexers//_load_lexers

pygments.lexer//__call__

1.pygments.lexers//guess_lexer

.

.

re//_compile

1../AnsiLogger/print_data

pygments//highlight

2../ColorFormatter/format_body

...

...

...

.

.

pygments//format

pygments//lex

現在は大規模なプログラムの実行トレースに対して実験すべく、アルゴリズムと実装を改良中

まとめ「ストロング・スタイルで行こう」▶ もしあなたが● 研究時間をたっぷり持っていて● 好きに(な)研究対象(ネタ)を選べて● 研究用ツールを自作できて● 実験する手間が惜しくないなら

▶ 目の前にブルー・オーシャンが広がっています

好きなドメインなら何が問題か知っているはず

自由度アップ!独自の実装/実験実験すればアイデア見つかる

解くべき問題がわかっている+アプローチのためのアイデアがある+自分たちのグループしか実験できない

➔ ブルー・オーシャン �

コードクローン研究/応用の広がりタイプ

I, II, III, IV解析対象

クローンの進化

検出手法・アルゴリズム

視覚化クローン

メトリクス

クローン追跡

クローン管理

プロダクトの品質評価コードの剽窃

検出ライセンス違反検出

コード(バグ)パターン検索

リファクタリング編集のサポート

vs. 開発プロセス

vs. 設計/アーキテクチャ

コードクラス階層

Code decay

バージョン管理システム

トリアージ良いクローン・悪いクローン

vs. バグ

散布図

多言語対応

適用例) FreeBSD vs Linux vs NetBSD● FreeBSD, Linux, NetBSDの間の

コードクローン– それぞれ100万行以上

● 2つのBSDの間からはコードクローンが多数

● LinuxとBSD(のいずれか)の間にはそれほどコードクローンはない

● それぞれのOS内にはコードクローンがある

実行トレースのn-gramを生成してクローン検出 [Kamiya2013]● ソースコード解釈して可能なメソッド呼び出し系列のn-gram

を生成● メソッド呼び出しの入れ子を考慮する

c

d

モジュールm ab

e

f

mmd

e

4-gramabde, bdefabmf ⇒ abcd, bcdfamef ⇒ acde, cdef

ストロングストロング・・スタイルスタイルで行こうで行こう ((仮仮))

神谷年洋神谷年洋[email protected]@cis.shimane-u.ac.jp

島根大学大学院総合理工学研究科島根大学大学院総合理工学研究科

些細な問題?● 散布図の中でファイルを並べる方法を探す

– ファイルのパス(≒サブシステムごと)– クローン率が高いものから順に並べる– 同じようなインポートを持っているもの

● コールツリー内でのコードクローンの分布を調べる– コードクローンになっているコードがコードクロー

ンになっているコードを呼び出している状況があるか

なぜ開発者でいつづけるのか● 「30年前の知識で開発を語るな」

– 研究遂行においても開発技術の知識は必要● トレンドの変化、言語の加速度的な変化

– 過去の分析が今も通用するか?– 比較的互換性を重視するJavaでさえ ➔

02 04 06 08 10 12 14 16 181.4

5総称型アノテーション

7 コレクション

8ラムダ+型推論Stream

9REPLモジュール