#include "clang/Basic/Version.h"

#if CLANG_VERSION_MAJOR == 3 && CLANG_VERSION_MINOR == 4 && !defined(CLANG_VERSION_PATCHLEVEL)
#elif CLANG_VERSION_MAJOR == 3 && CLANG_VERSION_MINOR == 4 && CLANG_VERSION_PATCHLEVEL == 2
#elif CLANG_VERSION_MAJOR == 3 && CLANG_VERSION_MINOR == 6 && CLANG_VERSION_PATCHLEVEL == 2
#elif CLANG_VERSION_MAJOR == 3 && CLANG_VERSION_MINOR == 7 && CLANG_VERSION_PATCHLEVEL == 1
#else
#warning "Invalid clang version used! Only 3.4, 3.4.2, 3.6.2, and 3.7.1 are supported by this code."
#endif

#include "ClangIntroSema.h"
#include "ClangWeaverBase.h"
using namespace clang;

#ifdef __APPLE__
#define WRAP(x) x
#else
#define WRAP(x) __wrap_##x
#endif

extern "C" void WRAP(_ZN5clang4Sema31ActOnStartCXXMemberDeclarationsEPNS_5ScopeEPNS_4DeclENS_14SourceLocationEbS5_) (
    Sema &that, Scope *S, Decl *TagDecl, SourceLocation FinalLoc, bool IsFinalSpelledSealed, SourceLocation LBraceLoc);
void WRAP(_ZN5clang4Sema31ActOnStartCXXMemberDeclarationsEPNS_5ScopeEPNS_4DeclENS_14SourceLocationEbS5_) (
    Sema &that, Scope *S, Decl *TagDecl, SourceLocation FinalLoc, bool IsFinalSpelledSealed, SourceLocation LBraceLoc) {
  ClangIntroSema &sema = (ClangIntroSema&)that;
  sema.ActOnStartCXXMemberDeclarations(S, TagDecl, FinalLoc, IsFinalSpelledSealed,
      LBraceLoc);
}

extern "C" void __real__ZN5clang4Sema31ActOnStartCXXMemberDeclarationsEPNS_5ScopeEPNS_4DeclENS_14SourceLocationEbS5_ (
    clang::Sema &that, clang::Scope *S, clang::Decl *TagDecl, clang::SourceLocation FinalLoc,
    bool IsFinalSpelledSealed, clang::SourceLocation LBraceLoc);
void RealActOnStartCXXMemberDeclarations (clang::Sema &that, clang::Scope *S,
    clang::Decl *TagDecl, clang::SourceLocation FinalLoc,
    bool IsFinalSpelledSealed, clang::SourceLocation LBraceLoc) {
  __real__ZN5clang4Sema31ActOnStartCXXMemberDeclarationsEPNS_5ScopeEPNS_4DeclENS_14SourceLocationEbS5_ (that, S, TagDecl,
        FinalLoc, IsFinalSpelledSealed, LBraceLoc);
}


extern "C" void WRAP(_ZN5clang4Sema19ActOnBaseSpecifiersEPNS_4DeclEPPNS_16CXXBaseSpecifierEj)(
    clang::Sema &that, clang::Decl *ClassDecl, clang::CXXBaseSpecifier **Bases, unsigned NumBases);
void WRAP(_ZN5clang4Sema19ActOnBaseSpecifiersEPNS_4DeclEPPNS_16CXXBaseSpecifierEj)(
    clang::Sema &that, clang::Decl *ClassDecl, clang::CXXBaseSpecifier **Bases, unsigned NumBases) {
  ClangIntroSema &sema = (ClangIntroSema&)that;
  sema.ActOnBaseSpecifiers (ClassDecl, Bases, NumBases);
}

extern "C" void __real__ZN5clang4Sema19ActOnBaseSpecifiersEPNS_4DeclEPPNS_16CXXBaseSpecifierEj(
    clang::Sema &sema, clang::Decl *ClassDecl, clang::CXXBaseSpecifier **Bases, unsigned NumBases);
void RealActOnBaseSpecifiers (clang::Sema &that, clang::Decl *ClassDecl,
    clang::CXXBaseSpecifier **Bases, unsigned NumBases) {
  __real__ZN5clang4Sema19ActOnBaseSpecifiersEPNS_4DeclEPPNS_16CXXBaseSpecifierEj(
      that, ClassDecl, Bases, NumBases);
}

