• 検索結果がありません。

提案するクローン検出手法

6. オブジェクト指向プログラミング言語向けのコードクローン検出手法

6.4. 提案するクローン検出手法

本研究においては,名前の変形や構造の識別を可能にするために,ソースファイルをトー 字句解析

変形

検出

変形されたトークン列上での クローン

整形

変形されたトークン列から 変形前のトークン列への

マッピング 変形された

トークン列 ソースファイル

クローン トークン列

クローン検出

図 6.1 提 案するコードクローン検 出 手法 の概 要

クン列として表現することとした.従って,ソースファイル中の構造(文や関数の定義)はトーク ン列 の部 分 列 として表 現 される.名 前 の変 形 や構 造 の識 別 は,トークン列 の変 形 ルールに よって実 現 することとした.提 案 するトークン単 位 の比 較 によるのクローン検 出 プロセスの全 体を図 6.1に示す.プロセスは以下の4つのステップから構成される.

(1) 字句解析

ソースファイルの各 行 がプログラミング言 語 の字 句 ルールに従 ってトークンに切 り分 けら れる.すべてのソースファイルのトークンを連結してひとつのトークン列にするので,単一 のソースファイルからクローンを検出 するのとまったく同じ方 法 で,複数 のソースファイル からクローンを検出することができる.

(2) 変形

トークン列 は以 下 の(2-1),(2-2)を経 て変 形 される.同 時 に,変 形 されたトークン列 か ら変形前のトークン列へのマッピングが保存され,後の整形ステップで用いられる.

(2-1) 変形ルールによる変形

変 形 ルールによって,トークン列 が変 形 され,トークンが付 け加 えられたり,削 除 さ れたり,変更されたりする.表 6.1 と表 6.2 に示す変形ルールは,識別子の正 規 化(RC1, RC2, RJ1, RJ2)および構造の識別RC3, RC4, RJ3, and RJ4)を行う.

表 6.1 C++向 けの変 形ルール

# ルール

RC1 (Name '::')+ Name2 Æ Name2

ここで,+演 算 子 は正 規 表 現 の後 置 演 算 子 であり,1回 以 上 の繰 り返 しを意 味 する.

RC2 Name '<' ParameterList '>' Æ Name

ここで,ParameterList は名 前 ,数 値 ,文 字 列 ,演 算 子 ,’,’,および式 の並 び.

式 はトークンの並 びであり,’(‘で始 まって,対 応 する’)’で終 了 し,’;’を含 まない.

RC3 '=' '{' InitalizationList, '}' Æ '=' '{' UniqueIdentifier '}'

ここで,InitalizationList は名 前 ,数 値 ,文 字 列 ,演 算 子 ,’,’, ‘(‘, ‘)’, ‘{‘, および’}’の並 び.

UniqueIdentifier はユニークなトークンであり,ほかの場 所 には出 現 しない.

RC4 トップレベルの定 義 や宣 言 の終 わりにUniqueIdentifier を挿 入 する.

(2-2)パラメータ置換

次 に,型 ,変 数 ,定 数 に関 係 するすべての識 別 子 が,単 一 の特 殊 なトークンに置 き換 えられる(この置 換 は「parameterized match」[3]の前 処 理 である).この置 換により,変数名が付け替えられたコード断片を等価とみなすことができる.

(3) 検出

変形されたトークン列のすべての部分列のうち,等価なペアがクローンとして検出される.

各クローンは,4つ組 (cp, cl, op, ol)として表現される.ここで,cpと opは それぞれ 最初のコード断片ともうひとつのコード断片の位置であり,cl と ol はそれらの長さであ る.

(4) 整形

クローンの位 置 が入 力 ソースファイル上 での行 番 号 に変 換 され,整 形 されて出 力 され る.

表 6.2 Java向けの変形 ルール

# Rule

RJ1 ( PackageName ‘.’ )+ ClassName Æ ClassName

