2013-11-20 8 views
14

Wie kann ich die eingestellte Überladungsauflösung prüfen?So überprüfen Sie die Überladungsauflösung, die für eine bestimmte Rufstelle eingestellt wurde

Ich habe 4 konkurrierende Funktionen in mehreren Call-Sites verwendet. An einer Aufrufseite erwarte ich, dass eine Funktion aufgerufen wird, aber eine andere wird vom Compiler aufgerufen. Ich weiß nicht warum/es ist nicht trivial. Um zu lernen, was los ist, benutze ich enable_if/disable_if, um Funktionen ein-/auszuschalten, aber das ist wirklich langsam/langwierig/nervig.

Also möchte ich der Compiler mir sagen "Warum?". Das heißt, für diese einzelnen Aufrufort:

  • alle von ADL gefunden Funktionen,
  • alle Funktionen in der Überladungsauflösung Satz,
  • alle von der Überladungsauflösung abgelehnt Funktionen eingestellt und warum sie abgelehnt wurden, und
  • die Ränge der Funktionen in der Überladungsauflösung eingestellt sowie der Grund für ihre Reihen.

Informationen zur Zugriffssteuerung sind nicht erforderlich.

Grundsätzlich hoffe ich auf die Aufrufstelle mit einem #pragma oder ähnlichem (__builtin ...) zu markieren. Aber libclang wäre auch eine Option.

Ich habe Zugang zu Tip-of-Trunk und gcc, kann aber auch andere Compiler/Tools installieren.

+2

Etwas offtopic, aber wenn Sie nicht fest vorhersagen können, welche bestimmte Funktion von dem überladenen Haufen aufgerufen wird, ist es ein schlechtes Design. Ihre überladenen Versionen sollten offensichtlich unterschieden werden. – Mikhail

+1

@Mikhail Ich habe die richtige Überlastung vorhergesagt. Es wurde nicht abgeholt, weil es eine nicht-konstante Elementfunktion in einem const-Objekt aufgerufen hat (ich hatte vergessen, eine const-Überladung hinzuzufügen ... mein Schlechter). Ich weiß, mischen Sie nicht universelle Referenzen + Überladung ... es sei denn, es ist das Richtige zu tun.Der Compiler könnte den Umgang damit viel einfacher machen. – gnzlbg

Antwort

5

Ich kann mir vorstellen, ein clang Plug-in schreiben zu prüfen, welche Funktion aufgerufen wird und was andere in der Überlasteinstellung sind. Ich würde denken, die Nachschlage-Regeln zu verfolgen und herauszufinden, warum die Kandidaten aus der Überladungsmenge verworfen werden und warum die ausgewählte Funktion der beste Kandidat in der Überladungsmenge ist, ist etwas ganz anderes.

Ich habe nicht mit der Ermittlung von Überladungssätzen usw. gespielt. Unten ist jedoch ein einfacher Ausgangspunkt: ein Clang-Plug-In, das die Funktion namens if eine Funktion mit einem bestimmten Namen (derzeit fest codiert "foo") gefunden. Es werden auch die gefundenen Überladungen gedruckt.

ich den Code kompilieren und es mit den Befehlen ausgeführt wird (natürlich, diese in einer make Datei gespeichert sind):

/opt/llvm-debug/bin/clang -I/usr/include/c++/4.2.1 -I/opt/llvm-debug/include -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -g -fno-exceptions -fno-rtti -c -o MacOS/overloads.o overloads.cpp 
/opt/llvm-debug/bin/clang -L/opt/llvm-debug/lib -Wl,-undefined,dynamic_lookup -dynamiclib -o MacOS/overloads.dylib MacOS/overloads.o 
/opt/llvm-debug/bin/clang -cc1 -load MacOS/overloads.dylib -plugin overloads -plugin-arg-overloads argument -fexceptions tst.cpp 

Die Version von Klirren verwendet wird, mit Debug-Informationen gebaut: sonst ist es doesn‘ t scheint ein Debug-Symbol zu finden. Ich sollte wahrscheinlich herausfinden, wie man ein Werkzeug direkt baut und nicht innerhalb von Klängen läuft.

#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"); 

Der Code ist nicht hübsch und tut nicht wirklich, was Sie suchen. Formatieren Sie die Funktionsdeklarationen ein bisschen netter, möglicherweise ein wenig mit dem Objekt Sema untersuchen, warum es keine Übereinstimmung ist, etc. könnte den Code einigermaßen nahe an das Werkzeug, das Sie suchen, denke ich.