LoginSignup
24
20

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-03-26

libclangのドキュメント等を読んで使い方を調べたり実際にプログラムを書いて色々確認したりしたのでメモ。
本文中では関数名の頭についてるclang_は省略してあります。

CXIndex

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

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

CXTranslationUnit

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

void clang_disposeTranslationUnit(
    CXTranslationUnit
);

astファイルから作る時

createTranslationUnitcreateTranslationUnit2を使う。
最後に2が付いている方はエラーコードを返す。
エラーコードが不要なら2がない方を使えば良さそう。

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

ソースファイルから作る時

parseTranslationUnitparseTranslationUnit2createTranslationUnitFromSourceFileを使う。
どれもclangを実行する時と同じコマンドライン引数を渡せる。
コマンドライン引数にソースファイル名が含まれる時は2つ目の引数をNULLにできる。
parseTranslationUnitunsigned optionsCXTranslationUnit_SkipFunctionBodiesを渡すと関数本体を無視できる。

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が返る。

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

ASTの走査

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

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

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

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

関数の構造

function.cpp
void f(int, float);

このプログラムのASTは

  • FunctionDecl
    • ParmDecl
    • ParmDecl

のようになる。各値はgetCursorKindで得られるenum CXCursorKindの各値の頭に付いてるCXCursor_を省略したもの。
ParmDeclの数はgetNumArgumentsで得られる。
ParmDeclCursor_getArgumentを使っても得られる。
getCursorTypevoid (int, float)getCursorDisplayNamef(int, float)getCursorSpellingfが得られる。

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ができる。

クラスの構造

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))とすると基底クラスの名前が得られる。

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

メンバ関数

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と同じ構造。
overridefinalCXXMethodの子要素になる。
virtualstatic等はCXXMethod_isVirtual等で確認できる。

メンバ変数

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

24
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
20