0

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.

Andreas Geo
  • 365
  • 2
  • 15

1 Answers1

0

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.

Nishant Sharma
  • 683
  • 9
  • 16
  • Thank you for your answer. This will clarify things and will get me moving on. I dump the corresponding line and I can see the __builtin_va_start(ap, param) but I have never came accross something like that before (defining a macro for a function call.). On your last point I have already implemented VisitVarDecl and VisitFuctionDecl. The VisitStmt is to help me get the function calls. If there is a better way to get them please let me know. – Andreas Geo Jul 09 '16 at 10:43
  • You can call functions like visitCallExpr, visitCXXMemberCallExpr for a regular function and a member function call. There might be more but I am not aware of that. Also, if your original question is resolved I will appreciate if you mark it. – Nishant Sharma Jul 11 '16 at 00:47
  • Thank you for your comment. I didnt know visitCallExpr exists!! I didn't came across that function in the doxygen. I was using this source http://clang.llvm.org/doxygen/classclang_1_1idx_1_1ASTVisitor.html You are right. VisitCallExpr() also exists.. – Andreas Geo Jul 11 '16 at 11:01
  • Since I am not working with ASTVisiters in Clang, I never went too much into details as to what all is there. But, it seems like they have a visiter callback for every data structure. – Nishant Sharma Jul 11 '16 at 11:17