Search code examples
clangabstract-syntax-treellvm-clang

Building call graphs using Clang AST, link parameters to arguments


I am trying to build call graphs using Clang AST.

Is there a way to somehow link the parameters of a function to the arguments of an inner function call?

For example, given the following function:

void chainedIncrement(int *ptr) {
    simplePointerIncr(ptr);

    for (int i=0;i<3;i++) {
        simplePointerIncr(ptr);
    }
}

I looking for a way to be able to link ptr from chainedIncrement function to the argument of simplePointerIncr function. Doing this will allow building a call graph. Maybe there is a way of getting the same id while calling getId() on parameters and arguments.

I tried to use the following AST matcher:

functionDecl(hasDescendant(callExpr(callee(functionDecl().bind("calleeFunc")),unless(isExpansionInSystemHeader())).bind("callExpr");)).bind("outerFunc")

It seems that arguments are of type Expr while function parameters are of type ParmVarDecl. Assuming that the parameter is passed as-is, without modification to an inner function, is there a way to link them somehow?

Thanks

UPDATE: Added my solution

There is a matcher called forEachArgumentWithParam(). It allows to bind arguments to a callee function to its parameters.

Another matcher, equalsBoundNode() allows to bind the parameters of the outer function, to the arguments of the callee function.

auto calleeArgVarDecl = declRefExpr(to(varDecl().bind("callerArg")));

auto innerCallExpr = callExpr(
        forEachArgumentWithParam(calleeArgVarDecl, parmVarDecl().bind("calleeParam")),
        callee(functionDecl().bind("calleeFunc")),unless(isExpansionInSystemHeader())).bind("callExpr");

auto fullMatcher = functionDecl(forEachDescendant(innerCallExpr),forEachDescendant(parmVarDecl(equalsBoundNode("callerArg")).bind("outerFuncParam"))).bind("outerFunc");

Solution

  • There is a matcher called forEachArgumentWithParam(). It allows to bind arguments to a callee function to its parameters.

    Another matcher, equalsBoundNode() allows to bind the parameters of the outer function, to the arguments of the callee function.

    auto calleeArgVarDecl = declRefExpr(to(varDecl().bind("callerArg")));
    
    auto innerCallExpr = callExpr(
            forEachArgumentWithParam(calleeArgVarDecl, parmVarDecl().bind("calleeParam")),
            callee(functionDecl().bind("calleeFunc")),unless(isExpansionInSystemHeader())).bind("callExpr");
    
    auto fullMatcher = functionDecl(forEachDescendant(innerCallExpr),forEachDescendant(parmVarDecl(equalsBoundNode("callerArg")).bind("outerFuncParam"))).bind("outerFunc");