【问题标题】:AST visitor function call expression not recognizes correctly the function callAST 访问者函数调用表达式无法正确识别函数调用
【发布时间】:2023-03-18 04:24:02
【问题描述】:

您好,我已经实现了一个运行良好的 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
}

我的 ASTvisitor 代码是这样的:

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 递归访问者识别为正常的函数调用。

谢谢。

【问题讨论】:

    标签: c++ abstract-syntax-tree llvm-clang


    【解决方案1】:

    它没有作为函数显示给您的原因是它实际上不是函数。如果你去看&lt;cstdarg&gt;头文件你会发现这个函数是一个宏

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

    现在,它被称为LinkageSpecDecl,它将链接到它所指向的实际函数decl。

    解决此类问题的方法是查看您尝试解析的代码的原始 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
    }
    

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

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

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

    【讨论】:

    • 感谢您的回答。这将澄清事情并让我继续前进。我转储了相应的行,我可以看到 __builtin_va_start(ap, param) 但我以前从未遇到过类似的事情(为函数调用定义宏。)。关于你的最后一点,我已经实现了 VisitVarDecl 和 VisitFuctionDecl。 VisitStmt 是为了帮助我获取函数调用。如果有更好的方法来获取它们,请告诉我。
    • 您可以调用visitCallExpr、visitCXXMemberCallExpr等函数来进行常规函数和成员函数调用。可能还有更多,但我不知道。另外,如果您的原始问题得到解决,如果您标记它,我将不胜感激。
    • 感谢您的评论。我不知道 visitCallExpr 存在!!我没有在 doxygen 中遇到该功能。我正在使用这个来源clang.llvm.org/doxygen/classclang_1_1idx_1_1ASTVisitor.html你是对的。 VisitCallExpr() 也存在..
    • 由于我没有与 Clang 中的 ASTVisiters 一起工作,所以我从不详细介绍所有内容。但是,他们似乎对每个数据结构都有一个访问者回调。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 2015-05-02
    相关资源
    最近更新 更多