C++ 如何检查给定呼叫站点的过载解决方案集

C++ 如何检查给定呼叫站点的过载解决方案集,c++,debugging,gcc,clang,overload-resolution,C++,Debugging,Gcc,Clang,Overload Resolution,如何检查过载分辨率集 我在多个呼叫站点中使用了4个相互竞争的功能。在一个调用站点中,我希望调用一个函数,但编译器会调用另一个函数。我不知道为什么/这不是小事。为了了解发生了什么,我使用enable\u if/disable\u if来打开/关闭函数,但这真的很慢/乏味/烦人 所以我想让编译器告诉我“为什么?”。也就是说,对于此单一呼叫站点: ADL发现的所有功能 重载分辨率集中的所有函数 从重载解析集中拒绝的所有函数以及拒绝的原因,以及 重载解析集中函数的秩及其秩的原因 不需要有关访问控制的

如何检查过载分辨率集

我在多个呼叫站点中使用了4个相互竞争的功能。在一个调用站点中,我希望调用一个函数,但编译器会调用另一个函数。我不知道为什么/这不是小事。为了了解发生了什么,我使用
enable\u if/disable\u if
来打开/关闭函数,但这真的很慢/乏味/烦人

所以我想让编译器告诉我“为什么?”。也就是说,对于此单一呼叫站点:

  • ADL发现的所有功能
  • 重载分辨率集中的所有函数
  • 从重载解析集中拒绝的所有函数以及拒绝的原因,以及
  • 重载解析集中函数的秩及其秩的原因
不需要有关访问控制的信息

基本上,我希望用
#pragma
或类似的(
u-builtin
..)标记呼叫站点。但libclang也是一种选择

我可以访问tip of trunk clang和gcc,但如果需要,可以安装其他编译器/工具。

我可以想象编写一个插件来检查调用的函数以及重载集中的其他函数。不过,我认为追踪查找规则,找出重载集中的候选函数被丢弃的原因,以及所选函数是重载集中的最佳候选函数的原因是完全不同的

我还没有尝试过确定重载集等。但是,下面是一个简单的起点:一个叮当作响的插件,如果找到一个具有特定名称的函数(当前硬编码为
“foo”
),它将打印所调用的函数。它还打印找到的重载

我正在编译代码并使用命令运行它(显然,这些命令存储在
make
文件中):

使用的clang版本是使用调试信息构建的:否则它似乎找不到调试符号。我可能应该了解如何直接构建工具,而不是从clang内部运行

#include <clang/Frontend/FrontendPluginRegistry.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Lex/Preprocessor.h>
#include <clang/Lex/PPCallbacks.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/AST.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Sema/Sema.h>
#include <clang/Sema/Lookup.h>
#include <llvm/Support/raw_ostream.h>
#include <string>

using namespace clang;
using namespace llvm;
typedef clang::CompilerInstance  CI;
typedef clang::DeclGroupRef      DGR;
typedef clang::DiagnosticsEngine DE;

// ----------------------------------------------------------------------------

namespace
{
    struct Consumer: clang::ASTConsumer
    {
        Consumer(CI& c, std::string const& name): c_(&c), name_(name) {}
        bool HandleTopLevelDecl(clang::DeclGroupRef DG);
        CI*         c_;
        std::string name_;
    };
}

// ----------------------------------------------------------------------------

struct Visitor: RecursiveASTVisitor<Visitor>
{
    CI*         c_;
    std::string name_;
    Visitor(CI* c, std::string const& name): c_(c), name_(name) {}

    bool VisitCallExpr(CallExpr* d);
};

bool Visitor::VisitCallExpr(CallExpr* c) {
    FunctionDecl* fun = c->getDirectCallee();
    if (fun && fun->getNameAsString() == this->name_) {
        SourceLocation w(c->getExprLoc());
        DE &de(this->c_->getDiagnostics());
        int id = de.getCustomDiagID(DE::Warning, "function call: %0");
        int info = de.getCustomDiagID(DE::Note, "function called");
        DiagnosticBuilder(de.Report(w, id))
            << fun->getNameAsString()
            ;
        DiagnosticBuilder(de.Report(fun->getLocStart(), info))
            << fun->getNameAsString()
            ;
        Sema& sema = this->c_->getSema();
        LookupResult result(sema, fun->getDeclName(), w, Sema::LookupOrdinaryName);
        DeclContext* context = fun->getDeclContext();
        if (sema.LookupName(result, sema.getScopeForContext(context))) {
            int over = de.getCustomDiagID(DE::Note, "function overload");
            LookupResult::Filter filter = result.makeFilter();
            while (filter.hasNext()) {
                DiagnosticBuilder(de.Report(filter.next()->getLocStart(), over))
                    ;
            }
            filter.done();
        }
    }
    //else {
    //    // I think the callee was a function object or a function pointer
    //}

    return true;
}

