Geminiを用いた効果的なコードクローン分析方法

コードクローンを対象とした
リファクタリングの有効性に関する調査
肥後 芳樹,楠本 真二,井上 克郎
大阪大学 大学院情報科学研究科
{y-higo, kusumoto, inoue}@ist.osaka-u.ac.jp
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
1
コードクローン

コードクローンとは
 ソースコード中に存在する一致または類似したコード片
 コピーアンドペーストなどのさまざまな理由により生成される
コピーアンドペースト
コピーアンド
ペースト

ソフトウェアの保守を困難にする
 あるコード片にバグがあると,そのコードクローン全てについて修
正の検討を行う必要がある
 機能を追加する場合も同様のことがいえる
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
2
リファクタリング
ソフトウェアの外部的な振る舞いを保ったままで,内部構造
を改善していくこと
 リファクタリングを行うことでソフトウェアの保守性が増し,後の
保守作業効率が向上する


これまでに多くのリファクタリングすべきコードのパターン(Bad
Smell)とその対処法(Refactoring Pattern)が提案されて
いる[1][2]
 コードクローンは最も優先してリファクタリングを行うべきものの1
つとされている
しかし,具体的な評価事例はほとんど報告されていない
[1] M. Fowler: Refactoring: Improving the Design of Existing Code, Addison-Wesley, 1999.
[2] Refactoring Home Page: http://www.refactoring.com/
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
3
研究の目的と概要
コードクローンに対するリファクタリングのコストと効果を調査し,
その有効性を評価する
 実験対象は複数バージョンのソースコードが公開されている
オープンソースソフトウェア

 最初のバージョンに対してコードクローン検出
& リファクタリング
 リファクタリングのコストとして以下のものを用いた
ソースコード修正と回帰テストに要した時間
 リファクタリングの効果として以下のものを用いた
CKメトリクス値の変化
総行数の増減
集約箇所の後のバージョンでの修正回数
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
4
CKメトリクス


Chidamber と Kemerer が提案したオブジェクト指向ソフトウェアの複
雑度を測定するメトリクス[3]であり,広く用いられている
各メトリクスは,クラス単位で計測される
 WMC(Weighted Methods per Class): そのクラスに定義されて
いるメソッドに重み付けをして足し合わせた値
 DIT(Depth of Inheritance Tree): クラス階層における継承の深さ
 NOC(Number of Children): サブクラスの数
 CBO(Coupling Between Objects): 関係しているクラスの数
 RFC(Response For a Class): そのクラスのオブジェクトにメッセー
ジが送られた結果,実行されうるすべてのメソッドの数を表す
 LCOM(Lack of Cohesion Of Methods): そのクラスのメソッドが
お互いに関連している程度を表す
[3] Chidamber S. R. and Kemerer C. F.: “A Metrics Suite for Object Oriented Design”, IEEE Transaction
on Software Engineering, Vol. 20, No. 6, pp. 476-493 (1994).
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
5
コードクローンに対するリファクタリング

コードクローンは最も優先してリファクタリングを行うべきコード
(のパターン)の1つとされている

どのようにリファクタリングを行うかは,コードクローン間の関係
によって異なる[1]
 同一クラス内の複数個所が重複している場合
 兄弟クラス間で重複コードが見られる場合
 まったく関係のないクラス間で重複コードが見られる場合
[1] M. Fowler: Refactoring: Improving the Design of Existing Code, Addison-Wesley, 1999.
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
6
コードクローンに対するリファクタリング:
同一クラス内の複数箇所が重複している場合
Extract Method を適用して,各メソッドの内部からコードク
ローンを抽出し,新たなメソッドとして定義する.
 抽出箇所は,そのメソッドの呼び出し文に変更する.

void printTaxi(int amount){
String name = getTaxiName();
System.out.println(“name:” + name);
System.out.println(“amount:” + amount);
}
void printBus(int amount){
String name = getBusName();
System.out.println(“name:” + name);
System.out.println(“amount:” + amount);
}
void printTaxi(int amount){
String name = getTaxiName();
print(name, amount);
}
void printBus(int amount){
String name = getBusName();
print(name, amount);
}
void print(String name, int amount){
System.out.println(“name:” + name);
System.out.println(“amount:” + amount);
}
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
7
コードクローンに対するリファクタリング
兄弟クラス間で重複コードを共有している場合
各クラスに対して Extract Method を行い,次に Pull Up
Field や Pull Up Method を適用すれば解決する
 場合によっては,Form Template Method などを適用する
