2017-03-17 18 views
2

私はlibtoolingでASTを解析しようとしているClangの初心者です。 特定の関数を見つけて、元のソースファイルから新しいファイルにそのASTを移動したいと思います。Clang:元のファイルから新しいファイルに関数のASTを書き込む

私はMatchFinderで関数を見つける方法を知っていました。 新しいファイル(.cまたは.cpp)にASTを書き込む方法が不思議でした。

ありがとうございました!

+0

関数のAST、または基礎となるソースコードを記述しますか? –

+0

@Those Who Call Me Tim、特定の機能を別のファイルに分割したい。 1)ASTレベル(MatchFinderによる)でこの関数を見つけ、2)別のファイルに書き出し、3)元のファイルからそれを削除することができます。 – ignorer

答えて

3

要約:ソーステキストを取得するには、SourceManagerで作業してください。ファンクションを元のファイルから削除するには、Replacementを生成し、RefactoringToolで適用します。コールバックのrunメソッドがアクセス権を取得することによって開始すると

auto matcher(std::string const & fname) { 
    return functionDecl(hasName(fname)).bind("f_decl"); 
} 

まず、ここでは次のようになりますAST照合を想定し、関数定義のためのソースコードを取得する方法です一致ASTノード、関数宣言によって覆われたソース領域を取得し、実際のソースにSourceLocationオブジェクトに関するSouceManagerへの参照を取得:

virtual void run(MatchResult_t const & result) override { 
    using namespace clang; 
    FunctionDecl * f_decl = const_cast<FunctionDecl *>(
     result.Nodes.getNodeAs<FunctionDecl>("f_decl")); 
    if(f_decl) { 
    SourceManager &sm(result.Context->getSourceManager()); 
    SourceRange decl_range(f_decl->getSourceRange()); 
    SourceLocation decl_begin(decl_range.getBegin()); 
    SourceLocation decl_start_end(decl_range.getEnd()); 
    SourceLocation decl_end_end(end_of_the_end(decl_start_end,sm)); 

decl_start_endとで何? SourceRangeを使用するには1つのキャッチがあります:終了位置はコードの終了位置ではありません。それは範囲内の最後のトークンの始まりです。したがって、関数定義のためにdecl_range.getEnd()でSourceManagerに行くと、中かっこは得られません。

const char * buff_begin(sm.getCharacterData(decl_begin)); 
    const char * buff_end(sm.getCharacterData(decl_end_end)); 
    std::string const func_string(buff_begin,buff_end); 
:あなたはSourceManagerの文字バッファへのポインタを取得することができ、正確な開始と終了の位置で、 run()

SourceLocation 
end_of_the_end(SourceLocation const & start_of_end, SourceManager & sm){ 
    LangOptions lopt; 
    return Lexer::getLocForEndOfToken(start_of_end, 0, sm, lopt); 
} 

戻る:end_of_the_end()は、コードの最後のビットの位置を取得するためにレクサーを使用しています

func_stringには関数のソースコードがあります。新しいファイルなどに書き込むことができます。

元のファイル内の関数のソースを削除するには、置換を生成して、RefactoringToolでそれを適用させることができます。交換を作成するために、我々はrun()に、コードの2行を追加する必要があります。

uint32_t const decl_length = 
     sm.getFileOffset(decl_end_end) - sm.getFileOffset(decl_begin); 
    Replacement repl(sm,decl_begin,decl_length,""); 

交換用のctorの交換が開始するために、どのくらいの上書きするSourceManagerを取り、何で上書きします。この置換は、元の関数定義全体を何も上書きしません。

リファクタリングツールにどのように置き換えられますか? RefactoringToolのReplacementsメンバを参照してコールバッククラスを構築することができます。 runでは、1は、結論になります。

repls_.insert(repl); 

私はCoARCT, a collection of Clang refactoring examplesにアプリケーション/ FunctionMover.ccで作業サンプルアプリケーションを追加しました。

関連する問題