void doDecl(Consumer* c, Decl* d) {
    Visitor(c->c_, c->name_).TraverseDecl(d);
}

// ----------------------------------------------------------------------------

bool Consumer::HandleTopLevelDecl(DeclGroupRef DG) {
    std::for_each(DG.begin(), DG.end(),
        std::bind1st(std::ptr_fun(&doDecl), this));
    return true;
}

// ----------------------------------------------------------------------------

namespace
{
    class Plug
        : public clang::PluginASTAction
    {
    protected:
        ASTConsumer*
        CreateASTConsumer(CompilerInstance& c, llvm::StringRef);
        bool ParseArgs(clang::CompilerInstance const&,
                       std::vector<std::string> const&) {
            return true;
        }
    };
}

ASTConsumer*
Plug::CreateASTConsumer(CompilerInstance& c, llvm::StringRef) {
    return new Consumer(c, "foo");
}

static clang::FrontendPluginRegistry::Add<Plug>
    registerPlugin("overloads", "report overloads of a function at a call");
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间铿锵;
使用名称空间llvm;
typedef-clang::CompilerInstance CI;
typedef-clang::DeclGroupRef-DGR;
typedef clang::诊断引擎DE;
// ----------------------------------------------------------------------------
名称空间
{
结构使用者:clang::ASTConsumer
{
消费者(CI&c,std::string const&name):c_(&c),name_(name){}
bool handletopleveloveldecl(clang::DeclGroupRef DG);
CI*c_;
std::字符串名称;
};
}
// ----------------------------------------------------------------------------
结构访问者:RecursiveASTVisitor
{
CI*c_;
std::字符串名称;
访问者(CI*c,std::string const&name):c_(c),name_(name){}
bool VisitCallExpr(CallExpr*d);
};
bool Visitor::VisitCallExpr(CallExpr*c){
FunctionDecl*fun=c->getDirectCallee();
if(fun&&fun->getnameastring()==此->名称){
SourceLocation w(c->getExprLoc());
DE&DE(this->c_->getDiagnostics());
int id=de.getCustomDiagID(de::警告,“函数调用:%0”);
int info=de.getCustomDiagID(de::注意,“调用函数”);
诊断生成器(de.Report(w,id))
getNameAsString()
;
DiagnosticBuilder(de.Report(fun->getLocStart(),info))
getNameAsString()
;
Sema&Sema=this->c_->getSema();
LookupResult结果(sema,fun->getDeclName(),w,sema::LookupOrdinaryName);
DeclContext*context=fun->getDeclContext();
if(sema.LookupName(result,sema.getScopeForContext(context))){
int over=de.getCustomDiagID(de::注意,“函数重载”);
LookupResult::Filter Filter=result.makeFilter();
while(filter.hasNext()){
DiagnosticBuilder(de.Report(filter.next()->getLocStart(),结束))
;
}
filter.done();
}
}
//否则{
////我认为被调用方是函数对象或函数指针
//}
返回true;
}
无效doDecl(消费者*c,十二月*d){
访问者(c->c,c->name)。遍历了CL(d);
}
// ----------------------------------------------------------------------------
bool Consumer::HandleTopLevelDecl(DeclGroupRef DG){
std::for_each(DG.begin(),DG.end(),
std::bind1st(std::ptr_-fun(&doDecl),this));
返回true;
}
// ----------------------------------------------------------------------------
名称空间
{
类插头
:public clang::PluginASTAction
{
受保护的:
阿斯特消费者*
CreateASTConsumer(编译器立场&c,llvm::StringRef);
bool ParseArgs(铿锵::编译器状态常量&,
std::vector const&){
返回true;
}
};
}
阿斯特消费者*
Plug::CreateASTConsumer(编译器立场&c,llvm::StringRef){
返回新消费者(c,“foo”);
}
静态clang::FrontendPluginRegistry::Add
registerPlugin(“重载”,“在调用时报告函数重载”);

