0

我有一个匹配构造函数中的 uninit 双字段的问题。鉴于下面的代码

class un_init_double {
  public:
    un_init_double() {
      init_param_ = 0;
    }
    bool compare(un_init_double& other) {
      if (other.un_init_param_ == un_init_param_) {
        return true;
      }
      return false;
    }
  private:
    double un_init_param_;
    double init_param_;
};

我想匹配未在构造函数中调用二元运算符 = 的 un_init_param_ 字段。但我找不到这样做的方法。

我在 clang-query 中输入以下命令

clang-query> match cxxRecordDecl(
has(fieldDecl(hasType(asString("double"))).bind("double_field")), has(cxxConstructorDecl(hasDescendant(binaryOperator(hasEitherOperand(memberExpr()))))))

但是如何指定 memberExpr 与 prew 部分 fieldDecl 相关?换句话说,如何指定fieldDecl和memberExpr的连接?

我找到了匹配 init_param_ 的方法,但是如何找到没有匹配的字段?


clang-query> match cxxRecordDecl(has(cxxConstructorDecl(hasDescendant(binaryOperator(hasEitherOperand(memberExpr(hasDeclaration(fieldDecl(hasType(asString("double"))))).bind("member")))))))

Match #1:

~/code_test/ast_matcher/test.cc:9:7: note: "member" binds here
      init_param_ = 0;
      ^~~~~~~~~~~
~/code_test/ast_matcher/test.cc:6:1: note: "root" binds here
class un_init_double {
^~~~~~~~~~~~~~~~~~~~~~
1 match.
clang-query>
4

1 回答 1

0

调试时,我编写了一个复杂的方法来执行此检查:

// match record
cxxRecordDecl(
  has(
    // constuctor has init double fieldDecl with binaryoperator = , bind to init_double_field
    cxxConstructorDecl(
      hasDescendant(
        binaryOperator(
          hasOperatorName("="),
          hasEitherOperand(memberExpr(hasDeclaration(fieldDecl(hasType(asString("double"))).bind("init_double_field"))))
        )
      )
    )
  ),
  has(
    // match double field which didn't call binaryoperator = in constructor
    fieldDecl(hasType(asString("double")), unless(equalsBoundNode("init_double_field"))).bind("un_init_double_field")
  )
)

好像行得通,但是如果我在构造函数中加一句:“ un_init_param_ = 1;”,还是把un_init_param_当作uninit_field。发现它是由 ast 匹配器导致的,它只会匹配第一个而不是全部匹配。所以我将匹配器修改为:

cxxRecordDecl(
  has(
    cxxConstructorDecl(
      forEachDescendant(
        binaryOperator(
          hasOperatorName("="),
          hasEitherOperand(memberExpr(hasDeclaration(fieldDecl(hasType(asString("double"))).bind("init_double_field"))))
        )
      )
    )
  ), 
  has(
      fieldDecl(hasType(asString("double")), unless(equalsBoundNode("init_double_field"))).bind("un_init_double_field")
  )
)

我将原始 test.cpp 修改为:

int f(int x) {
  int result = (x / 42);
  return result;
}

class un_init_double {
  public:
    un_init_double() {
      init_param_0_ = 0;
      init_param_1_ = 0;
    }
    bool compare(un_init_double& other) {
      if (other.un_init_param_ == un_init_param_) {
        return true;
      }
      return false;
    }
  private:
    double un_init_param_;
    double init_param_0_;
    double init_param_1_;
};

新的 ast 匹配器可以匹配如下:

Match #1:

/home/qcraft/code_test/ast_dump/test.cpp:20:5: note: "init_double_field" binds here
    double init_param_0_;
    ^~~~~~~~~~~~~~~~~~~~
/home/qcraft/code_test/ast_dump/test.cpp:6:1: note: "root" binds here
class un_init_double {
^~~~~~~~~~~~~~~~~~~~~~
/home/qcraft/code_test/ast_dump/test.cpp:19:5: note: "un_init_double_field" binds here
    double un_init_param_;
    ^~~~~~~~~~~~~~~~~~~~~

Match #2:

/home/qcraft/code_test/ast_dump/test.cpp:21:5: note: "init_double_field" binds here
    double init_param_1_;
    ^~~~~~~~~~~~~~~~~~~~
/home/qcraft/code_test/ast_dump/test.cpp:6:1: note: "root" binds here
class un_init_double {
^~~~~~~~~~~~~~~~~~~~~~
/home/qcraft/code_test/ast_dump/test.cpp:19:5: note: "un_init_double_field" binds here
    double un_init_param_;
    ^~~~~~~~~~~~~~~~~~~~~
2 matches.
clang-query> 

于 2022-01-30T03:52:50.787 回答