場合もありうる

Employee
Employee
getName()
Salesman
getName()
Engineer
getName()
Salesman
Engineer
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
8
コードクローンに対するリファクタリング
まったく関係のないクラス間で重複コードが見られる場合

Extract Class を適用し,古いクラスから新しいクラスへと処
理を委譲するように変更を行う
Person
name
officeAreaCode
officeNumber
name
getTelephoneNumber()
getTelephoneNumber()
Company
address
officeAreaCode
officeNumber
Person
1
Company
1
Telephon Number
areaCode
number
1
1
getTelephoneNumber()
address
getTelephoneNumber()
getTelephoneNumber()
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
9
本研究で扱うコードクローン

コードクローンの一般的な定義はない
 これまでにいくつかのコードクローン検出手法が提案されている
が,それらはどれも異なった定義を持つ

リファクタリング可能なコードクローンを検出したい
 コードクローン検出に
CCFinder[3] と CCShaper[4] を用いる
[3] T. Kamiya, S. Kusumoto, and K. Inoue, CCFinder: A multi-linguistic token-based code clone
detection system for large scale source code, IEEE Transactions on Software Engineering, vol.
28, no. 7, pp. 654-670, Jul. 2002.
[4] 肥後 芳樹,植田 泰士,神谷 年洋,楠本 真二,井上 克郎:コードクローン解析に基づくリファクタリングの試み,
情報処理学会論文誌, Vol.45, No.5, pp1357-1366, 2004-5
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
10
クローンペアとクローンセット

クローンペア
 互いに一致または類似しているコード片の対(ペア)

クローンセット
 互いに一致または類似しているコード片の集合(セット)
C1
C2
C3
C4
C5
クローンペア
(C1, C2)
クローンセット
{C1, C2, C4}
(C1, C4)
{C3, C5}
(C2, C4)
(C3, C5)
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
11
コードクローン検出ツール:CCFinder
概要

ソースコードをトークン単位で直接比較することにより,コード
クローンを検出する

より実用的なコードクローンを見つけることができるように設計
されている
 ユーザ定義名の置き換え
 テーブル初期化部分の取り除き
 モジュールの区切りの認識

検出結果はテキスト形式で出力

数百万行単位のソフトウェアからでも数十分で検出可能
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
12
コードクローン抽出ツール:CCShaper
概要

CCFinderが検出したコードクローンに含まれるプログラミング
言語の構造的なまとまりの部分を抽出
 コードクローン情報をリファクタリングに用いる場合に便利
 CCFinderが検出するコードクローンはトークンの並びであり,必
ずしもリファクタリングの適用が容易なまとまりにはなっていない

現在はJava言語のみに対応
 抽出するコードクローンの単位は以下の12個
