use*_*963 20 c++ clang 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;
}
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,如果代码部分不包含任何宏,我到底做了什么.我的问题是:clang处理扩展(如果我转换一个有问题的语句,它将显示扩展版本)宏是否有所不同?如果是这样我怎么能让它工作?
可能有用的其他信息:
我正在使用Rewriter :: ReplaceStmt用新创建的CompoundStmt替换每个案例的子语句,我注意到如果"from"参数包含一个宏,则replaceStmt返回true,并且该方法返回true的唯一方法是if
Rewriter :: getRangeSize(from-> getSourceRange())
返回-1
Mar*_* A. 25
您的问题是由SourceLocation的设计引起的.
一篇文章如下:
SourceLocation设计灵活,足以同时处理未扩展位置和宏扩展位置.
如果令牌是扩展的结果,那么有两个不同的位置需要考虑:拼写位置(对应于令牌的字符的位置)和实例化位置(令牌使用的位置 -宏实例化点).
我们以下面的简单源文件为例:
#define MACROTEST bool
int main() {
int var = 2;
switch(var)
{
case 1:
{
MACROTEST newvar;
}break;
case 2:
{
MACROTEST newvar;
break;
}
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
并假设我们要替换两个声明语句
MACROTEST newvar;
Run Code Online (Sandbox Code Playgroud)
声明声明
int var = 2;
Run Code Online (Sandbox Code Playgroud)
为了得到这样的东西
#define MACROTEST bool
int main() {
int var = 2;
switch(var)
{
case 1:
{
int var = 2;
}break;
case 2:
{
int var = 2;
break;
}
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我们输出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;
}
Run Code Online (Sandbox Code Playgroud)
(请注意,由于我的文本编辑器使用了制表符,因此字符数可能与普通空格不同)
最终,这会触发Rewriter::getRangeSizefailure(-1)和后续返回值(这意味着失败 - 请参阅文档).Rewriter::ReplaceStmt true
发生的事情如下:你收到了几个SourceLocation标记,其中第一个是宏ID(isMacroID()将返回true),而后者则不是.
为了成功获得宏扩展语句的范围,我们需要退后一步,与SourceManager所有拼写位置和实例化位置的查询网关进行通信(如果你不记得这些,请退后一步)条款)需求.我不能比文档中提供的详细描述更清楚:
可以查询SourceManager以获取有关SourceLocation对象的信息,将它们转换为拼写或扩展位置.拼写位置表示对应于令牌的字节来自何处,而扩展位置表示位置在用户视图中的位置.例如,在宏扩展的情况下,拼写位置指示扩展的令牌来自何处,扩展位置指定扩展的位置.
在这一点上,您应该首先解释为什么我首先解释了所有这些内容:如果您打算使用源范围进行替换,则需要使用适当的扩展间隔.
回到我提出的示例,这是实现它的代码:
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!";
Run Code Online (Sandbox Code Playgroud)
这declaration_statement是两者中的任何一个
MACROTEST newvar;
Run Code Online (Sandbox Code Playgroud)
虽然replacer_statement是用于替换的声明
int var = 2;
Run Code Online (Sandbox Code Playgroud)
上面的代码将为您提供:
#define MACROTEST bool
int main() {
int var = 2;
switch(var)
{
case 1:
{
int var = 2;
}break;
case 2:
{
int var = 2;
break;
}
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
即完全和成功地替代宏观扩展的陈述.
参考文献:
为了获取与宏扩展相关的文件位置,可以使用 API 函数来检索信息:
SourceLocation startLoc = rewriter.getSourceMgr().getFileLoc(
declaration_statement->getLocStart());
SourceLocation endLoc = rewriter.getSourceMgr().getFileLoc(
declaration_statement->getLocEnd());
Run Code Online (Sandbox Code Playgroud)
这个 API 函数的作用与 Marco 在他的代码中编写的相同,但是是自动执行的。
如果我们看一下函数getFileLoc ()的实现:
这是函数的描述: 给定 Loc,如果它是宏位置,则返回扩展位置或拼写位置,具体取决于它是否来自宏参数。
SourceLocation getFileLoc(SourceLocation Loc) const {
if (Loc.isFileID()) return Loc;
return getFileLocSlowCase(Loc);
}
SourceLocation SourceManager::getFileLocSlowCase(SourceLocation Loc) const {
do {
if (isMacroArgExpansion(Loc))
Loc = getImmediateSpellingLoc(Loc);
else
Loc = getImmediateExpansionRange(Loc).first;
} while (!Loc.isFileID());
return Loc;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2568 次 |
| 最近记录: |