既存ソフトウェア中の頻出コード片を用いたコード補完手法の提案

Download Report

Transcript 既存ソフトウェア中の頻出コード片を用いたコード補完手法の提案

コーディングパターンと
キーワードを用いて生成した
コードスニペットの推薦
大阪大学
○関山 太朗,伊達 浩典,石尾 隆,井上 克郎
1
プログラム上のパターン

何度も書かかれた類似したソースコードの断片
 ソースコードの断片:コード片,コードスニペット
...for (String s : strs) {
...
}...
...for (Object o : collection) {
...
}...
for ([iterable type]
[iterable element] : [iterable]) {
}
2
開発環境におけるコード補完

キーワードからよく使うコード片を生成
 よく使うコード片を素早く利用できる
 知らない機能を発見することがある

例: Eclipseのコード補完
 “foreach”
キーワードからコレクションの各要素を順に処理
するコード片を生成
foreach
for ([iterable type]
[iterable element] : [iterable]) {
}
Eclipseコード補完の例
3
既存のコード補完の問題

使用できるパターンが限定されている
 コード補完の実装であらかじめ用意されている
 対象のプログラミング言語でよく使用される

ソフトウェア固有のパターンを用いたコード片の生成を
行うことができない

既存のパターンと類似した処理を再度記述することに
 欠陥の混入と開発コストの増大につながる
4
ソフトウェア固有のパターン(1/2)

ソフトウェア固有の機能が含まれているパターン
jEditに頻出するコード片
if (!buffer.isEditable()) {
getToolkit().beep();
return ;
} ...
テキストが編集できなければ
音を鳴らして終了する処理
jEditの機能である編集の可否をチェックする
メソッド isEditable が含まれている
5
ソフトウェア固有のパターン(2/2)

再利用可能だが1つにまとめられないパターンが存在
関数
jEditに頻出するコード片
if (!buffer.isEditable()) {
getToolkit().beep();
return ;
} ...
関数化
void exitUnlessEditable() {
if (!buffer.isEditable()) {
getToolkit().beep();
return ;
}}
関数の適用
exitUnlessEditableメソッドの呼び出し後に
inputCharメソッドの実行を終了できない
void inputChar(char c) {
exitUnlessEditable();
... }
関数適用時のコード片
6
コーディングパターン
我々の研究グループではソフトウェア固有のパターン
を得るための手法を提案してきた[Ishio, 2008]
 コーディングパターンとは

 ソフトウェアに頻出するコード片
 メソッド呼び出しと制御文の開始と終了の列
コーディングパターン
jEditに頻出するコード片
if (!buffer.isEditable()) {
getToolkit().beep();
return ;
} ...
コーディング
パターンの抽出
JEditBuffer.isEditable()
IF
JComponent.getToolkit()
Toolkit.beep()
END-IF
[Ishio, 2008] Ishio, T., Date, H., Miyake, T. and Inoue, K.:Mining Coding Patterns to Detect Crosscutting Concerns
in Java Programs. Inproceedings of 15th Working Conference on Reverse Engineering, pp.123-132 (2008).
7
提案手法

既存のコード補完の問題点を解決
 ソフトウェア固有のパターンと類似した処理を再度記述する
ことを防ぐ

コーディングパターンに基づくコード補完手法の提案
 ソフトウェア固有のパターンはコーディングパターンとして得
られる
8
提案手法:
コーディングパターンに基づくコード補完手法
開発者が入力
した単語(キーワード)
1.パターンの検索
パターン
データベース
開発者が編集して
いるソースコード
2.コード片の生成
キーワードに
関連したパターン
3.ソースコード
へ挿入
パターンから
生成したコード片
9
パターンデータベースの構築
コーディングパターンの取得には既存手法を使用
 コーディングパターンを保存したデータベースをパター
ン検索の前に構築

コーディングパターン
jEditに頻出するコード片
if (!buffer.isEditable()) {
getToolkit().beep();
return ;
} ...
コーディング
パターンの抽出
JEditBuffer.isEditable()
IF
JComponent.getToolkit()
Toolkit.beep()
END-IF
10
パターンの検索

入力キーワードに関連したパターン
 パターンに入力キーワードと一致する単語が多く出現
 一致する単語のうち,重みの大きい単語が多い


単語の重みは自然言語検索で利用されているTF-IDF[Salton,1987]
で決定
検索結果:
入力キーワードに最も関連している k 個のパターン
 実装したツールでは
