如果语句包含宏,则clang无法替换该语句 我使用CLAN尝试和C++ C++解析一些C++文件,并使所有的断片对都使用特定的样式。

如果语句包含宏,则clang无法替换该语句 我使用CLAN尝试和C++ C++解析一些C++文件,并使所有的断片对都使用特定的样式。,c++,clang,clang++,C++,Clang,Clang++,示例: **Original** switch(...) { case 1: { <code> }break; case 2: { <code> break; } } **After replacement** switch(...) { case 1: { <code> break; } case 2: { &l

示例

**Original**

switch(...)
{
   case 1:
   {
      <code>
   }break;

   case 2:
   {
      <code>
      break;
   }
}

**After replacement**

switch(...)
{
   case 1:
   {
      <code>
      break;
   }

   case 2:
   {
      <code>
      break;
   }
}
到目前为止,如果代码部分不包含任何宏,我所拥有的正是我想要的。 我的问题是:clang是否以不同的方式对待扩展宏(如果我转储有问题的语句,它将显示扩展版本)?如果是这样的话,我怎样才能让它工作呢

其他可能有帮助的信息:

我使用新创建的CompoundStmt替换每个案例的子语句,我注意到ReplaceStmt如果“from”参数包含宏,则返回true,而方法返回true的唯一方式是

(from->())


返回-1

您的问题是由的设计引起的

文章如下:


使用clang的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
)和随后的
true
返回值(这意味着失败-请参阅文档)

发生的情况如下:您收到了两个标记,其中第一个是宏ID(将返回true),而后者不是

为了成功地获得宏扩展语句的范围,我们需要后退一步,并与作为所有拼写位置和实例化位置的查询网关(如果您不记得这些术语,请后退一步)的需要进行通信。我无法比提供的详细描述更清楚:

可以查询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!";
replacer\u语句
是用于替换的语句

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;
}
i、 e.宏扩展语句的完整和成功替换


参考资料:

  • 强氧剂
  • 叮当声源代码

为了获取与宏扩展相关的文件位置,可以使用API函数检索信息:

SourceLocation startLoc = rewriter.getSourceMgr().getFileLoc(
    declaration_statement->getLocStart());
SourceLocation endLoc = rewriter.getSourceMgr().getFileLoc(
    declaration_statement->getLocEnd());
此API函数与Marco在其代码中编写的函数相同,但会自动执行

如果我们看一下函数的实现getFileLoc():

以下是该功能的说明: 给定Loc,如果是宏位置,则返回扩展位置或拼写位置,具体取决于它是否来自宏参数

SourceLocation startLoc = rewriter.getSourceMgr().getFileLoc(
    declaration_statement->getLocStart());
SourceLocation endLoc = rewriter.getSourceMgr().getFileLoc(
    declaration_statement->getLocEnd());
 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;
}