コードクローンの分布情報を 用いた特徴抽出手法の提案 井上研究室 服部 剛之 1 コードクローン ソースコード中に存在する同一,もしくは類似したコード 片を同一システム中に持つコード片 (以降単にクローンと呼ぶ) コピーアンドペースト等により生成される ソフトウェア保守を困難にする コードの変更が必要な場合 バグ修正,機能追加 保守作業の手間が増大 クローンセット 2 CCFinder,Gemini クローンを対象とした保守支援ツール 検出ツール: CCFinder[1] 分析ツール: Gemini[2] 国内外の個人・組織に配布 研究機関での利用 企業での商用ソフトウェア開発プロセスへの導入 配布先からのフィードバックを得ている [1] 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, 28(7):654-670, 2002. [2] Y. Ueda, T. Kamiya, S. Kusumoto and K. Inoue, “Gemini: Maintenance Support Environment Based on Code Clone Analysis”, Proc. of the 8th IEEE International Symposium on Software Metrics, 67-76, 2002. 3 フィードバックから得られた情報 クローン情報の利用法 リファクタリング支援 設計情報との一貫性確認 互いにクローンになっているものを1つにまとめる 設計上説明できるクローンであるか 問題点 検出されたクローンの数が多すぎてどれをみるべきかわからない 調査の関心がないクローン(定型処理など)が含まれていて,どの クローンから見ていけばいいかわからない クローンの特徴を知る必要性 4 目的とアプローチ 目的: クローン分析の効率化 クローンを特徴に基づいて分類する 分類を使って,調査の関心がないクローン(定型処理な ど)をフィルタする アプローチ: メトリクスを用いてクローンを分類 以下のメトリクスを用いる RAD: クローン間の遠さの尺度 NIF: クローンが存在するファイルの数 RNR: クローン内の重複した処理の少なさの度合い 5 RAD: クローン間の遠さの尺度 RAD: 与えられたクローンセットの各要素を含む ファイルから共通の親ディレクトリまでの距離の 最大値 •RAD = 2 •例:RAD = 1 2 1 ファイルC ファイルA ファイルB は,クローンを表す ファイルA ファイルB 6 NIF: クローンが存在するファイルの数 NIF: 与えられたクローンセットの各要素を含む ファイルの数 •例:NIF = 2 •NIF = 3 ファイルC ファイルA ファイルB 2 は,クローンを表す ファイルA ファイルB 3 7 RNR: クローン内の重複した処理の 少なさの度合い ∑ Tokensrepeated(C) RNR = 1 - C∈S ∑ Tokensall(C) C∈S S: クローンセット C: クローンセットの要素 Tokensall(C) : クローンC中の総トークン数 Tokensrepeated(C) : クローンC中の繰り返し部分のトークン数 8トークン X A B A B A B Y 4トークン 直前の繰り返し Tokensall = 8 Tokensrepeated = 4 8 クローンの分布に着目した分類方法 RAD,NIFは,クローンの分布の特徴を表すメト リクス 値の高低により,クローンを4つに分類する RAD 高 vertical global local horizontal 低 低 高 NIF 9 カテゴリ: local クローンがディレクトリ階層上近い少数のファイ ルに存在する RAD 高 vertical global local horizontal 低 は,クローンを表す 低 高 NIF 10 カテゴリ: horizontal クローンがディレクトリ階層上近い多数のファイ ルに存在する RAD 高 vertical global local horizontal 低 は,クローンを表す 低 高 NIF 11 カテゴリ: vertical クローンがディレクトリ階層上遠くの少数のファイ ルに存在する RAD 高 vertical global local horizontal 低 低 は,クローンを表す 高 NIF 12 カテゴリ: global クローンがプログラム広範囲の多数のファイル に存在する RAD 高 vertical global local horizontal 低 低 は,クローンを表す 高 NIF 13 実験 目的: RAD,NIF,RNRに着目して分類した各カテゴリに含まれるクロー ンの特徴を調べる Java,C,C++で書かれたオープンソースソフトウェアについて分類を 行った CCFinderにより検出された30トークン以上のクローンセットを対象 人の手によって確認 Java: Ant,Webmail,httpunit,Art of Illusion C : Small Device C Compiler,Sketch C++ : CppUnit,SWIG 総ファイル数: 2948個 総クローンセット数(30トークン以上): 14874個 Ant 総ファイル数: 954個 総クローンセット数(30トークン以上): 1643個 14 クローンの特徴を表す指標 クローンが含まれる関数の名前を用いて指標を定義する クローンがどのような関数に存在するかで分類 same: 同じ名前の関数内に存在するクローン similar: 名前の似た関数内に存在するクローン 名前が似ている: 関数名の一部に共通した単語を持つ 例) addConfiguredInputMapper addConfiguredOutputMapper addConfiguredErrorMapper different: 異なる関数内に存在するクローン クローンセットが各指標に該当するか調べることで分類し たカテゴリを評価する 複数の指標に該当することを許す 15 評価条件 カテゴリ分けでのRAD,NIFの高低の閾値はそれぞれの 最大値の半分とした RNRについては次のように分割した RNR低: 0 ≦ RNR ≦ 0.3 RNR中: 0.3 < RNR ≦ 0.7 RNR高: 0.7 < RNR ≦ 1 低 中 高 RNR 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 16 RNRに着目した特徴 RNRの低いクローンは単純なロジックのクロー ンであった(繰り返しの多いクローン) public static String getMethodAccess(int access_flags) { StringBuffer sb = new StringBuffer(); if (isPublic(access_flags)) { sb.append("public "); 全体が1つのクローン } else if (isPrivate(access_flags)) { sb.append("private "); } else if (isProtected(access_flags)) { sb.append("protected "); } if (isFinal(access_flags)) { sb.append("final "); } 直前の繰り返し if (isStatic(access_flags)) { sb.append("static "); } if (isSynchronized(access_flags)) { sb.append("synchronized "); } 17 Antでのクローンセットの分布 RAD 高 vertical 33個 global 7個 local 530個 horizontal 11個 低 低 高 NIF 要素数が3以上のクローンセットについて調べた (検出されたクローンセットの約35%) 18 カテゴリ: local の結果 RNR高: 305個 RNR中: 131個 RNR低: 94個 different similar same 0 20 40 60 80 100 % same,similarに該当するクローンが多い あるデータ構造の要素に対して処理を行う各メソッド内にクロー ンが見られた 同じデータ構造を用いている 19 カテゴリ: localに属するクローンの例 public int getClassEntry(String className) { int index = -1; for (int i = 0; i < entries.size() && index == -1; ++i) { Object element = entries.elementAt(i); if (element instanceof ClassCPInfo) { ClassCPInfo classinfo = (ClassCPInfo) element; if (classinfo.getClassName().equals(className)) { index = i; } } } return index; 同じクローンセットに含まれるメソッドの例として, getConstantEntry getMethodRefEntry などが存在した } 20 カテゴリ: horizontal の結果 RNR高: 9個 RNR中: 1個 RNR低: 1個 different similar same 0 20 40 60 80 100 % sameに該当するクローンが多い 例えば他のプログラムを実行するメソッドにクローンが見られた 引数ごとに異なるメソッドとして実装されている 21 カテゴリ: horizontalに属するクローンの例 public void execute() throws BuildException { Commandline commandLine = new Commandline(); Project aProj = getProject(); int result = 0; if (getViewPath() == null) { setViewPath(aProj.getBaseDir().getPath()); } 外部プログラムの各機能を 呼び出すメソッド中に クローンが存在した commandLine.setExecutable(getClearToolCommand()); commandLine.createArgument().setValue(COMMAND_CHECKIN); checkOptions(commandLine); if (!getFailOnErr()) { getProject().log("Ignoring any errors that occur for: " + getViewPathBasename(),Project.MSG_VERBOSE); } result = run(commandLine); if (Execute.isFailure(result) && getFailOnErr()) { String msg = "Failed executing: " + commandLine.toString(); throw new BuildException(msg, getLocation()); } } 22 カテゴリ: vertical の結果 RNR高: 4個 RNR中: 12個 RNR低: 17個 different similar same 0 20 40 60 80 100 % differentに該当するクローンが多い 類似した構造のパッケージにクローンが見られた 23 カテゴリ: vertical に属するクローンの例 main ant taskdefs while (classEnum.hasMoreElements()) { String className = (String) classEnum.nextElement(); log(" Class " + className + " affects:", Project.MSG_DEBUG); testcases Hashtable affectedClasses = (Hashtable) affectedClassMap.get(className); Enumeration affectedClassEnum = affectedClasses.keys(); while (affectedClassEnum.hasMoreElements()) { ant String affectedClass = (String) affectedClassEnum.nextElement(); ClassFileInfo info taskdefs = (ClassFileInfo) affectedClasses.get(affectedClass); log(" " + affectedClass + " in " + info.absoluteFile.getPath(), Project.MSG_DEBUG); } 24 カテゴリ: global の例 RNR高: 4個 RNR中: 0個 RNR低: 3個 different similar same 0 20 40 60 80 100 % differentに該当するクローンがほとんどである 定型処理に該当するクローンが見られた 25 カテゴリ: global に属するクローンの例 } catch (IOException ioex) { throw new BuildException("Error while + ioex.getMessage(), ioex); } finally { if (reader != null) { try { reader.close(); } catch (IOException ignore) { // ignore } } if (os != null) { try { os.close(); } catch (IOException ignore) { // ignore } } } } concatenating: " クローンが存在しているメソッドは ストリームを閉じる処理を2回続けて 行う内容であった 26 考察 異なるソフトウェアでも,同じカテゴリに分類されたクローンに同じ特 徴が見られた ソフトウェアの記述言語を問わない メトリクス値に基づいてクローンの特徴を抽出可能 各カテゴリの特徴を利用することでクローンをフィルタすることができ る 例1) globalに属するクローンは定型処理であるので,リファクタリング 対象にならない 例2) verticalに属するクローンは設計情報との一貫性を確認すること が有益 他のパッケージからのアドホックなコピーの恐れ 例3) RNRが低いクローンは単純なロジックの繰り返しであるので利 用しにくい 単純な代入文の連続など リファクタリングの対象にならない 27 まとめと今後の課題 まとめ コードクローン分析の効率化を支援するコードクロー ンの特徴抽出手法の提案と評価 今後の課題 分類の詳細化 ツールとしての実装 実際の開発現場での適用実験と評価 28 29
© Copyright 2024 ExpyDoc