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.
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
@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