How to match specify stmt inside a double for loop body?

I want to match callExpr inside a double for loop body which ref to the loop init variable. See the follow code snippet:

for (int I = 0; ...) {
  for (int J = 0;  ...) {
    ...
   doSomething(I, J); // this one I want to match
   int X = I;
   int Y = J;
   doSomething(X, Y); // also match this one
   doSomething(1, 2); //  but not this one
  }
}

I can match the double for loop and the call stmt, but I don’t known how to bound to the I and J, any suggestions?
Thanks

You need to create a .bind("identifier") in the matcher for the loop variable, where "identifier" is a unique (within the matcher) identifier string that the matched nodes will be associated with, and then you need to iterate the arguments of the callExpr (either with hasArgument and index, or hasAnyArgument, or with the forEachArgumentWithParam) where you want to have the argument passed to be a declRefExpr(to(varDecl(equalsBoundNode("identifier")))). Because you have two variables, you’ll need to repeat this sub-matcher for separate indices, and identifiers.

You might also want to use the traverse() “matcher” to ignore implicit nodes, because virtually always if an argument is passed, it actually is an ImplicitCast <LValue2RValue> first, and then the DeclRefExpr in the AST.

It is also generally advised to use either clang-query on the command-line (with enable output dump so you always see the AST fragments) or use Compiler Explorer (aka Godbolt) with the appropriate splits. (First change compiler from GCC to Clang, then use the “Add tool” and add Clang-Query, and optionally also an AST View.) In the browser, there are fancy features like mousing over a statement result in highlights in the source-code and the AST view. (It’s also easier to tinker with the expressions when you’re starting out, because you don’t have to deal with editing inputs in an interactive terminal, nor having to deal with recompiling Clang-Tidy all the time you make a change.)


Eventually, you’ll have to bind nodes to some identifier anyway because the check() function needs to receive a node for which it can emit diagnostics. (Usually, the node has a location, and a diagnostic is emitted at that particular location.)

Thanks, it works with equalsBoundNode.
Both clang-query and clang-check are nice tool, I use them a lot these days. But the problem is I don’t know what matcher can be use to match some special cases. As AST Matcher Reference here and the ASTMatchers.h header not always contains example and description.

One more question, now I use compoundStmt to match the callExpr in loop body, but only find the first callExpr. Is it any other way to match all the call exprs?

compoundStmt(anyOf(
                  has(callExpr(callee(DoSthDecl), hasArgument(0, RefI),
                               hasArgument(1, RefJ))
                          .bind("doSth")),
                  allOf(has(VarX), has(VarY),
                        has(callExpr(callee(DoSthDecl), hasArgument(0, RefX),
                                     hasArgument(1, RefY))
                                .bind("doSth")))))

That depends heavily on what you are trying to match in particular. You get the first CallExpr because your top level match fires only once, for the compound-statement, which has the relevant child.

There are iterating matches like hasDescendant (transitive children search but match only once), or forEachDescendant. Usually matchers with the name forEach in them will create a new top-level match (and thus a check()) callback for each child matched, and the top-level matched node will just be the same.

In more trivial cases, simply restructuring the matcher so that the outermost matcher is more appropriate helps with these issues, but I think because you are binding declarations from the enclosing for loops already, you will need some sort of for-each like behaviour. So you will need to match the “double for loop” on the top level, and foreach-match the calls inside. And you will get as many check() calls as there are calls inside. Some bound nodes will change, some will stay the same.

It also helps if you have many smaller matchers that you combine together. In the extreme case, you can use the AST_MATCHER macros to create (within the scope of your check’s TU!) local matchers where your actual match predicate is imperative C++ code querying the AST library.