diff --git a/include/CppInterOp/CppInterOp.h b/include/CppInterOp/CppInterOp.h index 5e6122fe6..8f55d53f2 100644 --- a/include/CppInterOp/CppInterOp.h +++ b/include/CppInterOp/CppInterOp.h @@ -733,7 +733,7 @@ CPPINTEROP_API bool ActivateInterpreter(TInterp_t I); /// Clang-REPL, etcetera). In practice, the selected interpreter should not /// matter, since the library will function in the same way. ///\returns the current interpreter instance, if any. -CPPINTEROP_API TInterp_t GetInterpreter(); +CPPINTEROP_API TInterp_t GetInterpreter(TInterp_t I = nullptr); /// Sets the Interpreter instance with an external interpreter, meant to /// be called by an external library that manages it's own interpreter. diff --git a/lib/CppInterOp/CppInterOp.cpp b/lib/CppInterOp/CppInterOp.cpp index f1527b4a8..92ece4760 100755 --- a/lib/CppInterOp/CppInterOp.cpp +++ b/lib/CppInterOp/CppInterOp.cpp @@ -60,7 +60,9 @@ #include "llvm/Support/raw_ostream.h" #include +#include #include +#include #include #include #include @@ -71,6 +73,7 @@ #include #include #include +#include #include #include #include @@ -95,18 +98,19 @@ namespace Cpp { using namespace clang; using namespace llvm; using namespace std; - -#define LOCK(InterpInfo) \ - std::lock_guard interop_lock( \ - (InterpInfo).InterpreterLock) +using namespace std::chrono_literals; #define NULLPTR (static_cast(nullptr)) -struct InterpreterInfo { +class InterpreterInfo { + friend class LOCK; + +private: compat::Interpreter* Interpreter = nullptr; bool isOwned = true; - std::recursive_mutex InterpreterLock; + std::mutex InterpreterLock; +public: InterpreterInfo(compat::Interpreter* I, bool Owned) : Interpreter(I), isOwned(Owned) {} @@ -116,6 +120,7 @@ struct InterpreterInfo { other.Interpreter = nullptr; other.isOwned = false; } + compat::Interpreter& operator*() { return *Interpreter; } InterpreterInfo& operator=(InterpreterInfo&& other) noexcept { if (this != &other) { // Delete current resource if owned @@ -139,6 +144,11 @@ struct InterpreterInfo { // Disable copy semantics (to avoid accidental double deletes) InterpreterInfo(const InterpreterInfo&) = delete; InterpreterInfo& operator=(const InterpreterInfo&) = delete; + + [[nodiscard]] clang::Sema& getSema() const { return Interpreter->getSema(); } + [[nodiscard]] clang::ASTContext& getASTContext() const { + return Interpreter->getSema().getASTContext(); + } }; // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) @@ -148,69 +158,122 @@ static llvm::ManagedStatic>> static llvm::ManagedStatic< std::unordered_map> sInterpreterASTMap; -static std::recursive_mutex InterpreterStackLock; -static std::recursive_mutex LLVMLock; +static int IsSomeThreadWriting = 0; +static std::mutex IsSomeThreadWritingMutex; +static std::mutex InterpreterStackLock; +static std::mutex LLVMLock; // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) +class LOCK { + std::mutex& M; + +public: + LOCK(InterpreterInfo& I) : M(I.InterpreterLock) { + M.lock(); + IsSomeThreadWritingMutex.lock(); + IsSomeThreadWriting++; + IsSomeThreadWritingMutex.unlock(); + } + ~LOCK() { + IsSomeThreadWritingMutex.lock(); + IsSomeThreadWriting--; + IsSomeThreadWritingMutex.unlock(); + M.unlock(); + } + LOCK() = delete; + LOCK(const LOCK&) = delete; + LOCK(LOCK&&) = delete; + LOCK operator=(const LOCK&) = delete; + LOCK operator=(LOCK&&) = delete; +}; + +struct WAIT_ON_ALL { + WAIT_ON_ALL() { + while (true) { + IsSomeThreadWritingMutex.lock(); + if (IsSomeThreadWriting == 0) + return; + IsSomeThreadWritingMutex.unlock(); + std::this_thread::sleep_for(0ms); // give control to other threads + } + } + ~WAIT_ON_ALL() { IsSomeThreadWritingMutex.unlock(); } + WAIT_ON_ALL(const WAIT_ON_ALL&) = delete; + WAIT_ON_ALL(WAIT_ON_ALL&&) = delete; + WAIT_ON_ALL operator=(const WAIT_ON_ALL&) = delete; + WAIT_ON_ALL operator=(WAIT_ON_ALL&&) = delete; +}; + +#define LOCK(InterpInfo) LOCK interop_lock((InterpInfo)) + static InterpreterInfo& getInterpInfo(const clang::Decl* D) { - std::lock_guard Lock(InterpreterStackLock); - if (!D) - return *sInterpreters->back(); - if (sInterpreters->size() == 1) - return *sInterpreters->back(); - return *(*sInterpreterASTMap)[&D->getASTContext()]; + { + std::lock_guard Lock(InterpreterStackLock); + if (!D) + return *sInterpreters->back(); + if (sInterpreters->size() == 1) + return *sInterpreters->back(); + } + // D->getASTContext is not thread safe in the following condition + // thread 1: + // Cpp::Declare("class Klass;") // add a declaration + // thread 2: + // Cpp::Declare("class Klass{};") // add a definition + // thread 3: + // auto result = Cpp::GetNamed("Klass"); + // if (result) + // getInterpInfo(result); // getASTContext may read wrong data + // if definition is being written, + // and the declaration has already been written + WAIT_ON_ALL WAIT; + { + std::lock_guard Lock(InterpreterStackLock); + return *(*sInterpreterASTMap)[&D->getASTContext()]; + } } static InterpreterInfo& getInterpInfo(const void* D) { - std::lock_guard Lock(InterpreterStackLock); - if (!D) - return *sInterpreters->back(); + { + std::lock_guard Lock(InterpreterStackLock); + if (!D) + return *sInterpreters->back(); + if (sInterpreters->size() == 1) + return *sInterpreters->back(); + } QualType QT = QualType::getFromOpaquePtr(D); - if (auto* D = QT->getAsTagDecl()) - return getInterpInfo(D); - if (sInterpreters->size() == 1) - return *sInterpreters->back(); - for (auto& item : *sInterpreterASTMap) { - if (item.first->getAllocator().identifyObject(D)) - return *item.second; + if (auto* D = QT->getAsTagDecl()) { + WAIT_ON_ALL WAIT; + { + std::lock_guard Lock(InterpreterStackLock); + return *(*sInterpreterASTMap)[&D->getASTContext()]; + } + } + WAIT_ON_ALL WAIT; + { + std::lock_guard Lock(InterpreterStackLock); + for (auto& item : *sInterpreterASTMap) { + if (item.first->getAllocator().identifyObject(D)) + return *item.second; + } } llvm_unreachable( "This pointer does not belong to any interpreter instance.\n"); } static InterpreterInfo& getInterpInfo(compat::Interpreter* I) { - std::lock_guard Lock(InterpreterStackLock); + std::lock_guard Lock(InterpreterStackLock); if (!I) return *sInterpreters->back(); - auto res = - std::find_if(sInterpreters->begin(), sInterpreters->end(), - [&](const auto& item) { return item->Interpreter == I; }); + auto res = std::find_if(sInterpreters->begin(), sInterpreters->end(), + [&](const auto& item) { return (&**item) == I; }); if (res != sInterpreters->end()) return **res; llvm_unreachable("Invalid State"); } -static compat::Interpreter& getInterp(const clang::Decl* D) { - std::lock_guard Lock(InterpreterStackLock); - if (!D) - return *getInterpInfo(NULLPTR).Interpreter; - if (sInterpreters->size() == 1) - return *sInterpreters->back()->Interpreter; - return *(*sInterpreterASTMap)[&D->getASTContext()]->Interpreter; -} -static compat::Interpreter& getInterp(const void* D) { - return *getInterpInfo(D).Interpreter; -} - -static clang::Sema& getSema(const clang::Decl* D) { - return getInterpInfo(D).Interpreter->getSema(); -} -static clang::Sema& getSema(const void* D) { return getInterp(D).getSema(); } - -static clang::ASTContext& getASTContext(const clang::Decl* D) { - return getSema(D).getASTContext(); -} -static clang::ASTContext& getASTContext(const void* D) { - return getSema(D).getASTContext(); -} +int Declare(compat::Interpreter& I, const char* code, bool silent); +static TCppType_t GetTypeFromScope(clang::Decl* D, compat::Interpreter& I); +static TCppIndex_t GetNumBases(compat::Interpreter& I, clang::CXXRecordDecl* D); +static TCppScope_t GetBaseClass(clang::CXXRecordDecl* CXXRD, TCppIndex_t ibase); +static TCppScope_t GetGlobalScope(compat::Interpreter& I); static void ForceCodeGen(Decl* D, compat::Interpreter& I) { // The decl was deferred by CodeGen. Force its emission. @@ -295,7 +358,7 @@ void JitCall::ReportInvokeStart(void* result, ArgList args, void* self) const { std::string Name; llvm::raw_string_ostream OS(Name); auto FD = (const FunctionDecl*)m_FD; - FD->getNameForDiagnostic(OS, FD->getASTContext().getPrintingPolicy(), + FD->getNameForDiagnostic(OS, PrintingPolicy((LangOptions())), /*Qualified=*/true); LLVM_DEBUG(dbgs() << "Run '" << Name << "', compiled at: " << (void*)m_GenericCall << " with result at: " << result @@ -308,7 +371,7 @@ void JitCall::ReportInvokeStart(void* object, unsigned long nary, std::string Name; llvm::raw_string_ostream OS(Name); auto FD = (const FunctionDecl*)m_FD; - FD->getNameForDiagnostic(OS, FD->getASTContext().getPrintingPolicy(), + FD->getNameForDiagnostic(OS, PrintingPolicy(LangOptions()), /*Qualified=*/true); LLVM_DEBUG(dbgs() << "Finish '" << Name << "', compiled at: " << (void*)m_DestructorCall); @@ -339,20 +402,19 @@ std::string Demangle(const std::string& mangled_name) { } void EnableDebugOutput(bool value /* =true*/) { - std::lock_guard Lock(LLVMLock); + std::lock_guard Lock(LLVMLock); llvm::DebugFlag = value; } bool IsDebugOutputEnabled() { - std::lock_guard Lock(LLVMLock); + std::lock_guard Lock(LLVMLock); return llvm::DebugFlag; } -static void InstantiateFunctionDefinition(Decl* D) { +static void InstantiateFunctionDefinition(Decl* D, compat::Interpreter& I) { if (auto* FD = llvm::dyn_cast_or_null(D)) { - LOCK(getInterpInfo(FD)); - compat::SynthesizingCodeRAII RAII(&getInterp(FD)); - getSema(FD).InstantiateFunctionDefinition(SourceLocation(), FD, + compat::SynthesizingCodeRAII RAII(&I); + I.getSema().InstantiateFunctionDefinition(SourceLocation(), FD, /*Recursive=*/true, /*DefinitionRequired=*/true); } @@ -416,13 +478,14 @@ bool IsComplete(TCppScope_t scope) { Decl* D = static_cast(scope); - LOCK(getInterpInfo(D)); + auto& IF = getInterpInfo(D); + LOCK(IF); if (isa(D)) { - QualType QT = QualType::getFromOpaquePtr(GetTypeFromScope(scope)); - clang::Sema& S = getSema(D); + QualType QT = QualType::getFromOpaquePtr(GetTypeFromScope(D, *IF)); + clang::Sema& S = IF.getSema(); SourceLocation fakeLoc = GetValidSLoc(S); #ifdef CPPINTEROP_USE_CLING - cling::Interpreter::PushTransactionRAII RAII(&getInterp(D)); + cling::Interpreter::PushTransactionRAII RAII(&*IF); #endif // CPPINTEROP_USE_CLING return S.isCompleteType(fakeLoc, QT); } @@ -619,7 +682,8 @@ size_t GetSizeOfType(TCppType_t type) { return SizeOf(TT->getDecl()); // FIXME: Can we get the size of a non-tag type? - auto TI = getASTContext(type).getTypeInfo(QT); + auto& IF = getInterpInfo(type); + auto TI = IF.getASTContext().getTypeInfo(QT); size_t TypeSize = TI.Width; return TypeSize / 8; } @@ -645,15 +709,18 @@ std::string GetName(TCppType_t klass) { std::string GetCompleteName(TCppType_t klass) { auto* D = (Decl*)klass; - auto& C = getSema(D).getASTContext(); + auto& IF = getInterpInfo(D); + auto& C = IF.getASTContext(); - PrintingPolicy Policy = C.getPrintingPolicy(); + PrintingPolicy Policy((LangOptions())); Policy.SuppressUnwrittenScope = true; Policy.SuppressScope = true; Policy.AnonymousTagLocations = false; Policy.SuppressTemplateArgsInCXXConstructors = false; Policy.SuppressDefaultTemplateArgs = false; Policy.AlwaysIncludeTypeForTemplateArgument = true; + Policy.SuppressTagKeyword = true; + Policy.Bool = true; if (auto* ND = llvm::dyn_cast_or_null(D)) { if (auto* TD = llvm::dyn_cast(ND)) { @@ -696,16 +763,19 @@ std::string GetQualifiedName(TCppType_t klass) { // FIXME: Figure out how to merge with GetCompleteName. std::string GetQualifiedCompleteName(TCppType_t klass) { auto* D = (Decl*)klass; - auto& C = getSema(D).getASTContext(); + auto& IF = getInterpInfo(D); + auto& C = IF.getASTContext(); if (auto* ND = llvm::dyn_cast_or_null(D)) { if (auto* TD = llvm::dyn_cast(ND)) { std::string type_name; QualType QT = C.getTagDeclType(TD); - PrintingPolicy PP = C.getPrintingPolicy(); + PrintingPolicy PP((LangOptions())); PP.FullyQualifiedName = true; PP.SuppressUnwrittenScope = true; PP.SuppressElaboration = true; + PP.SuppressTagKeyword = true; + PP.Bool = true; QT.getAsStringInternal(type_name, PP); return type_name; @@ -736,18 +806,15 @@ std::vector GetUsingNamespaces(TCppScope_t scope) { return {}; } +static TCppScope_t GetGlobalScope(compat::Interpreter& I) { + return I.getSema().getASTContext().getTranslationUnitDecl()->getFirstDecl(); +} + TCppScope_t GetGlobalScope(TInterp_t interp) { - if (interp) { - auto* I = static_cast(interp); - return I->getSema() - .getASTContext() - .getTranslationUnitDecl() - ->getFirstDecl(); - } - return getSema(NULLPTR) - .getASTContext() - .getTranslationUnitDecl() - ->getFirstDecl(); + auto* I = static_cast(interp); + auto& IF = getInterpInfo(I); + LOCK(IF); + return GetGlobalScope(*IF); } static Decl* GetScopeFromType(QualType QT) { @@ -813,32 +880,41 @@ TCppScope_t GetScopeFromCompleteName(const std::string& name, std::string delim = "::"; size_t start = 0; size_t end = name.find(delim); - TCppScope_t curr_scope = 0; + TCppScope_t curr_scope = Cpp::GetGlobalScope(interp); while (end != std::string::npos) { - curr_scope = GetScope(name.substr(start, end - start), curr_scope, interp); + curr_scope = GetScope(name.substr(start, end - start), curr_scope); start = end + delim.length(); end = name.find(delim, start); } return GetScope(name.substr(start, end), curr_scope, interp); } -TCppScope_t GetNamed(const std::string& name, TCppScope_t parent /*= nullptr*/, - TInterp_t interp /*= nullptr*/) { - if (!parent) - parent = GetGlobalScope(interp); - - auto* D = static_cast(parent); - LOCK(getInterpInfo(D)); - +static clang::Decl* GetNamed(compat::Interpreter& I, const std::string& name, + Cpp::Decl* D) { + if (!D) + D = static_cast(GetGlobalScope(I)); D = GetUnderlyingScope(D); auto* Within = llvm::dyn_cast(D); - auto* ND = Cpp_utils::Lookup::Named(&getSema(D), name, Within); + auto* ND = Cpp_utils::Lookup::Named(&I.getSema(), name, Within); if (ND && ND != (clang::NamedDecl*)-1) { - return (TCppScope_t)(ND->getCanonicalDecl()); + return ND->getCanonicalDecl(); } + return nullptr; +} - return 0; +TCppScope_t GetNamed(const std::string& name, TCppScope_t parent /*= nullptr*/, + TInterp_t interp /*= nullptr*/) { + auto* D = static_cast(parent); + InterpreterInfo* IF = nullptr; + if (!D && interp) { + auto* I = static_cast(interp); + IF = &getInterpInfo(I); + } else { + IF = &getInterpInfo(D); + } + LOCK(*IF); + return GetNamed(**IF, name, D); } TCppScope_t GetParentScope(TCppScope_t scope) { @@ -860,23 +936,39 @@ TCppScope_t GetParentScope(TCppScope_t scope) { return (TCppScope_t)P; } -TCppIndex_t GetNumBases(TCppScope_t klass) { - auto* D = (Decl*)klass; - +static TCppIndex_t GetNumBases(compat::Interpreter& I, + clang::CXXRecordDecl* D) { if (auto* CTSD = llvm::dyn_cast_or_null(D)) { - LOCK(getInterpInfo(CTSD)); if (!CTSD->hasDefinition()) - compat::InstantiateClassTemplateSpecialization(getInterp(CTSD), CTSD); + compat::InstantiateClassTemplateSpecialization(I, CTSD); } + if (D->hasDefinition()) + return D->getNumBases(); + return 0; +} + +TCppIndex_t GetNumBases(TCppScope_t klass) { + auto* D = static_cast(klass); if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { - LOCK(getInterpInfo(CXXRD)); - if (CXXRD->hasDefinition()) - return CXXRD->getNumBases(); + auto& IF = getInterpInfo(CXXRD); + LOCK(IF); + return GetNumBases(*IF, CXXRD); } - return 0; } +static TCppScope_t GetBaseClass(clang::CXXRecordDecl* CXXRD, + TCppIndex_t ibase) { + if (CXXRD->getNumBases() <= ibase) + return nullptr; + + auto type = (CXXRD->bases_begin() + ibase)->getType(); + if (const auto* RT = type->getAs()) + return (TCppScope_t)RT->getDecl(); + + return nullptr; +} + TCppScope_t GetBaseClass(TCppScope_t klass, TCppIndex_t ibase) { auto* D = (Decl*)klass; auto* CXXRD = llvm::dyn_cast_or_null(D); @@ -884,14 +976,7 @@ TCppScope_t GetBaseClass(TCppScope_t klass, TCppIndex_t ibase) { return nullptr; LOCK(getInterpInfo(CXXRD)); - if (CXXRD->getNumBases() <= ibase) - return nullptr; - - auto type = (CXXRD->bases_begin() + ibase)->getType(); - if (auto RT = type->getAs()) - return (TCppScope_t)RT->getDecl(); - - return 0; + return GetBaseClass(CXXRD, ibase); } // FIXME: Consider dropping this interface as it seems the same as @@ -975,14 +1060,15 @@ int64_t GetBaseClassOffset(TCppScope_t derived, TCppScope_t base) { CXXRecordDecl* DCXXRD = cast(DD); CXXRecordDecl* BCXXRD = cast(BD); - LOCK(getInterpInfo(DD)); + auto& IF = getInterpInfo(DD); + LOCK(IF); CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, /*DetectVirtual=*/false); DCXXRD->isDerivedFrom(BCXXRD, Paths); // FIXME: We might want to cache these requests as they seem expensive. - return ComputeBaseOffset(getSema(DD).getASTContext(), DCXXRD, Paths.front()); + return ComputeBaseOffset(IF.getASTContext(), DCXXRD, Paths.front()); } template @@ -992,7 +1078,8 @@ static void GetClassDecls(TCppScope_t klass, return; auto* D = (clang::Decl*)klass; - LOCK(getInterpInfo(D)); + auto& IF = getInterpInfo(D); + LOCK(IF); if (auto* TD = dyn_cast(D)) D = GetScopeFromType(TD->getUnderlyingType()); @@ -1002,11 +1089,11 @@ static void GetClassDecls(TCppScope_t klass, auto* CXXRD = dyn_cast(D); #ifdef CPPINTEROP_USE_CLING - cling::Interpreter::PushTransactionRAII RAII(&getInterp(CXXRD)); + cling::Interpreter::PushTransactionRAII RAII(&*IF); #endif // CPPINTEROP_USE_CLING if (CXXRD->hasDefinition()) CXXRD = CXXRD->getDefinition(); - getSema(CXXRD).ForceDeclarationOfImplicitMembers(CXXRD); + IF.getSema().ForceDeclarationOfImplicitMembers(CXXRD); for (Decl* DI : CXXRD->decls()) { if (auto* MD = dyn_cast(DI)) methods.push_back(MD); @@ -1032,7 +1119,7 @@ static void GetClassDecls(TCppScope_t klass, // Result is appended to the decls, i.e. CXXRD, iterator // non-shadowed decl will be push_back later // methods.push_back(Result); - getSema(CXXRD).findInheritingConstructor(SourceLocation(), CXXCD, CUSD); + IF.getSema().findInheritingConstructor(SourceLocation(), CXXCD, CUSD); } } } @@ -1069,15 +1156,16 @@ TCppFunction_t GetDefaultConstructor(compat::Interpreter& interp, TCppFunction_t GetDefaultConstructor(TCppScope_t scope) { auto* CXXRD = static_cast(scope); - return GetDefaultConstructor(getInterp(CXXRD), scope); + return GetDefaultConstructor(*getInterpInfo(CXXRD), scope); } TCppFunction_t GetDestructor(TCppScope_t scope) { auto* D = (clang::Decl*)scope; if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { - LOCK(getInterpInfo(CXXRD)); - getSema(CXXRD).ForceDeclarationOfImplicitMembers(CXXRD); + auto& IF = getInterpInfo(CXXRD); + LOCK(IF); + IF.getSema().ForceDeclarationOfImplicitMembers(CXXRD); return CXXRD->getDestructor(); } @@ -1096,13 +1184,14 @@ std::vector GetFunctionsUsingName(TCppScope_t scope, if (!scope || name.empty()) return {}; - LOCK(getInterpInfo(D)); + auto& IF = getInterpInfo(D); + LOCK(IF); D = GetUnderlyingScope(D); std::vector funcs; llvm::StringRef Name(name); - auto& S = getSema(D); + auto& S = IF.getSema(); DeclarationName DName = &S.getASTContext().Idents.get(name); clang::LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName, For_Visible_Redeclaration); @@ -1124,7 +1213,8 @@ std::vector GetFunctionsUsingName(TCppScope_t scope, TCppType_t GetFunctionReturnType(TCppFunction_t func) { auto* D = (clang::Decl*)func; if (auto* FD = llvm::dyn_cast_or_null(D)) { - LOCK(getInterpInfo(FD)); + auto& IF = getInterpInfo(FD); + LOCK(IF); QualType Type = FD->getReturnType(); if (Type->isUndeducedAutoType()) { bool needInstantiation = false; @@ -1136,7 +1226,7 @@ TCppType_t GetFunctionReturnType(TCppFunction_t func) { } if (needInstantiation) { - InstantiateFunctionDefinition(FD); + InstantiateFunctionDefinition(FD, *IF); } Type = FD->getReturnType(); } @@ -1202,11 +1292,13 @@ std::string GetFunctionSignature(TCppFunction_t func) { std::string Signature; raw_string_ostream SS(Signature); - PrintingPolicy Policy = getASTContext(D).getPrintingPolicy(); + PrintingPolicy Policy((LangOptions())); // Skip printing the body Policy.TerseOutput = true; Policy.FullyQualifiedName = true; Policy.SuppressDefaultTemplateArgs = false; + Policy.SuppressTagKeyword = true; + Policy.Bool = true; FD->print(SS, Policy); SS.flush(); return Signature; @@ -1254,9 +1346,10 @@ bool ExistsFunctionTemplate(const std::string& name, TCppScope_t parent, auto* D = static_cast(parent); auto* Within = llvm::dyn_cast(D); - LOCK(getInterpInfo(D)); + auto& IF = getInterpInfo(D); + LOCK(IF); - auto* ND = Cpp_utils::Lookup::Named(&getSema(D), name, Within); + auto* ND = Cpp_utils::Lookup::Named(&IF.getSema(), name, Within); if ((intptr_t)ND == (intptr_t)0) return false; @@ -1270,21 +1363,26 @@ bool ExistsFunctionTemplate(const std::string& name, TCppScope_t parent, } // Looks up all constructors in the current DeclContext +static void LookupConstructors(compat::Interpreter& I, const std::string& name, + clang::CXXRecordDecl* CXXRD, + std::vector& funcs) { + I.getSema().ForceDeclarationOfImplicitMembers(CXXRD); + DeclContextLookupResult Result = I.getSema().LookupConstructors(CXXRD); + // Obtaining all constructors when we intend to lookup a method under a + // scope can lead to crashes. We avoid that by accumulating constructors + // only if the Decl matches the lookup name. + for (auto* i : Result) + if (GetName(i) == name) + funcs.push_back(i); +} void LookupConstructors(const std::string& name, TCppScope_t parent, std::vector& funcs) { auto* D = (Decl*)parent; if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { - LOCK(getInterpInfo(CXXRD)); - - getSema(CXXRD).ForceDeclarationOfImplicitMembers(CXXRD); - DeclContextLookupResult Result = getSema(CXXRD).LookupConstructors(CXXRD); - // Obtaining all constructors when we intend to lookup a method under a - // scope can lead to crashes. We avoid that by accumulating constructors - // only if the Decl matches the lookup name. - for (auto* i : Result) - if (GetName(i) == name) - funcs.push_back(i); + auto& IF = getInterpInfo(CXXRD); + LOCK(IF); + LookupConstructors(*IF, name, CXXRD, funcs); } } @@ -1294,11 +1392,13 @@ bool GetClassTemplatedMethods(const std::string& name, TCppScope_t parent, if (!D && name.empty()) return false; - LOCK(getInterpInfo(D)); + auto& IF = getInterpInfo(D); + LOCK(IF); // Accumulate constructors - LookupConstructors(name, parent, funcs); - auto& S = getSema(D); + if (auto* CXXRD = llvm::dyn_cast(D)) + LookupConstructors(*IF, name, CXXRD, funcs); + auto& S = IF.getSema(); D = GetUnderlyingScope(D); llvm::StringRef Name(name); DeclarationName DName = &S.getASTContext().Idents.get(name); @@ -1342,11 +1442,11 @@ BestOverloadFunctionMatch(const std::vector& candidates, InterpreterInfo& II = getInterpInfo(static_cast(candidates[0])); LOCK(II); - auto& S = II.Interpreter->getSema(); + auto& S = II.getSema(); auto& C = S.getASTContext(); #ifdef CPPINTEROP_USE_CLING - cling::Interpreter::PushTransactionRAII RAII(II.Interpreter); + cling::Interpreter::PushTransactionRAII RAII(&*II); #endif // The overload resolution interfaces in Sema require a list of expressions. @@ -1472,12 +1572,9 @@ bool IsStaticMethod(TCppConstFunction_t method) { return false; } -TCppFuncAddr_t GetFunctionAddress(const char* mangled_name, - TInterp_t interp /*=nullptr*/) { - auto* I = static_cast(interp); - if (!I) - I = &getInterp(NULLPTR); - auto FDAorErr = compat::getSymbolAddress(*I, mangled_name); +static TCppFuncAddr_t GetFunctionAddress(compat::Interpreter& I, + const char* mangled_name) { + auto FDAorErr = compat::getSymbolAddress(I, mangled_name); if (llvm::Error Err = FDAorErr.takeError()) llvm::consumeError(std::move(Err)); // nullptr if missing else @@ -1485,10 +1582,19 @@ TCppFuncAddr_t GetFunctionAddress(const char* mangled_name, return nullptr; } +TCppFuncAddr_t GetFunctionAddress(const char* mangled_name, + TInterp_t interp /*=nullptr*/) { + auto* I = static_cast(interp); + if (!I) + I = &*getInterpInfo(NULLPTR); + return GetFunctionAddress(*I, mangled_name); +} -static TCppFuncAddr_t GetFunctionAddress(const FunctionDecl* FD) { - const auto get_mangled_name = [](const FunctionDecl* FD) { - auto* MangleCtxt = getASTContext(FD).createMangleContext(); +static TCppFuncAddr_t GetFunctionAddress(const FunctionDecl* FD, + clang::ASTContext& ASTContext) { + const auto get_mangled_name = [](const FunctionDecl* FD, + clang::ASTContext& ASTContext) { + auto* MangleCtxt = ASTContext.createMangleContext(); if (!MangleCtxt->shouldMangleDeclName(FD)) { return FD->getNameInfo().getName().getAsString(); @@ -1506,8 +1612,14 @@ static TCppFuncAddr_t GetFunctionAddress(const FunctionDecl* FD) { }; // Constructor and Destructors needs to be handled differently - if (!llvm::isa(FD) && !llvm::isa(FD)) - return GetFunctionAddress(get_mangled_name(FD).c_str()); + if (!llvm::isa(FD) && !llvm::isa(FD)) { + compat::Interpreter* I = nullptr; + { + std::lock_guard Lock(InterpreterStackLock); + I = &**(*sInterpreterASTMap)[&ASTContext]; + } + return GetFunctionAddress(*I, get_mangled_name(FD, ASTContext).c_str()); + } return 0; } @@ -1515,15 +1627,16 @@ static TCppFuncAddr_t GetFunctionAddress(const FunctionDecl* FD) { TCppFuncAddr_t GetFunctionAddress(TCppFunction_t method) { auto* D = static_cast(method); if (auto* FD = llvm::dyn_cast_or_null(D)) { - LOCK(getInterpInfo(FD)); + auto& IF = getInterpInfo(FD); + LOCK(IF); if ((IsTemplateInstantiationOrSpecialization(FD) || FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization) && !FD->getDefinition()) - InstantiateFunctionDefinition(D); - ASTContext& C = getASTContext(FD); + InstantiateFunctionDefinition(D, *IF); + ASTContext& C = IF.getASTContext(); if (isDiscardableGVALinkage(C.GetGVALinkageForFunction(FD))) - ForceCodeGen(FD, getInterp(FD)); - return GetFunctionAddress(FD); + ForceCodeGen(FD, *IF); + return GetFunctionAddress(FD, C); } return nullptr; } @@ -1542,9 +1655,10 @@ void GetDatamembers(TCppScope_t scope, std::vector& datamembers) { auto* D = (Decl*)scope; if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { - LOCK(getInterpInfo(CXXRD)); + auto& IF = getInterpInfo(CXXRD); + LOCK(IF); - getSema(CXXRD).ForceDeclarationOfImplicitMembers(CXXRD); + IF.getSema().ForceDeclarationOfImplicitMembers(CXXRD); if (CXXRD->hasDefinition()) CXXRD = CXXRD->getDefinition(); @@ -1615,8 +1729,9 @@ TCppScope_t LookupDatamember(const std::string& name, TCppScope_t parent) { Within = llvm::dyn_cast(D); } - LOCK(getInterpInfo(D)); - auto* ND = Cpp_utils::Lookup::Named(&getSema(D), name, Within); + auto& IF = getInterpInfo(D); + LOCK(IF); + auto* ND = Cpp_utils::Lookup::Named(&IF.getSema(), name, Within); if (ND && ND != (clang::NamedDecl*)-1) { if (llvm::isa_and_nonnull(ND)) { return (TCppScope_t)ND; @@ -1691,7 +1806,7 @@ intptr_t GetVariableOffset(compat::Interpreter& I, Decl* D, while (!stack.empty()) { CXXRecordDecl* RD = stack.back(); stack.pop_back(); - size_t num_bases = GetNumBases(RD); + size_t num_bases = GetNumBases(I, RD); bool flag = false; for (size_t i = 0; i < num_bases; i++) { auto* CRD = static_cast(GetBaseClass(RD, i)); @@ -1732,9 +1847,9 @@ intptr_t GetVariableOffset(compat::Interpreter& I, Decl* D, if (!address) { if (!VD->hasInit()) { #ifdef CPPINTEROP_USE_CLING - cling::Interpreter::PushTransactionRAII RAII(&getInterp(VD)); + cling::Interpreter::PushTransactionRAII RAII(&I); #endif // CPPINTEROP_USE_CLING - getSema(VD).InstantiateVariableDefinition(SourceLocation(), VD); + I.getSema().InstantiateVariableDefinition(SourceLocation(), VD); VD = VD->getDefinition(); } if (VD->hasInit() && @@ -1767,9 +1882,10 @@ intptr_t GetVariableOffset(TCppScope_t var, TCppScope_t parent) { auto* D = static_cast(var); if (!D) return 0; - LOCK(getInterpInfo(D)); + auto& IF = getInterpInfo(D); + LOCK(IF); auto* RD = llvm::dyn_cast_or_null(static_cast(parent)); - return GetVariableOffset(getInterp(D), D, RD); + return GetVariableOffset(*IF, D, RD); } // Check if the Access Specifier of the variable matches the provided value. @@ -1815,8 +1931,8 @@ bool IsPODType(TCppType_t type) { if (QT.isNull()) return false; - - return QT.isPODType(getASTContext(type)); + auto& IF = getInterpInfo(type); + return QT.isPODType(IF.getASTContext()); } bool IsPointerType(TCppType_t type) { @@ -1848,7 +1964,8 @@ bool IsRValueReferenceType(TCppType_t type) { TCppType_t GetPointerType(TCppType_t type) { QualType QT = QualType::getFromOpaquePtr(type); - return getASTContext(type) + auto& IF = getInterpInfo(type); + return IF.getASTContext() .getPointerType(QT) .getAsOpaquePtr(); // FIXME: which ASTContext? } @@ -1856,8 +1973,14 @@ TCppType_t GetPointerType(TCppType_t type) { TCppType_t GetReferencedType(TCppType_t type, bool rvalue) { QualType QT = QualType::getFromOpaquePtr(type); if (rvalue) - return getASTContext(type).getRValueReferenceType(QT).getAsOpaquePtr(); - return getASTContext(type).getLValueReferenceType(QT).getAsOpaquePtr(); + return getInterpInfo(type) + .getASTContext() + .getRValueReferenceType(QT) + .getAsOpaquePtr(); + return getInterpInfo(type) + .getASTContext() + .getLValueReferenceType(QT) + .getAsOpaquePtr(); } TCppType_t GetNonReferenceType(TCppType_t type) { @@ -2029,8 +2152,7 @@ TCppType_t GetType(const std::string& name, TInterp_t interp) { if (I) builtin = findBuiltinType(name, I->getSema().getASTContext()); else - builtin = - findBuiltinType(name, getInterp(NULLPTR).getSema().getASTContext()); + builtin = findBuiltinType(name, getInterpInfo(NULLPTR).getASTContext()); if (!builtin.isNull()) return builtin.getAsOpaquePtr(); @@ -2045,16 +2167,13 @@ TCppType_t GetType(const std::string& name, TInterp_t interp) { TCppType_t GetComplexType(TCppType_t type) { QualType QT = QualType::getFromOpaquePtr(type); - LOCK(getInterpInfo(type)); - return getASTContext(type).getComplexType(QT).getAsOpaquePtr(); + auto& IF = getInterpInfo(type); + LOCK(IF); + return IF.getASTContext().getComplexType(QT).getAsOpaquePtr(); } -TCppType_t GetTypeFromScope(TCppScope_t klass) { - if (!klass) - return 0; - - auto* D = (Decl*)klass; - ASTContext& C = getASTContext(D); +static TCppType_t GetTypeFromScope(clang::Decl* D, compat::Interpreter& I) { + ASTContext& C = I.getSema().getASTContext(); if (ValueDecl* VD = dyn_cast(D)) return VD->getType().getAsOpaquePtr(); @@ -2062,10 +2181,19 @@ TCppType_t GetTypeFromScope(TCppScope_t klass) { return C.getTypeDeclType(cast(D)).getAsOpaquePtr(); } +TCppType_t GetTypeFromScope(TCppScope_t klass) { + if (!klass) + return nullptr; + + auto* D = static_cast(klass); + return GetTypeFromScope(D, *getInterpInfo(D)); +} + // Internal functions that are not needed outside the library are // encompassed in an anonymous namespace as follows. namespace { -static unsigned long long gWrapperSerial = 0LL; +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +std::atomic gWrapperSerial = 0LL; enum EReferenceType { kNotReference, kLValueReference, kRValueReference }; @@ -2099,15 +2227,17 @@ void get_type_as_string(QualType QT, std::string& type_name, ASTContext& C, Policy.SuppressTagKeyword = !QT->isEnumeralType(); Policy.FullyQualifiedName = true; Policy.UsePreferredNames = false; + Policy.Bool = true; QT.getAsStringInternal(type_name, Policy); } static void GetDeclName(const clang::Decl* D, ASTContext& Context, std::string& name) { // Helper to extract a fully qualified name from a Decl - PrintingPolicy Policy(Context.getPrintingPolicy()); + PrintingPolicy Policy((LangOptions())); Policy.SuppressTagKeyword = true; Policy.SuppressUnwrittenScope = true; + Policy.Bool = true; Policy.PrintCanonicalTypes = true; if (const TypeDecl* TD = dyn_cast(D)) { // This is a class, struct, or union member. @@ -2136,8 +2266,9 @@ void collect_type_info(const FunctionDecl* FD, QualType& QT, // needed for building the wrapper function. // ASTContext& C = FD->getASTContext(); - PrintingPolicy Policy(C.getPrintingPolicy()); + PrintingPolicy Policy((LangOptions())); Policy.SuppressElaboration = true; + Policy.Bool = true; refType = kNotReference; if (QT->isRecordType()) { if (forArgument) { @@ -2282,10 +2413,10 @@ const DeclContext* get_non_transparent_decl_context(const FunctionDecl* FD) { return DC; } -void make_narg_call(const FunctionDecl* FD, const std::string& return_type, - const unsigned N, std::ostringstream& typedefbuf, - std::ostringstream& callbuf, const std::string& class_name, - int indent_level) { +void make_narg_call(const FunctionDecl* FD, compat::Interpreter& I, + const std::string& return_type, const unsigned N, + std::ostringstream& typedefbuf, std::ostringstream& callbuf, + const std::string& class_name, int indent_level) { // // Make a code string that follows this pattern: // @@ -2308,6 +2439,8 @@ void make_narg_call(const FunctionDecl* FD, const std::string& return_type, bool op_flag = !FD->isOverloadedOperator() || FD->getOverloadedOperator() == clang::OO_Call; + Cpp::Sema& Sema = I.getSema(); + bool ShouldCastFunction = !isa(FD) && N == FD->getNumParams() && op_flag && !FD->isTemplateInstantiation(); @@ -2332,7 +2465,7 @@ void make_narg_call(const FunctionDecl* FD, const std::string& return_type, QualType QT = Ty.getCanonicalType(); std::string arg_type; ASTContext& C = FD->getASTContext(); - get_type_as_string(QT, arg_type, C, C.getPrintingPolicy()); + get_type_as_string(QT, arg_type, C, PrintingPolicy((LangOptions()))); callbuf << arg_type; } if (FD->isVariadic()) @@ -2363,10 +2496,11 @@ void make_narg_call(const FunctionDecl* FD, const std::string& return_type, { std::string complete_name; llvm::raw_string_ostream stream(complete_name); - PrintingPolicy PP = FD->getASTContext().getPrintingPolicy(); + PrintingPolicy PP((LangOptions())); PP.FullyQualifiedName = true; PP.SuppressUnwrittenScope = true; PP.SuppressElaboration = true; + PP.Bool = true; FD->getNameForDiagnostic(stream, PP, /*Qualified=*/false); name = complete_name; @@ -2445,10 +2579,10 @@ void make_narg_call(const FunctionDecl* FD, const std::string& return_type, // available, while there is a move constructor. // include utility header if not already included for std::move - DeclarationName DMove = &getASTContext(FD).Idents.get("move"); - auto result = getSema(FD).getStdNamespace()->lookup(DMove); + DeclarationName DMove = &Sema.getASTContext().Idents.get("move"); + auto result = Sema.getStdNamespace()->lookup(DMove); if (result.empty()) - Cpp::Declare("#include "); + Cpp::Declare(I, "#include ", false); // move construction as needed for classes (note that this is implicit) callbuf << "std::move(*(" << type_name.c_str() << "*)args[" << i << "])"; @@ -2574,7 +2708,7 @@ void make_narg_call_with_return(compat::Interpreter& I, const FunctionDecl* FD, std::ostringstream typedefbuf; std::ostringstream callbuf; indent(callbuf, indent_level); - make_narg_call(FD, "void", N, typedefbuf, callbuf, class_name, + make_narg_call(FD, I, "void", N, typedefbuf, callbuf, class_name, indent_level); callbuf << ";\n"; indent(callbuf, indent_level); @@ -2619,7 +2753,7 @@ void make_narg_call_with_return(compat::Interpreter& I, const FunctionDecl* FD, // // Write the actual function call. // - make_narg_call(FD, type_name, N, typedefbuf, callbuf, class_name, + make_narg_call(FD, I, type_name, N, typedefbuf, callbuf, class_name, indent_level); // // End the placement new. @@ -2643,7 +2777,7 @@ void make_narg_call_with_return(compat::Interpreter& I, const FunctionDecl* FD, std::ostringstream callbuf; indent(callbuf, indent_level); callbuf << "(void)("; - make_narg_call(FD, type_name, N, typedefbuf, callbuf, class_name, + make_narg_call(FD, I, type_name, N, typedefbuf, callbuf, class_name, indent_level); callbuf << ");\n"; indent(callbuf, indent_level); @@ -2659,9 +2793,8 @@ void make_narg_call_with_return(compat::Interpreter& I, const FunctionDecl* FD, int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD, std::string& wrapper_name, std::string& wrapper) { assert(FD && "generate_wrapper called without a function decl!"); - LOCK(getInterpInfo(FD)); - ASTContext& Context = FD->getASTContext(); + ASTContext& Context = I.getSema().getASTContext(); // // Get the class or namespace name. // @@ -2791,7 +2924,7 @@ int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD, // header file. break; } - if (!GetFunctionAddress(FD)) { + if (!GetFunctionAddress(FD, I.getSema().getASTContext())) { if (!Pattern->hasBody()) { llvm::errs() << "TClingCallFunc::make_wrapper" << ":" @@ -2889,7 +3022,7 @@ int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD, } if (needInstantiation) { clang::FunctionDecl* FDmod = const_cast(FD); - InstantiateFunctionDefinition(FDmod); + InstantiateFunctionDefinition(FDmod, I); if (!FD->isDefined(Definition)) { llvm::errs() << "TClingCallFunc::make_wrapper" @@ -3080,12 +3213,18 @@ int get_wrapper_code(compat::Interpreter& I, const FunctionDecl* FD, JitCall::GenericCall make_wrapper(compat::Interpreter& I, const FunctionDecl* FD) { static std::map gWrapperStore; + static std::mutex gWrapperStoreMutex; LOCK(getInterpInfo(FD)); - auto R = gWrapperStore.find(FD); - if (R != gWrapperStore.end()) - return (JitCall::GenericCall)R->second; + { + std::lock_guard Lock(gWrapperStoreMutex); + auto R = gWrapperStore.find(FD); + if (R != gWrapperStore.end()) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) + return (JitCall::GenericCall)R->second; + } + } std::string wrapper_name; std::string wrapper_code; @@ -3103,6 +3242,7 @@ JitCall::GenericCall make_wrapper(compat::Interpreter& I, void* wrapper = compile_wrapper(I, wrapper_name, wrapper_code, withAccessControl); if (wrapper) { + std::lock_guard Lock(gWrapperStoreMutex); gWrapperStore.insert(std::make_pair(FD, wrapper)); } else { llvm::errs() << "TClingCallFunc::make_wrapper" @@ -3174,12 +3314,18 @@ static JitCall::DestructorCall make_dtor_wrapper(compat::Interpreter& interp, //-- static map gDtorWrapperStore; + static std::mutex gDtorWrapperStoreMutex; LOCK(getInterpInfo(D)); - auto I = gDtorWrapperStore.find(D); - if (I != gDtorWrapperStore.end()) - return (JitCall::DestructorCall)I->second; + { + std::lock_guard Lock(gDtorWrapperStoreMutex); + auto I = gDtorWrapperStore.find(D); + if (I != gDtorWrapperStore.end()) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) + return (JitCall::DestructorCall)I->second; + } + } // // Make the wrapper name. @@ -3279,6 +3425,7 @@ static JitCall::DestructorCall make_dtor_wrapper(compat::Interpreter& interp, void* F = compile_wrapper(interp, wrapper_name, wrapper, /*withAccessControl=*/false); if (F) { + std::lock_guard Lock(gDtorWrapperStoreMutex); gDtorWrapperStore.insert(make_pair(D, F)); } else { llvm::errs() << "make_dtor_wrapper" @@ -3288,6 +3435,7 @@ static JitCall::DestructorCall make_dtor_wrapper(compat::Interpreter& interp, } LLVM_DEBUG(dbgs() << "Compiled '" << (F ? "" : "un") << "successfully:\n" << wrapper << "'\n"); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) return (JitCall::DestructorCall)F; } #undef DEBUG_TYPE @@ -3326,7 +3474,7 @@ CPPINTEROP_API JitCall MakeFunctionCallable(TInterp_t I, CPPINTEROP_API JitCall MakeFunctionCallable(TCppConstFunction_t func) { const auto* D = static_cast(func); - return MakeFunctionCallable(&getInterp(D), func); + return MakeFunctionCallable(&*getInterpInfo(D), func); } namespace { @@ -3357,7 +3505,7 @@ static std::string MakeResourcesPath() { TInterp_t CreateInterpreter(const std::vector& Args /*={}*/, const std::vector& GpuArgs /*={}*/) { - std::lock_guard Lock(InterpreterStackLock); + std::lock_guard Lock(InterpreterStackLock); assert(sInterpreters->size() == sInterpreterASTMap->size()); std::string MainExecutableName = sys::fs::getMainExecutable(nullptr, nullptr); @@ -3438,17 +3586,16 @@ TInterp_t CreateInterpreter(const std::vector& Args /*={}*/, sInterpreters->emplace_back( std::make_unique(I, /*Owned=*/true)); sInterpreterASTMap->insert( - {&sInterpreters->back()->Interpreter->getSema().getASTContext(), - sInterpreters->back().get()}); + {&(*sInterpreters->back()).getASTContext(), sInterpreters->back().get()}); assert(sInterpreters->size() == sInterpreterASTMap->size()); return I; } static inline auto find_interpreter_in_stack(TInterp_t I) { - return std::find_if( - sInterpreters->begin(), sInterpreters->end(), - [&I](const auto& Info) { return Info->Interpreter == I; }); + auto* Interp = static_cast(I); + return std::find_if(sInterpreters->begin(), sInterpreters->end(), + [&](const auto& Info) { return (&**Info) == Interp; }); } static inline auto find_interpreter_in_map(InterpreterInfo* I) { @@ -3457,7 +3604,7 @@ static inline auto find_interpreter_in_map(InterpreterInfo* I) { } bool DeleteInterpreter(TInterp_t I /*=nullptr*/) { - std::lock_guard Lock(InterpreterStackLock); + std::lock_guard Lock(InterpreterStackLock); assert(sInterpreters->size() == sInterpreterASTMap->size()); if (sInterpreters->empty()) return false; @@ -3482,7 +3629,7 @@ bool DeleteInterpreter(TInterp_t I /*=nullptr*/) { } TInterp_t TakeInterpreter(TInterp_t I /*=nullptr*/) { - std::lock_guard Lock(InterpreterStackLock); + std::lock_guard Lock(InterpreterStackLock); assert(sInterpreters->size() == sInterpreterASTMap->size()); if (!I) { @@ -3490,7 +3637,7 @@ TInterp_t TakeInterpreter(TInterp_t I /*=nullptr*/) { sInterpreterASTMap->erase(foundAST); InterpreterInfo* res = sInterpreters->back().release(); sInterpreters->pop_back(); - return res->Interpreter; + return &**res; } auto found = find_interpreter_in_stack(I); @@ -3502,18 +3649,17 @@ TInterp_t TakeInterpreter(TInterp_t I /*=nullptr*/) { InterpreterInfo* res = (*found).release(); sInterpreters->erase(found); assert(sInterpreters->size() == sInterpreterASTMap->size()); - return res->Interpreter; + return &**res; } bool ActivateInterpreter(TInterp_t I) { - std::lock_guard Lock(InterpreterStackLock); + std::lock_guard Lock(InterpreterStackLock); if (!I) return false; - auto found = - std::find_if(sInterpreters->begin(), sInterpreters->end(), - [&I](const auto& Info) { return Info->Interpreter == I; }); + auto found = std::find_if(sInterpreters->begin(), sInterpreters->end(), + [&I](const auto& Info) { return (&**Info) == I; }); if (found == sInterpreters->end()) return false; @@ -3523,40 +3669,48 @@ bool ActivateInterpreter(TInterp_t I) { return true; // success } -TInterp_t GetInterpreter() { - std::lock_guard Lock(InterpreterStackLock); +TInterp_t GetInterpreter(TInterp_t I) { + std::lock_guard Lock(InterpreterStackLock); if (sInterpreters->empty()) return nullptr; - return sInterpreters->back()->Interpreter; + if (!I) + return &**sInterpreters->back(); + auto res = std::find_if(sInterpreters->begin(), sInterpreters->end(), + [&](const auto& item) { return (&**item) == I; }); + if (res != sInterpreters->end()) + return &***res; + return nullptr; } void UseExternalInterpreter(TInterp_t I) { - std::lock_guard Lock(InterpreterStackLock); + std::lock_guard Lock(InterpreterStackLock); sInterpreters->emplace_back( std::make_unique(static_cast(I), /*isOwned=*/false)); sInterpreterASTMap->insert( - {&sInterpreters->back()->Interpreter->getSema().getASTContext(), - sInterpreters->back().get()}); + {&(*sInterpreters->back()).getASTContext(), sInterpreters->back().get()}); assert(sInterpreters->size() == sInterpreterASTMap->size()); } void AddSearchPath(const char* dir, bool isUser, bool prepend, TInterp_t I /*=nullptr*/) { auto* interp = static_cast(I); - LOCK(getInterpInfo(interp)); + auto& IF = getInterpInfo(interp); + LOCK(IF); if (interp) interp->getDynamicLibraryManager()->addSearchPath(dir, isUser, prepend); else - getInterp(NULLPTR).getDynamicLibraryManager()->addSearchPath(dir, isUser, - prepend); + (*IF).getDynamicLibraryManager()->addSearchPath(dir, isUser, prepend); } const char* GetResourceDir(TInterp_t I /*=nullptr*/) { auto* interp = static_cast(I); if (interp) return interp->getCI()->getHeaderSearchOpts().ResourceDir.c_str(); - return getInterp(NULLPTR).getCI()->getHeaderSearchOpts().ResourceDir.c_str(); + return (*getInterpInfo(NULLPTR)) + .getCI() + ->getHeaderSearchOpts() + .ResourceDir.c_str(); } ///\returns 0 on success. @@ -3617,11 +3771,12 @@ void DetectSystemCompilerIncludePaths(std::vector& Paths, void AddIncludePath(const char* dir, TInterp_t I /*=nullptr*/) { auto* interp = static_cast(I); - LOCK(getInterpInfo(interp)); + auto& IF = getInterpInfo(interp); + LOCK(IF); if (interp) interp->AddIncludePath(dir); else - getInterp(NULLPTR).AddIncludePath(dir); + (*IF).AddIncludePath(dir); } void GetIncludePaths(std::vector& IncludePaths, bool withSystem, @@ -3631,7 +3786,7 @@ void GetIncludePaths(std::vector& IncludePaths, bool withSystem, if (interp) interp->GetIncludePaths(paths, withSystem, withFlags); else - getInterp(NULLPTR).GetIncludePaths(paths, withSystem, withFlags); + (*getInterpInfo(NULLPTR)).GetIncludePaths(paths, withSystem, withFlags); for (auto& i : paths) IncludePaths.push_back(i); } @@ -3664,18 +3819,20 @@ int Declare(compat::Interpreter& I, const char* code, bool silent) { int Declare(const char* code, bool silent, TInterp_t I /*=nullptr*/) { auto* interp = static_cast(I); - LOCK(getInterpInfo(interp)); + auto& IF = getInterpInfo(interp); + LOCK(IF); if (interp) return Declare(*interp, code, silent); - return Declare(getInterp(NULLPTR), code, silent); + return Declare(*IF, code, silent); } int Process(const char* code, TInterp_t I /*=nullptr*/) { auto* interp = static_cast(I); - LOCK(getInterpInfo(interp)); + auto& IF = getInterpInfo(interp); + LOCK(IF); if (interp) return interp->process(code); - return getInterp(NULLPTR).process(code); + return (*IF).process(code); } intptr_t Evaluate(const char* code, bool* HadError /*=nullptr*/, @@ -3691,11 +3848,12 @@ intptr_t Evaluate(const char* code, bool* HadError /*=nullptr*/, auto* interp = static_cast(I); compat::Interpreter::CompilationResult res; - LOCK(getInterpInfo(interp)); + auto& IF = getInterpInfo(interp); + LOCK(IF); if (interp) res = interp->evaluate(code, V); else - res = getInterp(NULLPTR).evaluate(code, V); + res = (*IF).evaluate(code, V); if (res != 0) { // 0 is success if (HadError) @@ -3711,37 +3869,42 @@ std::string LookupLibrary(const char* lib_name, TInterp_t I /*=nullptr*/) { auto* interp = static_cast(I); if (interp) return interp->getDynamicLibraryManager()->lookupLibrary(lib_name); - return getInterp(NULLPTR).getDynamicLibraryManager()->lookupLibrary(lib_name); + return (*getInterpInfo(NULLPTR)) + .getDynamicLibraryManager() + ->lookupLibrary(lib_name); } bool LoadLibrary(const char* lib_stem, bool lookup, TInterp_t I /*=nullptr*/) { auto* interp = static_cast(I); - LOCK(getInterpInfo(interp)); + auto& IF = getInterpInfo(interp); + LOCK(IF); compat::Interpreter::CompilationResult res; if (interp) res = interp->loadLibrary(lib_stem, lookup); else - res = getInterp(NULLPTR).loadLibrary(lib_stem, lookup); + res = (*IF).loadLibrary(lib_stem, lookup); return res == compat::Interpreter::kSuccess; } void UnloadLibrary(const char* lib_stem, TInterp_t I /*=nullptr*/) { auto* interp = static_cast(I); - LOCK(getInterpInfo(interp)); + auto& IF = getInterpInfo(interp); + LOCK(IF); if (interp) interp->getDynamicLibraryManager()->unloadLibrary(lib_stem); else - getInterp(NULLPTR).getDynamicLibraryManager()->unloadLibrary(lib_stem); + (*IF).getDynamicLibraryManager()->unloadLibrary(lib_stem); } std::string SearchLibrariesForSymbol(const char* mangled_name, bool search_system /*true*/, TInterp_t I /*=nullptr*/) { auto* interp = static_cast(I); - LOCK(getInterpInfo(interp)); + auto& IF = getInterpInfo(interp); + LOCK(IF); if (!interp) - interp = &getInterp(NULLPTR); + interp = &*IF; auto* DLM = interp->getDynamicLibraryManager(); return DLM->searchLibrariesForSymbol(mangled_name, search_system); } @@ -3780,6 +3943,7 @@ bool InsertOrReplaceJitSymbol(compat::Interpreter& I, JITDylib& DyLib = *Jit.getProcessSymbolsJITDylib().get(); if (Error Err = Symbol.takeError()) { + std::lock_guard Lock(LLVMLock); logAllUnhandledErrors(std::move(Err), errs(), "[InsertOrReplaceJitSymbol] error: "); #define DEBUG_TYPE "orc" @@ -3828,42 +3992,45 @@ bool InsertOrReplaceJitSymbol(compat::Interpreter& I, bool InsertOrReplaceJitSymbol(const char* linker_mangled_name, uint64_t address, TInterp_t I /*=nullptr*/) { auto* interp = static_cast(I); - LOCK(getInterpInfo(interp)); + auto& IF = getInterpInfo(interp); + LOCK(IF); if (interp) return InsertOrReplaceJitSymbol(*interp, linker_mangled_name, address); - return InsertOrReplaceJitSymbol(getInterp(NULLPTR), linker_mangled_name, - address); + return InsertOrReplaceJitSymbol(*IF, linker_mangled_name, address); } std::string ObjToString(const char* type, void* obj) { - LOCK(getInterpInfo(NULLPTR)); // FIXME: not enough information to lock the - // current interpreter - return getInterp(NULLPTR).toString(type, obj); + auto& IF = getInterpInfo(NULLPTR); + LOCK(IF); // FIXME: not enough information to lock the + // current interpreter + return (*IF).toString(type, obj); } static Decl* InstantiateTemplate(TemplateDecl* TemplateD, - TemplateArgumentListInfo& TLI, Sema& S, + TemplateArgumentListInfo& TLI, + compat::Interpreter& I, bool instantiate_body) { // This is not right but we don't have a lot of options to choose from as a // template instantiation requires a valid source location. - SourceLocation fakeLoc = GetValidSLoc(S); + SourceLocation fakeLoc = GetValidSLoc(I.getSema()); if (auto* FunctionTemplate = dyn_cast(TemplateD)) { FunctionDecl* Specialization = nullptr; clang::sema::TemplateDeductionInfo Info(fakeLoc); - Template_Deduction_Result Result = - S.DeduceTemplateArguments(FunctionTemplate, &TLI, Specialization, Info, - /*IsAddressOfFunction*/ true); + Template_Deduction_Result Result = I.getSema().DeduceTemplateArguments( + FunctionTemplate, &TLI, Specialization, Info, + /*IsAddressOfFunction*/ true); if (Result != Template_Deduction_Result_Success) { // FIXME: Diagnose what happened. (void)Result; } if (instantiate_body) - InstantiateFunctionDefinition(Specialization); + InstantiateFunctionDefinition(Specialization, I); return Specialization; } if (auto* VarTemplate = dyn_cast(TemplateD)) { - DeclResult R = S.CheckVarTemplateId(VarTemplate, fakeLoc, fakeLoc, TLI); + DeclResult R = + I.getSema().CheckVarTemplateId(VarTemplate, fakeLoc, fakeLoc, TLI); if (R.isInvalid()) { // FIXME: Diagnose } @@ -3872,12 +4039,14 @@ static Decl* InstantiateTemplate(TemplateDecl* TemplateD, // This will instantiate tape type and return it. SourceLocation noLoc; - QualType TT = S.CheckTemplateIdType(TemplateName(TemplateD), noLoc, TLI); + QualType TT = + I.getSema().CheckTemplateIdType(TemplateName(TemplateD), noLoc, TLI); if (TT.isNull()) return nullptr; // Perhaps we can extract this into a new interface. - S.RequireCompleteType(fakeLoc, TT, diag::err_tentative_def_incomplete_type); + I.getSema().RequireCompleteType(fakeLoc, TT, + diag::err_tentative_def_incomplete_type); return GetScopeFromType(TT); // ASTContext &C = S.getASTContext(); @@ -3892,15 +4061,15 @@ static Decl* InstantiateTemplate(TemplateDecl* TemplateD, } Decl* InstantiateTemplate(TemplateDecl* TemplateD, - ArrayRef TemplateArgs, Sema& S, - bool instantiate_body) { + ArrayRef TemplateArgs, + compat::Interpreter& I, bool instantiate_body) { // Create a list of template arguments. TemplateArgumentListInfo TLI{}; for (auto TA : TemplateArgs) - TLI.addArgument( - S.getTrivialTemplateArgumentLoc(TA, QualType(), SourceLocation())); + TLI.addArgument(I.getSema().getTrivialTemplateArgumentLoc( + TA, QualType(), SourceLocation())); - return InstantiateTemplate(TemplateD, TLI, S, instantiate_body); + return InstantiateTemplate(TemplateD, TLI, I, instantiate_body); } TCppScope_t InstantiateTemplate(compat::Interpreter& I, TCppScope_t tmpl, @@ -3931,7 +4100,7 @@ TCppScope_t InstantiateTemplate(compat::Interpreter& I, TCppScope_t tmpl, #ifdef CPPINTEROP_USE_CLING cling::Interpreter::PushTransactionRAII RAII(&I); #endif - return InstantiateTemplate(TmplD, TemplateArgs, S, instantiate_body); + return InstantiateTemplate(TmplD, TemplateArgs, I, instantiate_body); } TCppScope_t InstantiateTemplate(TCppScope_t tmpl, @@ -3939,9 +4108,10 @@ TCppScope_t InstantiateTemplate(TCppScope_t tmpl, size_t template_args_size, bool instantiate_body) { auto* D = static_cast(tmpl); - LOCK(getInterpInfo(D)); - return InstantiateTemplate(getInterp(D), tmpl, template_args, - template_args_size, instantiate_body); + auto& IF = getInterpInfo(D); + LOCK(IF); + return InstantiateTemplate(*IF, tmpl, template_args, template_args_size, + instantiate_body); } void GetClassTemplateInstantiationArgs(TCppScope_t templ_instance, @@ -3974,16 +4144,17 @@ InstantiateTemplateFunctionFromString(const char* function_template, TInterp_t interp /*=nullptr*/) { // FIXME: Drop this interface and replace it with the proper overload // resolution handling and template instantiation selection. + auto* I = static_cast(interp); + auto& IF = getInterpInfo(I); + LOCK(IF); // Try to force template instantiation and overload resolution. static unsigned long long var_count = 0; std::string id = "__Cppyy_GetMethTmpl_" + std::to_string(var_count++); std::string instance = "auto " + id + " = " + function_template + ";\n"; - auto* I = static_cast(interp); - LOCK(getInterpInfo(I)); - if (!Cpp::Declare(instance.c_str(), /*silent=*/false, interp)) { - auto* VD = static_cast(Cpp::GetNamed(id, nullptr, interp)); + if (!Cpp::Declare(*IF, instance.c_str(), /*silent=*/false)) { + auto* VD = llvm::dyn_cast(Cpp::GetNamed(*IF, id, nullptr)); Expr* E = VD->getInit()->IgnoreImpCasts(); if (auto* DRE = llvm::dyn_cast(E)) return DRE->getDecl(); @@ -4072,12 +4243,13 @@ bool IsTypeDerivedFrom(TCppType_t derived, TCppType_t base) { auto derivedType = clang::QualType::getFromOpaquePtr(derived); auto baseType = clang::QualType::getFromOpaquePtr(base); auto* CXXRD = baseType->getAsRecordDecl(); - LOCK(getInterpInfo(CXXRD)); - auto& S = getSema(CXXRD); + auto& IF = getInterpInfo(CXXRD); + LOCK(IF); + auto& S = IF.getSema(); auto fakeLoc = GetValidSLoc(S); #ifdef CPPINTEROP_USE_CLING - cling::Interpreter::PushTransactionRAII RAII(&getInterp(CXXRD)); + cling::Interpreter::PushTransactionRAII RAII(&*IF); #endif return S.IsDerivedFrom(fakeLoc, derivedType, baseType); } @@ -4183,7 +4355,8 @@ OperatorArity GetOperatorArity(TCppFunction_t op) { void GetOperator(TCppScope_t scope, Operator op, std::vector& operators, OperatorArity kind) { Decl* D = static_cast(scope); - LOCK(getInterpInfo(D)); + auto& IF = getInterpInfo(D); + LOCK(IF); if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { auto fn = [&operators, kind, op](const RecordDecl* RD) { ASTContext& C = RD->getASTContext(); @@ -4199,7 +4372,7 @@ void GetOperator(TCppScope_t scope, Operator op, fn(CXXRD); CXXRD->forallBases(fn); } else if (auto* DC = llvm::dyn_cast_or_null(D)) { - ASTContext& C = getSema(D).getASTContext(); + ASTContext& C = IF.getASTContext(); DeclContextLookupResult Result = DC->lookup(C.DeclarationNames.getCXXOperatorName( (clang::OverloadedOperatorKind)op)); @@ -4249,7 +4422,7 @@ TCppObject_t Construct(compat::Interpreter& interp, TCppScope_t scope, TCppObject_t Construct(TCppScope_t scope, void* arena /*=nullptr*/, TCppIndex_t count /*=1UL*/) { auto* D = static_cast(scope); - return Construct(getInterp(D), scope, arena, count); + return Construct(*getInterpInfo(D), scope, arena, count); } bool Destruct(compat::Interpreter& interp, TCppObject_t This, const Decl* Class, @@ -4265,7 +4438,7 @@ bool Destruct(compat::Interpreter& interp, TCppObject_t This, const Decl* Class, bool Destruct(TCppObject_t This, TCppConstScope_t scope, bool withFree /*=true*/, TCppIndex_t count /*=0UL*/) { const auto* Class = static_cast(scope); - return Destruct(getInterp(Class), This, Class, withFree, count); + return Destruct(*getInterpInfo(Class), This, Class, withFree, count); } class StreamCaptureInfo { @@ -4369,16 +4542,16 @@ std::string EndStdStreamCapture() { void CodeComplete(std::vector& Results, const char* code, unsigned complete_line /* = 1U */, unsigned complete_column /* = 1U */) { - LOCK(getInterpInfo(NULLPTR)); // FIXME: Not enough info to lock the current - // interpreter - compat::codeComplete(Results, getInterp(NULLPTR), code, complete_line, - complete_column); + auto& IF = getInterpInfo(NULLPTR); + LOCK(IF); // FIXME: Not enough info to lock the current + // interpreter + compat::codeComplete(Results, *IF, code, complete_line, complete_column); } int Undo(unsigned N, TInterp_t interp) { auto* I = static_cast(interp); if (!I) - I = &getInterp(NULLPTR); + I = &*getInterpInfo(NULLPTR); #ifdef CPPINTEROP_USE_CLING cling::Interpreter::PushTransactionRAII RAII(I); I->unload(N); diff --git a/lib/CppInterOp/CppInterOpInterpreter.h b/lib/CppInterOp/CppInterOpInterpreter.h index 4833c0bd5..967bf71f5 100644 --- a/lib/CppInterOp/CppInterOpInterpreter.h +++ b/lib/CppInterOp/CppInterOpInterpreter.h @@ -39,6 +39,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/Triple.h" +#include #include #include @@ -151,10 +152,14 @@ class Interpreter { moduleExtensions = {}, void* extraLibHandle = nullptr, bool noRuntime = true) { // Initialize all targets (required for device offloading) - llvm::InitializeAllTargetInfos(); - llvm::InitializeAllTargets(); - llvm::InitializeAllTargetMCs(); - llvm::InitializeAllAsmPrinters(); + static std::once_flag call_once_flag; + std::call_once(call_once_flag, []() { + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllAsmParsers(); + }); std::vector vargs(argv + 1, argv + argc); auto CI = compat::createClangInterpreter(vargs); @@ -339,7 +344,10 @@ class Interpreter { const clang::CompilerInstance* getCI() const { return getCompilerInstance(); } - clang::Sema& getSema() const { return getCI()->getSema(); } + [[nodiscard]] clang::Sema& getSema() const { return getCI()->getSema(); } + [[nodiscard]] clang::ASTContext& getASTContext() const { + return getSema().getASTContext(); + } const DynamicLibraryManager* getDynamicLibraryManager() const { assert(compat::getExecutionEngine(*inner) && "We must have an executor"); diff --git a/unittests/CppInterOp/EnumReflectionTest.cpp b/unittests/CppInterOp/EnumReflectionTest.cpp index f4b3d47de..68a97330f 100644 --- a/unittests/CppInterOp/EnumReflectionTest.cpp +++ b/unittests/CppInterOp/EnumReflectionTest.cpp @@ -8,11 +8,13 @@ #include "gtest/gtest.h" +#include + using namespace TestUtils; using namespace llvm; using namespace clang; -TEST(ScopeReflectionTest, IsEnumScope) { +static void EnumReflectionTest_IsEnumScope() { std::vector Decls, SubDecls; std::string code = R"( enum Switch { @@ -34,7 +36,7 @@ TEST(ScopeReflectionTest, IsEnumScope) { EXPECT_FALSE(Cpp::IsEnumScope(SubDecls[1])); } -TEST(ScopeReflectionTest, IsEnumConstant) { +static void EnumReflectionTest_IsEnumConstant() { std::vector Decls, SubDecls; std::string code = R"( enum Switch { @@ -56,7 +58,7 @@ TEST(ScopeReflectionTest, IsEnumConstant) { EXPECT_TRUE(Cpp::IsEnumConstant(SubDecls[1])); } -TEST(EnumReflectionTest, IsEnumType) { +static void EnumReflectionTest_IsEnumType() { std::vector Decls; std::string code = R"( enum class E { @@ -84,7 +86,7 @@ TEST(EnumReflectionTest, IsEnumType) { EXPECT_TRUE(Cpp::IsEnumType(Cpp::GetVariableType(Decls[5]))); } -TEST(EnumReflectionTest, GetIntegerTypeFromEnumScope) { +static void EnumReflectionTest_GetIntegerTypeFromEnumScope() { std::vector Decls; std::string code = R"( enum Switch : bool { @@ -134,7 +136,7 @@ TEST(EnumReflectionTest, GetIntegerTypeFromEnumScope) { EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[5])),"NULL TYPE"); } -TEST(EnumReflectionTest, GetIntegerTypeFromEnumType) { +static void EnumReflectionTest_GetIntegerTypeFromEnumType() { std::vector Decls; std::string code = R"( enum Switch : bool { @@ -194,7 +196,7 @@ TEST(EnumReflectionTest, GetIntegerTypeFromEnumType) { EXPECT_EQ(get_int_type_from_enum_var(Decls[11]), "NULL TYPE"); // When a non Enum Type variable is used } -TEST(EnumReflectionTest, GetEnumConstants) { +static void EnumReflectionTest_GetEnumConstants() { std::vector Decls; std::string code = R"( enum ZeroEnum { @@ -238,7 +240,7 @@ TEST(EnumReflectionTest, GetEnumConstants) { EXPECT_EQ(Cpp::GetEnumConstants(Decls[5]).size(), 0); } -TEST(EnumReflectionTest, GetEnumConstantType) { +static void EnumReflectionTest_GetEnumConstantType() { std::vector Decls; std::string code = R"( enum Enum0 { @@ -269,7 +271,7 @@ TEST(EnumReflectionTest, GetEnumConstantType) { EXPECT_EQ(get_enum_constant_type_as_str(nullptr), "NULL TYPE"); } -TEST(EnumReflectionTest, GetEnumConstantValue) { +static void EnumReflectionTest_GetEnumConstantValue() { std::vector Decls; std::string code = R"( enum Counter { @@ -297,7 +299,7 @@ TEST(EnumReflectionTest, GetEnumConstantValue) { EXPECT_EQ(Cpp::GetEnumConstantValue(Decls[1]), 0); // Checking value of non enum constant } -TEST(EnumReflectionTest, GetEnums) { +static void EnumReflectionTest_GetEnums() { std::string code = R"( enum Color { Red, @@ -338,13 +340,13 @@ TEST(EnumReflectionTest, GetEnums) { int myVariable; )"; - Cpp::CreateInterpreter(); - Interp->declare(code); + Cpp::TInterp_t I = Cpp::CreateInterpreter(); + Cpp::Declare(code.c_str(), false, I); std::vector enumNames1, enumNames2, enumNames3, enumNames4; - Cpp::TCppScope_t globalscope = Cpp::GetScope("", 0); - Cpp::TCppScope_t Animals_scope = Cpp::GetScope("Animals", 0); - Cpp::TCppScope_t myClass_scope = Cpp::GetScope("myClass", 0); - Cpp::TCppScope_t unsupported_scope = Cpp::GetScope("myVariable", 0); + Cpp::TCppScope_t globalscope = Cpp::GetScope("", nullptr, I); + Cpp::TCppScope_t Animals_scope = Cpp::GetScope("Animals", nullptr, I); + Cpp::TCppScope_t myClass_scope = Cpp::GetScope("myClass", nullptr, I); + Cpp::TCppScope_t unsupported_scope = Cpp::GetScope("myVariable", nullptr, I); Cpp::GetEnums(globalscope,enumNames1); Cpp::GetEnums(Animals_scope,enumNames2); @@ -359,3 +361,23 @@ TEST(EnumReflectionTest, GetEnums) { EXPECT_TRUE(std::find(enumNames3.begin(), enumNames3.end(), "Color") != enumNames3.end()); EXPECT_TRUE(enumNames4.empty()); } + +TEST(EnumReflectionTest, EnumReflectionTest) { + std::vector> fns = { + {"EnumReflectionTest_IsEnumScope", EnumReflectionTest_IsEnumScope}, + {"EnumReflectionTest_IsEnumConstant", EnumReflectionTest_IsEnumConstant}, + {"EnumReflectionTest_IsEnumType", EnumReflectionTest_IsEnumType}, + {"EnumReflectionTest_GetIntegerTypeFromEnumScope", + EnumReflectionTest_GetIntegerTypeFromEnumScope}, + {"EnumReflectionTest_GetIntegerTypeFromEnumType", + EnumReflectionTest_GetIntegerTypeFromEnumType}, + {"EnumReflectionTest_GetEnumConstants", + EnumReflectionTest_GetEnumConstants}, + {"EnumReflectionTest_GetEnumConstantType", + EnumReflectionTest_GetEnumConstantType}, + {"EnumReflectionTest_GetEnumConstantValue", + EnumReflectionTest_GetEnumConstantValue}, + {"EnumReflectionTest_GetEnums", EnumReflectionTest_GetEnums}, + }; + ThreadPoolExecutor::run(fns); +} diff --git a/unittests/CppInterOp/FunctionReflectionTest.cpp b/unittests/CppInterOp/FunctionReflectionTest.cpp index caf0d3391..6aa12bec5 100644 --- a/unittests/CppInterOp/FunctionReflectionTest.cpp +++ b/unittests/CppInterOp/FunctionReflectionTest.cpp @@ -14,12 +14,16 @@ #include "gtest/gtest.h" #include +#include using namespace TestUtils; using namespace llvm; using namespace clang; -TEST(FunctionReflectionTest, GetClassMethods) { +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +static Cpp::TInterp_t I = nullptr; + +static void FunctionReflectionTest_GetClassMethods() { std::vector Decls; std::string code = R"( class A; @@ -49,7 +53,8 @@ TEST(FunctionReflectionTest, GetClassMethods) { using MyInt = int; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I1 = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I1); auto get_method_name = [](Cpp::TCppFunction_t method) { return Cpp::GetFunctionSignature(method); @@ -130,7 +135,7 @@ TEST(FunctionReflectionTest, GetClassMethods) { }; )"; - GetAllTopLevelDecls(code, Decls); + I1 = GetAllTopLevelDecls(code, Decls); EXPECT_EQ(Decls.size(), 2); std::vector templ_methods1; @@ -157,7 +162,7 @@ TEST(FunctionReflectionTest, GetClassMethods) { EXPECT_EQ(get_method_name(templ_methods2[6]), "inline TT::~TT()"); // C API - auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter()); + auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter(I1)); auto C_API_SHIM = [&](Cpp::TCppFunction_t method) { auto Str = clang_getFunctionSignature( make_scope(static_cast(method), I)); @@ -171,7 +176,7 @@ TEST(FunctionReflectionTest, GetClassMethods) { clang_Interpreter_dispose(I); } -TEST(FunctionReflectionTest, ConstructorInGetClassMethods) { +static void FunctionReflectionTest_ConstructorInGetClassMethods() { std::vector Decls; std::string code = R"( struct S { @@ -180,7 +185,8 @@ TEST(FunctionReflectionTest, ConstructorInGetClassMethods) { }; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); auto has_constructor = [](Decl* D) { std::vector methods; @@ -195,7 +201,7 @@ TEST(FunctionReflectionTest, ConstructorInGetClassMethods) { EXPECT_TRUE(has_constructor(Decls[0])); } -TEST(FunctionReflectionTest, HasDefaultConstructor) { +static void FunctionReflectionTest_HasDefaultConstructor() { std::vector Decls; std::string code = R"( class A { @@ -221,13 +227,15 @@ TEST(FunctionReflectionTest, HasDefaultConstructor) { )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I1 = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I1); + EXPECT_TRUE(Cpp::HasDefaultConstructor(Decls[0])); EXPECT_TRUE(Cpp::HasDefaultConstructor(Decls[1])); EXPECT_FALSE(Cpp::HasDefaultConstructor(Decls[3])); // C API - auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter()); + auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter(I1)); EXPECT_TRUE(clang_hasDefaultConstructor(make_scope(Decls[0], I))); EXPECT_TRUE(clang_hasDefaultConstructor(make_scope(Decls[1], I))); EXPECT_FALSE(clang_hasDefaultConstructor(make_scope(Decls[3], I))); @@ -236,7 +244,7 @@ TEST(FunctionReflectionTest, HasDefaultConstructor) { clang_Interpreter_dispose(I); } -TEST(FunctionReflectionTest, GetDestructor) { +static void FunctionReflectionTest_GetDestructor() { std::vector Decls; std::string code = R"( class A { @@ -254,7 +262,8 @@ TEST(FunctionReflectionTest, GetDestructor) { } )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I1 = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I1); EXPECT_TRUE(Cpp::GetDestructor(Decls[0])); EXPECT_TRUE(Cpp::GetDestructor(Decls[1])); @@ -264,7 +273,7 @@ TEST(FunctionReflectionTest, GetDestructor) { EXPECT_FALSE(Cpp::GetDestructor(Decls[3])); // C API - auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter()); + auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter(I1)); EXPECT_TRUE(clang_getDestructor(make_scope(Decls[0], I)).data[0]); EXPECT_TRUE(clang_getDestructor(make_scope(Decls[1], I)).data[0]); // Clean up resources @@ -272,7 +281,7 @@ TEST(FunctionReflectionTest, GetDestructor) { clang_Interpreter_dispose(I); } -TEST(FunctionReflectionTest, GetFunctionsUsingName) { +static void FunctionReflectionTest_GetFunctionsUsingName() { std::vector Decls; std::string code = R"( class A { @@ -294,7 +303,8 @@ TEST(FunctionReflectionTest, GetFunctionsUsingName) { typedef A shadow_A; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); // This lambda can take in the scope and the name of the function // and returns the size of the vector returned by GetFunctionsUsingName @@ -316,7 +326,7 @@ TEST(FunctionReflectionTest, GetFunctionsUsingName) { EXPECT_EQ(get_number_of_funcs_using_name(Decls[2], ""), 0); } -TEST(FunctionReflectionTest, GetClassDecls) { +static void FunctionReflectionTest_GetClassDecls() { std::vector Decls, SubDecls; std::string code = R"( class MyTemplatedMethodClass { @@ -340,7 +350,9 @@ TEST(FunctionReflectionTest, GetClassDecls) { }; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + GetAllSubDecls(Decls[0], SubDecls); std::vector methods; @@ -353,7 +365,7 @@ TEST(FunctionReflectionTest, GetClassDecls) { EXPECT_EQ(Cpp::GetName(methods[3]), Cpp::GetName(SubDecls[8])); } -TEST(FunctionReflectionTest, GetFunctionTemplatedDecls) { +static void FunctionReflectionTest_GetFunctionTemplatedDecls() { std::vector Decls, SubDecls; std::string code = R"( class MyTemplatedMethodClass { @@ -377,7 +389,9 @@ TEST(FunctionReflectionTest, GetFunctionTemplatedDecls) { }; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + GetAllSubDecls(Decls[0], SubDecls); std::vector template_methods; @@ -390,7 +404,7 @@ TEST(FunctionReflectionTest, GetFunctionTemplatedDecls) { EXPECT_EQ(Cpp::GetName(template_methods[3]), Cpp::GetName(SubDecls[6])); } -TEST(FunctionReflectionTest, GetFunctionReturnType) { +static void FunctionReflectionTest_GetFunctionReturnType() { std::vector Decls, SubDecls, TemplateSubDecls; std::string code = R"( namespace N { class C {}; } @@ -437,7 +451,7 @@ TEST(FunctionReflectionTest, GetFunctionReturnType) { }; )"; - GetAllTopLevelDecls(code, Decls, true); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls, true); GetAllSubDecls(Decls[2], SubDecls); GetAllSubDecls(Decls[12], TemplateSubDecls); @@ -471,7 +485,7 @@ TEST(FunctionReflectionTest, GetFunctionReturnType) { Cpp::GetTypeAsString(Cpp::GetFunctionReturnType(TemplateSubDecls[3])), "long"); - ASTContext& C = Interp->getCI()->getASTContext(); + ASTContext& C = TU_getASTContext(I); std::vector args = {C.IntTy.getAsOpaquePtr(), C.DoubleTy.getAsOpaquePtr()}; std::vector explicit_args; @@ -487,7 +501,7 @@ TEST(FunctionReflectionTest, GetFunctionReturnType) { "double"); } -TEST(FunctionReflectionTest, GetFunctionNumArgs) { +static void FunctionReflectionTest_GetFunctionNumArgs() { std::vector Decls, TemplateSubDecls; std::string code = R"( void f1() {} @@ -513,7 +527,9 @@ TEST(FunctionReflectionTest, GetFunctionNumArgs) { )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + GetAllSubDecls(Decls[5], TemplateSubDecls); EXPECT_EQ(Cpp::GetFunctionNumArgs(Decls[0]), (size_t) 0); EXPECT_EQ(Cpp::GetFunctionNumArgs(Decls[1]), (size_t) 4); @@ -526,7 +542,7 @@ TEST(FunctionReflectionTest, GetFunctionNumArgs) { EXPECT_EQ(Cpp::GetFunctionNumArgs(TemplateSubDecls[3]), 3); } -TEST(FunctionReflectionTest, GetFunctionRequiredArgs) { +static void FunctionReflectionTest_GetFunctionRequiredArgs() { std::vector Decls, TemplateSubDecls; std::string code = R"( void f1() {} @@ -547,7 +563,9 @@ TEST(FunctionReflectionTest, GetFunctionRequiredArgs) { }; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + GetAllSubDecls(Decls[5], TemplateSubDecls); EXPECT_EQ(Cpp::GetFunctionRequiredArgs(Decls[0]), (size_t) 0); @@ -561,7 +579,7 @@ TEST(FunctionReflectionTest, GetFunctionRequiredArgs) { EXPECT_EQ(Cpp::GetFunctionRequiredArgs(TemplateSubDecls[3]), 2); } -TEST(FunctionReflectionTest, GetFunctionArgType) { +static void FunctionReflectionTest_GetFunctionArgType() { std::vector Decls; std::string code = R"( void f1(int i, double d, long l, char ch) {} @@ -569,7 +587,9 @@ TEST(FunctionReflectionTest, GetFunctionArgType) { int a; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[0], 0)), "int"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[0], 1)), "double"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[0], 2)), "long"); @@ -581,7 +601,7 @@ TEST(FunctionReflectionTest, GetFunctionArgType) { EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetFunctionArgType(Decls[2], 0)), "NULL TYPE"); } -TEST(FunctionReflectionTest, GetFunctionSignature) { +static void FunctionReflectionTest_GetFunctionSignature() { std::vector Decls; std::string code = R"( class C { @@ -604,7 +624,9 @@ TEST(FunctionReflectionTest, GetFunctionSignature) { class ABC {}; )"; - GetAllTopLevelDecls(code, Decls, true); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls, true); + EXPECT_TRUE(I); + GetAllSubDecls(Decls[0], Decls); GetAllSubDecls(Decls[1], Decls); @@ -625,7 +647,7 @@ TEST(FunctionReflectionTest, GetFunctionSignature) { EXPECT_EQ(Cpp::GetFunctionSignature(nullptr), ""); } -TEST(FunctionReflectionTest, IsTemplatedFunction) { +static void FunctionReflectionTest_IsTemplatedFunction() { std::vector Decls; std::vector SubDeclsC1; std::string code = R"( @@ -644,7 +666,9 @@ TEST(FunctionReflectionTest, IsTemplatedFunction) { class ABC {}; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I1 = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I1); + GetAllSubDecls(Decls[2], SubDeclsC1); EXPECT_FALSE(Cpp::IsTemplatedFunction(Decls[0])); @@ -654,7 +678,7 @@ TEST(FunctionReflectionTest, IsTemplatedFunction) { EXPECT_TRUE(Cpp::IsTemplatedFunction(SubDeclsC1[2])); // C API - auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter()); + auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter(I1)); EXPECT_FALSE(clang_isTemplatedFunction(make_scope(Decls[0], I))); EXPECT_TRUE(clang_isTemplatedFunction(make_scope(Decls[1], I))); EXPECT_FALSE(clang_isTemplatedFunction(make_scope(Decls[3], I))); @@ -665,7 +689,7 @@ TEST(FunctionReflectionTest, IsTemplatedFunction) { clang_Interpreter_dispose(I); } -TEST(FunctionReflectionTest, ExistsFunctionTemplate) { +static void FunctionReflectionTest_ExistsFunctionTemplate() { std::vector Decls; std::string code = R"( template @@ -679,13 +703,15 @@ TEST(FunctionReflectionTest, ExistsFunctionTemplate) { void f(char ch) {} )"; - GetAllTopLevelDecls(code, Decls); - EXPECT_TRUE(Cpp::ExistsFunctionTemplate("f", 0)); + Cpp::TInterp_t I1 = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I1); + + EXPECT_TRUE(Cpp::ExistsFunctionTemplate("f", Cpp::GetGlobalScope(I1))); EXPECT_TRUE(Cpp::ExistsFunctionTemplate("f", Decls[1])); EXPECT_FALSE(Cpp::ExistsFunctionTemplate("f", Decls[2])); // C API - auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter()); + auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter(I1)); EXPECT_TRUE(clang_existsFunctionTemplate("f", make_scope(Decls[1], I))); EXPECT_FALSE(clang_existsFunctionTemplate("f", make_scope(Decls[2], I))); // Clean up resources @@ -693,30 +719,29 @@ TEST(FunctionReflectionTest, ExistsFunctionTemplate) { clang_Interpreter_dispose(I); } -TEST(FunctionReflectionTest, InstantiateTemplateFunctionFromString) { +static void FunctionReflectionTest_InstantiateTemplateFunctionFromString() { #if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \ defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) GTEST_SKIP() << "Test fails with Cling on Windows on ARM"; #endif if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; - std::vector interpreter_args = { "-include", "new" }; - Cpp::CreateInterpreter(interpreter_args); std::string code = R"(#include )"; - Interp->process(code); + EXPECT_FALSE(Cpp::Process(code.c_str(), I)); const char* str = "std::make_unique"; - auto* Instance1 = (Decl*)Cpp::InstantiateTemplateFunctionFromString(str); + auto* Instance1 = + static_cast(Cpp::InstantiateTemplateFunctionFromString(str, I)); EXPECT_TRUE(Instance1); } -TEST(FunctionReflectionTest, InstantiateFunctionTemplate) { +static void FunctionReflectionTest_InstantiateFunctionTemplate() { std::vector Decls; std::string code = R"( template T TrivialFnTemplate() { return T(); } )"; - GetAllTopLevelDecls(code, Decls); - ASTContext& C = Interp->getCI()->getASTContext(); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + ASTContext& C = TU_getASTContext(I); std::vector args1 = {C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(), @@ -729,7 +754,7 @@ template T TrivialFnTemplate() { return T(); } EXPECT_TRUE(TA1.getAsType()->isIntegerType()); } -TEST(FunctionReflectionTest, InstantiateTemplateMethod) { +static void FunctionReflectionTest_InstantiateTemplateMethod() { std::vector Decls; std::string code = R"( class MyTemplatedMethodClass { @@ -743,8 +768,8 @@ TEST(FunctionReflectionTest, InstantiateTemplateMethod) { } )"; - GetAllTopLevelDecls(code, Decls); - ASTContext& C = Interp->getCI()->getASTContext(); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + ASTContext& C = TU_getASTContext(I); std::vector args1 = {C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls[1], args1.data(), @@ -757,7 +782,7 @@ TEST(FunctionReflectionTest, InstantiateTemplateMethod) { EXPECT_TRUE(TA1.getAsType()->isIntegerType()); } -TEST(FunctionReflectionTest, LookupConstructors) { +static void FunctionReflectionTest_LookupConstructors() { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -784,7 +809,9 @@ TEST(FunctionReflectionTest, LookupConstructors) { MyClass::MyClass(T t) {} )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + std::vector ctors; Cpp::LookupConstructors("MyClass", Decls[0], ctors); @@ -798,7 +825,7 @@ TEST(FunctionReflectionTest, LookupConstructors) { EXPECT_EQ(Cpp::GetFunctionSignature(ctors[3]), "MyClass::MyClass(T t)"); } -TEST(FunctionReflectionTest, GetClassTemplatedMethods) { +static void FunctionReflectionTest_GetClassTemplatedMethods() { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -833,7 +860,9 @@ TEST(FunctionReflectionTest, GetClassTemplatedMethods) { void MyClass::templatedStaticMethod(T param) {} )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + std::vector templatedMethods; Cpp::GetClassTemplatedMethods("MyClass", Decls[0], templatedMethods); Cpp::GetClassTemplatedMethods("templatedMethod", Decls[0], templatedMethods); @@ -856,7 +885,8 @@ TEST(FunctionReflectionTest, GetClassTemplatedMethods) { "void MyClass::templatedStaticMethod(T param)"); } -TEST(FunctionReflectionTest, GetClassTemplatedMethods_VariadicsAndOthers) { +static void +FunctionReflectionTest_GetClassTemplatedMethods_VariadicsAndOthers() { std::vector Decls; std::string code = R"( class MyClass { @@ -889,7 +919,9 @@ TEST(FunctionReflectionTest, GetClassTemplatedMethods_VariadicsAndOthers) { void MyClass::staticVariadic(T t, Args... args) {} )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + std::vector templatedMethods; Cpp::GetClassTemplatedMethods("fixedMethod", Decls[0], templatedMethods); Cpp::GetClassTemplatedMethods("defaultMethod", Decls[0], templatedMethods); @@ -910,7 +942,7 @@ TEST(FunctionReflectionTest, GetClassTemplatedMethods_VariadicsAndOthers) { "void MyClass::staticVariadic(T t, Args ...args)"); } -TEST(FunctionReflectionTest, InstantiateVariadicFunction) { +static void FunctionReflectionTest_InstantiateVariadicFunction() { std::vector Decls; std::string code = R"( class MyClass {}; @@ -922,8 +954,8 @@ TEST(FunctionReflectionTest, InstantiateVariadicFunction) { void VariadicFnExtended(int fixedParam, Args... args) {} )"; - GetAllTopLevelDecls(code, Decls); - ASTContext& C = Interp->getCI()->getASTContext(); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + ASTContext& C = TU_getASTContext(I); std::vector args1 = {C.DoubleTy.getAsOpaquePtr(), C.IntTy.getAsOpaquePtr()}; @@ -973,7 +1005,7 @@ TEST(FunctionReflectionTest, InstantiateVariadicFunction) { "fixedParam, MyClass args, double args)"); } -TEST(FunctionReflectionTest, BestOverloadFunctionMatch1) { +static void FunctionReflectionTest_BestOverloadFunctionMatch1() { std::vector Decls; std::string code = R"( class MyTemplatedMethodClass { @@ -1011,7 +1043,7 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch1) { } )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); std::vector candidates; EXPECT_FALSE(Cpp::BestOverloadFunctionMatch({}, {}, {})); @@ -1019,7 +1051,7 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch1) { for (auto decl : Decls) if (Cpp::IsTemplatedFunction(decl)) candidates.push_back((Cpp::TCppFunction_t)decl); - ASTContext& C = Interp->getCI()->getASTContext(); + ASTContext& C = TU_getASTContext(I); std::vector args0; std::vector args1 = { @@ -1055,7 +1087,7 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch1) { "template<> long MyTemplatedMethodClass::get_size<1, int>(int a)"); } -TEST(FunctionReflectionTest, BestOverloadFunctionMatch2) { +static void FunctionReflectionTest_BestOverloadFunctionMatch2() { std::vector Decls; std::string code = R"( template @@ -1078,7 +1110,7 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch2) { void somefunc(int arg1, double arg2) {} )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); std::vector candidates; for (auto decl : Decls) @@ -1087,16 +1119,16 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch2) { EXPECT_EQ(candidates.size(), 5); - ASTContext& C = Interp->getCI()->getASTContext(); + ASTContext& C = TU_getASTContext(I); std::vector args1 = {C.IntTy.getAsOpaquePtr()}; std::vector args2 = { - Cpp::GetVariableType(Cpp::GetNamed("a"))}; + Cpp::GetVariableType(Cpp::GetNamed("a", Cpp::GetGlobalScope(I)))}; std::vector args3 = {C.IntTy.getAsOpaquePtr(), C.IntTy.getAsOpaquePtr()}; std::vector args4 = { - Cpp::GetVariableType(Cpp::GetNamed("a")), - Cpp::GetVariableType(Cpp::GetNamed("a"))}; + Cpp::GetVariableType(Cpp::GetNamed("a", Cpp::GetGlobalScope(I))), + Cpp::GetVariableType(Cpp::GetNamed("a", Cpp::GetGlobalScope(I)))}; std::vector args5 = {C.IntTy.getAsOpaquePtr(), C.DoubleTy.getAsOpaquePtr()}; @@ -1125,7 +1157,7 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch2) { "void somefunc(int arg1, double arg2)"); } -TEST(FunctionReflectionTest, BestOverloadFunctionMatch3) { +static void FunctionReflectionTest_BestOverloadFunctionMatch3() { std::vector Decls; std::string code = R"( template @@ -1151,7 +1183,7 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch3) { } )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); std::vector candidates; for (auto decl : Decls) @@ -1160,15 +1192,17 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch3) { EXPECT_EQ(candidates.size(), 2); - ASTContext& C = Interp->getCI()->getASTContext(); + ASTContext& C = TU_getASTContext(I); std::vector args1 = { - Cpp::GetVariableType(Cpp::GetNamed("a")), - Cpp::GetVariableType(Cpp::GetNamed("a"))}; + Cpp::GetVariableType(Cpp::GetNamed("a", Cpp::GetGlobalScope(I))), + Cpp::GetVariableType(Cpp::GetNamed("a", Cpp::GetGlobalScope(I)))}; std::vector args2 = { - Cpp::GetVariableType(Cpp::GetNamed("a")), C.IntTy.getAsOpaquePtr()}; + Cpp::GetVariableType(Cpp::GetNamed("a", Cpp::GetGlobalScope(I))), + C.IntTy.getAsOpaquePtr()}; std::vector args3 = { - Cpp::GetVariableType(Cpp::GetNamed("a")), C.DoubleTy.getAsOpaquePtr()}; + Cpp::GetVariableType(Cpp::GetNamed("a", Cpp::GetGlobalScope(I))), + C.DoubleTy.getAsOpaquePtr()}; std::vector explicit_args; @@ -1180,14 +1214,14 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch3) { Cpp::BestOverloadFunctionMatch(candidates, explicit_args, args3); candidates.clear(); - Cpp::GetOperator( - Cpp::GetScopeFromType(Cpp::GetVariableType(Cpp::GetNamed("a"))), - Cpp::Operator::OP_Minus, candidates); + Cpp::GetOperator(Cpp::GetScopeFromType(Cpp::GetVariableType( + Cpp::GetNamed("a", Cpp::GetGlobalScope(I)))), + Cpp::Operator::OP_Minus, candidates); EXPECT_EQ(candidates.size(), 1); std::vector args4 = { - Cpp::GetVariableType(Cpp::GetNamed("a"))}; + Cpp::GetVariableType(Cpp::GetNamed("a", Cpp::GetGlobalScope(I)))}; Cpp::TCppFunction_t func4 = Cpp::BestOverloadFunctionMatch(candidates, explicit_args, args4); @@ -1203,7 +1237,7 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch3) { "template<> A A::operator-(A rhs)"); } -TEST(FunctionReflectionTest, BestOverloadFunctionMatch4) { +static void FunctionReflectionTest_BestOverloadFunctionMatch4() { std::vector Decls, SubDecls; std::string code = R"( template @@ -1224,7 +1258,7 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch4) { A b; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); GetAllSubDecls(Decls[1], SubDecls); std::vector candidates; for (auto i : SubDecls) { @@ -1235,18 +1269,18 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch4) { EXPECT_EQ(candidates.size(), 4); - ASTContext& C = Interp->getCI()->getASTContext(); + ASTContext& C = TU_getASTContext(I); + + Cpp::TCppType_t a = + Cpp::GetVariableType(Cpp::GetNamed("a", Cpp::GetGlobalScope(I))); + Cpp::TCppType_t b = + Cpp::GetVariableType(Cpp::GetNamed("b", Cpp::GetGlobalScope(I))); std::vector args1 = {}; std::vector args2 = {C.IntTy.getAsOpaquePtr()}; - std::vector args3 = { - Cpp::GetVariableType(Cpp::GetNamed("a"))}; - std::vector args4 = { - Cpp::GetVariableType(Cpp::GetNamed("a")), - Cpp::GetVariableType(Cpp::GetNamed("b"))}; - std::vector args5 = { - Cpp::GetVariableType(Cpp::GetNamed("a")), - Cpp::GetVariableType(Cpp::GetNamed("a"))}; + std::vector args3 = {a}; + std::vector args4 = {a, b}; + std::vector args5 = {a, a}; std::vector explicit_args1; std::vector explicit_args2 = {C.IntTy.getAsOpaquePtr(), @@ -1274,7 +1308,7 @@ TEST(FunctionReflectionTest, BestOverloadFunctionMatch4) { "template<> void B::fn(A x, A y)"); } -TEST(FunctionReflectionTest, IsPublicMethod) { +static void FunctionReflectionTest_IsPublicMethod() { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -1290,7 +1324,8 @@ TEST(FunctionReflectionTest, IsPublicMethod) { }; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); GetAllSubDecls(Decls[0], SubDecls); EXPECT_TRUE(Cpp::IsPublicMethod(SubDecls[2])); @@ -1301,7 +1336,7 @@ TEST(FunctionReflectionTest, IsPublicMethod) { EXPECT_FALSE(Cpp::IsPublicMethod(SubDecls[9])); } -TEST(FunctionReflectionTest, IsProtectedMethod) { +static void FunctionReflectionTest_IsProtectedMethod() { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -1316,7 +1351,9 @@ TEST(FunctionReflectionTest, IsProtectedMethod) { }; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + GetAllSubDecls(Decls[0], SubDecls); EXPECT_FALSE(Cpp::IsProtectedMethod(SubDecls[2])); @@ -1326,7 +1363,7 @@ TEST(FunctionReflectionTest, IsProtectedMethod) { EXPECT_TRUE(Cpp::IsProtectedMethod(SubDecls[8])); } -TEST(FunctionReflectionTest, IsPrivateMethod) { +static void FunctionReflectionTest_IsPrivateMethod() { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -1341,7 +1378,9 @@ TEST(FunctionReflectionTest, IsPrivateMethod) { }; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + GetAllSubDecls(Decls[0], SubDecls); EXPECT_FALSE(Cpp::IsPrivateMethod(SubDecls[2])); @@ -1351,7 +1390,7 @@ TEST(FunctionReflectionTest, IsPrivateMethod) { EXPECT_FALSE(Cpp::IsPrivateMethod(SubDecls[8])); } -TEST(FunctionReflectionTest, IsConstructor) { +static void FunctionReflectionTest_IsConstructor() { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -1366,7 +1405,9 @@ TEST(FunctionReflectionTest, IsConstructor) { }; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + GetAllSubDecls(Decls[0], SubDecls); EXPECT_TRUE(Cpp::IsConstructor(SubDecls[2])); @@ -1398,7 +1439,7 @@ TEST(FunctionReflectionTest, IsConstructor) { EXPECT_EQ(templCtorCount, 1); } -TEST(FunctionReflectionTest, IsDestructor) { +static void FunctionReflectionTest_IsDestructor() { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -1413,7 +1454,9 @@ TEST(FunctionReflectionTest, IsDestructor) { }; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + GetAllSubDecls(Decls[0], SubDecls); EXPECT_FALSE(Cpp::IsDestructor(SubDecls[2])); @@ -1423,7 +1466,7 @@ TEST(FunctionReflectionTest, IsDestructor) { EXPECT_FALSE(Cpp::IsDestructor(SubDecls[8])); } -TEST(FunctionReflectionTest, IsStaticMethod) { +static void FunctionReflectionTest_IsStaticMethod() { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -1432,7 +1475,9 @@ TEST(FunctionReflectionTest, IsStaticMethod) { }; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + GetAllSubDecls(Decls[0], SubDecls); EXPECT_FALSE(Cpp::IsStaticMethod(Decls[0])); @@ -1441,6 +1486,7 @@ TEST(FunctionReflectionTest, IsStaticMethod) { } TEST(FunctionReflectionTest, GetFunctionAddress) { + // XXX: no parallel #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -1455,15 +1501,13 @@ TEST(FunctionReflectionTest, GetFunctionAddress) { std::string code = "int f1(int i) { return i * i; }"; std::vector interpreter_args = {"-include", "new"}; - GetAllTopLevelDecls(code, Decls, /*filter_implicitGenerated=*/false, - interpreter_args); + Cpp::TInterp_t I = GetAllTopLevelDecls( + code, Decls, /*filter_implicitGenerated=*/false, interpreter_args); testing::internal::CaptureStdout(); - Interp->declare("#include "); - Interp->process( - "void * address = (void *) &f1; \n" - "std::cout << address; \n" - ); + Cpp::Declare("#include "); + Cpp::Process("void * address = (void *) &f1; \n" + "std::cout << address; \n"); std::string output = testing::internal::GetCapturedStdout(); std::stringstream address; @@ -1472,7 +1516,7 @@ TEST(FunctionReflectionTest, GetFunctionAddress) { EXPECT_FALSE(Cpp::GetFunctionAddress(Cpp::GetGlobalScope())); - Interp->declare(R"( + Cpp::Declare(R"( template T add1(T t) { return t + 1; } )"); @@ -1481,7 +1525,7 @@ TEST(FunctionReflectionTest, GetFunctionAddress) { Cpp::GetClassTemplatedMethods("add1", Cpp::GetGlobalScope(), funcs); EXPECT_EQ(funcs.size(), 1); - ASTContext& C = Interp->getCI()->getASTContext(); + ASTContext& C = TU_getASTContext(I); std::vector argument = {C.DoubleTy.getAsOpaquePtr()}; Cpp::TCppScope_t add1_double = Cpp::InstantiateTemplate(funcs[0], argument.data(), argument.size()); @@ -1490,7 +1534,7 @@ TEST(FunctionReflectionTest, GetFunctionAddress) { EXPECT_TRUE(Cpp::GetFunctionAddress(add1_double)); } -TEST(FunctionReflectionTest, IsVirtualMethod) { +static void FunctionReflectionTest_IsVirtualMethod() { std::vector Decls, SubDecls; std::string code = R"( class A { @@ -1500,7 +1544,9 @@ TEST(FunctionReflectionTest, IsVirtualMethod) { }; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + GetAllSubDecls(Decls[0], SubDecls); EXPECT_EQ(Cpp::GetName(SubDecls[2]), "x"); @@ -1510,7 +1556,7 @@ TEST(FunctionReflectionTest, IsVirtualMethod) { EXPECT_FALSE(Cpp::IsVirtualMethod(Decls[0])); } -TEST(FunctionReflectionTest, JitCallAdvanced) { +static void FunctionReflectionTest_JitCallAdvanced() { #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -1532,8 +1578,8 @@ TEST(FunctionReflectionTest, JitCallAdvanced) { std::vector interpreter_args = {"-include", "new"}; - GetAllTopLevelDecls(code, Decls, /*filter_implicitGenerated=*/false, - interpreter_args); + Cpp::TInterp_t I1 = GetAllTopLevelDecls( + code, Decls, /*filter_implicitGenerated=*/false, interpreter_args); auto *CtorD = (clang::CXXConstructorDecl*)Cpp::GetDefaultConstructor(Decls[0]); auto Ctor = Cpp::MakeFunctionCallable(CtorD); @@ -1545,7 +1591,7 @@ TEST(FunctionReflectionTest, JitCallAdvanced) { EXPECT_TRUE(Cpp::Destruct(object, Decls[1])); // C API - auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter()); + auto* I = clang_createInterpreterFromRawPtr(Cpp::GetInterpreter(I1)); auto S = clang_getDefaultConstructor(make_scope(Decls[0], I)); void* object_c = nullptr; clang_invoke(S, &object_c, nullptr, 0, nullptr); @@ -1559,6 +1605,7 @@ TEST(FunctionReflectionTest, JitCallAdvanced) { #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST #ifndef _WIN32 // Death tests do not work on Windows TEST(FunctionReflectionTest, JitCallDebug) { + // XXX: no parallel #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -1652,6 +1699,7 @@ template int instantiation_in_host(); #endif TEST(FunctionReflectionTest, GetFunctionCallWrapper) { + // XXX: no parallel #ifdef EMSCRIPTEN GTEST_SKIP() << "Test fails for Emscipten builds"; #endif @@ -1670,12 +1718,12 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { GetAllTopLevelDecls(code, Decls, /*filter_implicitGenerated=*/false, interpreter_args); - Interp->process(R"( + Cpp::Process(R"( #include void f2(std::string &s) { printf("%s", s.c_str()); }; )"); - Interp->process(R"( + Cpp::Process(R"( namespace NS { int f3() { return 3; } @@ -1729,7 +1777,7 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { EXPECT_EQ(callback(), 3); // FIXME: Do we need to support private ctors? - Interp->process(R"( + Cpp::Process(R"( class C { public: C() { printf("Default Ctor Called\n"); } @@ -1766,9 +1814,9 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { }; )"; - GetAllTopLevelDecls(code1, Decls1, /*filter_implicitGenerated=*/false, - interpreter_args); - ASTContext& C = Interp->getCI()->getASTContext(); + Cpp::TInterp_t I = GetAllTopLevelDecls( + code1, Decls1, /*filter_implicitGenerated=*/false, interpreter_args); + ASTContext& C = TU_getASTContext(I); std::vector argument = {C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls1[0], argument.data(), @@ -1786,7 +1834,7 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { EXPECT_EQ(result, a + b); // call with pointers - Interp->process(R"( + Cpp::Process(R"( void set_5(int *out) { *out = 5; } @@ -1803,7 +1851,7 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { set_5_f.Invoke(nullptr, {set_5_args, 1}); EXPECT_EQ(b, 5); - Interp->process(R"( + Cpp::Process(R"( class TypedefToPrivateClass { private: class PC { @@ -1832,7 +1880,7 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { EXPECT_TRUE(res); // templated operators - Interp->process(R"( + Cpp::Process(R"( class TOperator{ public: template @@ -1859,7 +1907,7 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { FCI_op.Invoke((void*)&boolean, {args, /*args_size=*/1}, toperator); EXPECT_TRUE(boolean); - Interp->process(R"( + Cpp::Process(R"( namespace N1 { template struct Klass3 { @@ -1899,7 +1947,7 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { auto chrono_op_fn_callable = Cpp::MakeFunctionCallable(kop); EXPECT_EQ(chrono_op_fn_callable.getKind(), Cpp::JitCall::kGenericCall); - Interp->process(R"( + Cpp::Process(R"( namespace my_std { template struct pair { @@ -1980,7 +2028,7 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { auto fn_callable = Cpp::MakeFunctionCallable(fn); EXPECT_EQ(fn_callable.getKind(), Cpp::JitCall::kGenericCall); - Interp->process(R"( + Cpp::Process(R"( template bool call_move(T&& t) { return true; @@ -2001,7 +2049,7 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { EXPECT_EQ(call_move_callable.getKind(), Cpp::JitCall::kGenericCall); // instantiation in host, no template function body - Interp->process("template T instantiation_in_host();"); + Cpp::Process("template T instantiation_in_host();"); unresolved_candidate_methods.clear(); Cpp::GetClassTemplatedMethods("instantiation_in_host", Cpp::GetGlobalScope(), @@ -2029,7 +2077,7 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { EXPECT_EQ(instantiation_in_host_callable.getKind(), Cpp::JitCall::kUnknown); // expect to fail - Interp->process(R"( + Cpp::Process(R"( template struct tuple {}; @@ -2054,7 +2102,7 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { auto tuple_tuple_callable = Cpp::MakeFunctionCallable(tuple_tuple); EXPECT_EQ(tuple_tuple_callable.getKind(), Cpp::JitCall::kGenericCall); - Interp->process(R"( + Cpp::Process(R"( namespace EnumFunctionSameName { enum foo { FOO = 42 }; void foo() {} @@ -2188,7 +2236,7 @@ TEST(FunctionReflectionTest, GetFunctionCallWrapper) { EXPECT_FALSE(Cpp::IsLambdaClass(Cpp::GetFunctionReturnType(bar))); } -TEST(FunctionReflectionTest, IsConstMethod) { +static void FunctionReflectionTest_IsConstMethod() { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -2197,7 +2245,9 @@ TEST(FunctionReflectionTest, IsConstMethod) { }; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + GetAllSubDecls(Decls[0], SubDecls); Cpp::TCppFunction_t method = nullptr; // Simulate an invalid method pointer @@ -2206,7 +2256,7 @@ TEST(FunctionReflectionTest, IsConstMethod) { EXPECT_FALSE(Cpp::IsConstMethod(method)); } -TEST(FunctionReflectionTest, GetFunctionArgName) { +static void FunctionReflectionTest_GetFunctionArgName() { std::vector Decls; std::string code = R"( void f1(int i, double d, long l, char ch) {} @@ -2222,7 +2272,9 @@ TEST(FunctionReflectionTest, GetFunctionArgName) { void get_size(long k, A, char ch = 'a', double l = 0.0) {} )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + EXPECT_EQ(Cpp::GetFunctionArgName(Decls[0], 0), "i"); EXPECT_EQ(Cpp::GetFunctionArgName(Decls[0], 1), "d"); EXPECT_EQ(Cpp::GetFunctionArgName(Decls[0], 2), "l"); @@ -2246,7 +2298,7 @@ TEST(FunctionReflectionTest, GetFunctionArgName) { EXPECT_EQ(Cpp::GetFunctionArgName(Decls[4], 3), "l"); } -TEST(FunctionReflectionTest, GetFunctionArgDefault) { +static void FunctionReflectionTest_GetFunctionArgDefault() { std::vector Decls; std::string code = R"( void f1(int i, double d = 4.0, const char *s = "default", char ch = 'c') {} @@ -2272,7 +2324,7 @@ TEST(FunctionReflectionTest, GetFunctionArgDefault) { }; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); EXPECT_EQ(Cpp::GetFunctionArgDefault(Decls[0], 0), ""); EXPECT_EQ(Cpp::GetFunctionArgDefault(Decls[0], 1), "4."); @@ -2295,7 +2347,7 @@ TEST(FunctionReflectionTest, GetFunctionArgDefault) { EXPECT_EQ(Cpp::GetFunctionArgDefault(Decls[4], 2), "\'a\'"); EXPECT_EQ(Cpp::GetFunctionArgDefault(Decls[4], 3), "0."); - ASTContext& C = Interp->getCI()->getASTContext(); + ASTContext& C = TU_getASTContext(I); Cpp::TemplateArgInfo template_args[1] = {C.IntTy.getAsOpaquePtr()}; Cpp::TCppScope_t my_struct = Cpp::InstantiateTemplate(Decls[6], template_args, 1); @@ -2311,6 +2363,7 @@ TEST(FunctionReflectionTest, GetFunctionArgDefault) { } TEST(FunctionReflectionTest, Construct) { + // XXX: no parallel #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -2338,7 +2391,9 @@ TEST(FunctionReflectionTest, Construct) { void construct() { return; } )"; - GetAllTopLevelDecls(code, Decls, false, interpreter_args); + Cpp::TInterp_t I1 = GetAllTopLevelDecls(code, Decls, false, interpreter_args); + EXPECT_TRUE(I1); + GetAllSubDecls(Decls[1], SubDecls); testing::internal::CaptureStdout(); Cpp::TCppScope_t scope = Cpp::GetNamed("C"); @@ -2391,7 +2446,7 @@ TEST(FunctionReflectionTest, Construct) { } // Test zero initialization of PODs and default initialization cases -TEST(FunctionReflectionTest, ConstructPOD) { +static void FunctionReflectionTest_ConstructPOD() { #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -2402,10 +2457,8 @@ TEST(FunctionReflectionTest, ConstructPOD) { #ifdef _WIN32 GTEST_SKIP() << "Disabled on Windows. Needs fixing."; #endif - std::vector interpreter_args = {"-include", "new"}; - Cpp::CreateInterpreter(interpreter_args); - Interp->declare(R"( + EXPECT_FALSE(Cpp::Declare(R"( namespace PODS { struct SomePOD_B { int fInt; @@ -2414,9 +2467,10 @@ TEST(FunctionReflectionTest, ConstructPOD) { int fInt; double fDouble; }; - })"); + })", + false, I)); - auto *ns = Cpp::GetNamed("PODS"); + auto* ns = Cpp::GetNamed("PODS", Cpp::GetGlobalScope(I)); Cpp::TCppScope_t scope = Cpp::GetNamed("SomePOD_B", ns); EXPECT_TRUE(scope); Cpp::TCppObject_t object = Cpp::Construct(scope); @@ -2435,6 +2489,7 @@ TEST(FunctionReflectionTest, ConstructPOD) { // Test nested constructor calls TEST(FunctionReflectionTest, ConstructNested) { + // XXX: no parallel #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -2449,7 +2504,7 @@ TEST(FunctionReflectionTest, ConstructNested) { std::vector interpreter_args = {"-include", "new"}; Cpp::CreateInterpreter(interpreter_args); - Interp->declare(R"( + Cpp::Declare(R"( #include extern "C" int printf(const char*,...); class A { @@ -2497,6 +2552,7 @@ TEST(FunctionReflectionTest, ConstructNested) { } TEST(FunctionReflectionTest, ConstructArray) { + // XXX: no parallel #if defined(EMSCRIPTEN) GTEST_SKIP() << "Test fails for Emscripten builds"; #endif @@ -2508,7 +2564,7 @@ TEST(FunctionReflectionTest, ConstructArray) { Cpp::CreateInterpreter(); - Interp->declare(R"( + Cpp::Declare(R"( #include extern "C" int printf(const char*,...); class C { @@ -2549,6 +2605,7 @@ TEST(FunctionReflectionTest, ConstructArray) { } TEST(FunctionReflectionTest, Destruct) { + // XXX: no parallel #ifdef EMSCRIPTEN GTEST_SKIP() << "Test fails for Emscipten builds"; #endif @@ -2562,7 +2619,7 @@ TEST(FunctionReflectionTest, Destruct) { std::vector interpreter_args = {"-include", "new"}; Cpp::CreateInterpreter(interpreter_args); - Interp->declare(R"( + Cpp::Declare(R"( #include extern "C" int printf(const char*,...); class C { @@ -2606,7 +2663,7 @@ TEST(FunctionReflectionTest, Destruct) { // Failure test, this wrapper should not compile since we explicitly delete // the destructor - Interp->declare(R"( + Cpp::Declare(R"( class D { public: D() {} @@ -2620,6 +2677,7 @@ TEST(FunctionReflectionTest, Destruct) { } TEST(FunctionReflectionTest, DestructArray) { + // XXX: no parallel #ifdef EMSCRIPTEN GTEST_SKIP() << "Test fails for Emscipten builds"; #endif @@ -2633,7 +2691,7 @@ TEST(FunctionReflectionTest, DestructArray) { std::vector interpreter_args = {"-include", "new"}; Cpp::CreateInterpreter(interpreter_args); - Interp->declare(R"( + Cpp::Declare(R"( #include extern "C" int printf(const char*,...); class C { @@ -2697,6 +2755,7 @@ TEST(FunctionReflectionTest, DestructArray) { } TEST(FunctionReflectionTest, UndoTest) { + // XXX: no parallel #ifdef _WIN32 GTEST_SKIP() << "Disabled on Windows. Needs fixing."; #endif @@ -2723,11 +2782,10 @@ TEST(FunctionReflectionTest, UndoTest) { #endif } -TEST(FunctionReflectionTest, FailingTest1) { +static void FunctionReflectionTest_FailingTest1() { #ifdef _WIN32 GTEST_SKIP() << "Disabled on Windows. Needs fixing."; #endif - Cpp::CreateInterpreter(); EXPECT_FALSE(Cpp::Declare(R"( class WithOutEqualOp1 {}; class WithOutEqualOp2 {}; @@ -2737,12 +2795,15 @@ TEST(FunctionReflectionTest, FailingTest1) { template bool is_equal(const C1& c1, const C2& c2) { return (bool)(c1 == c2); } - )")); + )", + false, I)); - Cpp::TCppType_t o1 = Cpp::GetTypeFromScope(Cpp::GetNamed("o1")); - Cpp::TCppType_t o2 = Cpp::GetTypeFromScope(Cpp::GetNamed("o2")); + Cpp::TCppType_t o1 = + Cpp::GetTypeFromScope(Cpp::GetNamed("o1", Cpp::GetGlobalScope(I))); + Cpp::TCppType_t o2 = + Cpp::GetTypeFromScope(Cpp::GetNamed("o2", Cpp::GetGlobalScope(I))); std::vector fns; - Cpp::GetClassTemplatedMethods("is_equal", Cpp::GetGlobalScope(), fns); + Cpp::GetClassTemplatedMethods("is_equal", Cpp::GetGlobalScope(I), fns); EXPECT_EQ(fns.size(), 1); Cpp::TemplateArgInfo args[2] = {{o1}, {o2}}; @@ -2751,6 +2812,91 @@ TEST(FunctionReflectionTest, FailingTest1) { Cpp::JitCall jit_call = Cpp::MakeFunctionCallable(fn); EXPECT_EQ(jit_call.getKind(), Cpp::JitCall::kUnknown); // expected to fail - EXPECT_FALSE(Cpp::Declare("int x = 1;")); - EXPECT_FALSE(Cpp::Declare("int y = x;")); + EXPECT_FALSE(Cpp::Declare("int x = 1;", false, I)); + EXPECT_FALSE(Cpp::Declare("int y = x;", false, I)); } + +TEST(FunctionReflectionTest, FunctionReflectionTest) { + I = Cpp::CreateInterpreter({"-include", "new"}); + EXPECT_TRUE(I); + + std::vector> fns = { + {"FunctionReflectionTest_GetClassMethods", + FunctionReflectionTest_GetClassMethods}, + {"FunctionReflectionTest_ConstructorInGetClassMethods", + FunctionReflectionTest_ConstructorInGetClassMethods}, + {"FunctionReflectionTest_HasDefaultConstructor", + FunctionReflectionTest_HasDefaultConstructor}, + {"FunctionReflectionTest_GetDestructor", + FunctionReflectionTest_GetDestructor}, + {"FunctionReflectionTest_GetFunctionsUsingName", + FunctionReflectionTest_GetFunctionsUsingName}, + {"FunctionReflectionTest_GetClassDecls", + FunctionReflectionTest_GetClassDecls}, + {"FunctionReflectionTest_GetFunctionTemplatedDecls", + FunctionReflectionTest_GetFunctionTemplatedDecls}, + {"FunctionReflectionTest_GetFunctionReturnType", + FunctionReflectionTest_GetFunctionReturnType}, + {"FunctionReflectionTest_GetFunctionNumArgs", + FunctionReflectionTest_GetFunctionNumArgs}, + {"FunctionReflectionTest_GetFunctionRequiredArgs", + FunctionReflectionTest_GetFunctionRequiredArgs}, + {"FunctionReflectionTest_GetFunctionArgType", + FunctionReflectionTest_GetFunctionArgType}, + {"FunctionReflectionTest_GetFunctionSignature", + FunctionReflectionTest_GetFunctionSignature}, + {"FunctionReflectionTest_IsTemplatedFunction", + FunctionReflectionTest_IsTemplatedFunction}, + {"FunctionReflectionTest_ExistsFunctionTemplate", + FunctionReflectionTest_ExistsFunctionTemplate}, + {"FunctionReflectionTest_InstantiateTemplateFunctionFromString", + FunctionReflectionTest_InstantiateTemplateFunctionFromString}, + {"FunctionReflectionTest_InstantiateFunctionTemplate", + FunctionReflectionTest_InstantiateFunctionTemplate}, + {"FunctionReflectionTest_InstantiateTemplateMethod", + FunctionReflectionTest_InstantiateTemplateMethod}, + {"FunctionReflectionTest_LookupConstructors", + FunctionReflectionTest_LookupConstructors}, + {"FunctionReflectionTest_GetClassTemplatedMethods", + FunctionReflectionTest_GetClassTemplatedMethods}, + {"FunctionReflectionTest_GetClassTemplatedMethods_VariadicsAndOthers", + FunctionReflectionTest_GetClassTemplatedMethods_VariadicsAndOthers}, + {"FunctionReflectionTest_InstantiateVariadicFunction", + FunctionReflectionTest_InstantiateVariadicFunction}, + {"FunctionReflectionTest_BestOverloadFunctionMatch1", + FunctionReflectionTest_BestOverloadFunctionMatch1}, + {"FunctionReflectionTest_BestOverloadFunctionMatch2", + FunctionReflectionTest_BestOverloadFunctionMatch2}, + {"FunctionReflectionTest_BestOverloadFunctionMatch3", + FunctionReflectionTest_BestOverloadFunctionMatch3}, + {"FunctionReflectionTest_BestOverloadFunctionMatch4", + FunctionReflectionTest_BestOverloadFunctionMatch4}, + {"FunctionReflectionTest_IsPublicMethod", + FunctionReflectionTest_IsPublicMethod}, + {"FunctionReflectionTest_IsProtectedMethod", + FunctionReflectionTest_IsProtectedMethod}, + {"FunctionReflectionTest_IsPrivateMethod", + FunctionReflectionTest_IsPrivateMethod}, + {"FunctionReflectionTest_IsConstructor", + FunctionReflectionTest_IsConstructor}, + {"FunctionReflectionTest_IsDestructor", + FunctionReflectionTest_IsDestructor}, + {"FunctionReflectionTest_IsStaticMethod", + FunctionReflectionTest_IsStaticMethod}, + {"FunctionReflectionTest_IsVirtualMethod", + FunctionReflectionTest_IsVirtualMethod}, + {"FunctionReflectionTest_JitCallAdvanced", + FunctionReflectionTest_JitCallAdvanced}, + {"FunctionReflectionTest_IsConstMethod", + FunctionReflectionTest_IsConstMethod}, + {"FunctionReflectionTest_GetFunctionArgName", + FunctionReflectionTest_GetFunctionArgName}, + {"FunctionReflectionTest_GetFunctionArgDefault", + FunctionReflectionTest_GetFunctionArgDefault}, + {"FunctionReflectionTest_ConstructPOD", + FunctionReflectionTest_ConstructPOD}, + {"FunctionReflectionTest_FailingTest1", + FunctionReflectionTest_FailingTest1}, + }; + ThreadPoolExecutor::run(fns); +} \ No newline at end of file diff --git a/unittests/CppInterOp/InterpreterTest.cpp b/unittests/CppInterOp/InterpreterTest.cpp index 5800fe64e..440a1b89c 100644 --- a/unittests/CppInterOp/InterpreterTest.cpp +++ b/unittests/CppInterOp/InterpreterTest.cpp @@ -379,7 +379,6 @@ TEST(InterpreterTest, MultipleInterpreter) { #ifdef _WIN32 GTEST_SKIP() << "Disabled on Windows. Needs fixing."; #endif - GTEST_SKIP() << "Test does not consistently pass so skipping for now"; // delete all old interpreters while (Cpp::DeleteInterpreter()) ; diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index 53b2ee894..edad46375 100644 --- a/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -20,12 +20,16 @@ #include "gtest/gtest.h" #include +#include using namespace TestUtils; using namespace llvm; using namespace clang; -TEST(ScopeReflectionTest, Demangle) { +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +static Cpp::TInterp_t I = nullptr; + +static void ScopeReflectionTest_Demangle() { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -55,7 +59,7 @@ TEST(ScopeReflectionTest, Demangle) { std::string::npos); } -TEST(ScopeReflectionTest, IsAggregate) { +static void ScopeReflectionTest_IsAggregate() { std::vector Decls; std::string code = R"( char cv[4] = {}; @@ -81,7 +85,7 @@ TEST(ScopeReflectionTest, IsAggregate) { } // Check that the CharInfo table has been constructed reasonably. -TEST(ScopeReflectionTest, IsNamespace) { +static void ScopeReflectionTest_IsNamespace() { std::vector Decls; GetAllTopLevelDecls("namespace N {} class C{}; int I;", Decls); EXPECT_TRUE(Cpp::IsNamespace(Decls[0])); @@ -89,7 +93,7 @@ TEST(ScopeReflectionTest, IsNamespace) { EXPECT_FALSE(Cpp::IsNamespace(Decls[2])); } -TEST(ScopeReflectionTest, IsClass) { +static void ScopeReflectionTest_IsClass() { std::vector Decls; GetAllTopLevelDecls("namespace N {} class C{}; int I;", Decls); EXPECT_FALSE(Cpp::IsClass(Decls[0])); @@ -97,7 +101,7 @@ TEST(ScopeReflectionTest, IsClass) { EXPECT_FALSE(Cpp::IsClass(Decls[2])); } -TEST(ScopeReflectionTest, IsClassPolymorphic) { +static void ScopeReflectionTest_IsClassPolymorphic() { std::vector Decls; GetAllTopLevelDecls(R"( namespace N {} @@ -119,7 +123,7 @@ TEST(ScopeReflectionTest, IsClassPolymorphic) { EXPECT_FALSE(Cpp::IsClassPolymorphic(Decls[3])); } -TEST(ScopeReflectionTest, IsComplete) { +static void ScopeReflectionTest_IsComplete() { std::vector Decls; std::string code = R"( namespace N {} @@ -144,7 +148,7 @@ TEST(ScopeReflectionTest, IsComplete) { EXPECT_FALSE(Cpp::IsComplete(nullptr)); } -TEST(ScopeReflectionTest, SizeOf) { +static void ScopeReflectionTest_SizeOf() { std::vector Decls; std::string code = R"(namespace N {} class C{}; int I; struct S; enum E : int; union U{}; class Size4{int i;}; @@ -162,8 +166,8 @@ TEST(ScopeReflectionTest, SizeOf) { EXPECT_EQ(Cpp::SizeOf(Decls[7]), sizeof(B)); } - TEST(ScopeReflectionTest, IsBuiltin) { + // XXX: no parallel #if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \ defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) GTEST_SKIP() << "Test fails with Cling on Windows on ARM"; @@ -176,8 +180,9 @@ TEST(ScopeReflectionTest, IsBuiltin) { std::vector interpreter_args = { "-include", "new" }; - Cpp::CreateInterpreter(interpreter_args); - ASTContext &C = Interp->getCI()->getASTContext(); + Cpp::TInterp_t I = Cpp::CreateInterpreter(interpreter_args); + EXPECT_TRUE(I); + ASTContext& C = TU_getASTContext(I); EXPECT_TRUE(Cpp::IsBuiltin(C.BoolTy.getAsOpaquePtr())); EXPECT_TRUE(Cpp::IsBuiltin(C.CharTy.getAsOpaquePtr())); EXPECT_TRUE(Cpp::IsBuiltin(C.SignedCharTy.getAsOpaquePtr())); @@ -191,15 +196,15 @@ TEST(ScopeReflectionTest, IsBuiltin) { EXPECT_TRUE(Cpp::IsBuiltin(C.getComplexType(C.Float128Ty).getAsOpaquePtr())); // std::complex - Interp->declare("#include "); - Sema &S = Interp->getCI()->getSema(); + EXPECT_FALSE(Cpp::Declare("#include ", false, I)); + Sema& S = TU_getSema(I); auto lookup = S.getStdNamespace()->lookup(&C.Idents.get("complex")); auto *CTD = cast(lookup.front()); for (ClassTemplateSpecializationDecl *CTSD : CTD->specializations()) EXPECT_TRUE(Cpp::IsBuiltin(C.getTypeDeclType(CTSD).getAsOpaquePtr())); } -TEST(ScopeReflectionTest, IsTemplate) { +static void ScopeReflectionTest_IsTemplate() { std::vector Decls; std::string code = R"(template class A{}; @@ -225,7 +230,7 @@ TEST(ScopeReflectionTest, IsTemplate) { EXPECT_FALSE(Cpp::IsTemplate(Decls[3])); } -TEST(ScopeReflectionTest, IsTemplateSpecialization) { +static void ScopeReflectionTest_IsTemplateSpecialization() { std::vector Decls; std::string code = R"( template @@ -241,7 +246,7 @@ TEST(ScopeReflectionTest, IsTemplateSpecialization) { Cpp::GetScopeFromType(Cpp::GetVariableType(Decls[1])))); } -TEST(ScopeReflectionTest, IsTypedefed) { +static void ScopeReflectionTest_IsTypedefed() { std::vector Decls; std::string code = R"( typedef int I; @@ -255,7 +260,7 @@ TEST(ScopeReflectionTest, IsTypedefed) { EXPECT_FALSE(Cpp::IsTypedefed(Decls[2])); } -TEST(ScopeReflectionTest, IsAbstract) { +static void ScopeReflectionTest_IsAbstract() { std::vector Decls; std::string code = R"( class A {}; @@ -275,7 +280,7 @@ TEST(ScopeReflectionTest, IsAbstract) { EXPECT_FALSE(Cpp::IsAbstract(Decls[2])); } -TEST(ScopeReflectionTest, IsVariable) { +static void ScopeReflectionTest_IsVariable() { std::vector Decls; std::string code = R"( int i; @@ -299,7 +304,7 @@ TEST(ScopeReflectionTest, IsVariable) { EXPECT_TRUE(Cpp::IsVariable(SubDecls[3])); } -TEST(ScopeReflectionTest, GetName) { +static void ScopeReflectionTest_GetName() { std::vector Decls; std::string code = R"(namespace N {} class C{}; int I; struct S; enum E : int; union U{}; class Size4{int i;}; @@ -317,7 +322,7 @@ TEST(ScopeReflectionTest, GetName) { EXPECT_EQ(Cpp::GetName(nullptr), ""); } -TEST(ScopeReflectionTest, GetCompleteName) { +static void ScopeReflectionTest_GetCompleteName() { std::vector Decls; std::string code = R"(namespace N {} class C{}; @@ -337,7 +342,8 @@ TEST(ScopeReflectionTest, GetCompleteName) { template void fn(T1 t1, T2 t2) {} )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); EXPECT_EQ(Cpp::GetCompleteName(Decls[0]), "N"); EXPECT_EQ(Cpp::GetCompleteName(Decls[1]), "C"); @@ -355,7 +361,7 @@ TEST(ScopeReflectionTest, GetCompleteName) { EXPECT_EQ(Cpp::GetCompleteName(Decls[11]), "fn"); EXPECT_EQ(Cpp::GetCompleteName(nullptr), ""); - ASTContext& C = Interp->getCI()->getASTContext(); + ASTContext& C = TU_getASTContext(I); Cpp::TemplateArgInfo template_args[2] = {C.IntTy.getAsOpaquePtr(), C.DoubleTy.getAsOpaquePtr()}; Cpp::TCppScope_t fn = Cpp::InstantiateTemplate(Decls[11], template_args, 2); @@ -363,7 +369,7 @@ TEST(ScopeReflectionTest, GetCompleteName) { EXPECT_EQ(Cpp::GetCompleteName(fn), "fn"); } -TEST(ScopeReflectionTest, GetQualifiedName) { +static void ScopeReflectionTest_GetQualifiedName() { std::vector Decls; std::string code = R"(namespace N { class C { @@ -383,7 +389,7 @@ TEST(ScopeReflectionTest, GetQualifiedName) { EXPECT_EQ(Cpp::GetQualifiedName(Decls[4]), "N::C::E"); } -TEST(ScopeReflectionTest, GetQualifiedCompleteName) { +static void ScopeReflectionTest_GetQualifiedCompleteName() { std::vector Decls; std::string code = R"(namespace N { class C { @@ -408,7 +414,7 @@ TEST(ScopeReflectionTest, GetQualifiedCompleteName) { EXPECT_EQ(Cpp::GetQualifiedCompleteName(Decls[6]), "N::C::E"); } -TEST(ScopeReflectionTest, GetUsingNamespaces) { +static void ScopeReflectionTest_GetUsingNamespaces() { std::vector Decls, Decls1; std::string code = R"( namespace abc { @@ -422,10 +428,10 @@ TEST(ScopeReflectionTest, GetUsingNamespaces) { using I = int; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); std::vector usingNamespaces; - usingNamespaces = Cpp::GetUsingNamespaces( - Decls[0]->getASTContext().getTranslationUnitDecl()); + usingNamespaces = Cpp::GetUsingNamespaces(Cpp::GetGlobalScope(I)); //EXPECT_EQ(Cpp::GetName(usingNamespaces[0]), "runtime"); EXPECT_EQ(Cpp::GetName(usingNamespaces[usingNamespaces.size()-2]), "std"); @@ -441,26 +447,26 @@ TEST(ScopeReflectionTest, GetUsingNamespaces) { EXPECT_EQ(usingNamespaces1.size(), 0); } -TEST(ScopeReflectionTest, GetGlobalScope) { - EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetGlobalScope()), ""); - EXPECT_EQ(Cpp::GetName(Cpp::GetGlobalScope()), ""); +static void ScopeReflectionTest_GetGlobalScope() { + EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetGlobalScope(I)), ""); + EXPECT_EQ(Cpp::GetName(Cpp::GetGlobalScope(I)), ""); } -TEST(ScopeReflectionTest, GetUnderlyingScope) { +static void ScopeReflectionTest_GetUnderlyingScope() { std::vector Decls; std::string code = R"( - namespace N { + namespace NN { class C {}; } - typedef N::C NC; + typedef NN::C NC; typedef int INT; )"; GetAllTopLevelDecls(code, Decls); - EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetUnderlyingScope(Decls[0])), "N"); - EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetUnderlyingScope(Decls[1])), "N::C"); + EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetUnderlyingScope(Decls[0])), "NN"); + EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetUnderlyingScope(Decls[1])), "NN::C"); EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetUnderlyingScope(Decls[2])), "INT"); EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetUnderlyingScope(nullptr)), ""); } @@ -476,8 +482,9 @@ TEST(ScopeReflectionTest, GetScope) { typedef N::C T; )"; - Cpp::CreateInterpreter(); - Interp->declare(code); + Cpp::TInterp_t I = Cpp::CreateInterpreter(); + EXPECT_TRUE(I); + EXPECT_FALSE(Cpp::Declare(code.c_str(), false, I)); Cpp::TCppScope_t tu = Cpp::GetScope("", 0); Cpp::TCppScope_t ns_N = Cpp::GetScope("N", 0); Cpp::TCppScope_t cl_C = Cpp::GetScope("C", ns_N); @@ -491,8 +498,8 @@ TEST(ScopeReflectionTest, GetScope) { EXPECT_EQ(Cpp::GetQualifiedName(non_existent), ""); } -TEST(ScopeReflectionTest, GetScopefromCompleteName) { - std::string code = R"(namespace N1 { +static void ScopeReflectionTest_GetScopefromCompleteName() { + std::string code = R"(namespace NN1 { namespace N2 { class C { struct S {}; @@ -501,13 +508,18 @@ TEST(ScopeReflectionTest, GetScopefromCompleteName) { } )"; - Cpp::CreateInterpreter(); - - Interp->declare(code); - EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetScopeFromCompleteName("N1")), "N1"); - EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetScopeFromCompleteName("N1::N2")), "N1::N2"); - EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetScopeFromCompleteName("N1::N2::C")), "N1::N2::C"); - EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetScopeFromCompleteName("N1::N2::C::S")), "N1::N2::C::S"); + EXPECT_FALSE(Cpp::Declare(code.c_str(), false, I)); + + EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetScopeFromCompleteName("NN1", I)), + "NN1"); + EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetScopeFromCompleteName("NN1::N2", I)), + "NN1::N2"); + EXPECT_EQ( + Cpp::GetQualifiedName(Cpp::GetScopeFromCompleteName("NN1::N2::C", I)), + "NN1::N2::C"); + EXPECT_EQ( + Cpp::GetQualifiedName(Cpp::GetScopeFromCompleteName("NN1::N2::C::S", I)), + "NN1::N2::C::S"); } TEST(ScopeReflectionTest, GetNamed) { @@ -526,11 +538,8 @@ TEST(ScopeReflectionTest, GetNamed) { } )"; - std::vector interpreter_args = {"-include", "new"}; - - Cpp::CreateInterpreter(interpreter_args); + EXPECT_FALSE(Cpp::Declare(code.c_str(), false, I)); - Interp->declare(code); Cpp::TCppScope_t ns_N1 = Cpp::GetNamed("N1", nullptr); Cpp::TCppScope_t ns_N2 = Cpp::GetNamed("N2", ns_N1); Cpp::TCppScope_t cl_C = Cpp::GetNamed("C", ns_N2); @@ -546,7 +555,7 @@ TEST(ScopeReflectionTest, GetNamed) { EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetNamed("B", cl_C)), "N1::N2::C::B"); EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetNamed("S", cl_C)), "N1::N2::C::S"); - Interp->process("#include "); + EXPECT_FALSE(Cpp::Declare("#include ", false, I)); Cpp::TCppScope_t std_ns = Cpp::GetNamed("std", nullptr); Cpp::TCppScope_t std_string_class = Cpp::GetNamed("string", std_ns); Cpp::TCppScope_t std_string_npos_var = Cpp::GetNamed("npos", std_string_class); @@ -555,9 +564,9 @@ TEST(ScopeReflectionTest, GetNamed) { EXPECT_EQ(Cpp::GetQualifiedName(std_string_npos_var), "std::basic_string::npos"); } -TEST(ScopeReflectionTest, GetParentScope) { +static void ScopeReflectionTest_GetParentScope() { std::string code = R"(namespace N1 { - namespace N2 { + namespace NN2 { class C { int i; enum E { A, B }; @@ -567,11 +576,10 @@ TEST(ScopeReflectionTest, GetParentScope) { } )"; - Cpp::CreateInterpreter(); + EXPECT_FALSE(Cpp::Declare(code.c_str(), false, I)); - Interp->declare(code); - Cpp::TCppScope_t ns_N1 = Cpp::GetNamed("N1"); - Cpp::TCppScope_t ns_N2 = Cpp::GetNamed("N2", ns_N1); + Cpp::TCppScope_t ns_N1 = Cpp::GetNamed("N1", Cpp::GetGlobalScope(I)); + Cpp::TCppScope_t ns_N2 = Cpp::GetNamed("NN2", ns_N1); Cpp::TCppScope_t cl_C = Cpp::GetNamed("C", ns_N2); Cpp::TCppScope_t int_i = Cpp::GetNamed("i", cl_C); Cpp::TCppScope_t en_E = Cpp::GetNamed("E", cl_C); @@ -580,14 +588,14 @@ TEST(ScopeReflectionTest, GetParentScope) { EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetParentScope(ns_N1)), ""); EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetParentScope(ns_N2)), "N1"); - EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetParentScope(cl_C)), "N1::N2"); - EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetParentScope(int_i)), "N1::N2::C"); - EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetParentScope(en_E)), "N1::N2::C"); - EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetParentScope(en_A)), "N1::N2::C::E"); - EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetParentScope(en_B)), "N1::N2::C::E"); + EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetParentScope(cl_C)), "N1::NN2"); + EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetParentScope(int_i)), "N1::NN2::C"); + EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetParentScope(en_E)), "N1::NN2::C"); + EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetParentScope(en_A)), "N1::NN2::C::E"); + EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetParentScope(en_B)), "N1::NN2::C::E"); } -TEST(ScopeReflectionTest, GetScopeFromType) { +static void ScopeReflectionTest_GetScopeFromType() { std::vector Decls; std::string code = R"( namespace N { @@ -631,7 +639,7 @@ TEST(ScopeReflectionTest, GetScopeFromType) { "N::C"); } -TEST(ScopeReflectionTest, GetNumBases) { +static void ScopeReflectionTest_GetNumBases() { std::vector Decls; std::string code = R"( class A {}; @@ -663,6 +671,7 @@ TEST(ScopeReflectionTest, GetNumBases) { } TEST(ScopeReflectionTest, GetBaseClass) { + // XXX: no parallel std::vector Decls; std::string code = R"( class A {}; @@ -711,7 +720,7 @@ TEST(ScopeReflectionTest, GetBaseClass) { EXPECT_EQ(Cpp::GetCompleteName(A_class), "A"); } -TEST(ScopeReflectionTest, IsSubclass) { +static void ScopeReflectionTest_IsSubclass() { std::vector Decls; std::string code = R"( class A {}; @@ -753,7 +762,7 @@ TEST(ScopeReflectionTest, IsSubclass) { EXPECT_FALSE(Cpp::IsSubclass(Decls[4], nullptr)); } -TEST(ScopeReflectionTest, GetBaseClassOffset) { +static void ScopeReflectionTest_GetBaseClassOffset() { std::vector Decls; #define Stringify(s) Stringifyx(s) #define Stringifyx(...) #__VA_ARGS__ @@ -790,7 +799,7 @@ CODE; EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[6], Decls[0]), (char *)(A*)g - (char *)g); } -TEST(ScopeReflectionTest, GetAllCppNames) { +static void ScopeReflectionTest_GetAllCppNames() { std::vector Decls; std::string code = R"( class A { int a; }; @@ -833,6 +842,7 @@ TEST(ScopeReflectionTest, GetAllCppNames) { } TEST(ScopeReflectionTest, InstantiateNNTPClassTemplate) { + // XXX: no parallel std::vector Decls; std::string code = R"( template @@ -845,9 +855,10 @@ TEST(ScopeReflectionTest, InstantiateNNTPClassTemplate) { enum { value = 1 }; };)"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I1 = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I1); - ASTContext &C = Interp->getCI()->getASTContext(); + ASTContext& C = TU_getASTContext(I1); Cpp::TCppType_t IntTy = C.IntTy.getAsOpaquePtr(); std::vector args1 = {{IntTy, "5"}}; EXPECT_TRUE(Cpp::InstantiateTemplate(Decls[0], args1.data(), @@ -865,14 +876,15 @@ TEST(ScopeReflectionTest, InstantiateNNTPClassTemplate) { clang_Interpreter_dispose(I); } -TEST(ScopeReflectionTest, InstantiateVarTemplate) { +static void ScopeReflectionTest_InstantiateVarTemplate() { std::vector Decls; std::string code = R"( template constexpr T pi = T(3.1415926535897932385L); )"; - GetAllTopLevelDecls(code, Decls); - ASTContext& C = Interp->getCI()->getASTContext(); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + ASTContext& C = TU_getASTContext(I); std::vector args1 = {C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(), @@ -895,8 +907,9 @@ TEST(ScopeReflectionTest, InstantiateFunctionTemplate) { template T TrivialFnTemplate() { return T(); } )"; - GetAllTopLevelDecls(code, Decls); - ASTContext& C = Interp->getCI()->getASTContext(); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + ASTContext& C = TU_getASTContext(I); std::vector args1 = {C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(), @@ -909,23 +922,25 @@ template T TrivialFnTemplate() { return T(); } EXPECT_TRUE(TA1.getAsType()->isIntegerType()); } -TEST(ScopeReflectionTest, InstantiateTemplateFunctionFromString) { +static void ScopeReflectionTest_InstantiateTemplateFunctionFromString() { #if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \ defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) GTEST_SKIP() << "Test fails with Cling on Windows on ARM"; #endif if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; - std::vector interpreter_args = {"-include", "new"}; - Cpp::CreateInterpreter(interpreter_args); + std::string code = R"(#include )"; - Interp->process(code); + + EXPECT_FALSE(Cpp::Declare(code.c_str(), false, I)); + const char* str = "std::make_unique"; - auto* Instance1 = (Decl*)Cpp::InstantiateTemplateFunctionFromString(str); + auto* Instance1 = + static_cast(Cpp::InstantiateTemplateFunctionFromString(str, I)); EXPECT_TRUE(Instance1); } -TEST(ScopeReflectionTest, InstantiateTemplate) { +static void ScopeReflectionTest_InstantiateTemplate() { std::vector Decls; std::string code = R"( template @@ -965,8 +980,9 @@ TEST(ScopeReflectionTest, InstantiateTemplate) { class C2{}; )"; - GetAllTopLevelDecls(code, Decls); - ASTContext &C = Interp->getCI()->getASTContext(); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + ASTContext& C = TU_getASTContext(I); std::vector args1 = {C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(), @@ -1016,7 +1032,7 @@ TEST(ScopeReflectionTest, InstantiateTemplate) { EXPECT_TRUE(TA4_1.getAsIntegral() == 3); } -TEST(ScopeReflectionTest, GetClassTemplateInstantiationArgs) { +static void ScopeReflectionTest_GetClassTemplateInstantiationArgs() { std::vector Decls; std::string code = R"( template struct __Cppyy_AppendTypesSlow {}; @@ -1025,11 +1041,12 @@ TEST(ScopeReflectionTest, GetClassTemplateInstantiationArgs) { __Cppyy_AppendTypesSlow<> v3; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); - auto *v1 = Cpp::GetNamed("v1"); - auto *v2 = Cpp::GetNamed("v2"); - auto *v3 = Cpp::GetNamed("v3"); + auto* v1 = Cpp::GetNamed("v1", Cpp::GetGlobalScope(I)); + auto* v2 = Cpp::GetNamed("v2", Cpp::GetGlobalScope(I)); + auto* v3 = Cpp::GetNamed("v3", Cpp::GetGlobalScope(I)); EXPECT_TRUE(v1 && v2 && v3); auto *v1_class = Cpp::GetScopeFromType(Cpp::GetVariableType(v1)); @@ -1053,8 +1070,7 @@ TEST(ScopeReflectionTest, GetClassTemplateInstantiationArgs) { EXPECT_TRUE(instance_types.size() == 0); } - -TEST(ScopeReflectionTest, IncludeVector) { +static void ScopeReflectionTest_IncludeVector() { #if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \ defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) GTEST_SKIP() << "Test fails with Cling on Windows on ARM"; @@ -1065,17 +1081,13 @@ TEST(ScopeReflectionTest, IncludeVector) { #include #include )"; - std::vector interpreter_args = {"-include", "new"}; - Cpp::CreateInterpreter(interpreter_args); - Interp->declare(code); + EXPECT_FALSE(Cpp::Declare(code.c_str(), false, I)); } -TEST(ScopeReflectionTest, GetOperator) { +static void ScopeReflectionTest_GetOperator() { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; - Cpp::CreateInterpreter(); - std::string code = R"( class MyClass { public: @@ -1108,39 +1120,41 @@ TEST(ScopeReflectionTest, GetOperator) { } )"; - Cpp::Declare(code.c_str()); + EXPECT_FALSE(Cpp::Declare(code.c_str(), false, I)); std::vector ops; - Cpp::GetOperator(Cpp::GetGlobalScope(), Cpp::Operator::OP_Plus, ops); + Cpp::GetOperator(Cpp::GetGlobalScope(I), Cpp::Operator::OP_Plus, ops); EXPECT_EQ(ops.size(), 1); ops.clear(); - Cpp::GetOperator(Cpp::GetGlobalScope(), Cpp::Operator::OP_Minus, ops); + Cpp::GetOperator(Cpp::GetGlobalScope(I), Cpp::Operator::OP_Minus, ops); EXPECT_EQ(ops.size(), 1); ops.clear(); - Cpp::GetOperator(Cpp::GetGlobalScope(), Cpp::Operator::OP_Star, ops); + Cpp::GetOperator(Cpp::GetGlobalScope(I), Cpp::Operator::OP_Star, ops); EXPECT_EQ(ops.size(), 0); ops.clear(); // operators defined within a namespace - Cpp::GetOperator(Cpp::GetScope("extra_ops"), Cpp::Operator::OP_Plus, ops); + Cpp::GetOperator(Cpp::GetScope("extra_ops", Cpp::GetGlobalScope(I)), + Cpp::Operator::OP_Plus, ops); EXPECT_EQ(ops.size(), 2); ops.clear(); // unary operator - Cpp::GetOperator(Cpp::GetScope("extra_ops"), Cpp::Operator::OP_Tilde, ops); + Cpp::GetOperator(Cpp::GetScope("extra_ops", Cpp::GetGlobalScope(I)), + Cpp::Operator::OP_Tilde, ops); EXPECT_EQ(ops.size(), 1); ops.clear(); - Cpp::GetOperator(Cpp::GetScope("extra_ops"), Cpp::Operator::OP_Tilde, ops, - Cpp::OperatorArity::kUnary); + Cpp::GetOperator(Cpp::GetScope("extra_ops", Cpp::GetGlobalScope(I)), + Cpp::Operator::OP_Tilde, ops, Cpp::OperatorArity::kUnary); EXPECT_EQ(ops.size(), 1); ops.clear(); - Cpp::GetOperator(Cpp::GetScope("extra_ops"), Cpp::Operator::OP_Tilde, ops, - Cpp::OperatorArity::kBinary); + Cpp::GetOperator(Cpp::GetScope("extra_ops", Cpp::GetGlobalScope(I)), + Cpp::Operator::OP_Tilde, ops, Cpp::OperatorArity::kBinary); EXPECT_EQ(ops.size(), 0); std::string inheritance_code = R"( @@ -1159,13 +1173,73 @@ TEST(ScopeReflectionTest, GetOperator) { } }; )"; - Cpp::Declare(inheritance_code.c_str()); + EXPECT_FALSE(Cpp::Declare(inheritance_code.c_str(), false, I)); ops.clear(); - Cpp::GetOperator(Cpp::GetScope("Child"), Cpp::Operator::OP_Plus, ops); + Cpp::GetOperator(Cpp::GetScope("Child", Cpp::GetGlobalScope(I)), + Cpp::Operator::OP_Plus, ops); EXPECT_EQ(ops.size(), 1); ops.clear(); - Cpp::GetOperator(Cpp::GetScope("Child"), Cpp::Operator::OP_Minus, ops); + Cpp::GetOperator(Cpp::GetScope("Child", Cpp::GetGlobalScope(I)), + Cpp::Operator::OP_Minus, ops); EXPECT_EQ(ops.size(), 1); } + +TEST(ScopeReflectionTest, ScopeReflectionTest) { + I = Cpp::CreateInterpreter({"-include", "new"}); + EXPECT_TRUE(I); + + std::vector> fns = { + {"ScopeReflectionTest_Demangle", ScopeReflectionTest_Demangle}, + {"ScopeReflectionTest_IsAggregate", ScopeReflectionTest_IsAggregate}, + {"ScopeReflectionTest_IsNamespace", ScopeReflectionTest_IsNamespace}, + {"ScopeReflectionTest_IsClass", ScopeReflectionTest_IsClass}, + {"ScopeReflectionTest_IsClassPolymorphic", + ScopeReflectionTest_IsClassPolymorphic}, + {"ScopeReflectionTest_IsComplete", ScopeReflectionTest_IsComplete}, + {"ScopeReflectionTest_SizeOf", ScopeReflectionTest_SizeOf}, + {"ScopeReflectionTest_IsTemplate", ScopeReflectionTest_IsTemplate}, + {"ScopeReflectionTest_IsTemplateSpecialization", + ScopeReflectionTest_IsTemplateSpecialization}, + {"ScopeReflectionTest_IsTypedefed", ScopeReflectionTest_IsTypedefed}, + {"ScopeReflectionTest_IsAbstract", ScopeReflectionTest_IsAbstract}, + {"ScopeReflectionTest_IsVariable", ScopeReflectionTest_IsVariable}, + {"ScopeReflectionTest_GetName", ScopeReflectionTest_GetName}, + {"ScopeReflectionTest_GetCompleteName", + ScopeReflectionTest_GetCompleteName}, + {"ScopeReflectionTest_GetQualifiedName", + ScopeReflectionTest_GetQualifiedName}, + {"ScopeReflectionTest_GetQualifiedCompleteName", + ScopeReflectionTest_GetQualifiedCompleteName}, + {"ScopeReflectionTest_GetUsingNamespaces", + ScopeReflectionTest_GetUsingNamespaces}, + {"ScopeReflectionTest_GetGlobalScope", + ScopeReflectionTest_GetGlobalScope}, + {"ScopeReflectionTest_GetUnderlyingScope", + ScopeReflectionTest_GetUnderlyingScope}, + {"ScopeReflectionTest_GetScopefromCompleteName", + ScopeReflectionTest_GetScopefromCompleteName}, + {"ScopeReflectionTest_GetParentScope", + ScopeReflectionTest_GetParentScope}, + {"ScopeReflectionTest_GetScopeFromType", + ScopeReflectionTest_GetScopeFromType}, + {"ScopeReflectionTest_GetNumBases", ScopeReflectionTest_GetNumBases}, + {"ScopeReflectionTest_IsSubclass", ScopeReflectionTest_IsSubclass}, + {"ScopeReflectionTest_GetBaseClassOffset", + ScopeReflectionTest_GetBaseClassOffset}, + {"ScopeReflectionTest_GetAllCppNames", + ScopeReflectionTest_GetAllCppNames}, + {"ScopeReflectionTest_InstantiateVarTemplate", + ScopeReflectionTest_InstantiateVarTemplate}, + {"ScopeReflectionTest_InstantiateTemplateFunctionFromString", + ScopeReflectionTest_InstantiateTemplateFunctionFromString}, + {"ScopeReflectionTest_InstantiateTemplate", + ScopeReflectionTest_InstantiateTemplate}, + {"ScopeReflectionTest_GetClassTemplateInstantiationArgs", + ScopeReflectionTest_GetClassTemplateInstantiationArgs}, + {"ScopeReflectionTest_IncludeVector", ScopeReflectionTest_IncludeVector}, + {"ScopeReflectionTest_GetOperator", ScopeReflectionTest_GetOperator}, + }; + ThreadPoolExecutor::run(fns); +} \ No newline at end of file diff --git a/unittests/CppInterOp/TypeReflectionTest.cpp b/unittests/CppInterOp/TypeReflectionTest.cpp index 215d30f10..c9fe09737 100644 --- a/unittests/CppInterOp/TypeReflectionTest.cpp +++ b/unittests/CppInterOp/TypeReflectionTest.cpp @@ -12,12 +12,16 @@ #include "gtest/gtest.h" #include +#include using namespace TestUtils; using namespace llvm; using namespace clang; -TEST(TypeReflectionTest, GetTypeAsString) { +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +static Cpp::TInterp_t I = nullptr; + +static void TypeReflectionTest_GetTypeAsString() { std::vector Decls; std::string code = R"( namespace N { @@ -38,7 +42,8 @@ TEST(TypeReflectionTest, GetTypeAsString) { )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); QualType QT1 = llvm::dyn_cast(Decls[1])->getType(); QualType QT2 = llvm::dyn_cast(Decls[2])->getType(); QualType QT3 = llvm::dyn_cast(Decls[3])->getType(); @@ -57,7 +62,7 @@ TEST(TypeReflectionTest, GetTypeAsString) { EXPECT_EQ(Cpp::GetTypeAsString(QT7.getAsOpaquePtr()), "char[4]"); } -TEST(TypeReflectionTest, GetSizeOfType) { +static void TypeReflectionTest_GetSizeOfType() { std::vector Decls; std::string code = R"( struct S { @@ -73,7 +78,8 @@ TEST(TypeReflectionTest, GetSizeOfType) { FwdDecl *f; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); EXPECT_EQ(Cpp::GetSizeOfType(Cpp::GetVariableType(Decls[1])), 1); EXPECT_EQ(Cpp::GetSizeOfType(Cpp::GetVariableType(Decls[2])), 4); @@ -85,7 +91,7 @@ TEST(TypeReflectionTest, GetSizeOfType) { sizeof(intptr_t)); } -TEST(TypeReflectionTest, GetCanonicalType) { +static void TypeReflectionTest_GetCanonicalType() { std::vector Decls; std::string code = R"( typedef int I; @@ -95,7 +101,8 @@ TEST(TypeReflectionTest, GetCanonicalType) { D d; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); auto D2 = Cpp::GetVariableType(Decls[2]); auto D3 = Cpp::GetVariableType(Decls[3]); @@ -109,13 +116,14 @@ TEST(TypeReflectionTest, GetCanonicalType) { } TEST(TypeReflectionTest, GetType) { + // XXX: no parallel Cpp::CreateInterpreter(); std::string code = R"( class A {}; )"; - Interp->declare(code); + EXPECT_FALSE(Cpp::Declare(code.c_str())); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("int")), "int"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("double")), "double"); @@ -133,7 +141,7 @@ TEST(TypeReflectionTest, GetType) { EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("struct")),"NULL TYPE"); } -TEST(TypeReflectionTest, IsRecordType) { +static void TypeReflectionTest_IsRecordType() { std::vector Decls; std::string code = R"( @@ -167,7 +175,8 @@ TEST(TypeReflectionTest, IsRecordType) { C cvar10[] = {}; C *cvar11[] = {cvar8}; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); auto is_var_of_record_ty = [] (Decl *D) { return Cpp::IsRecordType(Cpp::GetVariableType(D)); @@ -200,7 +209,7 @@ TEST(TypeReflectionTest, IsRecordType) { EXPECT_FALSE(is_var_of_record_ty(Decls[24])); } -TEST(TypeReflectionTest, GetUnderlyingType) { +static void TypeReflectionTest_GetUnderlyingType() { std::vector Decls; std::string code = R"( @@ -241,7 +250,10 @@ TEST(TypeReflectionTest, GetUnderlyingType) { enum E { e1, e2 }; E evar0 = e1; )"; - GetAllTopLevelDecls(code, Decls); + + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + auto get_underly_var_type_as_str = [] (Decl *D) { return Cpp::GetTypeAsString(Cpp::GetUnderlyingType(Cpp::GetVariableType(D))); }; @@ -278,7 +290,7 @@ TEST(TypeReflectionTest, GetUnderlyingType) { EXPECT_EQ(get_underly_var_type_as_str(Decls[30]), "E"); } -TEST(TypeReflectionTest, IsUnderlyingTypeRecordType) { +static void TypeReflectionTest_IsUnderlyingTypeRecordType() { std::vector Decls; std::string code = R"( @@ -312,7 +324,9 @@ TEST(TypeReflectionTest, IsUnderlyingTypeRecordType) { C cvar10[] = {}; C *cvar11[] = {cvar8}; )"; - GetAllTopLevelDecls(code, Decls); + + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); auto is_var_of_underly_record_ty = [] (Decl *D) { return Cpp::IsRecordType(Cpp::GetUnderlyingType(Cpp::GetVariableType(D))); @@ -346,6 +360,7 @@ TEST(TypeReflectionTest, IsUnderlyingTypeRecordType) { } TEST(TypeReflectionTest, GetComplexType) { + // XXX: no parallel Cpp::CreateInterpreter(); auto get_complex_type_as_string = [&](const std::string &element_type) { @@ -379,7 +394,7 @@ TEST(TypeReflectionTest, GetComplexType) { clang_Interpreter_dispose(I); } -TEST(TypeReflectionTest, GetTypeFromScope) { +static void TypeReflectionTest_GetTypeFromScope() { std::vector Decls; std::string code = R"( @@ -388,7 +403,8 @@ TEST(TypeReflectionTest, GetTypeFromScope) { int a = 10; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetTypeFromScope(Decls[0])), "C"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetTypeFromScope(Decls[1])), "S"); @@ -396,7 +412,7 @@ TEST(TypeReflectionTest, GetTypeFromScope) { EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetTypeFromScope(nullptr)), "NULL TYPE"); } -TEST(TypeReflectionTest, IsTypeDerivedFrom) { +static void TypeReflectionTest_IsTypeDerivedFrom() { std::vector Decls; std::string code = R"( @@ -413,7 +429,8 @@ TEST(TypeReflectionTest, IsTypeDerivedFrom) { E e; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); Cpp::TCppType_t type_A = Cpp::GetVariableType(Decls[5]); Cpp::TCppType_t type_B = Cpp::GetVariableType(Decls[6]); @@ -433,7 +450,7 @@ TEST(TypeReflectionTest, IsTypeDerivedFrom) { EXPECT_FALSE(Cpp::IsTypeDerivedFrom(type_A, type_E)); } -TEST(TypeReflectionTest, GetDimensions) { +static void TypeReflectionTest_GetDimensions() { std::vector Decls, SubDecls; std::string code = R"( @@ -458,7 +475,8 @@ TEST(TypeReflectionTest, GetDimensions) { S3::type arr; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); std::vector dims, truth_dims; @@ -529,6 +547,7 @@ TEST(TypeReflectionTest, GetDimensions) { } TEST(TypeReflectionTest, IsPODType) { + // XXX: no parallel std::vector Decls; std::string code = R"( @@ -544,13 +563,15 @@ TEST(TypeReflectionTest, IsPODType) { B b; )"; - GetAllTopLevelDecls(code, Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(code, Decls); + EXPECT_TRUE(I); + EXPECT_TRUE(Cpp::IsPODType(Cpp::GetVariableType(Decls[2]))); EXPECT_FALSE(Cpp::IsPODType(Cpp::GetVariableType(Decls[3]))); EXPECT_FALSE(Cpp::IsPODType(0)); } -TEST(TypeReflectionTest, IsSmartPtrType) { +static void TypeReflectionTest_IsSmartPtrType() { #if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \ defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) GTEST_SKIP() << "Test fails with Cling on Windows on ARM"; @@ -558,10 +579,14 @@ TEST(TypeReflectionTest, IsSmartPtrType) { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; - std::vector interpreter_args = {"-include", "new"}; - Cpp::CreateInterpreter(interpreter_args); +#if defined(__arm__) && defined(CPPINTEROP_USE_REPL) && defined(__linux__) + // look at https://stackoverflow.com/questions/75045297 + Cpp::TInterp_t I = + Cpp::CreateInterpreter({"-mno-outline-atomics", "-include", "new"}); + EXPECT_TRUE(I); +#endif - Interp->declare(R"( + Cpp::Declare(R"( #include template @@ -580,10 +605,11 @@ TEST(TypeReflectionTest, IsSmartPtrType) { C *raw_ptr; C object(); - )"); + )", + false, I); - auto get_type_from_varname = [&](const std::string &varname) { - return Cpp::GetVariableType(Cpp::GetNamed(varname)); + auto get_type_from_varname = [&](const std::string& varname) { + return Cpp::GetVariableType(Cpp::GetNamed(varname, Cpp::GetGlobalScope(I))); }; //EXPECT_TRUE(Cpp::IsSmartPtrType(get_type_from_varname("smart_ptr1"))); @@ -596,21 +622,19 @@ TEST(TypeReflectionTest, IsSmartPtrType) { EXPECT_FALSE(Cpp::IsSmartPtrType(get_type_from_varname("object"))); } -TEST(TypeReflectionTest, IsFunctionPointerType) { - std::vector interpreter_args = {"-include", "new"}; - Cpp::CreateInterpreter(interpreter_args); - - Interp->declare(R"( +static void TypeReflectionTest_IsFunctionPointerType() { + Cpp::Declare(R"( typedef int (*int_func)(int, int); int sum(int x, int y) { return x + y; } int_func f = sum; int i = 2; - )"); + )", + false, I); - EXPECT_TRUE( - Cpp::IsFunctionPointerType(Cpp::GetVariableType(Cpp::GetNamed("f")))); - EXPECT_FALSE( - Cpp::IsFunctionPointerType(Cpp::GetVariableType(Cpp::GetNamed("i")))); + EXPECT_TRUE(Cpp::IsFunctionPointerType( + Cpp::GetVariableType(Cpp::GetNamed("f", Cpp::GetGlobalScope(I))))); + EXPECT_FALSE(Cpp::IsFunctionPointerType( + Cpp::GetVariableType(Cpp::GetNamed("i", Cpp::GetGlobalScope(I))))); } TEST(TypeReflectionTest, OperatorSpelling) { @@ -621,9 +645,9 @@ TEST(TypeReflectionTest, OperatorSpelling) { EXPECT_EQ(Cpp::GetOperatorFromSpelling("invalid"), Cpp::OP_None); } -TEST(TypeReflectionTest, TypeQualifiers) { - Cpp::CreateInterpreter(); +static void TypeReflectionTest_TypeQualifiers() { Cpp::Declare(R"( + namespace TypeQualifiers { int *a; int *__restrict__ b; int *const c = 0; @@ -632,16 +656,20 @@ TEST(TypeReflectionTest, TypeQualifiers) { int *__restrict__ const f = nullptr; int *__restrict__ volatile g; int *__restrict__ const volatile h = nullptr; - )"); - - Cpp::TCppType_t a = Cpp::GetVariableType(Cpp::GetNamed("a")); - Cpp::TCppType_t b = Cpp::GetVariableType(Cpp::GetNamed("b")); - Cpp::TCppType_t c = Cpp::GetVariableType(Cpp::GetNamed("c")); - Cpp::TCppType_t d = Cpp::GetVariableType(Cpp::GetNamed("d")); - Cpp::TCppType_t e = Cpp::GetVariableType(Cpp::GetNamed("e")); - Cpp::TCppType_t f = Cpp::GetVariableType(Cpp::GetNamed("f")); - Cpp::TCppType_t g = Cpp::GetVariableType(Cpp::GetNamed("g")); - Cpp::TCppType_t h = Cpp::GetVariableType(Cpp::GetNamed("h")); + } + )", + false, I); + + Cpp::TCppScope_t ns = Cpp::GetNamed("TypeQualifiers", Cpp::GetGlobalScope(I)); + EXPECT_TRUE(ns); + Cpp::TCppType_t a = Cpp::GetVariableType(Cpp::GetNamed("a", ns)); + Cpp::TCppType_t b = Cpp::GetVariableType(Cpp::GetNamed("b", ns)); + Cpp::TCppType_t c = Cpp::GetVariableType(Cpp::GetNamed("c", ns)); + Cpp::TCppType_t d = Cpp::GetVariableType(Cpp::GetNamed("d", ns)); + Cpp::TCppType_t e = Cpp::GetVariableType(Cpp::GetNamed("e", ns)); + Cpp::TCppType_t f = Cpp::GetVariableType(Cpp::GetNamed("f", ns)); + Cpp::TCppType_t g = Cpp::GetVariableType(Cpp::GetNamed("g", ns)); + Cpp::TCppType_t h = Cpp::GetVariableType(Cpp::GetNamed("h", ns)); EXPECT_FALSE(Cpp::HasTypeQualifier(nullptr, Cpp::QualKind::Const)); EXPECT_FALSE(Cpp::RemoveTypeQualifier(nullptr, Cpp::QualKind::Const)); @@ -686,3 +714,31 @@ TEST(TypeReflectionTest, TypeQualifiers) { Cpp::QualKind::Volatile | Cpp::QualKind::Restrict)); } + +TEST(TypeReflectionTest, TypeReflectionTest) { + I = Cpp::CreateInterpreter({"-include", "new"}); + EXPECT_TRUE(I); + + std::vector> fns = { + {"TypeReflectionTest_GetTypeAsString", + TypeReflectionTest_GetTypeAsString}, + {"TypeReflectionTest_GetSizeOfType", TypeReflectionTest_GetSizeOfType}, + {"TypeReflectionTest_GetCanonicalType", + TypeReflectionTest_GetCanonicalType}, + {"TypeReflectionTest_IsRecordType", TypeReflectionTest_IsRecordType}, + {"TypeReflectionTest_GetUnderlyingType", + TypeReflectionTest_GetUnderlyingType}, + {"TypeReflectionTest_IsUnderlyingTypeRecordType", + TypeReflectionTest_IsUnderlyingTypeRecordType}, + {"TypeReflectionTest_GetTypeFromScope", + TypeReflectionTest_GetTypeFromScope}, + {"TypeReflectionTest_IsTypeDerivedFrom", + TypeReflectionTest_IsTypeDerivedFrom}, + {"TypeReflectionTest_GetDimensions", TypeReflectionTest_GetDimensions}, + {"TypeReflectionTest_IsSmartPtrType", TypeReflectionTest_IsSmartPtrType}, + {"TypeReflectionTest_IsFunctionPointerType", + TypeReflectionTest_IsFunctionPointerType}, + {"TypeReflectionTest_TypeQualifiers", TypeReflectionTest_TypeQualifiers}, + }; + ThreadPoolExecutor::run(fns); +} diff --git a/unittests/CppInterOp/Utils.cpp b/unittests/CppInterOp/Utils.cpp index e048b0df5..4e9c5abbf 100644 --- a/unittests/CppInterOp/Utils.cpp +++ b/unittests/CppInterOp/Utils.cpp @@ -10,17 +10,25 @@ #include "clang/Sema/Sema.h" #include +#include +#include +#include +#include +#include #include +#include #include using namespace clang; using namespace llvm; +using namespace std::chrono_literals; -void TestUtils::GetAllTopLevelDecls( +Cpp::TInterp_t TestUtils::GetAllTopLevelDecls( const std::string& code, std::vector& Decls, bool filter_implicitGenerated /* = false */, const std::vector& interpreter_args /* = {} */) { - Cpp::CreateInterpreter(interpreter_args); + Cpp::TInterp_t I = Cpp::CreateInterpreter(interpreter_args); + auto* Interp = static_cast(I); #ifdef CPPINTEROP_USE_CLING cling::Transaction *T = nullptr; Interp->declare(code, &T); @@ -43,6 +51,7 @@ void TestUtils::GetAllTopLevelDecls( Decls.push_back(D); } #endif + return I; } void TestUtils::GetAllSubDecls(Decl *D, std::vector& SubDecls, @@ -69,3 +78,33 @@ void dispose_string(CXString string) { CXScope make_scope(const clang::Decl* D, const CXInterpreter I) { return {CXCursor_UnexposedDecl, 0, {D, nullptr, I}}; } + +void ThreadPoolExecutor::run( + std::vector>& fns, unsigned runners) { + std::vector> futures; + std::vector names; + for (size_t i = 0, size = fns.size(); i < size;) { + if (futures.size() != runners) { + std::cout << "Running: " << std::get<0>(fns[i]) << "\n"; + futures.emplace_back(std::async(std::launch::async, std::get<1>(fns[i]))); + names.emplace_back(std::get<0>(fns[i])); + i++; + continue; + } + assert(futures.size() == names.size()); + for (size_t i = 0, size = futures.size(); i < size; i++) { + if (futures[0].wait_for(0ms) == std::future_status::ready) { + std::cout << "Finished: " << names[0] << "\n"; + futures.erase(futures.begin()); + names.erase(names.begin()); + } + } + } + assert(futures.size() == names.size()); + for (size_t i = 0, size = futures.size(); i < size; i++) { + futures[0].wait(); + std::cout << "Finished: " << names[0] << "\n"; + futures.erase(futures.begin()); + names.erase(names.begin()); + } +} diff --git a/unittests/CppInterOp/Utils.h b/unittests/CppInterOp/Utils.h index 2b7b12590..7d1a1dd4d 100644 --- a/unittests/CppInterOp/Utils.h +++ b/unittests/CppInterOp/Utils.h @@ -8,8 +8,9 @@ #include "llvm/Support/Valgrind.h" -#include #include +#include +#include #include using namespace clang; @@ -18,12 +19,16 @@ using namespace llvm; namespace clang { class Decl; } -#define Interp (static_cast(Cpp::GetInterpreter())) + +#define TU_getSema(I) (static_cast(I))->getSema() +#define TU_getASTContext(I) \ + (static_cast(I))->getSema().getASTContext() + namespace TestUtils { -void GetAllTopLevelDecls(const std::string& code, - std::vector& Decls, - bool filter_implicitGenerated = false, - const std::vector& interpreter_args = {}); +TInterp_t +GetAllTopLevelDecls(const std::string& code, std::vector& Decls, + bool filter_implicitGenerated = false, + const std::vector& interpreter_args = {}); void GetAllSubDecls(clang::Decl* D, std::vector& SubDecls, bool filter_implicitGenerated = false); } // end namespace TestUtils @@ -34,4 +39,9 @@ void dispose_string(CXString string); CXScope make_scope(const clang::Decl* D, const CXInterpreter I); +struct ThreadPoolExecutor { + static void run(std::vector>& fns, + unsigned runners = std::thread::hardware_concurrency()); +}; + #endif // CPPINTEROP_UNITTESTS_LIBCPPINTEROP_UTILS_H diff --git a/unittests/CppInterOp/VariableReflectionTest.cpp b/unittests/CppInterOp/VariableReflectionTest.cpp index 5c9829316..02add5f34 100644 --- a/unittests/CppInterOp/VariableReflectionTest.cpp +++ b/unittests/CppInterOp/VariableReflectionTest.cpp @@ -11,12 +11,16 @@ #include #include +#include using namespace TestUtils; using namespace llvm; using namespace clang; -TEST(VariableReflectionTest, GetDatamembers) { +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +static Cpp::TInterp_t I = nullptr; + +static void VariableReflectionTest_GetDatamembers() { std::vector Decls; std::string code = R"( class C { @@ -113,7 +117,8 @@ TEST(VariableReflectionTest, GetDatamembers) { CODE -TEST(VariableReflectionTest, DatamembersWithAnonymousStructOrUnion) { + static void + VariableReflectionTest_DatamembersWithAnonymousStructOrUnion() { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -162,7 +167,7 @@ TEST(VariableReflectionTest, DatamembersWithAnonymousStructOrUnion) { #endif } -TEST(VariableReflectionTest, GetTypeAsString) { +static void VariableReflectionTest_GetTypeAsString() { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -180,11 +185,10 @@ TEST(VariableReflectionTest, GetTypeAsString) { } )"; - Cpp::CreateInterpreter(); - EXPECT_EQ(Cpp::Declare(code.c_str()), 0); + EXPECT_EQ(Cpp::Declare(code.c_str(), false, I), 0); Cpp::TCppScope_t wrapper = - Cpp::GetScopeFromCompleteName("my_namespace::Wrapper"); + Cpp::GetScopeFromCompleteName("my_namespace::Wrapper", I); EXPECT_TRUE(wrapper); std::vector datamembers; @@ -195,7 +199,7 @@ TEST(VariableReflectionTest, GetTypeAsString) { "my_namespace::Container"); } -TEST(VariableReflectionTest, LookupDatamember) { +static void VariableReflectionTest_LookupDatamember() { std::vector Decls; std::string code = R"( class C { @@ -219,7 +223,7 @@ TEST(VariableReflectionTest, LookupDatamember) { EXPECT_EQ(Cpp::GetQualifiedName(Cpp::LookupDatamember("k", Decls[0])), ""); } -TEST(VariableReflectionTest, GetVariableType) { +static void VariableReflectionTest_GetVariableType() { std::vector Decls; std::string code = R"( class C {}; @@ -268,7 +272,8 @@ TEST(VariableReflectionTest, GetVariableType) { CODE -TEST(VariableReflectionTest, GetVariableOffset) { + static void + VariableReflectionTest_GetVariableOffset() { #ifdef EMSCRIPTEN #if CLANG_VERSION_MAJOR < 20 GTEST_SKIP() << "Test fails for Emscipten builds"; @@ -277,7 +282,8 @@ TEST(VariableReflectionTest, GetVariableOffset) { std::vector Decls; #define Stringify(s) Stringifyx(s) #define Stringifyx(...) #__VA_ARGS__ - GetAllTopLevelDecls(Stringify(CODE), Decls); + Cpp::TInterp_t I = GetAllTopLevelDecls(Stringify(CODE), Decls); + EXPECT_TRUE(I); #undef Stringifyx #undef Stringify #undef CODE @@ -311,11 +317,11 @@ TEST(VariableReflectionTest, GetVariableOffset) { int y; int z; }; - Cpp::Declare("struct K;"); - Cpp::TCppScope_t k = Cpp::GetNamed("K"); + EXPECT_FALSE(Cpp::Declare("struct K;", false, I)); + Cpp::TCppScope_t k = Cpp::GetNamed("K", Cpp::GetGlobalScope(I)); EXPECT_TRUE(k); - Cpp::Declare("struct K { int x; int y; int z; };"); + EXPECT_FALSE(Cpp::Declare("struct K { int x; int y; int z; };", false, I)); datamembers.clear(); Cpp::GetDatamembers(k, datamembers); @@ -325,17 +331,19 @@ TEST(VariableReflectionTest, GetVariableOffset) { EXPECT_EQ(Cpp::GetVariableOffset(datamembers[1]), offsetof(K, y)); EXPECT_EQ(Cpp::GetVariableOffset(datamembers[2]), offsetof(K, z)); - Cpp::Declare(R"( + EXPECT_FALSE(Cpp::Declare(R"( template struct ClassWithStatic { static T const ref_value; }; template T constexpr ClassWithStatic::ref_value = 42; - )"); + )", + false, I)); - Cpp::TCppScope_t klass = Cpp::GetNamed("ClassWithStatic"); + Cpp::TCppScope_t klass = + Cpp::GetNamed("ClassWithStatic", Cpp::GetGlobalScope(I)); EXPECT_TRUE(klass); - ASTContext& C = Interp->getCI()->getASTContext(); + ASTContext& C = TU_getASTContext(I); std::vector template_args = { {C.IntTy.getAsOpaquePtr()}}; Cpp::TCppScope_t klass_instantiated = Cpp::InstantiateTemplate( @@ -381,7 +389,8 @@ TEST(VariableReflectionTest, GetVariableOffset) { CODE -TEST(VariableReflectionTest, VariableOffsetsWithInheritance) { + static void + VariableReflectionTest_VariableOffsetsWithInheritance() { #if CLANG_VERSION_MAJOR == 18 && defined(CPPINTEROP_USE_CLING) && \ defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) GTEST_SKIP() << "Test fails with Cling on Windows on ARM"; @@ -389,19 +398,16 @@ TEST(VariableReflectionTest, VariableOffsetsWithInheritance) { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; - std::vector interpreter_args = {"-include", "new"}; - Cpp::CreateInterpreter(interpreter_args); - - Cpp::Declare("#include"); + EXPECT_FALSE(Cpp::Declare("#include", false, I)); #define Stringify(s) Stringifyx(s) #define Stringifyx(...) #__VA_ARGS__ - Cpp::Declare(Stringify(CODE)); + EXPECT_FALSE(Cpp::Declare(Stringify(CODE), false, I)); #undef Stringifyx #undef Stringify #undef CODE - Cpp::TCppScope_t myklass = Cpp::GetNamed("MyKlass"); + Cpp::TCppScope_t myklass = Cpp::GetNamed("MyKlass", Cpp::GetGlobalScope(I)); EXPECT_TRUE(myklass); size_t num_bases = Cpp::GetNumBases(myklass); @@ -437,7 +443,7 @@ TEST(VariableReflectionTest, VariableOffsetsWithInheritance) { ((intptr_t)&(my_k.s)) - ((intptr_t)&(my_k))); } -TEST(VariableReflectionTest, IsPublicVariable) { +static void VariableReflectionTest_IsPublicVariable() { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -460,7 +466,7 @@ TEST(VariableReflectionTest, IsPublicVariable) { EXPECT_FALSE(Cpp::IsPublicVariable(SubDecls[7])); } -TEST(VariableReflectionTest, IsProtectedVariable) { +static void VariableReflectionTest_IsProtectedVariable() { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -481,7 +487,7 @@ TEST(VariableReflectionTest, IsProtectedVariable) { EXPECT_TRUE(Cpp::IsProtectedVariable(SubDecls[6])); } -TEST(VariableReflectionTest, IsPrivateVariable) { +static void VariableReflectionTest_IsPrivateVariable() { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -502,7 +508,7 @@ TEST(VariableReflectionTest, IsPrivateVariable) { EXPECT_FALSE(Cpp::IsPrivateVariable(SubDecls[6])); } -TEST(VariableReflectionTest, IsStaticVariable) { +static void VariableReflectionTest_IsStaticVariable() { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -518,7 +524,7 @@ TEST(VariableReflectionTest, IsStaticVariable) { EXPECT_TRUE(Cpp::IsStaticVariable(SubDecls[2])); } -TEST(VariableReflectionTest, IsConstVariable) { +static void VariableReflectionTest_IsConstVariable() { std::vector Decls, SubDecls; std::string code = R"( class C { @@ -535,7 +541,7 @@ TEST(VariableReflectionTest, IsConstVariable) { EXPECT_TRUE(Cpp::IsConstVariable(SubDecls[2])); } -TEST(VariableReflectionTest, DISABLED_GetArrayDimensions) { +static void VariableReflectionTest_DISABLED_GetArrayDimensions() { std::vector Decls; std::string code = R"( int a; @@ -559,7 +565,7 @@ TEST(VariableReflectionTest, DISABLED_GetArrayDimensions) { // EXPECT_TRUE(is_vec_eq(Cpp::GetArrayDimensions(Decls[2]), {1,2})); } -TEST(VariableReflectionTest, StaticConstExprDatamember) { +static void VariableReflectionTest_StaticConstExprDatamember() { if (llvm::sys::RunningOnValgrind()) GTEST_SKIP() << "XFAIL due to Valgrind report"; @@ -567,9 +573,7 @@ TEST(VariableReflectionTest, StaticConstExprDatamember) { GTEST_SKIP() << "Disabled on Windows. Needs fixing."; #endif - Cpp::CreateInterpreter(); - - Cpp::Declare(R"( + EXPECT_FALSE(Cpp::Declare(R"( class MyClass { public: static constexpr int x = 3; @@ -590,9 +594,10 @@ TEST(VariableReflectionTest, StaticConstExprDatamember) { template struct Elements : public integral_constant {}; - )"); + )", + false, I)); - Cpp::TCppScope_t MyClass = Cpp::GetNamed("MyClass"); + Cpp::TCppScope_t MyClass = Cpp::GetNamed("MyClass", Cpp::GetGlobalScope(I)); EXPECT_TRUE(MyClass); std::vector datamembers; @@ -602,13 +607,13 @@ TEST(VariableReflectionTest, StaticConstExprDatamember) { intptr_t offset = Cpp::GetVariableOffset(datamembers[0]); EXPECT_EQ(3, *(size_t*)offset); - ASTContext& C = Interp->getCI()->getASTContext(); + ASTContext& C = TU_getASTContext(I); std::vector template_args = { {C.IntTy.getAsOpaquePtr(), "5"}}; - Cpp::TCppFunction_t MyTemplatedClass = - Cpp::InstantiateTemplate(Cpp::GetNamed("MyTemplatedClass"), - template_args.data(), template_args.size()); + Cpp::TCppFunction_t MyTemplatedClass = Cpp::InstantiateTemplate( + Cpp::GetNamed("MyTemplatedClass", Cpp::GetGlobalScope(I)), + template_args.data(), template_args.size()); EXPECT_TRUE(MyTemplatedClass); datamembers.clear(); @@ -622,8 +627,8 @@ TEST(VariableReflectionTest, StaticConstExprDatamember) { {C.IntTy.getAsOpaquePtr()}, {C.FloatTy.getAsOpaquePtr()}}; Cpp::TCppFunction_t Elements = Cpp::InstantiateTemplate( - Cpp::GetNamed("Elements"), ele_template_args.data(), - ele_template_args.size()); + Cpp::GetNamed("Elements", Cpp::GetGlobalScope(I)), + ele_template_args.data(), ele_template_args.size()); EXPECT_TRUE(Elements); EXPECT_EQ(1, Cpp::GetNumBases(Elements)); @@ -638,18 +643,18 @@ TEST(VariableReflectionTest, StaticConstExprDatamember) { EXPECT_EQ(2, *(size_t*)offset); } -TEST(VariableReflectionTest, GetEnumConstantDatamembers) { - Cpp::CreateInterpreter(); - - Cpp::Declare(R"( +static void VariableReflectionTest_GetEnumConstantDatamembers() { + EXPECT_FALSE(Cpp::Declare(R"( class MyEnumClass { enum { FOUR, FIVE, SIX }; enum A { ONE, TWO, THREE }; enum class B { SEVEN, EIGHT, NINE }; }; - )"); + )", + false, I)); - Cpp::TCppScope_t MyEnumClass = Cpp::GetNamed("MyEnumClass"); + Cpp::TCppScope_t MyEnumClass = + Cpp::GetNamed("MyEnumClass", Cpp::GetGlobalScope(I)); EXPECT_TRUE(MyEnumClass); std::vector datamembers; @@ -662,8 +667,7 @@ TEST(VariableReflectionTest, GetEnumConstantDatamembers) { EXPECT_EQ(datamembers2.size(), 6); } -TEST(VariableReflectionTest, Is_Get_Pointer) { - Cpp::CreateInterpreter(); +static void VariableReflectionTest_Is_Get_Pointer() { std::vector Decls; std::string code = R"( class A {}; @@ -694,8 +698,7 @@ TEST(VariableReflectionTest, Is_Get_Pointer) { EXPECT_FALSE(Cpp::GetPointeeType(Cpp::GetVariableType(Decls[5]))); } -TEST(VariableReflectionTest, Is_Get_Reference) { - Cpp::CreateInterpreter(); +static void VariableReflectionTest_Is_Get_Reference() { std::vector Decls; std::string code = R"( class A {}; @@ -732,8 +735,7 @@ TEST(VariableReflectionTest, Is_Get_Reference) { Cpp::GetReferencedType(Cpp::GetVariableType(Decls[1]), true))); } -TEST(VariableReflectionTest, GetPointerType) { - Cpp::CreateInterpreter(); +static void VariableReflectionTest_GetPointerType() { std::vector Decls; std::string code = R"( class A {}; @@ -754,3 +756,48 @@ TEST(VariableReflectionTest, GetPointerType) { EXPECT_EQ(Cpp::GetPointerType(Cpp::GetVariableType(Decls[5])), Cpp::GetVariableType(Decls[6])); } + +TEST(VariableReflectionTest, VariableReflectionTest) { + I = Cpp::CreateInterpreter({"-include", "new"}); + EXPECT_TRUE(I); + + std::vector> fns = { + {"VariableReflectionTest_GetDatamembers", + VariableReflectionTest_GetDatamembers}, + {"VariableReflectionTest_DatamembersWithAnonymousStructOrUnion", + VariableReflectionTest_DatamembersWithAnonymousStructOrUnion}, + {"VariableReflectionTest_GetTypeAsString", + VariableReflectionTest_GetTypeAsString}, + {"VariableReflectionTest_LookupDatamember", + VariableReflectionTest_LookupDatamember}, + {"VariableReflectionTest_GetVariableType", + VariableReflectionTest_GetVariableType}, + {"VariableReflectionTest_GetVariableOffset", + VariableReflectionTest_GetVariableOffset}, + {"VariableReflectionTest_VariableOffsetsWithInheritance", + VariableReflectionTest_VariableOffsetsWithInheritance}, + {"VariableReflectionTest_IsPublicVariable", + VariableReflectionTest_IsPublicVariable}, + {"VariableReflectionTest_IsProtectedVariable", + VariableReflectionTest_IsProtectedVariable}, + {"VariableReflectionTest_IsPrivateVariable", + VariableReflectionTest_IsPrivateVariable}, + {"VariableReflectionTest_IsStaticVariable", + VariableReflectionTest_IsStaticVariable}, + {"VariableReflectionTest_IsConstVariable", + VariableReflectionTest_IsConstVariable}, + {"VariableReflectionTest_DISABLED_GetArrayDimensions", + VariableReflectionTest_DISABLED_GetArrayDimensions}, + {"VariableReflectionTest_StaticConstExprDatamember", + VariableReflectionTest_StaticConstExprDatamember}, + {"VariableReflectionTest_GetEnumConstantDatamembers", + VariableReflectionTest_GetEnumConstantDatamembers}, + {"VariableReflectionTest_Is_Get_Pointer", + VariableReflectionTest_Is_Get_Pointer}, + {"VariableReflectionTest_Is_Get_Reference", + VariableReflectionTest_Is_Get_Reference}, + {"VariableReflectionTest_GetPointerType", + VariableReflectionTest_GetPointerType}, + }; + ThreadPoolExecutor::run(fns); +}