宣言:クラス,インターフェース
関数:メソッド,コンストラクタ,スタティックイニシャライザ
文:do, for, if, switch, synchronized, try, while,
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
13
コード片1
609:
610:
611:
612:
613:
614:
615:
616:
617:
618:
619:
620:
621:
622:
623:
624:
625:
626:
627:
628:
reset();
grammar = g;
// Lookup make-switch threshold in the grammar generic options
if (grammar.hasOption("codeGenMakeSwitchThreshold")) {
try {
makeSwitchThreshold = grammar.getIntegerOption("codeGenMakeSwitchThreshold");
//System.out.println("setting codeGenMakeSwitchThreshold to " + makeSwitchThreshold);
} catch (NumberFormatException e) {
tool.error(
"option 'codeGenMakeSwitchThreshold' must be an integer",
grammar.getClassName(),
grammar.getOption("codeGenMakeSwitchThreshold").getLine()
);
}
}
CCFinderが検出する
クローン
// Lookup bitset-test threshold in the grammar generic options
if (grammar.hasOption("codeGenBitsetTestThreshold")) {
try {
bitsetTestThreshold = grammar.getIntegerOption("codeGenBitsetTestThreshold");
コード片2
623:
624:
625:
626:
627:
628:
629:
630:
631:
632:
633:
634:
635:
636:
637:
638:
639:
640:
641:
642:
}
// Lookup bitset-test threshold in the grammar generic options
if (grammar.hasOption("codeGenBitsetTestThreshold")) {
try {
bitsetTestThreshold = grammar.getIntegerOption("codeGenBitsetTestThreshold");
//System.out.println("setting codeGenBitsetTestThreshold to " + bitsetTestThreshold);
} catch (NumberFormatException e) {
tool.error(
"option 'codeGenBitsetTestThreshold' must be an integer",
grammar.getClassName(),
grammar.getOption("codeGenBitsetTestThreshold").getLine()
);
}
}
CCShaperが抽出す
るクローン
// Lookup debug code-gen in the grammar generic options
if (grammar.hasOption("codeGenDebug")) {
Token t = grammar.getOption("codeGenDebug");
if (t.getText().equals("true")) {
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
14
コード片3
1007:
1008:
1009:
1010:
1011:
1012:
1013:
1014:
1015:
1016:
1017:
1018:
1019:
コード片4
if ( inputState.guessing==0 ) {
buf.append(a.getText());
}
{
_loop144:
do {
if ((LA(1)==WILDCARD)) {
match(WILDCARD);
a=id();
if ( inputState.guessing==0 ) {
buf.append('.'); buf.append(a.getText());
}
}
1527:
1528:
1529:
1530:
1531:
1532:
1533:
1534:
1535:
1536:
1537:
1538:
1539:
if ( inputState.guessing==0 ) {
t=a.getText();
}
{
_loop84:
do {
if ((LA(1)==COMMA)) {
match(COMMA);
id();
if ( inputState.guessing==0 ) {
t+=","+b.getText();
}
}
CCFinderが検出する
クローンペア
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
15
実験:
概要

実験対象はオープンソースソフトウェア Ant
 記述言語:
Java
 15バージョンのソースコードを用いた
 バージョン番号:1.1, 1.2, 1.3, 1.4, 1.5, 1.5.1, 1.5.2, 1.5.3, 1.5.4, 1.6.0,
1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.6.5


最も古いバージョン(1.1)からコードクローン検出を行い,検出された全
てのコードクローンに対してリファクタリングを試みた
リファクタリングのコストとして以下のものを用いた
 ソースコード修正と回帰テストに要した時間

リファクタリングの効果として以下のものを用いた
 CKメトリクス値の変化
 総行数の増減
 集約箇所の後のバージョンでの修正回数
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
16
実験:
バージョン1.1に対するリファクタリング

コードクローンのリファクタリングを行うために
 CCFinderとCCShaperを用いて50トークン以上のコードクローンを検出
 バージョン1.1の規模
 ソースファイル数:83
 総行数:19,986
 検出時間は約1分
 7個のクローンセットを検出
 そのうちの6つが実際にリファクタリングすることができた
 ソースコード修正後,付属のテストケースを用いて回帰テストを行った

その後の修正回数を調査するために
 バージョン1.2~1.6.5の該当箇所を調査
 前のバージョンから修正を加わっているかどうかを diff で調査
 クローンセットになっているかを CCFinder と CCShaper を用いて調査
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
17
実験:
検出されたコードクローン


以下は検出されたコードクローンの概要である
ID
S0
コード片数
2
単位
メソッド
分類
単一クラス内
時間
7分
S1
S2
S3
6
2
2
メソッド
メソッド
メソッド
単一クラス内
単一クラス内
単一クラス内
19分
-
S4
S5
S6
2
2
2
If文
メソッド
メソッド
兄弟クラス間
兄弟クラス間
関係のないクラス間
14分
5分
17分
15分
実際はもっと回帰テストに時間がかかる
 付属のユニットテストしか行っていない,結合テストなども行うべき
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
18
実験:
CKメトリクス値の変化(1/3)

S0のCKメトリクス値の変化
クラス名
DirectoryScanner

DIT
NOC
CBO
21(+1)
1
0
0
WMC
DIT
NOC
CBO
21(+1)
1
0
0
RFC
LCOM
47(+1) 158(+20)
S1のCKメトリクス値の変化
クラス名
DirectoryScanner

WMC
RFC
LCOM
47(+1) 158(+20)
S3のCKメトリクス値の変化 リファクタリング前に比べてメトリクス値が悪化
リファクタリング前に比べてメトリクス値が改善
クラス名
WMC
DIT
NOC
CBO
RFC
LCOM
17(+1)
1
23
4
24(+6)
98(+16)
$NestedElementHandler
4
2
0
4
14(-3)
0
$TaskHandler
4
2
0
7(-2)
21(-7)
0
Task
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
19
実験:
CKメトリクス値の変化(2/3)

S4のCKメトリクス値の変化
クラス名
WMC
DIT
NOC
CBO
RFC
LCOM
15(+2)
1
0
7(+1)
66(+7)
79(+27)
Expand
4
2
0
5
35(-3)
2
Untar
4
2
0
8
36(-3)
2
WMC
DIT
NOC
CBO
RFC
LCOM
Javac
23(-1)
3
1
11
93
128(-105)
MatchingTask
16(+1)
2
11
5(+1)
56(+4)
94(+79)
Rmic
17(-1)
3
0
8
66(-2)
98(-17)
WMC
DIT
NOC
CBO
RFC
LCOM
NewClass
2
1
0
2
7
1
JavacOutputStream
4
1
0
2(+1)
10(-1)
0
ProjectHelper

S5のCKメトリクス値の変化
クラス名

S6のCKメトリクス値の変化
クラス名
TaskOutputStream
3
1
0
2(+1)
8(-1)
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
0
20
実験:
CKメトリクス値の変化(3/3)

コードクローンのリファクタリングは,必ずしもCKメトリクス値を改善すると
は限らない
 中には,クローンセット
S0 や S1 のようにメトリクス値を悪化させているだけ
のリファクタリングも存在した

CKメトリクスを測定するために ckjm を用いた
 このツールはメトリクス
WMC として,単純にそのクラスで定義されたメソッ
ドの数を用いている
 WMCは Weigthed Method per Class の略
 本来は,各メソッドに対して重み付けを行った後,値を足し合わせる
Method のようにメソッド数が増えるリファクタリングの場合は,必
ず値が悪化してしまう
 サイクロマチック数などを用いて適切に重み付けをすれば,メソッド数を増
やすリファクタリングであっても WMC の改善があるかもしれない
 Extract
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
21
実験:
総行数の変化


下図は各クローンセットのリファクタリング後の総行数の変化を表す
リファクタリング
S0後
S1後
S3後
S4後
S5後
S6後
行数
19,982
(-4)
19,964
(-22)
19,981
(-5)
19981
(-5)
19,962
(-24)
19,990
(+4)
5つのリファクタリングで総行数が減っている
 多くても20行程度しか減っておらず,サイズ面で効果があるとはいい難い
Class”パターンを適用したリファクタリングは,新しいクラスを作
成したために,リファクタリング前に比べて行数が増えてしまっている
 “Extract
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
22
実験:
修正の流れ(1/5)(クローンセット S0,S2)

クローンセット S0
1.1
1.2
1.3
1.4
1.5
1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0
C0’
C0’’
C1
C1’
C1’’
コード片は
Cn で表され,修正が加わるたびに Cn’, Cn’’ と変化していく
同一クローンセットに含まれるコード片は長方形で囲まれる

1.1
C0
クローンセット S2
1.2
1.3
1.4
1.5
1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0’
C1
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
23
実験:
修正の流れ(2/5)(クローンセット S1)
1.1
1.2
1.3
1.4
1.5
1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0
C0’
C0’’
C0’’’
C1
C1’
C1’’
C1’’’
C6
C7’
C7
C2
C2’
C2’’
C2’’’
C3
C3’
C3’’
C3’’’
C4
C4’
C4’’
C4’’’
C5
C5’
C5’’
C5’’’
C8
C8’
C8’’
C9
C9’
C9’’
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
24
実験:
修正の流れ(3/5)(クローンセット S3,S4)

1.1
クローンセット S3
1.2
1.3
1.4
1.5
1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0
C0’
C0’’
C0’’’
C0’’’’
C1
C1’
C1’’
C1’’’
C1’’’’

1.1
C0
クローンセット S4
1.2
1.3
C0’
1.4
1.5
1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0’’
C1
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
25
実験:
修正の流れ(4/5)(クローンセット S5,S6)

1.1
C0
クローンセット S5
1.2
1.3
1.4
1.5
1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0’
C1

1.1
C0
クローンセット S6
1.2
1.3
1.4
1.5
1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5
C0’
C1
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
26
実験:
修正の流れ(5/5)

リファクタリング箇所の後のバージョンでの修正回数はクローンセットに
よってさまざまであった
 全てのクローンセットがバージョンをまたいで存在しているわけではなく,各
コード片に対して異なる修正が加わった結果,コードクローンでなくなる場
合もあった.
 本実験では7つクローンセットのうちの4つ
 これらのクローンセットには一度も共通の修正がなかった
 一度でも共通の修正が加わった場合は,その後も修正される傾向がある
 実際に全てのコード片に同様の修正が加わった場合にリファクタリングを行う
ことで,その後の修正回数を減らすことができるのでは?
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
27
考察

リファクタリングが有効であるかどうかは,その効果がコストを上回ってい
るかどうかで決まる
 例:クローンセット
S0
 コスト:ソースコード修正と回帰テストに7分を要した
 効果(CKメトリクス):WMC,RFC,LCOM が悪化
 効果(修正回数):バージョン 1.5 と 1.6.3 での修正箇所が2つから1つに
減った
 効果とコストの大小関係は一意に決めることができない


本実験で行ったリファクタリングは,基本的かつ汎用的であり,ソース
コード修正を行う者のスキルや対象ソフトウェアのドメインを限定するも
のではない
リミテーション
 リファクタリングの規模が小さい
 メトリクス値で調査したのは複雑度の変化のみ
 他の面からの評価も必要である
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
28
まとめ


コードクローンに対するリファクタリングのコストと効果を調査した
実験対象は15バージョンのソースコードが公開されているオープンソー
スソフトウェア
 その最初のバージョンに対してリファクタリングを行った

コストの尺度
 ソースコード修正と回帰テストに要した時間

効果の尺度
 CKメトリクス値の変化
 総行数の増減
 集約箇所の後のバージョンでの修正回数

こらからの予定
 コスト・効果項目を増やす
 企業ソフトウェアでも実験を行う(+
開発者へのインタビュー)
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
29
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
30
コードクローン検出ツール: CCFinder
検出プロセス
Source files
static
throws
{{{ String
1. static
static
foo()
throws
RESyntaxException
{
{{ $$ $$
(( (( )) ))throws
$void
void
foofoo()
throws$$RESyntaxException
RESyntaxException
String aaa {
static
RESyntaxException
String
1.
void
throws
RESyntaxException
static void
$ $$foo
throws
]{{] {${$ "123,400"
,
[[ [][] String
$String
$$ =
new
$[] {
]]] === a[]
new
$[]
2. [[String
a[]
=
new
String
{ "123,400",
"123,400",
"abc", "orange
"orange 100"
100" };
};
2.
new
"abc",
[String
$String
"abc"
,
"orange
100"
}
;
org
.
apache
.
regexp
;
}
3. org.apache.regexp.RE
org.apache.regexp.RE
pat == new
new org.apache.regexp.RE("[0-9,]+");
org.apache.regexp.RE("[0-9,]+");
} ;
3.
pat
$$ === new
$$ pat
RE
pat
RE
new
4. .int
int
sum
0; org . apache . regexp
4.
sum
==new
0;
. RE
)) ;;; int
$$ ==== $0$00
$$ sum
$$
$$ ((( "[0-9,]+"
RE
int
sum
sum
5. for
for
(int"[0-9,]+"
i == 0;
0; ii) << a.length;
a.length;
++i)
5.
(int
i
++i)
;; for
$$ i$$i === 0$0$ ;;; i$$i <<<<
int
for (( int
6. a$ ifif. (pat.match(a[i]))
(pat.match(a[i]))
6.
;++
$$ ii)) ))if
$$ ;; ++
length
; ++
++
pat
pat
$ . length
if ifif(( ((($$ pat
7. .. match
sum
+=
Sample.parseNumber(pat.getParen(0));
7.
sum
+=
Sample.parseNumber(pat.getParen(0));
$$ (( (( $$ aa [[ [[ $$ ii ]] ]] )) )) )) ))) $$sum
sum
sum
. match
8.
System.out.println("sum
" ++ sum);
sum);
8. +=
System.out.println("sum
"getParen
+=
Sample
((( 000
(( $$ .. $$ (( ((pat
$$ .. $.$. parseNumber
parseNumber
pat$$ .=
. getParen
pat
.=
getParen
+=
9. }} )) )) ;; System
(( $$ ((( "sum
.. .$$. println
$$ .. .$$. out
System
out
println
"sum==="""
9.
println
"sum
static
String
$$ $$goo
}}} static
))) ;;; goo(String
$$ void
sum
static void
void
goo
String
10. static
static
void
goo(String
[]((a)
a)((( $$throws
throws
RESyntaxException {{
+++ sum
goo
String
10.
[]
RESyntaxException
static
{{ $$ $$ =
$$RE("[0-9,]+");
throws
RESyntaxException
RE exp
exp ===
[[[ exp
]]] )))=
RESyntaxException
RE
exp
11. a$a$RE
RE
exp
=throws
newRESyntaxException
throws
= {{{ RE
11.
new
RE("[0-9,]+");
new
RE
=
$$ )) ;;)) $$;; $$int
$$ (( "[0-9,]+"
int sum
sum
new
=sum$$=== 000
12. new
int
sum"[0-9,]+"
0;
12.
int
sum
== 0;
$$ i$$i === 0$0$ ;;; i$$i <<<<
for
int
for
((( int
for (int
13. ;;;for
for
0; ii << a.length;
a.length; ++i)
++i)
13.
(int
ii == 0;
$
(
$$ ii)) ))if
$$ ;; ++
if
(
exp
length
; ++
++
if
(
exp
a$a$ ... length
;++
(
exp
if ( $
14. . match
(exp.match(a[i]))
14.
ifif (exp.match(a[i]))
]
$
[
$
(
$
(
a
[
i
]
(
a
[
i
]
sum
sum
. $ ( $ [ $ ] )) )) )) ))) $$sum
15. +=
sum
+=
parseNumber(exp.getParen(0));
15.
sum
+=
parseNumber(exp.getParen(0));
(( .. $$ getParen
$$ (( ( $$exp.. ((. $$exp
+=
getParen
()) 0)) )(( )00 )) ))
parseNumber
exp
getParen
$$$ ... parseNumber
+= parseNumber
16. ;;;System.out.println("sum
System.out.println("sum
==="""""+++++sum
sum);
16.
sum);
$$ =
(( $$ ((++ "sum
.. .$$. println
$$ .. .$$. out
=
System
out
println
"sum
sum
System
"sum
sum
17. }}))) ;;; }}}
17.
字句解析
字句解析
トークン列
トークン列
変換処理
変換処理
変換後トークン列
変換後トークン列
検出処理
検出処理
クローン情報
クローン情報
出力整形処理
出力整形処理
クローンペア位置情報
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
31
リファクタリングできなかったクローンセット S2

コード片 C0
protected void fireTargetStarted(Target target) {
BuildEvent event = new BuildEvent(target);
for (int i = 0; i < listeners.size(); i++) {
BuildListener listener = (BuildListener) listeners.elementAt(i);
listener.targetStarted(event);
}
}

コード片 C1
protected void fireTaskStarted(Task task) {
BuildEvent event = new BuildEvent(task);
for (int i = 0; i < listeners.size(); i++) {
BuildListener listener = (BuildListener) listeners.elementAt(i);
listener.taskStarted(event);
}
}
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
32
Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
33