私は、clangプラグインを書いて、どの機能が呼び出されているのか、他のものが過負荷設定にあるのかを調べることができます。ルックアップ・ルールをトレースして、なぜオーバーロード・セットの候補が破棄され、なぜオーバーロード・セットの中で最良の候補であるのかを知ることができます。
私はオーバーロードセットなどを決定するのにはプレイしていませんが、以下は簡単な出発点です:特定の名前の関数(現在ハードコードされている ) 見つかった。また、検出されたオーバーロードも印刷されます。
私は(当然、これらは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
使用打ち鳴らすのバージョンは、デバッグ情報を使用して構築されています。それ以外の場合は」doesnのデバッグシンボルが見つかったようです。おそらく、ツールを直接構築し、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");
コードがきれいでなく、あなたが探しているものを実際に実行していません。しかし、関数宣言の書式を少し整えて、Sema
オブジェクトで少し調べてみると、それがマッチしないなどの理由で、あなたが探しているツールに合理的に近いコードが得られる可能性があります。
多少オフフックですが、オーバーロードされた束からどのような特定の関数が呼び出されるかを着実に予測できない場合、それは貧弱な設計です。あなたのオーバーロードバージョンは明らかに区別されるべきです。 – Mikhail
@Mikhail私は正しい過負荷を予測していました。それはconstオブジェクト内で非constメンバ関数を呼び出したので取り上げられませんでした(私はconstのオーバーロードを追加するのを忘れていました...)。私は知っている、普遍的な参照+オーバーロードを混在させないでください...その適切なことをしない限り。コンパイラはそれをもっと簡単に扱うことができます。 – gnzlbg