使用Clang AST访客匹配传递给ForStmt的条件中的函数的参数

问题描述

我试图匹配传递给ForStmt条件的整数值。但是,loopbound是对FunctionDecl调用,我似乎并没有通过ParamVarDecl得到它。

MWE: 我的测试示例:

void testASTVistor (int N) {
  N = 123;
  for (int i = 0; i <= GetBoundFunc(N),i++ ){
    //do Sth;
  }  
}

这是AST转储:

FunctionDecl 0x5602066f0db8 <FOO.cpp:XXX:XXX> col:X implicit used GetBoundFunc 'unsigned short (unsigned short) noexcept' extern
|-ParmVarDecl 0x5602066f0e50 <<invalid sloc>> <invalid sloc> 'unsigned short'
|-NoThrowAttr 0x5602066f0eb8 <col:X> Implicit
|-ConstAttr 0x5602066f0ef8 <col:X> Implicit
`-Attr 0x5602066f0f08 <col:X> Implicit

ASTRecursiveVisitor:

class BinaryVisitor : public clang::RecursiveASTVisitor<BinaryVisitor> {
public:
  bool VisitBinaryOperator(clang::BinaryOperator *BO) {
  
      if (const CallExpr *RHS = dyn_cast<CallExpr>(BO->getRHS()->IgnoreParenImpCasts())) {
        if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(RHS->getDirectCallee())) {
          if (FD->getNameAsstring().std::string::find("GetBoundFunc") != std::string::npos) {       
            if (const ParmVarDecl *Bound = dyn_cast<ParmVarDecl>(FD->getParamDecl(0))) {

    return true;
            }
          }
        }
};

/// ...
BinaryVisitor visitor;
visitor.TraverseDecl(someDecl);

我不确定为什么在这里Bound作为Null指针返回。我已经调试了代码,直到之前的IfStmt为止,它们似乎仍然有效。任何帮助将不胜感激。

解决方法

首先,示例代码(n = 123i <= myBoundFunc(N),i++)中似乎有一些错别字。

无论如何,了解AST发生什么的最简单方法是转储AST。 假设这是测试程序:

int myBoundFunc(int);

void testASTVistor (int N) {
  N = 123;
  for (int i = 0; i <= myBoundFunc(N); i++ ){
    //do Sth;
  }
}

您可以要求Clang转储AST:

clang -cc1 -ast-dump test.c

您将获得以下输出:

TranslationUnitDecl 0x7fd77b024408 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x7fd77b024ca0 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x7fd77b0249a0 '__int128'
|-TypedefDecl 0x7fd77b024d10 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x7fd77b0249c0 'unsigned __int128'
|-TypedefDecl 0x7fd77b024ff8 <<invalid sloc>> <invalid sloc> implicit __NSConstantString 'struct __NSConstantString_tag'
| `-RecordType 0x7fd77b024df0 'struct __NSConstantString_tag'
|   `-Record 0x7fd77b024d68 '__NSConstantString_tag'
|-TypedefDecl 0x7fd77b025090 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x7fd77b025050 'char *'
|   `-BuiltinType 0x7fd77b0244a0 'char'
|-TypedefDecl 0x7fd77b025368 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list 'struct __va_list_tag [1]'
| `-ConstantArrayType 0x7fd77b025310 'struct __va_list_tag [1]' 1
|   `-RecordType 0x7fd77b025170 'struct __va_list_tag'
|     `-Record 0x7fd77b0250e8 '__va_list_tag'
|-FunctionDecl 0x7fd77b0158d0 <test.c:1:1,col:20> col:5 used myBoundFunc 'int (int)'
| `-ParmVarDecl 0x7fd77b015800 <col:17> col:20 'int'
`-FunctionDecl 0x7fd77b015a98 <line:3:1,line:8:1> line:3:6 testASTVistor 'void (int)'
  |-ParmVarDecl 0x7fd77b0159d8 <col:21,col:25> col:25 used N 'int'
  `-CompoundStmt 0x7fd77b015df8 <col:28,line:8:1>
    |-BinaryOperator 0x7fd77b015b80 <line:4:3,col:7> 'int' '='
    | |-DeclRefExpr 0x7fd77b015b40 <col:3> 'int' lvalue ParmVar 0x7fd77b0159d8 'N' 'int'
    | `-IntegerLiteral 0x7fd77b015b60 <col:7> 'int' 123
    `-ForStmt 0x7fd77b015dc0 <line:5:3,line:7:3>
      |-DeclStmt 0x7fd77b015c40 <line:5:8,col:17>
      | `-VarDecl 0x7fd77b015bb8 <col:8,col:16> col:12 used i 'int' cinit
      |   `-IntegerLiteral 0x7fd77b015c20 <col:16> 'int' 0
      |-<<<NULL>>>
      |-BinaryOperator 0x7fd77b015d58 <col:19,col:37> 'int' '<='
      | |-ImplicitCastExpr 0x7fd77b015d40 <col:19> 'int' <LValueToRValue>
      | | `-DeclRefExpr 0x7fd77b015c58 <col:19> 'int' lvalue Var 0x7fd77b015bb8 'i' 'int'
      | `-CallExpr 0x7fd77b015d00 <col:24,col:37> 'int'
      |   |-ImplicitCastExpr 0x7fd77b015ce8 <col:24> 'int (*)(int)' <FunctionToPointerDecay>
      |   | `-DeclRefExpr 0x7fd77b015c78 <col:24> 'int (int)' Function 0x7fd77b0158d0 'myBoundFunc' 'int (int)'
      |   `-ImplicitCastExpr 0x7fd77b015d28 <col:36> 'int' <LValueToRValue>
      |     `-DeclRefExpr 0x7fd77b015c98 <col:36> 'int' lvalue ParmVar 0x7fd77b0159d8 'N' 'int'
      |-UnaryOperator 0x7fd77b015d98 <col:40,col:41> 'int' postfix '++'
      | `-DeclRefExpr 0x7fd77b015d78 <col:40> 'int' lvalue Var 0x7fd77b015bb8 'i' 'int'
      `-CompoundStmt 0x7fd77b015db0 <col:45,line:7:3>

如果我的问题正确无误,那么您正在寻找以下代码段:

  | `-CallExpr 0x7fd77b015d00 <col:24,col:37> 'int'
  |   |-ImplicitCastExpr 0x7fd77b015ce8 <col:24> 'int (*)(int)' <FunctionToPointerDecay>
  |   | `-DeclRefExpr 0x7fd77b015c78 <col:24> 'int (int)' Function 0x7fd77b0158d0 'myBoundFunc' 'int (int)'
  |   `-ImplicitCastExpr 0x7fd77b015d28 <col:36> 'int' <LValueToRValue>
  |     `-DeclRefExpr 0x7fd77b015c98 <col:36> 'int' lvalue ParmVar 0x7fd77b0159d8 'N'

在这种情况下,您不需要FunctionDecl,而是可以通过CallExpr获取RHS->getArg(0)的第一个arg并将其转换为DeclRefExpr,然后做进一步检查以获取所需的值。


FunctionDecl::getParamDecl返回NULL开始,很难不见myBoundFunc声明。