c++ 如果包含巨集,則clang將替換語句
我使用clang來嘗試解析(使用C API)一些C檔案,並使所有的case-break對使用特定的樣式.
例:
**Original** switch(...) { case 1: { <code> }break; case 2: { <code> break; } } **After replacement** switch(...) { case 1: { <code> break; } case 2: { <code> break; } }
到目前為止,如果程式碼部分不包含任何巨集,我到目前為止正是我想要的.
我的問題是:叮噹對待擴充套件(如果我做一個有問題的語句的轉儲會顯示擴充套件版本)巨集不同?如果是這樣我怎麼能得到這個工作?
可能有幫助的附加資訊:
我使用ofollow,noindex" target="_blank"> Rewriter::ReplaceStmt 用新建立的CompoundStmt替換每個案例的子語句,我注意到,如果“from”引數包含一個巨集,並且方法返回true的唯一方法是ReplaceStmt將返回true如果
07001(from->07002())
返回-1
的設計引起的.
文章如下:
使用clang的SourceLocation進行巨集擴充套件
SourceLocation
設計靈活,足以同時處理未展開的位置和巨集觀展開位置.
如果令牌是擴充套件的結果,則有兩個不同的位置要被保留:拼寫位置(與令牌對應的字元的位置)和例項化位置(使用令牌的位置 – 巨集例項化點).
以下簡單的原始檔為例:
#define MACROTEST bool int main() { int var = 2; switch(var) { case 1: { MACROTEST newvar; }break; case 2: { MACROTEST newvar; break; } } return 0; }
並假設我們要替換兩個宣告語句
MACROTEST newvar;
與宣告宣告
int var = 2;
為了得到這樣的東西
#define MACROTEST bool int main() { int var = 2; switch(var) { case 1: { int var = 2; }break; case 2: { int var = 2; break; } } return 0; }
如果我們輸出AST(-ast-dump),我們得到以下內容(我包含一個影象,因為它比只是未開啟的文字更直觀):
因為您可以看到我們感興趣的第一個DeclStmt報告的位置,從第1行到第10行:這意味著clang在轉儲中報告從巨集行的間隔到使用巨集的時間間隔:
#define MACROTEST [from_here]bool int main() { int var = 2; switch(var) { case 1: { MACROTEST newvar[to_here]; }break; case 2: { MACROTEST newvar; break; } } return 0; }
(注意,由於我的文字編輯器使用製表符,字元數可能與普通空格不一致)
最終,這是觸發Rewriter :: getRangeSize失敗(-1)和後續的
Rewriter::ReplaceStmt
真實返回值(這意味著失敗 – 請參閱文件).
發生的是以下幾點:你收到了幾個
SourceLocation
標記,第一個是一個巨集ID(
isMacroID()
將返回true),而後者不是.
為了成功獲得巨集擴充套件宣告的範圍,我們需要退後一步,並與
SourceManager
進行溝通,
SourceManager
是所有拼寫位置和例項化位置的查詢閘道器(如果您不記得,請退後一步這些術語)需求.我不能比in the documentation
的詳細說明更清楚:
The SourceManager can be queried for information about SourceLocationobjects, turning them into either spelling or expansion locations.Spelling locations represent where the bytes corresponding to a tokencame from and expansion locations represent where the location is inthe user’s view. In the case of a macro expansion, for example, thespelling location indicates where the expanded token came from and theexpansion location specifies where it was expanded.
在這一點上,您應該瞭解為什麼我首先解釋了所有這些東西:如果您打算使用源範圍進行替換,則需要使用適當的擴充套件間隔.
回到我提出的示例,這是實現它的程式碼:
SourceLocation startLoc = declaration_statement->getLocStart(); SourceLocation endLoc = declaration_statement->getLocEnd(); if( startLoc.isMacroID() ) { // Get the start/end expansion locations std::pair< SourceLocation, SourceLocation > expansionRange = rewriter.getSourceMgr().getImmediateExpansionRange( startLoc ); // We're just interested in the start location startLoc = expansionRange.first; } if( endLoc.isMacroID() ) { // will not be executed } SourceRange expandedLoc( startLoc, endLoc ); bool failure = rewriter.ReplaceText( expandedLoc, replacer_statement->getSourceRange() ); if( !failure ) std::cout << "This will get printed if you did it correctly!";
declaration_statement是兩者之一
MACROTEST newvar;
而replacer_statement是用於替換的語句
int var = 2;
上面的程式碼將會得到你的看法:
#define MACROTEST bool int main() { int var = 2; switch(var) { case 1: { int var = 2; }break; case 2: { int var = 2; break; } } return 0; }
即完全和成功地取代了巨集觀擴張的宣告.
參考文獻:
> clang doxygen API
> cl原始碼
http://stackoverflow.com/questions/24062989/clang-fails-replacing-a-statement-if-it-contains-a-macro