2017-03-17 55 views
2

我是嘗試通過libtooling分析AST的Clang的新手。 我想找到一個特定的功能,並將其AST從原始源文件移動到一個新文件。鏗鏘:從原始文件寫入函數的AST到新文件

我已經知道如何通過MatchFinder找到函數。 現在,我想知道如何將它的AST寫入一個新文件(.c或.cpp)

在此先感謝!

+0

是否要爲函數或底層源代碼編寫AST? –

+0

@那些叫我蒂姆,我想分割一個特定的功能到另一個文件。所以這個過程可能是:1)在AST級別(通過MatchFinder)找到這個函數,2)將它寫入另一個文件,3)從原始文件中移除它。 – ignorer

回答

3

摘要:獲取源文本,使用SourceManager;要從原始文件中刪除該功能,請生成Replacement並將其應用於RefactoringTool

首先,這裏有一個方法來獲得其中的一個函數定義的源代碼,假設AST匹配,看起來是這樣的:

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

回調的run方法將開始通過獲取的訪問匹配AST節點,得到由函數聲明所覆蓋的範圍源,並獲得到SouceManager,其涉及的SourceLocation對象的實際源的引用:

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:結束位置不是代碼結束的地方;它是範圍內最後一個標記的開始。因此,如果我們使用decl_range.getEnd()作爲函數定義進入SourceManager,我們將不會得到結束的大括號。 end_of_the_end()使用詞法分析器來獲取代碼的最後一位的位置:

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

回到run(),準確的開始和結束位置,就可以得到指針進入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); 

func_string有函數的源代碼;您可以寫入新文件等。

要消除原始文件中函數的來源,我們可以生成替換,並讓RefactoringTool將它應用於我們。要創建一個替換,我們需要的代碼兩行添加到run()

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

的替代構造函數取SourceManager,從哪裏開始更換,多少覆蓋,並與覆蓋內容。這種替換無需覆蓋整個原始函數定義。

我們如何獲得RefactoringTool的Replacement?我們可以通過引用RefactoringTool的替換成員來構造回調類。在run,一會又得出結論:

repls_.insert(repl); 

我在CoARCT, a collection of Clang refactoring examples在應用/ FunctionMover.cc增加了工作的示例應用程序。