AST 访问者函数调用表达式无法正确识别函数调用

AST visitor function call expression not recognizes correctly the function call

本文关键字:函数调用 识别 访问者 表达式 AST      更新时间:2023-10-16

您好,我已经实现了一个 AST 访问者,它运行良好,它可以在控制台中打印我想要从 AST 获得的信息,例如变量声明、函数声明和函数调用。今天,当我进行实验时,我遇到了一个未被识别为函数调用的函数调用。语法与函数调用相同。这是代码:

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
}

我的AST访问者代码是这样的:

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;
}

表达式 if(call->getDirectCallee()) 对于这些调用不成立。

如何提取"函数名称"及其参数,就像我对"普通"函数调用所做的那样?甚至有人让我了解为什么 AST 递归访问者无法将这些调用识别为普通函数调用。

谢谢。

它没有作为函数显示给你的原因是因为它实际上不是一个函数。如果你去看<cstdarg>头文件,你会看到该函数是一个宏

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

现在,它被称为LinkageSpecDecl,它将链接到它所指向的实际功能。

要解决这些问题,您可以做的是查看您尝试解析的代码的原始 ASTDump,因为它会告诉您会发生什么。

例如,我将您的函数更改为此函数。

#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
}

然后使用(假设上面的代码存储在 temp.cpp 中)生成它的 ast 转储:

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

另一个指针将代替visitStmt并检查功能decl,您可以做的是实现visitFuncDecl,visitDeclRef和其他,因为这将分别访问它们。 您不必进行投射和维护案例,因为一切都会在适当的功能中交给您。您可以阅读有关访问者模式如何为此工作的更多信息。我没有一个很好的链接,否则我也会给你。