k=3
[Salton,1987] Term Frequency – Inverse Document Frequency,
Salton G. and Buckley, C. 1987 Term Weighting Approaches in Automatic Text Retrieval. Technical Report.
UMI Order Number: TR87-881., Cornell University.
11
コード片の生成: パターン要素の変換
パターンの各要素をコード片へ変換
 このステップでは参照する変数は未定とする

コード片
パターン
JEditBuffer.isEditable()
???.isEditable();
IF
if (???) {
JComponent.getToolkit()
???.getToolkit();
Toolkit.beep()
???.beep();
END-IF
}
12
コード片の生成: 参照変数の決定
挿入箇所の直前で宣言した変数を使用
 メソッド呼び出しの戻り値は新しく宣言した変数へ代入

編集中のソースコード
JEditBuffer buf = ...;
コード片
???.isEditable();
if (???) {
???.getToolkit();
???.beep();
}
ソースコードへ挿入
するコード片
boolean var0 = buf.isEditable();
if (var0) {
JComponent var1;
Toolkit var2 = var1.getToolkit();
var2.beep();
}
13
ソースコードへの挿入
生成したコード片を開発者が編集しているソースコー
ドへ挿入
 挿入後のソースコードを開発者へ提示


開発者は必要に応じて提示されたソースコードを編集
14
実装: Eclipseプラグイン
コード片
入力キーワード
15
実験: 妥当性の検証
パターンの検索
2. コード片の生成
1.
開発者が入力
した単語(キーワード)
1.パターンの検索
パターン
データベース
開発者が編集して
いるソースコード
2.コード片の生成
キーワードに
関連したパターン
3.ソースコード
へ挿入
パターンから
生成したコード片
16
妥当性の検証: パターンの検索

対象



方法


Pa: jEdit4.3から取得したパターン集合
Pb: Paのうち重みの大きい単語が出現するパターン集合
パターン自身に出現する単語をキーワードとして検索し,順位を調査
結果
パターンが上位3位以内に含まれる確率
 Pa: 0.4371
 Pb: 0.9775

考察


目的のパターンを得るためには複数回の検索が必要な場合もある
実装ツールでは1回の実行時間は約1秒
17
妥当性の検証: コード片の生成

対象
 jEdit4.3のパターンからランダムに選んだ11個のパターン


パターンの総数: 7559
方法
1.
2.
3.
パターンが出現する既存ソースコードを1つ選び,削除
パターンと削除後のソースコードからコード片を生成
削除した部分と生成したコード片の変数の使用方法を比較
...;
if (!buffer.isEditable()) {
getToolkit().beep();
}
...;
...;
コード片の生成・置換
生成したコード片
比較
...;
18
妥当性の検証結果(1/2): コード片の生成

変数の使用方法が
一致するケース
変数の使用方法が
異なるケース
7
4
変数名のrename
変数の初期化
変数の使用方法が一致するケース
boolean var0;
{
StringTokenizer st = ...;
while (...) {
String keyCodeStr =
st.nextToken();
...
... (st.hasMoreTokens()) ...
}
while (var0) {
java.lang.String var1 =
st.nextToken();
boolean var2 =
st.hasMoreTokens();
}
既存のソースコード
}
生成したコード片
19
妥当性の検証結果(2/2): コード片の生成

変数の使用方法が異なるパターンの特徴
 GUIの設定
 同じ型の引数を複数とるメソッド呼び出しが出現
 基本データ型が出現

int 型など
int caret, newCaret; ...
{
if (...)
this.extendSelection(caret,
newCaret);
else { ...
this.selectNone();
}
} ...
boolean var0;
if (var0) {
this.extendSelection(newCaret,
newCaret);
} else {
this.selectNone();
}
同じ型の引数を複数とるメソッド呼び出しが出現する例
20
考察: コード片の生成

変数の使用方法が一致した理由
 パターンの要素間にはコード片がほとんど含まれない
 同一の型が同時に使用されることはほとんどない


例外: GUIで使用するクラスや基本型など
変数の使用方法が異なるケースの解決案
 パターンが出現するソースコードの利用

データフロー情報
21
まとめと今後の課題

まとめ
 コーディングパターンに基づくコード補完手法を提案
 提案手法に対する評価実験を行い,次の妥当性を検証



パターンの検索
コード片の生成
今後の課題
 データフロー情報を利用したコード片の生成
 実際のソフトウェア開発における評価
22