【问题标题】:Clang AST Matchers: how to find function body from a function declaration?Clang AST Matchers:如何从函数声明中找到函数体?
【发布时间】:2020-02-27 14:42:51
【问题描述】:

我正在尝试编写一个简单的 clang-tidy 检查器,它将检查多次调用 fopen() 的构造函数。我的意图是发现潜在的内存泄漏,以防第二次fopen() 调用中发生任何异常。

class Dummy_file
{
  FILE *f1_;
  FILE *f2_;
  public:
    Dummy_file(const char* f1_name, const char* f2_name, const char * mode){
        f1_ = fopen(f1_name, mode);
        f2_ = fopen(f2_name, mode);
    }
    ~Dummy_file(){
        fclose(f1_);
        fclose(f2_);
    }
};

使用这个

callExpr(callee(functionDecl(hasName("fopen")))).bind("fopencalls")

能够找到所有fopen() 调用。

但是我找不到cxxConstructorDecl使用这个。

cxxConstructorDecl(has(callExpr(callee(functionDecl(hasName("fopen")))))).bind("ctr")

我很怀疑,因为我使用的是cxxConstructorDecl,我的过滤器没有应用于构造函数体。 那么如何从函数声明中找到函数体呢?

【问题讨论】:

    标签: clang clang++ clang-ast-matchers


    【解决方案1】:

    简短说明

    您应该使用hasDescendant 匹配器而不是has 匹配器。 has 仅检查测试节点的 直接 子节点是否匹配,hasDescendant 匹配 任何 子节点。

    在这里你可以看到你的例子:

      |-CXXConstructorDecl <line:8:3, line:11:3> line:8:3 Dummy_file 'void (const char *, const char *, const char *)'
      | |-ParmVarDecl <col:14, col:26> col:26 used f1_name 'const char *'
      | |-ParmVarDecl <col:35, col:47> col:47 used f2_name 'const char *'
      | |-ParmVarDecl <col:56, col:68> col:68 used mode 'const char *'
      | `-CompoundStmt <col:74, line:11:3>
      |   |-BinaryOperator <line:9:5, col:30> 'FILE *' lvalue '='
      |   | |-MemberExpr <col:5> 'FILE *' lvalue ->f1_ 0x55d36491a230
      |   | | `-CXXThisExpr <col:5> 'Dummy_file *' this
      |   | `-CallExpr <col:11, col:30> 'FILE *'
      |   |   |-ImplicitCastExpr <col:11> 'FILE *(*)(const char *__restrict, const char *__restrict)' <FunctionToPointerDecay>
      |   |   | `-DeclRefExpr <col:11> 'FILE *(const char *__restrict, const char *__restrict)' lvalue Function 0x55d3648fa220 'fopen' 'FILE *(const char *__restrict, const char *__restrict)'
      |   |   |-ImplicitCastExpr <col:17> 'const char *' <LValueToRValue>
      |   |   | `-DeclRefExpr <col:17> 'const char *' lvalue ParmVar 0x55d36491a310 'f1_name' 'const char *'
      |   |   `-ImplicitCastExpr <col:26> 'const char *' <LValueToRValue>
      |   |     `-DeclRefExpr <col:26> 'const char *' lvalue ParmVar 0x55d36491a400 'mode' 'const char *'
    

    CallExpr 不是CXXConstructorDecl 的子代,而是BinaryOperator 的子代。

    解决方案

    下面我完成了你的匹配器并在clang-query中检查了它。

    clang-query> match cxxConstructorDecl(hasDescendant(callExpr(callee(functionDecl(hasName("fopen")))).bind("fopencall"))).bind("ctr")
    
    Match #1:
    
    $TEST_DIR/test.cpp:8:3: note: "ctr" binds here
      Dummy_file(const char *f1_name, const char *f2_name, const char *mode) {
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    $TEST_DIR/test.cpp:9:11: note: "fopencall" binds here
        f1_ = fopen(f1_name, mode);
              ^~~~~~~~~~~~~~~~~~~~
    $TEST_DIR/test.cpp:8:3: note: "root" binds here
      Dummy_file(const char *f1_name, const char *f2_name, const char *mode) {
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1 match.
    

    我希望这能回答你的问题!

    【讨论】:

      猜你喜欢
      • 2020-03-21
      • 1970-01-01
      • 1970-01-01
      • 2016-10-21
      • 1970-01-01
      • 2015-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多