代码不美观,也没有真正实现您所期望的功能。但是,将函数声明的格式设置得更好一些,可能使用
Sema
对象研究一下为什么它不匹配,等等。我认为,这样可以使代码合理地接近您正在寻找的工具。

有点离题,但是,当您无法稳定地预测将从重载堆中调用什么特定函数时,这是一个糟糕的设计。您的重载版本应该明显不同。@Mikhail我预测的重载是正确的。因为它调用了const对象中的一个非const成员函数(我忘了添加一个const重载…我的错),所以它没有被拾取。我知道,不要混合使用通用引用和重载。。。除非是
#include <clang/Frontend/FrontendPluginRegistry.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Lex/Preprocessor.h>
#include <clang/Lex/PPCallbacks.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/AST.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Sema/Sema.h>
#include <clang/Sema/Lookup.h>
#include <llvm/Support/raw_ostream.h>
#include <string>

using namespace clang;
using namespace llvm;
typedef clang::CompilerInstance  CI;
typedef clang::DeclGroupRef      DGR;
typedef clang::DiagnosticsEngine DE;

// ----------------------------------------------------------------------------

namespace
{
    struct Consumer: clang::ASTConsumer
    {
        Consumer(CI& c, std::string const& name): c_(&c), name_(name) {}
        bool HandleTopLevelDecl(clang::DeclGroupRef DG);
        CI*         c_;
        std::string name_;
    };
}

// ----------------------------------------------------------------------------

struct Visitor: RecursiveASTVisitor<Visitor>
{
    CI*         c_;
    std::string name_;
    Visitor(CI* c, std::string const& name): c_(c), name_(name) {}

    bool VisitCallExpr(CallExpr* d);
};

bool Visitor::VisitCallExpr(CallExpr* c) {
    FunctionDecl* fun = c->getDirectCallee();
    if (fun && fun->getNameAsString() == this->name_) {
        SourceLocation w(c->getExprLoc());
        DE &de(this->c_->getDiagnostics());
        int id = de.getCustomDiagID(DE::Warning, "function call: %0");
        int info = de.getCustomDiagID(DE::Note, "function called");
        DiagnosticBuilder(de.Report(w, id))
            << fun->getNameAsString()
            ;
        DiagnosticBuilder(de.Report(fun->getLocStart(), info))
            << fun->getNameAsString()
            ;
        Sema& sema = this->c_->getSema();
        LookupResult result(sema, fun->getDeclName(), w, Sema::LookupOrdinaryName);
        DeclContext* context = fun->getDeclContext();
        if (sema.LookupName(result, sema.getScopeForContext(context))) {
            int over = de.getCustomDiagID(DE::Note, "function overload");
            LookupResult::Filter filter = result.makeFilter();
            while (filter.hasNext()) {
                DiagnosticBuilder(de.Report(filter.next()->getLocStart(), over))
                    ;
            }
            filter.done();
        }
    }
    //else {
    //    // I think the callee was a function object or a function pointer
    //}

    return true;
}

void doDecl(Consumer* c, Decl* d) {
    Visitor(c->c_, c->name_).TraverseDecl(d);
}

// ----------------------------------------------------------------------------

bool Consumer::HandleTopLevelDecl(DeclGroupRef DG) {
    std::for_each(DG.begin(), DG.end(),
        std::bind1st(std::ptr_fun(&doDecl), this));
    return true;
}

// ----------------------------------------------------------------------------

namespace
{
    class Plug
        : public clang::PluginASTAction
    {
    protected:
        ASTConsumer*
        CreateASTConsumer(CompilerInstance& c, llvm::StringRef);
        bool ParseArgs(clang::CompilerInstance const&,
                       std::vector<std::string> const&) {
            return true;
        }
    };
}

ASTConsumer*
Plug::CreateASTConsumer(CompilerInstance& c, llvm::StringRef) {
    return new Consumer(c, "foo");
}

static clang::FrontendPluginRegistry::Add<Plug>
    registerPlugin("overloads", "report overloads of a function at a call");