2011年10月27日木曜日

CLangでクラスの中身を調べる: クラスとそのメンバ関数の列挙

クラスのメンバ関数はclang::CXXRecordDecl::method_begin(), method_end()で反復できる。この反復でclang::CXXMethodDeclが得られる。
CXXMethodDeclはヘッダを見ると、各関数の属性、例えば可視性であったり、戻り値の型であったりを取得できるようだ。

とりあえず、自分で明示的に定義したメンバ関数をリストアップしてみよう。

コード:
clang::ASTContext::const_type_iterator t = astContext.types_begin();
clang::ASTContext::const_type_iterator eot = astContext.types_end();
for(; t != eot; ++t)
{
    clang::CXXRecordDecl* pDecl = (*t)->getAsCXXRecordDecl();
    if( (pDecl != nullptr) && pDecl->hasDefinition() && pDecl->isClass() )
    {
        pDecl->getDeclName().dump();
        //pDecl->getDeclName().printName(llvm::outs());

        // 基本クラスを確認する。
        std::printf(">>>> base class >>>>\n");
        clang::CXXRecordDecl::base_class_iterator base = pDecl->bases_begin();
        clang::CXXRecordDecl::base_class_iterator eobase = pDecl->bases_end();
        for(; base != eobase; ++base)
        {
            // CXXRecordDecl::base_class_iterator は CXXBaseSpecifier* 。
            base->getType().dump();
        }
        std::printf("<<<<\n");

        // public なメンバ関数を列挙する。
        std::printf(">>>> method >>>>\n");
        clang::CXXRecordDecl::method_iterator method = pDecl->method_begin();
        clang::CXXRecordDecl::method_iterator eomethod = pDecl->method_end();
        for(; method != eomethod; ++method)
        {
            if( !method->isImplicit() && (method->getAccess() == clang::AS_public) )
            {
                method->dump();
            }
        }
        std::printf("<<<<\n");

        std::printf("\n---------------------------------------------------------\n");
    }
}

調べるcppはこんな感じ。
#include <cstdio>

namespace SuperNs
{
    class Super
    {
    public:
        Super()
        {
        }

        void super_public_method()
        {
        }
        
        virtual void super_public_virtual_method()
        {
        }

        virtual void super_public_virtual_method_nooverride()
        {
        }

    private:
        void super_private_method()
        {
        }
    };
}

namespace SubNs
{
    class Sub
        : public SuperNs::Super
    {
    public:
        Sub()
            : Super()
        {
        }

        void sub_public_method()
        {
        }
        
        virtual void super_public_virtual_method()
        {
        }

    private:
        void sub_private_method()
        {
        }
    };
}

int main(int, char**)
{
    std::printf("Hello,world\n");
    std::getchar();
    return 0;
}
結果:
_Lockit
>>>> base class >>>>
<<<<
>>>> method >>>>
_Lockit()_Lockit(int)void ~_Lockit() noexceptstatic void _Lockit_ctor(int)static void _Lockit_dtor(int)<<<<

---------------------------------------------------------
_Mutex
>>>> base class >>>>
<<<<
>>>> method >>>>
_Mutex()void ~_Mutex() noexceptvoid _Lock()void _Unlock()<<<<

---------------------------------------------------------
_Init_locks
>>>> base class >>>>
<<<<
>>>> method >>>>
_Init_locks()void ~_Init_locks() noexcept<<<<

---------------------------------------------------------
Super
>>>> base class >>>>
<<<<
>>>> method >>>>
Super() {
}

void super_public_method() {
}

virtual void super_public_virtual_method() {
}

virtual void super_public_virtual_method_nooverride() {
}

<<<<

---------------------------------------------------------
Sub
>>>> base class >>>>
: SuperNs::Super identifier
<<<<
>>>> method >>>>
Sub() : SuperNs::Super() {
}

void sub_public_method() {
}

virtual void super_public_virtual_method() {
}

<<<<

---------------------------------------------------------
Super
>>>> base class >>>>
<<<<
>>>> method >>>>
Super() {
}

void super_public_method() {
}

virtual void super_public_virtual_method() {
}

virtual void super_public_virtual_method_nooverride() {
}

<<<<

---------------------------------------------------------

なんでか、Superが2回反復されている(コピペミスではない)。その他は一応意図通り動いているようだ。ただ「親クラスのメンバ関数は子クラスで反復されない」のはちょっと困った。

0 件のコメント:

コメントを投稿