Understand APIチュートリアル3:Entity、References、Kind Filterとは

Understand

本記事は米国向けに公開されている開発元のブログ記事をベースとし、日本国内のUnderstand 7.0 APIの活用をご検討されているお客様向けに加筆・修正を加えたものとなります。

前回の記事はこちらをご確認ください。

※一部の記事の内容ではUnderstand 6.5が使用されていますが、基本的な機能はUnderstand 7.0でも同様にご利用いただけます。

チュートリアル目次

第1回:Understand APIチュートリアル1:Python API入門

第2回:Understand APIチュートリアル2:最初のAPIスクリプトの作成

第3回:Understand APIチュートリアル3:Entity、References、Kind Filterとは

EntityとReference

Pythonスクリプトを実行してAPIにアクセスし、 Understand プロジェクトを開く方法がわかったため、次はプロジェクトの実際のデータを見てみましょう。
Understandによって取得されるデータのほとんどは、Entity(エンティティ) Reference(参照)です。

用語説明
EntityEntity(エンティティ)とは、Understand が情報を取得するコード内のあらゆる要素 (ファイル、クラス、変数、関数など) です。Python API では、エンティティは Understand.Ent クラスで表されます。
ReferenceReference(参照)とはコード内でエンティティが出現する特定の位置を表します。参照は必ず「2つのエンティティ間の関係」として定義されます。例えば、関数Barは関数Fooの14行目で呼び出される、といった関係です。Python APIでは、参照はUnderstand.Refクラスで表現されます。

すべてのエンティティ参照には、API でクエリーできる固有の属性セットがあります。エンティティについて表示できる属性には、名前、タイプ、関連付けられているコメント、エンティティの種類、親エンティティ、パラメーターなどがあります。

一方、参照には、それに関連付けられたエンティティと、参照が発生するファイル、行、列、および参照の種類の両方が含まれます。

これを視覚的に理解しやすくするために、次の簡単な C言語のサンプルコードを例に説明しましょう。

myFile.c

void main() {
   char myString[];
   myString = “Hello World!”;
}

Understand は3つのエンティティ (青) と3つの参照 (緑) を識別します。

すべての参照は2つのオブジェクト間の関係であるため、実際には参照は双方向で保存されます。そのため、各参照の種類には逆の参照が存在します。DefineとDefineIn、SetとSetBy、CallとCallbyなどです。以下は、同じエンティティの逆参照です。

プロジェクト内のすべてのエンティティのリストを取得するには、db.ents()関数を使用します。エンティティのすべての参照のリストを取得するには、ent.refs()を使用します。

通常、すべてのエンティティまたは参照ではなく、その一部だけが必要なので、種別フィルター(Kind Filter)が役立ちます。

種別フィルター(Kind Filter)

種別フィルター(Kind Filter)とは、Understand でリストをフィルタリングするために使用する文字列です。最初のスクリプト(sample.py)で、既に小さな例を示しました。

db.ents(“file”):

前述の通り、db.ents() 関数自体は、ループ変数から名前空間まで、Understand 内のすべてのエンティティのリストを返します。種類を表す文字列に「file」を指定するとフィルターが作成され、フィルターに一致しないものはすべて除外されます。この場合、ファイルのみが返されます。

文字列に簡単なロジックを追加することもできます。

  • チルダ(~)はNOTを意味する
  • スペースはANDを意味する
  • カンマ(,)はトップレベルのORとして機能する

ファイルではなくすべてのクラスと関数をリストしたい場合は、以下のようにフィルターを変更するだけです。

db.ents(“class, function”)

これは、クラスでまたは関数である任意のエンティティを返すことを意味します。

未解決(unresolved)のエンティティとは、Understand が宣言の情報は持っているものの、定義の情報は持っていないエンティティです(printf が一般的な例です)。このフィルターは、プロジェクトで定義されているすべての非 volatile パブリック関数を返します。

db.ents(“function public ~unresolved ~volatile”)

※なお、未知(unknown)のエンティティはUnderstandが宣言も定義も情報を持っていないエンティティです。

使用例

今回の例では、プロジェクト内の各関数が定義されているファイルと行をリストアップします。
この例では、Understandデータベースが既に開かれていることを前提としています(最初のチュートリアルの最後にあるテンプレート(sample.py)を参照してください)。

まず、プロジェクトで定義されているすべての関数のリストを取得します。

ents = db.ents(“function ~unknown ~unresolved”)

次に、リストをソートして反復処理します。

for ent in sorted(ents,key= lambda ent: ent.longname()):

次に、各関数が定義されている参照を取得します。定義がない場合は、次の関数に進みます。

ref = ent.ref(“definein”)
if ref is None:
continue

次に、関数の名前とパラメーターを出力します。

print (ent.longname(),”(“,ent.parameters(),”)”)

最後に、参照が発生したファイルと行番号を出力します。

print (” “,ref.file().relname(),”(“,ref.line(),”)”)

スクリプト全体は次のようになります。

import understand db = understand.open("C:/projects/test.und")
ents = db.ents("function ~unknown ~unresolved")
for ent in sorted(ents,key= lambda ent: ent.longname()):
    ref = ent.ref("definein")
    if ref is None:
        continue
    print (ent.longname(),"(",ent.parameters(),")")
    print (" ",ref.file().relname(),"(",ref.line(),")")