你的问题是SourceLocation的设计造成的。
下面是一篇文章:
使用 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 true 返回值(这意味着失败 - 请参阅文档)。
发生的情况如下:您收到几个 SourceLocation 标记,其中第一个是宏 ID(isMacroID() 将返回 true),而后者不是。
为了成功获得宏扩展语句的范围,我们需要退后一步并与SourceManager 进行通信,这是您所有拼写位置和实例化位置(如果您不记得这些术语,请退后一步)需要。我不能比in the documentation提供的详细描述更清楚:
可以查询 SourceManager 以获取有关 SourceLocation 的信息
对象,将它们变成拼写或扩展位置。
拼写位置表示与令牌对应的字节的位置
来自,扩展位置表示该位置所在的位置
用户的看法。例如,在宏扩展的情况下,
拼写位置指示扩展标记的来源和
展开位置指定展开的位置。
此时您应该明白我为什么首先解释所有这些内容:如果您打算使用源范围进行替换,则需要使用适当的扩展间隔。。 p>
回到我提出的示例,这是实现它的代码:
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;
}
即宏扩展语句的完整且成功的替换。
参考资料: