Search code examples
c++clang-tidyclang-query

Clang AST matcher for variables compared to different variable types


I am new to clang-tidy and the following is practice so I can move to more complex matchers and tools.

Lets say we have

typedef int my_type;
void foo()
{
       int x = 0;//this should be identified as need to be fixed
       my_type z = 0;
       if( x == z){
               //match this case
       }

}

My goal is to identify variables that are compared against "my_type" in order to fix their declarations by changing their types to my_type.

Right now I am tryng to do the following

     auto my_type_decl = varDecl(hasType(asString("my_type")));
     auto my_type_decl_exp= declRefExpr(to(my_type_decl));
     auto binop = binaryOperator(has(implicitCastExpr(has(my_type_decl_exp))));
     auto other_decl_exp = declRefExpr(hasAncestor(binop), unless(to(my_type_decl)));
     //get ancestor functionDecl
     //get descendant varDecls that match the other_decl_exp

The problem here is that I disregard context. What would be the correct way to go about something like this?


Solution

  • You can bind node matchers to a name, and then retrieve those nodes from the match result.

    For example:

    // Match binary operators
    binaryOperator(
        // that are equality comparisons,
        hasOperatorName("=="),
        // where one side refers to a variable
        hasEitherOperand(ignoringImpCasts(declRefExpr(to(varDecl(
            // whose type is a typedef or type alias
            hasType(typedefNameDecl(
                // named "::my_type"
                hasName("::my_type"),
                // that aliases any type, which is bound to the name "aliased",
                hasType(type().bind("aliased"))))))))),
        // and where one side refers to a variable
        hasEitherOperand(ignoringImpCasts(declRefExpr(to(varDecl(
            // whose type is the same as the type bound to "aliased",
            // which is bound to the name "declToChange".
            hasType(type(equalsBoundNode("aliased")))).bind("declToChange"))))));
    

    And then:

    const auto *declToChange = result.Nodes.getNodeAs<VarDecl>("declToChange");
    

    Note that this matches the equality comparisons, so declToChange might point to the same VarDecl in multiple matches.

    In the following example, this matcher would produce two matches with declToChange bound to x, and none with declToChange bound to y:

    typedef int my_type;
    
    void foo() {
      int x = 0;
      int y = 0;
      my_type z = 0;
    
      if (x == z) {
      }
    
      if (z == x) {
      }
    }