Search code examples
c++abstract-syntax-treellvm-clang

AST visitor function call expression not recognizes correctly the function call


Hello I have implemented an AST visitor which is working quite good and it can print in the console the information I want from the AST such as variable declarations, function declarations and function calls. Today while I was experimenting I came across a function call which is not recognized as a function call. Syntacticaly is the same as a function call. Here is the code:

void  
TIFFError(const char* module, const char* fmt, ...)  
{  
   va_list ap;
   va_start(ap, fmt);    <------------------------------ THIS IS THE FUNCTION CALL
   if (_TIFFerrorHandler)
      (*_TIFFerrorHandler)(module, fmt, ap);
   if (_TIFFerrorHandlerExt)
      (*_TIFFerrorHandlerExt)(0, module, fmt, ap);
   va_end(ap);            <--------------------------------AND THIS ONE
}

My code of the ASTvisitor is this:

bool VisitStmt(Stmt *st)
{
    FullSourceLoc FullLocation = astContext->getFullLoc(st->getLocStart());
    FileID fileID = FullLocation.getFileID();
    unsigned int thisFileID = fileID.getHashValue();
    if(thisFileID == 1) //checks if the node is in the main = input file.
    {
        if (CallExpr *call = dyn_cast<CallExpr>(st))
        {
            numFuncCalls++;
            //call->dump(); //prints the corresponding line of the AST.
            FunctionDecl *func_decl;
            if(call->getDirectCallee())
            {
                func_decl = call ->getDirectCallee();
                string funcCall = func_decl->getNameInfo().getName().getAsString();
                cout << "Function call: " << funcCall << " with arguments ";
                APIs << funcCall << ",";
                for(int i=0, j = call->getNumArgs(); i<j; i++)
                {
                    //For each argument it prints its type. The function must be declared otherwise it will return int-for unknown argument type.
                    APIs << call->getArg(i)->getType().getAsString()<< ",";
                    cout << call->getArg(i)->getType().getAsString() << ", ";
                }
                cout << "\n";
            }
            else
            {
                Expr *expr = call->getCallee();
                string exprCall = expr->getStmtClassName();
                cout << "Expression call: " << exprCall << " with arguments ";
                APIs << exprCall << ",";
                for(int i=0, j = call->getNumArgs(); i<j; i++)
                {
                    //For each argument it prints its type. The function must be declared otherwise it will return int-for unknown argument type.
                    APIs << call->getArg(i)->getType().getAsString()<< ",";
                    cout << call->getArg(i)->getType().getAsString() << ", ";
                }
                cout << "\n";
            }
        }
    }
    return true;
}

The expression if(call->getDirectCallee()) is not true for those calls.

How can I extract the "function name" and its arguments like I am doing with the "normal" function calls? Or even somebody give me an insight why those calls are not recognized by AST recursive visitor as normal function calls.

Thank you.


Solution

  • The reason it's not showing to you as a function is because it is in fact not a function. If you go look at <cstdarg> header file you will see that the function is a MACRO

    #define va_start(ap, param) __builtin_va_start(ap, param)
    

    Now, it's something that's called LinkageSpecDecl which will link to the actual functiondecl it's pointing to.

    Something you can do to resolve such issues is to look at the raw ASTDump of the code you are trying to parse as it will tell you what to expect.

    For example, I changed your function to this.

    #include <cstdarg>
    
    void TIFFError(const char* module, const char* fmt, ...)  
    {  
        va_list ap;
        va_start(ap, fmt);    <------------------------------ THIS IS THE FUNCTION CALL
        if (_TIFFerrorHandler)
            (*_TIFFerrorHandler)(module, fmt, ap);
        if (_TIFFerrorHandlerExt)
            (*_TIFFerrorHandlerExt)(0, module, fmt, ap);
        va_end(ap);            <--------------------------------AND THIS ONE
    }
    

    And then generated it's ast dump using (assume the upper code is stored in temp.cpp):

    clang -Xclang -ast-dump -fsyntax-only temp.cpp 
    

    Another pointer will be instead of visitStmt and checking for functiondecl in that, what you can do is to implement visitFuncDecl, visitDeclRef, and others because that would visit them separately. you won't have to do cast and maintain cases as everything will come to you in a proper function. You can read more about how visitor patterns work for that. I don't have a very good link otherwise I would have given you that as well.