ここで,PackageNameは小 文 字 で始 まる語 .ClassNameは大 文 字 で始 まる語 . RJ2 NDotOrNew NClassName ‘(‘Æ NDotOrNew CalleeIdentifier ‘.’ NClassName ‘(‘

ここで,NDotOrNew は’.’や’new’以 外 で始 まるトークン.NClassName は小 文 字 で始 まる . CalleeIdentifier は省 略 されているcalleeをあらわす語.

RJ3 '=' '{' InitalizationList, '}' Æ '=' '{' UniqueIdentifier '}' ']' '{' InitalizationList, '}'

Æ ']' '{' UniqueIdentifier '}'

ここで,InitalizationList は名 前 ,数 値 ,文 字 列 ,演 算 子 ,',', '(', ')', '{',および'}'の並 .UniqueIdentifierはユニークなトークンであり,他 の場 所 には出 現 しない.

RJ4 トップレベルの定 義 や宣 言 の後 にUniqueIdentifierを挿 入 する.

図 6.2に,コードクローン検出プロセスを説明するための例となるC++コードを示す.左側の 数 字 は行 番 号 である.この入 力 はトークンに切 り分 けられる.切 り分 けられ,変 形 ルールによ って変形されたトークン列を図 6.3に示す.行 1, 3, 11, および 13 は短くなっている.次 にパラメータ置換 によって再 び変 形 される.パラメータ置 換を受けた後 のトークン列を図 6.4 に示す.この例では,識別子が単一のトークン $pに置き換えられている.

1 void print_lines(const set<string>& s) { 2 int c = 0;

3 set<string>::const_iterator i 4 = s.begin();

5 for (; i != s.end(); ++i) { 6 cout << c << ", "

7 << *i << endl;

8 ++c;

9 } 10 }

11 void print_table(const map<string, string>& m) { 12 int c = 0;

13 map<string, string>::const_iterator i 14 = m.begin();

15 for (; i != m.end(); ++i) { 16 cout << c << ", "

17 << i->first << " "

18 << i->second << endl;

19 ++c;

20 } 21 }

図 6.2 コードクローン検出 プロセスを説 明 するための例 題 コード

1 void print_lines ( const set & s ) { 2 int c = 0 ;

3 const_iterator I 4 = s . begin ( ) ;

5 for ( ; i != s . end ( ) ; ++ i ) { 6 cout << c << ", "

7 << * i << endl ; 8 ++ c ;

9 } 10 }

11 void print_table ( const map & m ) { 12 int c = 0 ;

13 const_iterator I 14 = m . begin ( ) ;

15 for ( ; i != m . end ( ) ; ++ i ) { 16 cout << c << ", "

17 << i -> first << " "

18 << i -> second << endl ; 19 ++ c ;

20 } 21 }

図 6.3 変形ルールによって変形されたトークン列

最終的に,クローン,すなわち,トークン列内の等価な部分列が検出される.ここで ti をi 番目のトークン (1 <= i <= 114)とする.さらに,行列{ dxy }を,dxy = 1 if tx is equal to ty, 0 otherwise,と定義する.行列の一部を図 6.5に示す.図で,dxy = 1かつx > yの部分 は’*’で示した.対称性より,dxy = dyx であり,また,明らかにdxx = 1であるので,x <= y の 部 分 には何 も置 かない.クローンは,行 列 の主 対 角 線 に平 行 な(右 下 がりの)‘*’の線 分 とし て検出される.行 1から7のコード断片と,行 11 から17のコード断片2 がクローンとして検 出される.行8から10までのコード断片と,行 19から21までのコード断片がもうひとつのク ローンとなる.行9,10,20,21は互いにクローンとなるが,非常に短くて自明なクローンであ り,クローン検出時に検 出するクローンの最小行 数でフィルタリングすることにより取り除くこと ができる.

2 より厳 密 には,「行11から始 まって行17の最 初 のトークンまでのコード断 片 と,行1から始 まって行7の最 初 のトー クンまでのコード断 片 ・・・」である.ツールの出 力 の中 では,クローンの位 置 は行 番 号 で示 される.

1 $p $p ( $p $p & $p ) { 2 $p $p = $p ;

3 $p $p

4 = $p . $p ( ) ;

5 for ( ; $p != $p . $p ( ) ; ++ $p ) { 6 $p << $p << $p

7 << * $p << $p ; 8 ++ $p ;

9 } 10 }

11 $p $p ($p $p & $p ) { 12 $p $p = $p ;

13 $p $p

14 = $p . $p ( ) ;

15 for ( ; $p != $p . $p ( ) ; ++ $p ) { 16 $p << $p << $p

17 << $p -> $p << $p 18 << $p -> $p << $p ; 19 ++ $p ;

20 } 21 }

図 6.4 パラメータ置 換を行 った後のトークン列

関連したドキュメント