WeaverBase *macro_recorder = 0;

extern "C" void __real__ZN5clang12Preprocessor3LexERNS_5TokenE(clang::Preprocessor &that, clang::Token &Result);
extern "C" void WRAP(_ZN5clang12Preprocessor3LexERNS_5TokenE)(clang::Preprocessor &that, clang::Token &Result);
void WRAP(_ZN5clang12Preprocessor3LexERNS_5TokenE)(clang::Preprocessor &that, clang::Token &Result) {
  static int lex_nested = 0;
  lex_nested++;
  __real__ZN5clang12Preprocessor3LexERNS_5TokenE(that, Result);
  lex_nested--;
  if (!lex_nested && macro_recorder) {
    macro_recorder->handle_token (that, Result);
  }
}

extern "C" void WRAP(_ZN5clang4Sema33ActOnFinishCXXMemberSpecificationEPNS_5ScopeENS_14SourceLocationEPNS_4DeclES3_S3_PNS_13AttributeListE)(
    clang::Sema &that, clang::Scope* S, clang::SourceLocation RLoc, Decl *TagDecl,
    clang::SourceLocation LBrac, clang::SourceLocation RBrac, clang::AttributeList *AttrList);
void WRAP(_ZN5clang4Sema33ActOnFinishCXXMemberSpecificationEPNS_5ScopeENS_14SourceLocationEPNS_4DeclES3_S3_PNS_13AttributeListE)(
    clang::Sema &that, clang::Scope* S, clang::SourceLocation RLoc, Decl *TagDecl,
    clang::SourceLocation LBrac, clang::SourceLocation RBrac, clang::AttributeList *AttrList) {
  ClangIntroSema &sema = (ClangIntroSema&)that;
  sema.ActOnFinishCXXMemberSpecification(S, RLoc, TagDecl, LBrac, RBrac, AttrList);
}

extern "C" void __real__ZN5clang4Sema33ActOnFinishCXXMemberSpecificationEPNS_5ScopeENS_14SourceLocationEPNS_4DeclES3_S3_PNS_13AttributeListE(
    clang::Sema &that, clang::Scope* S, clang::SourceLocation RLoc, Decl *TagDecl,
    clang::SourceLocation LBrac, clang::SourceLocation RBrac, clang::AttributeList *AttrList);
void RealActOnFinishCXXMemberSpecification (clang::Sema &that, clang::Scope* S,
    clang::SourceLocation RLoc, Decl *TagDecl, clang::SourceLocation LBrac,
    clang::SourceLocation RBrac, clang::AttributeList *AttrList) {
  __real__ZN5clang4Sema33ActOnFinishCXXMemberSpecificationEPNS_5ScopeENS_14SourceLocationEPNS_4DeclES3_S3_PNS_13AttributeListE(
      that, S, RLoc, TagDecl, LBrac, RBrac, AttrList);
}


extern "C" void WRAP(_ZN5clang4Sema25ActOnEndOfTranslationUnitEv)(clang::Sema &that);
void WRAP(_ZN5clang4Sema25ActOnEndOfTranslationUnitEv)(clang::Sema &that) {
  ClangIntroSema &sema = (ClangIntroSema&)that;
  sema.ActOnEndOfTranslationUnit();
}

extern "C" void __real__ZN5clang4Sema25ActOnEndOfTranslationUnitEv(clang::Sema &that);
void RealActOnEndOfTranslationUnit(clang::Sema &that) {
  __real__ZN5clang4Sema25ActOnEndOfTranslationUnitEv(that);
}

extern "C" bool WRAP(_ZN5clang4Sema19canSkipFunctionBodyEPNS_4DeclE)(clang::Sema &that, clang::Decl *D);
bool WRAP(_ZN5clang4Sema19canSkipFunctionBodyEPNS_4DeclE)(clang::Sema &that, clang::Decl *D) {
  ClangIntroSema &sema = (ClangIntroSema&)that;
  return sema.canSkipFunctionBody(D);
}

extern "C" bool __real__ZN5clang4Sema19canSkipFunctionBodyEPNS_4DeclE(clang::Sema &that, clang::Decl *D);
bool RealCanSkipFunctionBody(clang::Sema &that, clang::Decl *D) {
  return __real__ZN5clang4Sema19canSkipFunctionBodyEPNS_4DeclE(that, D);
}
