2013-11-20 7 views
14

Come posso controllare la risoluzione di sovraccarico impostata?Come ispezionare la risoluzione di sovraccarico impostata per un determinato sito di chiamata

Ho 4 funzioni concorrenti utilizzate in più siti di chiamata. In un sito di chiamata, mi aspetto che venga chiamata una funzione, ma un altro viene prelevato dal compilatore. Non so perché/non è banale. Per sapere cosa sta succedendo, sto usando enable_if/disable_if per attivare/disattivare le funzioni, ma questo è veramente lento/noioso/fastidioso.

Quindi vorrei che il compilatore mi dicesse "Perché?". Cioè, per questo singolo sito chiamata:

  • tutte le funzioni che si trovano da ADL,
  • tutte le funzioni nel set la risoluzione di sovraccarico,
  • tutte le funzioni respinti dalla risoluzione di sovraccarico impostate e il motivo per cui sono state respinte, e
  • i ranghi delle funzioni nella risoluzione di sovraccarico impostata e il motivo per i loro ranghi.

Non sono richieste informazioni sul controllo dell'accesso.

Fondamentalmente spero di contrassegnare il sito di chiamata con uno #pragma o simile (__builtin ...). Ma libclang sarebbe anche un'opzione.

Ho accesso a clang tip-of-trunk e gcc, ma se necessario è possibile installare altri compilatori/strumenti.

+2

Leggermente offopesto, ma quando non è possibile prevedere costantemente quale funzione particolare verrà chiamata dal gruppo sovraccarico, è un design scadente. Le tue versioni di overload dovrebbero essere ovviamente differenziate. – Mikhail

+1

@Mikhail stavo predicendo il sovraccarico corretto. Non veniva raccolto perché chiamava una funzione membro non const in un oggetto const (avevo dimenticato di aggiungere un overload const ... mio male). Lo so, non mescolare riferimenti universali + sovraccarico ... a meno che non sia la cosa giusta da fare.Il compilatore potrebbe renderlo molto più facile da gestire. – gnzlbg

risposta

5

Posso immaginare di scrivere un plug-in clang ispezionando quale funzione viene chiamata e quali altre sono nel set di sovraccarico. Penso che tracciando le regole di ricerca e scoprendo perché i candidati dal set di sovraccarico vengono scartati e perché la funzione scelta è la migliore candidata nel set di sovraccarico è qualcosa di molto diverso, però.

Non ho giocato con i set di sovraccarico, ecc. Tuttavia, di seguito è un semplice punto di partenza: un plug-in clang che stampa la funzione chiamata se una funzione con un nome specifico (attualmente codificata per essere "foo") è stato trovato. Stampa anche i sovraccarichi trovati.

Sto compilando il codice ed eseguirlo con i comandi (ovviamente, questi sono memorizzati in un file di make):

/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 

La versione di clang utilizzato è costruito con le informazioni di debug: in caso contrario esso doesn' t sembra trovare un simbolo di debug. Probabilmente dovrei scoprire come creare direttamente uno strumento e non correre da dentro il 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"); 

Il codice non è bello e in realtà non sta facendo quello che stai cercando. Tuttavia, la formattazione delle dichiarazioni di funzione è un po 'più bella, forse indagando un po' con l'oggetto Sema perché non è una corrispondenza, ecc. Potrebbe ottenere il codice ragionevolmente vicino allo strumento che stai cercando, credo.