libclangでC++を解析するためのメモ

[libclangのドキュメント](http://clang.llvm.org/doxygen/group__CINDEX.html)等を読んで使い方を調べたり実際にプログラムを書いて色々確認したりしたのでメモ。
本文中では関数名の頭についてる`clang_`は省略してあります。

# CXIndex
翻訳単位(translation unit)の集まり。`createIndex`で作って`disposeIndex`で削除する。

```cpp
CXIndex clang_createIndex(
    int excludeDeclarationsFromPCH,
    int displayDiagnostics
);
void clang_disposeIndex(
    CXIndex index
);
```

# CXTranslationUnit
`clang -emit-ast`で生成されるastファイルか普通のソースファイルから作る。
`disposeTranslationUnit`で削除。

```cpp
void clang_disposeTranslationUnit(
    CXTranslationUnit
);
```

## astファイルから作る時
`createTranslationUnit`か`createTranslationUnit2`を使う。
最後に`2`が付いている方はエラーコードを返す。
エラーコードが不要なら`2`がない方を使えば良さそう。

```cpp
CXTranslationUnit clang_createTranslationUnit(
    CXIndex CIdx,
    const char *ast_filename
);
enum CXErrorCode clang_createTranslationUnit2(
    CXIndex CIdx,
    const char *ast_filename,
    CXTranslationUnit *out_TU
);
```

## ソースファイルから作る時
`parseTranslationUnit`か`parseTranslationUnit2`か`createTranslationUnitFromSourceFile`を使う。
どれもclangを実行する時と同じコマンドライン引数を渡せる。
コマンドライン引数にソースファイル名が含まれる時は2つ目の引数を`NULL`にできる。
`parseTranslationUnit`の`unsigned options`に`CXTranslationUnit_SkipFunctionBodies`を渡すと関数本体を無視できる。

```cpp
CXTranslationUnit clang_parseTranslationUnit(
    CXIndex CIdx,
    const char *source_filename,
    const char *const *command_line_args,
    int num_command_line_args,
    struct CXUnsavedFile *unsaved_files,
    unsigned num_unsaved_files,
    unsigned options
);
enum CXErrorCode clang_parseTranslationUnit2(
    CXIndex CIdx,
    const char *source_filename,
    const char *const *command_line_args,
    int num_command_line_args,
    struct CXUnsavedFile *unsaved_files,
    unsigned num_unsaved_files,
    unsigned options,
    CXTranslationUnit *out_TU
);
CXTranslationUnit clang_createTranslationUnitFromSourceFile(
    CXIndex CIdx,
    const char *source_filename,
    int num_clang_command_line_args,
    const char *const *clang_command_line_args,
    unsigned num_unsaved_files,
    struct CXUnsavedFile *unsaved_files
);
```

# CXCursor
ある翻訳単位が持つASTのある要素を指す。
`getTranslationUnitCursor`でASTの根を指す`CXCursor`が得られる。
`getCursorKind`で要素の種類が得られる。
根に対して`getCursorKind`を呼ぶと`CXCursor_TranslationUnit`が返る。

```cpp
CXCursor clang_getTranslationUnitCursor(
    CXTranslationUnit
);
enum CXCursorKind clang_getCursorKind(
    CXCursor
);
```

# ASTの走査
走査を開始したい要素を指す`CXCursor`を引数にして`visitCursor`を呼び出す。
`visitCursor`の3つ目の引数の値が2つ目の引数に渡すコールバック関数の最後の引数になる。
コールバックの戻り値で

 * 走査をやめる(`CXChildVisit_Break`)
 * 次の要素に移る(`CXChildVisit_Continue`)
 * 子要素に移る(`CXChildVisit_Recurse`)

のいずれかの動作を行うことができる。

```cpp
typedef enum CXChildVisitResult(* CXCursorVisitor )(
    CXCursor cursor,
    CXCursor parent,
    CXClientData client_data
);
unsigned clang_visitChildren(
    CXCursor parent,
    CXCursorVisitor visitor,
    CXClientData client_data
);
```

## 関数の構造

``` cpp:function.cpp
void f(int, float);
```

このプログラムのASTは

 * `FunctionDecl`
   * `ParmDecl`
   * `ParmDecl`

のようになる。各値は`getCursorKind`で得られる`enum CXCursorKind`の各値の頭に付いてる`CXCursor_`を省略したもの。
`ParmDecl`の数は`getNumArguments`で得られる。
各`ParmDecl`は`Cursor_getArgument`を使っても得られる。
`getCursorType`で`void (int, float)`、`getCursorDisplayName`で`f(int, float)`、`getCursorSpelling`で`f`が得られる。

```cpp
int clang_Cursor_getNumArguments(
    CXCursor C
);
CXCursor clang_Cursor_getArgument(
    CXCursor C,
    unsigned i
);
CXType clang_getCursorType(
    CXCursor C
);
CXString clang_getCursorDisplayName(
    CXCursor
);
CXString clang_getCursorSpelling(
    CXCursor
);
```

## 変数の構造
変数は`VarDecl`となる。
関数ポインタの場合、`FunctoinDecl`と同様に子要素に`ParmDecl`ができる。

## クラスの構造

``` cpp:class.cpp
class Base1{};
class Base2{};
class Derived : public Base1, private Base2{};
```

このようなプログラムがあった時、`Derived`クラスのASTは

 * `ClassDecl`
   * `CXXBaseSpecifier`
     * `TypeRef`
   * `CXXBaseSpecifier`
     * `TypeRef`

のようになる。
`CXXBaseSpecifier`を引数にして`getCXXAccessSpecifier`を呼ぶと継承のアクセス指定子が得られる。
`getTypeSpelling(getCursorType(CXXBaseSpecifierもしくはTypeRefなCXCursor))`とすると基底クラスの名前が得られる。

```cpp
enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(
    CXCursor
);
CXString clang_getTypeSpelling(
    CXType CT
);
```

### メンバ関数

```cpp:member-function.cpp
class Base{
public:
    virtual void func(int);
};
class Derived : public Base{
public:
    void func(int) override;
};
```

とすると、`Derived`クラスのASTは

 * `ClassDecl`
   * `CXXBaseSpecifier`
     * `TypeRef`
   * `CXXMethod`
     * `CXXOverrideAttr`
     * `ParmDecl`

のようになる。
メンバ関数の部分は`FunctionDecl`と同じ構造。
`override`と`final`は`CXXMethod`の子要素になる。
`virtual`や`static`等は`CXXMethod_isVirtual`等で確認できる。


### メンバ変数
メンバ変数は`FieldDecl`となる。
構造は`VarDecl`と同じ。
`getCXXAccessSpecifier`でアクセス指定子が分かる。