以下に、本願の開示する解析方法、解析装置及び解析プログラムの実施例を図面に基づいて詳細に説明する。なお、この実施例によりこの発明が限定されるものではない。また、以下に示す各実施例は、矛盾を起こさない範囲で適宜組み合わせても良い。
本実施例における、後に説明する解析装置100は、動的型付き言語のソースコードを解析対象とする。図1は、動的型付き言語と静的型付き言語との値の差異の一例を示す図である。図1に示す動的型付き言語のソースコード9100及び静的型付き言語のソースコード9200は、いずれも2つのクラス「C」及び「D」を含む。また、2つのクラス「C」及び「D」は、それぞれ同じ名前の関数「f」を含む。
図1に示すように、静的型付き言語のソースコード9200においては、オブジェクトを生成する際に、オブジェクトの「型」がソースコード中に明記される。例えば、静的型付き言語のソースコード9200においては、オブジェクト「o」の変数及び引数の型は、クラス「C」で定義され、オブジェクト「o2」の変数及び引数の型は、クラス「D」で定義されることが明確に特定できる。この場合において、関数「send」のパラメータ値の候補は「3」のみとなる。また、ソースコード9201に示すように、同じ名前のオブジェクト「o」を生成する場合も、それぞれの変数及び引数の型は、ソースコードにおいて明確に定義される。
一方、動的型付き言語のソースコード9100においては、オブジェクトを生成する際に、オブジェクトの「型」がソースコード中に明記されない。例えば、静的型付き言語のソースコード9200においては、オブジェクト「o」の変数及び引数の型が、クラス「C」で定義されるか、クラス「D」で定義されるかが明確に特定されていない。この場合において、関数「send」のパラメータ値は、実行文の順序に応じて、「3」だけでなく「8」も候補となる場合がある。
このように、動的型付き言語においては、実行文の順序に応じてパラメータ値の候補が異なる場合がある。この場合、同一クラスの別オブジェクトを、同じオブジェクトとして扱い、実行順序を無視してプログラムを静的に解析する(いわゆる「曖昧な静的解析」をする)と、候補値の誤列挙が生じる場合がある。一方、動的型付き言語のソースコードをコンパイルするなどして実行可能な状態において値の候補を列挙する場合、候補値の誤列挙は生じないが、候補値の列挙漏れが生じる場合がある。
本実施例における解析装置100は、プログラムの関数内のデータの流れと処理の流れとを表現する有向グラフを生成し、データの流れと処理の流れとを用いて、動的型の参照解決と名前解決を実行する。また、解析装置100は、有向グラフをプログラムの関数単位で縮約し、縮約した結果のうち、解析指示を受けた関数に関する解決結果を合わせた後に、データの処理の流れを探索する。
解析装置100によるソースコードの処理について、図2乃至図3を用いて説明する。図2は、構文木の一例を示す図である。図2に示すように、解析装置100は、符号1000で示す動的型付き言語で記述されたソースコード1から、例えば後に説明するような処理により、アセンブラでの命令列の粒度で、構文木1010を生成する。
また、解析装置100は、生成された構文木1010から、さらに図3に示すような有向グラフ1100を生成する。図3は、有向グラフの一例を示す図である。図3において、有向グラフ1100は、処理に対応する第1ノード1111及び1114と、データの参照に対応する第2ノード1112及び1115と、データの設定に対応する第3ノード1116とを含む。
本実施例における有向グラフ1100は、例えば図3に示すように、第1ノード乃至第3ノードとエッジとを有する3部グラフである。図3においては、第2ノードを円形状で示すとともに、円形内に「1」などの正の値を示す。また、図3においては、第3ノードを円形状で示すとともに、円形内に「−1」などの負の値を示す。なお、図3に示すように、以下において、第1ノード1114から第2ノード1115へのエッジ1117、及び第3ノード1116から第1ノード1114へのエッジ1118の表記を省略する場合がある。
図3に示す第2ノード及び第3ノードは、関数内のデータの流れ(記憶領域の参照更新、処理の入出力値)と処理の流れとを示す。第2ノード及び第3ノードにおいて、絶対値が「1」であるノードは環境を示し、絶対値が「2」以上であるノードはパラメータを示す。
また、解析装置100は、図3に示すような有向グラフに対して、データの流れと処理の流れとの両方を用いて、参照解決と名前解決を行う。解析装置100は、解決結果を関数単位で縮約して保持する。さらに、解析装置100は、縮約した結果のうち、解析指示を受けた関数に関する解決結果を合わせた後に、データの処理の流れを探索する。
このように、本実施例における解析装置100は、関数内のデータの流れと処理の流れとを有向グラフで示して参照解決と名前解決を実行し、解析対象の関数のデータの流れ及び処理の流れをたどるので、動的型付言語解析時の列挙漏れや誤列挙を抑制できる。
[機能ブロック]
次に、本実施例における解析装置100について、図4を用いて説明する。図4は、実施例1における解析装置の一例を示す図である。図4に示すように、本実施例における解析装置100は、通信部110と、記憶部120と、制御部130とを有する。
通信部110は、有線又は無線を問わず、図示しない外部のサーバや、図示しない解析装置100の利用者や管理者の端末など、その他のコンピュータ等との通信を制御する。通信部110は、例えばNIC(Network Interface Card)等の通信インタフェース等である。
記憶部120は、例えば制御部130が実行するプログラムなどの各種データなどを記憶する。また、記憶部120は、ソースコードDB121、クラス定義DB122、元フローDB123、解決済みフローDB124、書換規則DB125、縮約済みフローDB126及び値候補DB127を有する。記憶部120は、RAM(Random Access Memory)、ROM(Read Only Memory)、フラッシュメモリなどの半導体メモリ素子や、HDD(Hard Disk Drive)などの記憶装置に対応する。なお、以下の説明では、データベースを「DB」と表記する場合がある。
ソースコードDB121は、解析対象とするプログラムのソースコードを記憶する。なお、ソースコードDB121に記憶される情報は、例えば後に説明する取得部131により入力される。
クラス定義DB122は、ソースコードから有向グラフを生成する際に用いられる各クラスの定義に関する情報を記憶する。クラス定義DB122は、クラスの定義に関する情報として、例えば図5に示すようなクラステーブル122−1と、図6に示すようなノード関係テーブル122−2とを記憶する。なお、クラス定義DB122に記憶される情報は、例えば図示しない解析装置100の管理者により予め入力される。
図5は、実施例1におけるクラステーブルの一例を示す図である。図5に示すように、クラステーブル122−1は、各ノードの名前と、当該名前のノードが示す内容とを対応付けて記憶する。例えば、クラス「λI&」は、当該ノードが「クラスメンバ関数の処理内容を定義する」クラスのノードであることを示す。
図6は、実施例1におけるノード関係テーブルの一例を示す図である。図6に示すように、ノード関係テーブル122−2は、クラステーブルに列挙された各クラスのノードに対応する第2ノード及び第3ノードの属性を示す。図6に示すように、第2ノード及び第3ノードの属性は、絶対値「1」で示される「環境」、絶対値「2」以降で示される「パラメータ」に加えて、「メモリ領域」を示す「plc」、「名前空間」を示す「def」などをさらに含む。また、クラス「λI&」の第2ノード及びクラス「R&」の第3ノードに示されるように、絶対値が最も大きい属性は、「継続」を示す場合がある。
図4に戻って、元フローDB123は、後に説明する変換部132により、ソースコードから生成される有向グラフに関する情報を記憶する。元フローDB123は、例えば図7に示すような有向グラフを構成するノードに関する情報を記憶するノードテーブル123−1と、図8に示すような有向グラフを構成するエッジに関する情報を記憶するエッジテーブル123−2とを有する。なお、元フローDB123に記憶される情報は、例えば変換部132により入力される。
図7は、実施例1におけるノードテーブルの一例を示す図である。図7に示すように、ノードテーブル123−1は、例えば、「格納位置」と、「ノード種類」と、「クラス」と、「属性」とを、「ID」に対応付けて記憶する。
図7において、「ID」は、ノードを一意に識別する識別子(Identifier)を示す。「格納位置」は、当該ノードに対応するソースコードが格納された位置を示す。「ノード種類」は、当該ノードが、図3に示す第1ノード乃至第3ノードのいずれに該当するかを示す。
図7において、「クラス」は、当該ノードがどのクラスに該当するかを示す。なお、クラスは、「ノード種類」が「1」であるノードについてのみ記憶される。「属性」は、当該ノードの属性を示す。例えば「ノード種類」が「1」であるノードの「属性」は、「‘http://’」などの文字列や、「self」などの関数名を記憶する。また、例えば「ノード種類」が「2」又は「3」であるノードの「属性」は、「1」や「−1」など、「環境」や「パラメータ」などの属性を記憶する。なお、後に説明するように、「ノード種類」が「2」又は「3」であるノードの「属性」は、メモリ領域を示す「plc」や、名前空間を示す「def」などの属性も含む。
例えば、図7に示すように、IDが「11」のノードは、第1ノードn1であり、クラスが「IV」であり、属性が「‘http://’」である。また、IDが「11」のノードに対応するソースコードは、「/src/rev.1/」に格納されている。
図8は、実施例1におけるエッジテーブルの一例を示す図である。図8に示すように、エッジテーブルは、「起点ID」と「終点ID」とを対応付けて記憶する。図8において、「起点ID」は、当該エッジの起点となるノードのIDを示し、「終点ID」は、当該エッジの終点となるIDを示す。
図4に戻って、解決済みフローDB124は、後に説明する解決部133により、参照解決及び名前解決を行う解決処理が行われた結果である有向グラフに関する情報を記憶する。解決済みフローDB124は、例えば図7に示すノードテーブル123−1及び図8に示すエッジテーブル123−2と同様に、有向グラフを構成するノード及びエッジに関する情報を記憶する。なお、解決済みフローDB124に記憶される情報は、例えば後に解決部133により入力される。
書換規則DB125は、有向グラフに対する、後に説明する解決処理、縮約処理及び結合処理に適用される書換規則に関する情報を記憶する。なお、書換規則DB125に記憶される情報は、例えば図示しない解析装置100の管理者により予め入力される。
図9は、実施例1における書換規則の一例を示す図である。図9に示すように、書換規則は、「内容」と、「種別」と、「優先度」とを「タイトル」に対応付けて記憶する。図9において、「タイトル」は、書換種別を一意に識別する情報である。「内容」は、当該タイトルの書換規則が適用される有向グラフの対象及び条件、並びに書換処理の内容を示す。
図9において、「種別」は、当該書換規則を行う処理の種別を示す。なお、本実施例において、種別「S」は解決処理に適用される書換規則を示し、種別「D」は縮約処理に適用される書換規則を示し、種別「M」は統合処理に適用される書換規則を示す。また、「優先度」は、当該書換規則が適用される順序を示す。本実施例においては、書換規則は、優先度が高い、すなわち優先度の値が小さいものから順に適用される。
図4に戻って、縮約済みフローDB126は、後に説明する縮約部134による縮約処理が行われた結果である有向グラフに関する情報を記憶する。縮約済みフローDB126は、例えば図7に示すノードテーブル123−1及び図8に示すエッジテーブル123−2と同様に、有向グラフを構成するノード及びエッジに関する情報を記憶する。なお、縮約済みフローDB126に記憶される情報は、例えば縮約部134により入力される。
値候補DB127は、後に説明する列挙処理の結果である値に関する情報を記憶する。値候補DB127は、対象となる関数において、引数又は変数の設定値の候補となる値を記憶する。なお、値候補DB127に記憶される情報は、例えば後に説明する列挙部135により入力される。
図4に戻って、制御部130は、解析装置100の全体的な処理を司る処理部である。制御部130は、例えば、CPU(Central Processing Unit)やMPU(Micro Processing Unit)等によって、内部の記憶装置に記憶されているプログラムがRAMを作業領域として実行されることにより実現される。また、制御部130は、例えば、ASIC(Application Specific Integrated Circuit)やFPGA(Field Programmable Gate Array)等の集積回路により実現されるようにしてもよい。
制御部130は、取得部131、変換部132、解決部133、縮約部134、列挙部135及び出力部136を有する。なお、取得部131、変換部132、解決部133、縮約部134、列挙部135及び出力部136は、プロセッサが有する電子回路の一例やプロセッサが実行するプロセスの一例である。
取得部131は、ソースコード及び解析対象の関数に関する情報を取得する。取得部131は、例えば通信部110を通じて、図示しない外部のサーバや利用者の端末から、ソースコードを取得し、ソースコードDB121に記憶する。
また、取得部131は、通信部110を通じて、例えば利用者の端末から解析対象の関数に関する指示を受け付ける。取得部131は、変換部132に対して、解析対象の関数に関する有向グラフの生成指示を出力するとともに、列挙部135に解析対象の関数を特定する情報を出力する。
次に、変換部132は、ソースコードを、図3に示すような有向グラフに変換する。なお、変換部132は、生成部の一例である。
変換部132は、取得部131から有向グラフの生成指示の出力を受けると、ソースコードDB121から解析対象の関数を含むソースコードを抽出し、例えば図10に示すようなグラフ要素を特定して、図2に示すような構文木を生成する。
図10は、グラフ要素の一例を示す図である。変換部132は、図10に示すような節点に対応する要素をソースコード中から特定し、図2に示すような構文木を生成する。さらに、変換部132は、生成された構文木を、図3に示すような有向グラフの形に変換し、元フローDB123に記憶する。
変換部132が生成する有向グラフは、例えばソースコードをアセンブラの粒度で分解したものである。すなわち、生成された有向グラフは、参照先のレジスタやメモリアドレスが特定できる形で、データの流れ及び処理の流れを示したものである。
変換部132により生成される有向グラフについて、図11及び図12を用いて説明する。図11は、実施例1におけるソースコード変換結果の一例を示す図である。符号2000に示す変換元となるソースコード2は、図2に示すソースコード1と同名のクラスであるが、関数「__init__」2001に加えて、別の関数「newSpace」2002をさらに定義している。
この場合において、変換部132は、関数「__init__」2001に対応するノード「λI&」2101に加えて、別の関数「newSpace」2002に対応するノード「λI&」2102をさらに含む有向グラフ2100を生成する。
図12は、実施例1におけるソースコード変換結果の別の一例を示す図である。符号3000に示すソースコード3は、クラス「Proxy」のオブジェクト「p」を生成する命令3001を含む。
この場合において、変換部132は、値の参照先「RI」としてクラス「Proxy」を示すノード3101を含む有向グラフ3100を生成する。なお、ノード3101の参照先を特定する処理については、後に説明する。
次に、解決部133は、有向グラフに対して参照解決及び名前解決を行う解決処理を実行する。解決部133は、元フローDB123から有向グラフに関する情報を読み出し、書換規則DB125に記憶された種別「S」の書換規則を有向グラフに適用する。解決部133は、種別「S」の書換規則を適用した有向グラフに関する情報を、解決済みフローDB124に記憶する。
本実施例における解決処理について、図13を用いて説明する。図13は、ソースコード1の解決処理の一例を示す図である。図13に示す有向グラフ1200は、図3に示す有向グラフ1100のレイアウトを変更したもので、ノード及びエッジの構成は有向グラフ1100と同様である。なお、以下の有向グラフを示す図面において、次の処理対象となるノード又はエッジを破線で示し、前の処理により変更されたノード又はエッジを太線で示す場合がある。
まず、解決部133は、書換規則DB125を参照し、元フローDB123に記憶される有向グラフ1200に含まれる主ノードλI&「__init__」(コンストラクタのメソッド名)に種別「S」の書換規則を適用する。まず、解決部133は、書換規則DB125に記憶される種別「S」の書換規則のうち、最も優先度が高い、すなわち優先度の値が最も小さい「M_I」を有向グラフ1200に適用するか否かを判定する。
この場合において、有向グラフ1200は対象となるグラフ形状「A&(−2)→(2)P(−plc)→(+plc)Class」を含まないので、解決部133は、書換規則「M_I」を有向グラフ1200に対して適用しない。
次に、解決部133は、書換規則DB125に記憶された種別「S」の書換規則のうち、2番目に優先度が高い書換規則「RI_E(1)」を有向グラフ1200に適用するか否かを判定する。この場合において、有向グラフ1200は対象となるグラフ形状「RI(−1)→(1)…(−1)→(1)λI&」に該当するノード「RI」1201を含むので、解決部133は、書換規則「RI_E(1)」を有向グラフ1200に適用する。
すなわち、解決部133は、有向グラフ1200のノード「RI」1201をノードID1301に変更する。また、解決部133は、ノードλI&からノードID1301の第2ノードへのエッジ1323を追加することにより、有向グラフ1200を有向グラフ1300に変換する。
同様に、解決部133は、変換された有向グラフ1300が、さらに別のノード「RI」1311を含むので、解決部133は、書換規則「RI_E(1)」を有向グラフ1300にも適用する。
すなわち、解決部133は、有向グラフ1300のノード「RI」1311をノードID1411に変更する。また、解決部133は、ノード「λI&」からノードID1411の第2ノードへのエッジ1433を追加することにより、有向グラフ1300を有向グラフ1400に変換する。
また、解決部133は、変換された有向グラフ1400は、書換規則「RI_E(1)」の対象となるグラフ形状に該当するノードを含まないと判定する。この場合、解決部133は、書換規則DB125に記憶された、優先度が書換規則「RI_E(1)」以下であるその他の種別「S」の書換規則を、有向グラフ1400に適用するか否かを判定する。
この場合において、有向グラフ1400は、その他の種別「S」の書換規則の対象となるグラフ形状を含んでいないため、解決部133はその他の種別「S」の書換規則を有向グラフ1400に適用しない。そして、解決部133は、全ての種別「S」の書換規則について、有向グラフ1400に適用するか否かを判定した後に、変換された有向グラフ1400を、解決済みフローDB124に記憶する。
次に、縮約部134は、解決済みの有向グラフを、プログラムの関数単位で縮約する縮約処理を実行する。縮約部134は、解決済みフローDB124から有向グラフに関する情報を読み出し、書換規則DB125に記憶された種別「D」の書換規則を有向グラフに適用する。縮約部134は、種別「D」の書換規則を適用した有向グラフに関する情報を、縮約済みフローDB126に記憶する。
本実施例における縮約処理について、図14を用いて説明する。図14は、ソースコード1の縮約処理の一例を示す図である。まず、縮約部134は、書換規則DB125を参照し、解決済みフローDB124に記憶される有向グラフ1400に含まれる主ノード「λI&」である「__init__」に、種別「D」の書換規則を適用する。まず、縮約部134は、書換規則DB125に記憶される種別「D」の書換規則のうち、最も優先度が高い、すなわち優先度の値が最も小さい「ID_E」を有向グラフ1400に適用するか否かを判定する。この場合において、有向グラフ1400は対象となるグラフ形状「ID」を含むので、縮約部134は、書換規則「ID_E」を有向グラフ1400に適用する。
すなわち、縮約部134は、有向グラフ1400のノード「ID」1401を削除するとともに、図13に示すノード「ID」1401に隣接するエッジ1412、1413、1422及び1423を削除する。また、縮約部134は、削除された各エッジの接続先を相互に接続するエッジ1513及び1523を追加する。これにより、縮約部134は、有向グラフ1400を有向グラフ1500に変換する。
同様に、縮約部134は、有向グラフ1500にも、さらに書換規則「ID_E」を適用することにより、ノード「ID」1511、並びにエッジ1512、1513、1532及び1533を削除するとともに、エッジ1613及び1633を追加する。これにより、縮約部134は、有向グラフ1500を有向グラフ1600に変換する。
また、縮約部134は、書換規則DB125に記憶された、優先度が書換規則「ID_E」以下であるその他の種別「D」の書換規則を、有向グラフ1600に適用するか否かを判定する。この場合において、有向グラフ1600は、その他の種別「D」の書換規則の対象となるグラフ形状を含んでいないため、縮約部134はその他の種別「D」の書換規則を有向グラフ1400に適用しない。そして、縮約部134は、全ての種別「D」の書換規則について、有向グラフ1600に適用するか否かを判定した後に、変換された有向グラフ1600を、縮約済みフローDB126に記憶する。
本実施例による解決部133及び縮約部134による処理の別の一例について、図15A乃至図15Fを用いて説明する。図15A乃至図15Fは、ソースコード3の解決処理及び縮約処理の一例を示す図である。まず、解決部133は、図12に示すソースコード3から生成された有向グラフ3100に対し、種別「S」の書換規則を適用する。この場合において、解決部133は、書換規則「RI_E(1)」を、対象となるグラフ形状に該当するノード「RI」3101に適用する。
また、縮約部134は、解決部133により書換規則「RI_E(1)」が適用された有向グラフ3100に対し、さらに種別「D」の書換規則を適用する。この場合において、縮約部134は、書換規則「ID_E」を有向グラフ3100に適用することにより、解決及び縮約された有向グラフ3200を生成する。
図15Aに示すように、有向グラフ3200は、有向グラフ3100に含まれるノード「RI」3101及び当該ノードの第2ノード及び第3ノードに接続するエッジ3112、3113及び3132が削除されている。また、有向グラフ3200は、ノード「RI」3211の第2ノードに接続するエッジ3212と、ノード「λI&」の第2ノード3109に接続するエッジ3233とが追加されている。
本実施例におけるソースコード3は、図12に示すように、クラス「Proxy」のオブジェクト「p」を生成する命令3001を含む。そこで、本実施例における列挙部135は、ソースコード3の参照解決及び名前解決に際し、クラス「Proxy」を呼び出すノードを追加する。
図15Bに移って、解決部133は、有向グラフ3200に対し、さらに書換規則「RI_E(2)」を適用する。これにより、解決部133は、有向グラフ3200からクラス「Proxy」に関するノード「RI」3211を削除する。また、解決部133は、主ノード「Class」3321、ノード「P」3311及び両ノードを接続するエッジ3313を追加することにより、有向グラフ3300を生成する。
また、解決部133は、有向グラフ3300に対し、さらに書換規則「M_I」を適用する。これにより、解決部133は、有向グラフ3200にノード「M」3431、ノード「RM」3441を追加することにより、有向グラフ3400を生成する。
図15Cに移って、解決部133は、有向グラフ3400に対し、さらに書換規則「DI_I」を適用する。これにより、解決部133は、有向グラフ3400からノード「WI」3451を削除するとともに、ノード「DI」3561、ノード「WI」3551及び両ノードを接続するエッジを追加することにより、有向グラフ3500を生成する。
また、解決部133は、有向グラフ3500に対し、さらに書換規則「DI_E」を適用する。これにより、解決部133は、有向グラフ3500のノード「DI」3561及びノード「WI」3551を削除するとともに、ノード「S」3661及びノード「U」3651を追加することにより、有向グラフ3600を生成する。
図15Dに移って、解決部133は、有向グラフ3600に対し、さらに書換規則「RI_I(4)」及び「P.E_E」を適用する。これにより、解決部133は、有向グラフ3400からノード「RI」3671を削除するとともに、ノード「P」3771及びこれに接続するエッジを追加する。また、解決部133は、ノード「S」3661及びノード「P」3771を、第2ノード「+plc」及び第3ノード「−plc」を介して接続する。さらに、解決部133は、ノード「M」3781とノード「RM」3789とを接続するエッジ3783を追加することにより、有向グラフ3700を生成する。
また、解決部133は、有向グラフ3700に対し、さらに書換規則「M_E(3)」を適用する。これにより、解決部133は、有向グラフ3700に、主ノード「Class」3821から第2ノード「+def」及び第3ノード「−def」を介して接続されたノード「S」3891を追加する。また、解決部133は、有向グラフ3700のノード「M」3781をノード「P」3881に置き換えて、有向グラフ3800を生成する。なお、ノード「S」3891とノード「M」3781とは、第2ノード「1」及び第3ノード「−1」に加えて、第2ノード「+plc」及び第3ノード「−plc」を介しても接続される。
図15Eに移って、解決部133は、有向グラフ3800に対し、さらに書換規則「CL_I(4)」を適用する。これにより、解決部133は、「__init__」メソッドに対応するノード「λI&」3901を呼び出すノード「CL」3911を有向グラフ3800に追加する。また、解決部133は、ノード「CL」3911に接続するエッジを修正して、有向グラフ3900を生成する。これにより、解決部133は、関数「Client.getResource」による、関数「Proxy.__init__」に対する呼出関係を有向グラフ3900に記録する。
同様に、解決部133は、有向グラフ3900に対し、さらに書換規則「CL_I(4)」を適用して、「newSpace」メソッドに対応するノード「λI&」3A01を呼び出すノード「CL」3A11を有向グラフ3800に追加する。また、解決部133は、ノード「CL」3A11に接続するエッジを修正して、有向グラフ3A00を生成する。これにより、解決部133は、関数「Client.getResource」による、関数「Proxy.newSpace」に対する呼出関係を有向グラフ3A00に記録する。
図15Fに移って、縮約部134は、有向グラフ3A00に対し、種別「D」の書換規則「unref_E,S_U_E」を適用する。これにより、縮約部134は、有向グラフ3A00から、ノード「RM」3A21及び3A22、ノード「P」3A31及び3A32、ノード「U」3A41及びノード「S」3A51を削除して、有向グラフ3B00を生成する。なお、有向グラフ6000は、有向グラフ3B00のレイアウトを変更したもので、ノード及びエッジの構成は有向グラフ3B00と同様である。
図4に戻って、列挙部135は、縮約済みの有向グラフを用いて、対象となる関数の引数又は変数の設定値の候補となる値を列挙する。列挙部135は、取得部131から解析対象の関数を特定する情報の出力を受けると、特定された関数の値の候補値を列挙する。なお、列挙部135は、探索部の一例である。
列挙部135は、特定された関数に対して、呼出先のプログラムがあるか否かを判定する。列挙部135は、呼出先のプログラムがあると判定した場合、呼出先のプログラムの有向グラフを、呼出元のプログラムの有向グラフと結合する。
列挙部135は、関数の呼出元の有向グラフを列挙して、書換規則DB125を参照し、種別「M」の書換規則を呼出先の有向グラフと呼出元の有向グラフとに適用する。具体的には、列挙部135は、列挙対象とする引数又は変数を含む関数の呼出元を列挙し、各呼出元関数に対応する有向グラフの関数呼出部分を、呼出先の有向グラフと結合する。
例えば、列挙部135は、呼出先の有向グラフを、サブグラフとして呼出元の有向グラフに追加する。なお、サブグラフとして追加される呼出先の有向グラフは、例えば主ノードを「λI& $2」のように変更する。そして、列挙部135は、呼出元のグラフにおける、ノード「A&」に対して種別「M」の書換規則を適用する。また、列挙部135は、呼出元の有向グラフと呼出先の有向グラフとが結合されたグラフに対して、さらに種別「M」の書換規則を適用する。
また、列挙部135は、種別「M」の書換規則を適用した有向グラフに対して、種別「S」の書換規則を適用する解決処理と、種別「D」の書換規則を適用する縮約処理とを繰り返す。
また、列挙部135は、全ての呼出先の有向グラフを結合した場合、又は呼出先のプログラムが無いと判定した場合、有向グラフの関数に対して値を設定するノードを列挙し、Fノードをデータの流れ及び処理の流れとは逆方向に探索していく。列挙部135は、IVノードに到達するまで探索を繰り返し、IVノードに到達すると、列挙されたノードを文字列に変換する。
出力部136は、解析処理の結果を出力する。出力部136は、値候補DB127に記憶された引数又は変数の候補値を抽出し、例えば通信部110を通じて、図示しない利用者の端末に出力する。
本実施例における解析装置100による列挙処理及び出力内容について、図16A乃至図16Gを用いて説明する。図16A乃至図16Gは、ソースコード3の列挙処理及び結合処理の一例を示す図である。以下においては、図12に示すソースコード3により生成されるオブジェクト「p」に含まれる「send」関数に渡される引数の候補値を列挙する処理について説明する。
「send」関数は、ソースコード3の「Client」クラスに含まれる「Client.getResource」関数により呼び出される。しかし、「send」関数は、ソースコード3ではなく、ソースコード2の「Proxy」クラスに含まれている。そこで、本実施例における列挙部135は、呼出元であるソースコード3の有向グラフと、呼出先であるソースコード2の有向グラフとの結合処理を行う。
図16Aに示すように、列挙部135は、図15Fに示すソースコード3の有向グラフ6000に対して、種別「M」の書換規則「AC_E」を適用する。まず、列挙部135は、図9に示す書換規則「AC_E」の処理1.を実行することにより、ノード「λI&」から始まるサブグラフを複製する。本実施例においては、列挙部135は、ソースコード2の「newSpace」関数を定義するノード「λI&」2201から始まるサブグラフ2200を追加する。なお、図16B以下においては、追加されたサブグラフ2200のノード「λI&」2201を、「λI& $2」と表す場合がある。これにより、列挙部135は、有向グラフ6000とサブグラフ2200とを含む有向グラフ6100を生成する。
図16Bに移って、列挙部135は、有向グラフ6100に対して、種別「M」の書換規則「AC_E」の処理2.1.を実行する。これにより、列挙部135は、有向グラフ6000のノード「CL」6221からサブグラフ2200のノード「RI」6211へ接続するエッジが追加された有向グラフ6200を生成する。
また、列挙部135は、有向グラフ6200に対して、書換規則「AC_E」の処理2.2.及び処理2.3.1.を実行する。これにより、ノード「P」6311からノード「RM」6312へ接続するエッジ6313、及びノード「IV」6321からノード「F」6322へ接続するエッジ6323が追加される。さらに、列挙部135は、ノード「R&」6331からノード「R&」6332へ接続するエッジ6333が追加された有向グラフ6300を生成する。なお、ソースコード3には、書換規則「AC_E」の処理2.3.2.及び2.3.3.の対象となるノード又はエッジは含まれない。
図16Cに移って、列挙部135は、有向グラフ6300に対して、書換規則「AC_E」の処理3.を実行する。これにより、列挙部135は、図16Bに示すノード「λI&」6341及び接続する各エッジが削除された有向グラフ6400を生成する。
また、列挙部135は、有向グラフ6400に対して、書換規則「AC_E」の処理4.を実行する。これにより、列挙部135は、図16Bに示すノード「R&」6331及び接続する各エッジが削除された有向グラフ6500を生成する。なお、列挙部135は、有向グラフ6500において、削除されたノード「R&」6331と接続されていたノード「A&」6401からノード「R&」6332へ接続するエッジを追加する。
ところで、クラス「Proxy」は、ソースコード2に加えて、ソースコード1にも定義されている。そこで、列挙部135は、呼出元であるソースコード3の有向グラフに、呼出先であるソースコード1の有向グラフをさらに結合する処理を行う。
図16Dに移って、列挙部135は、有向グラフ6400に対して、書換規則「AC_E」の処理1.を実行する。これにより、列挙部135は、有向グラフ6500に、ソースコード1の「__init__」関数を定義するノード「λI& $2」1701から始まるサブグラフ1700を追加した有向グラフ7000を生成する。
図16Eに移って、列挙部135は、有向グラフ7000に対して、書換規則「AC_E」の処理2.1.、2.2.、及び2.3.1.を実行する。これにより、列挙部135は、有向グラフ7000に、ノード「CL」7111からノード「IV」7112へ接続するエッジ、及びノード「λI&」7121からノード「F」7122へ接続するエッジを追加する。さらに、列挙部135は、有向グラフ7000に、ノード「R&」7131からノード「IV」7132へ接続するエッジ、及びノード「P」7141からノード「WM」7142へ接続するエッジを追加して、有向グラフ7100を生成する。
図16Fに移って、列挙部135は、有向グラフ7100に対して、書換規則「AC_E」の処理3.を実行する。これにより、列挙部135は、有向グラフ7000から、ノード「λI& $2」7151及びノード「A&」7161を削除して、有向グラフ7200を生成する。
さらに、列挙部135は、有向グラフ7200に対して、書換規則「AC_E」の処理4.、及び種別「D」の書換規則「unref_E」を実行する。これにより、列挙部135は、有向グラフ7200から、ノード「R&」7131、ノード「λI&」7211及び7212、ノード「CL」7211及び7222並びにノード「RM」7231を削除する。また、列挙部135は、削除される各ノードに接続するエッジを整理して、有向グラフ7300を生成する。
図16Gに移って、列挙部135は、統合された有向グラフ7300に対して、列挙処理を行う。有向グラフ7300において、「send」関数に関するノード「RI」7311は、ノード「A&」7321により参照される。また、ノード「A&」7321は、ノード「F」7331も参照している。そこで、列挙部135は、「send」関数に関するノード「RI」7311と呼出関係にあるノードを列挙する。
列挙部135は、ノード「F」7331に呼び出されるノード「F」7341及びノード「IV」7333を列挙する。また、列挙部135は、ノード「F」7341にさらに呼び出されるノード「F」7351及びノード「IV」7343を列挙する。さらに、列挙部135は、ノード「F」7351にさらに呼び出されるノード「λI&」7353及びノード「IV」7352を列挙する。
そして、列挙部135は、列挙されたノードを用いて、オブジェクト「p」に含まれる「send」関数に渡される引数の候補値を生成する。列挙部135は、ノード「IV」7333に対応する文字列「‘Foo’」7933と、ノード「IV」7343に対応する文字列「/create/space/」7943とを含む候補値を生成する。また、列挙部135は、候補値に、ノード「IV」7352に対応する文字列「‘http://’」7952と、ノード「λI&」7353に対応する変数「λI&Client.getResource.3」7953とをさらに含める。
そして、出力部136は、生成された候補値を含む出力画面7999を、例えば通信部110を通じて利用者の端末に出力する。
[処理の流れ]
次に、本実施例における処理について、図17乃至図22を用いて説明する。図17は、実施例1における解析処理の一例を示すフローチャートである。図17に示すように、解析装置100の取得部131は、例えば通信部110を通じて解析処理の開始指示を受け付けるまで待機する(S100:No)。
取得部131は、開始指示を受け付けたと判定した場合(S100:Yes)、変換部132に対して、解析対象の関数に関する有向グラフの生成指示を出力するとともに、列挙部135に解析対象の関数を特定する情報を出力する。
変換部132は、有向グラフの生成指示の出力を受けると、変換処理を開始する(S110)。図18は、実施例1における変換処理の一例を示すフローチャートである。図18に示すように、変換部132は、ソースコードDB121から、解析対象の関数を含むソースコードを読み出して、構文木に変換する(S111)。次に、変換部132は、ノードを格納する変数であるfuncdicと、グラフを格納する変数であるgraphとを初期化する(S112)。例えば、変換部132は、funcdic及びgraphを初期化する。
次に、変換部132は、生成した構文木の節点を、グラフ要素に変換する(S113)。変換部132は、全ての節点についてグラフ要素に変換するまで処理を繰り返す(S114:No)。変換部132は、全ての節点についてグラフ要素に変換すると(S114:Yes)、変換結果である有向グラフを元フローDB123に記憶し、S120に移行する。
図17に戻って、解決部133は、記憶された有向グラフに対して解決処理を行う(S120)。図19は、実施例1における解決処理の一例を示すフローチャートである。まず、解決部133は、有向グラフに含まれる主ノード「λI&」を列挙し(S121)、各主ノードに対して種別「S」の書換規則を適用する(S122)。解決部133は、全ての主ノード「λI&」に対して処理を繰り返す(S123:No)。解決部133は、全ての主ノード「λI&」に対処した場合(S123:Yes)、変換結果である有向グラフを解決済みフローDB124に記憶し、S130に移行する。
図17に戻って、縮約部134は、記憶された解決済みの有向グラフに対して縮約処理を行う(S130)。図20は、実施例1における縮約処理の一例を示すフローチャートである。まず、縮約部134は、有向グラフに含まれる主ノード「λI&」を列挙し(S131)、各主ノードに対して種別「D」の書換規則を適用する(S132)。縮約部134は、全ての主ノード「λI&」に対して処理を繰り返す(S133:No)。縮約部134は、全ての主ノード「λI&」に対処した場合(S133:Yes)、変換結果である有向グラフを縮約済みフローDB126に記憶し、S140に移行する。
図17に戻って、解決部133は、解決処理及び縮約処理によって有向グラフが更新されたか否かを判定する(S140)。解決部133は、有向グラフが更新されたと判定した場合(S140:Yes)、S120に戻って処理を繰り返す。
解決部133は、有向グラフが更新されていないと判定した場合(S140:No)、候補値の入力を受け付けるまで待機する(S150:No)。候補値の入力を受け付けた場合(S150:Yes)、列挙部135は、列挙処理を行う(S160)。
図21は、実施例1における列挙処理の一例を示すフローチャートである。列挙部135は、特定された関数に対して、呼出先のプログラムがあるか否かを判定する(S161)。列挙部135は、呼出先のプログラムがないと判定した場合(S161:No)、S162に移行する。一方、列挙部135は、呼出先のプログラムがあると判定した場合(S161:Yes)、結合処理を行う(S170)。
図22は、実施例1における結合処理の一例を示すフローチャートである。まず、列挙部135は、列挙対象とする引数又は変数を含む関数の呼出元を列挙する(S171)。次に、列挙部135は、書換規則DB125を参照し、種別「M」の書換規則を呼出先の有向グラフに適用する(S172)。
次に、列挙部135は、結合した有向グラフに含まれる主ノード「λI&」に対して、種別「M」の書換規則を適用する(S173)。列挙部135は、種別「M」の書換規則が適用されたグラフに含まれるノード「λI&」に対して、種別「S」の書換規則を適用する解決処理を行う(S174)。また、列挙部135は、ノード「λI&」に対して、種別「D」の書換規則を適用する解決処理を行う(S175)。
そして、列挙部135は、解決処理及び縮約処理によって結合した有向グラフが更新されたか否かを判定する(S176)。解決部133は、結合した有向グラフが更新されたと判定した場合(S176:Yes)、S174に戻って処理を繰り返す。
列挙部135は、結合した有向グラフが更新されていないと判定した場合(S176:No)、列挙した全ての呼出元に対して対処するまで、S172に戻って処理を繰り返す(S177:No)。列挙部135は、全ての呼出元に対して対処したと判定した場合(S177:Yes)、S161に戻る。
図21に戻って、列挙部135は、特定された関数に対して値を設定するノードを列挙する(S162)。次に、列挙部135は、有向グラフに含まれるFノードを、データの流れ及び処理の流れとは逆方向に探索していく(S163)。そして、列挙部135は、IVノードに到達するまで探索を繰り返す(S164:No)。
列挙部135は、IVノードに到達すると(S164:Yes)、列挙されたノードを文字列に変換し(S165)、S190に移行する。
そして、出力部136は、値候補DB127に記憶された引数又は変数の候補値を、通信部110を通じて出力し(S190)、処理を終了する。
[効果]
以上説明したように、本実施例における解析方法は、コンピュータが、プログラムの関数内のデータの流れと処理の流れとを表現する有向グラフを生成する。解析方法は、コンピュータが、データの流れと処理の流れとを用いて、動的型の参照解決と名前解決を実行する。解析方法は、コンピュータが、有向グラフをプログラムの関数単位で縮約する。さらに、解析方法は、コンピュータが、縮約した結果のうち、解析指示を受けた関数に関する解決結果を合わせた後に、データの処理の流れを探索する。これにより、動的型付き言語のソースコードを解析する際の誤列挙及び列挙漏れを抑制できる。
また、解析方法は、コンピュータが、処理に対応する第1ノードと、データの参照に対応する第2ノードと、データの設定に対応する第3ノードとの接続関係を示す3部グラフを生成する。また、解析方法は、コンピュータが、第2ノード及び第3ノードとして、環境を渡すノードを含む3部グラフを生成する。これにより、データの流れ及び処理の流れを容易に特定できる。
また、解析方法は、コンピュータが、有向グラフを、解析指示を受けた関数の呼出先となるソースコードから生成された有向グラフの一部又は全部と結合し、結合された新たな有向グラフを用いてデータの処理の流れを探索する。これにより、呼出関係にあるその他のソースコードも含めて、データの流れ及び処理の流れを特定できる。
また、解析方法は、コンピュータが、探索された、関数に渡される値の候補を出力するので、候補値を容易に知得できる。
また、解析方法は、コンピュータが、関数の呼出し時に参照されるオブジェクトの設定値候補を列挙することにより、関数が所属するクラスを特定する。これにより、誤列挙及び列挙漏れなく、候補値を列挙できる。
さらに、解析方法は、コンピュータが、有向グラフのうち、設定値候補の列挙対象の変数・引数が現れる関数に関連する部分に探索範囲を限定してデータの流れをたどるので、解析の時間を短縮できる。