clang 플러그인을 호출하여 어떤 함수가 호출되는지 그리고 다른 함수가 오버로드 집합에 있는지를 상상할 수 있습니다. 조회 규칙을 추적하고 왜 과부하 집합의 후보가 삭제되고 왜 선택된 함수가 과부하 집합에서 가장 적합한 후보인지는 알 수있을 것입니다.
오버로드 세트 등을 결정하는 데 익숙하지 않았습니다. 그러나 다음과 같은 간단한 시작점이 있습니다. 특정 이름 (현재 하드 코드 된) 인 경우 호출되는 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
디버그 기호를 찾은 것 같습니다. 아마도 도구를 직접 빌드하고 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 overload ...를 추가하는 것을 잊어 버렸습니다 ...). 나도 알아, 유니버설 참조 + 오버로드를 섞어하지 마십시오 ... 옳은 일을하지 않는 한.컴파일러는 쉽게 처리 할 수 있습니다. – gnzlbg