From 132ae3a6497ae000ba57680823afd1e7951ddc9a Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sat, 15 Jun 2024 20:00:57 +0900 Subject: [PATCH 01/23] Add C API and improve type safety --- include/clang-c/CXCppInterOp.h | 935 +++++++++++++++++ include/clang/Interpreter/CppInterOp.h | 12 +- lib/Interpreter/CMakeLists.txt | 1 + lib/Interpreter/CXCppInterOp.cpp | 1316 ++++++++++++++++++++++++ lib/Interpreter/CppInterOp.cpp | 154 +-- 5 files changed, 2354 insertions(+), 64 deletions(-) create mode 100644 include/clang-c/CXCppInterOp.h create mode 100644 lib/Interpreter/CXCppInterOp.cpp diff --git a/include/clang-c/CXCppInterOp.h b/include/clang-c/CXCppInterOp.h new file mode 100644 index 000000000..71bdd5f06 --- /dev/null +++ b/include/clang-c/CXCppInterOp.h @@ -0,0 +1,935 @@ +// NOLINTBEGIN() +#ifndef LLVM_CLANG_C_CXCPPINTEROP_H +#define LLVM_CLANG_C_CXCPPINTEROP_H + +#include "clang-c/CXErrorCode.h" +#include "clang-c/CXString.h" +#include "clang-c/ExternC.h" +#include "clang-c/Platform.h" +#include "llvm-c/LLJIT.h" + +#include +#include +#include + +LLVM_CLANG_C_EXTERN_C_BEGIN + +/** + * \defgroup CPPINTEROP_INTERPRETER_MANIP Interpreter manipulations + * + * @{ + */ + +/** + * An opaque pointer representing an interpreter context. + */ +typedef struct CXInterpreterImpl* CXInterpreter; + +/** + * Create a Clang interpreter instance from the given arguments. + * + * \param argv The arguments that would be passed to the interpreter. + * + * \param argc The number of arguments in \c argv. + * + * \returns a \c CXInterpreter. + */ +CXInterpreter clang_createInterpreter(const char* const* argv, int argc); + +typedef void* TInterp_t; + +/** + * Bridge between C API and C++ API. + * + * \returns a \c CXInterpreter. + */ +CXInterpreter clang_createInterpreterFromPtr(TInterp_t I); + +/** + * Returns a \c TInterp_t. + */ +TInterp_t clang_interpreter_getInterpreterAsPtr(CXInterpreter I); + +/** + * Dispose of the given interpreter context. + */ +void clang_interpreter_dispose(CXInterpreter I); + +/** + * Describes the return result of the different routines that do the incremental + * compilation. + */ +typedef enum { + /** + * The compilation was successful. + */ + CXInterpreter_Success = 0, + /** + * The compilation failed. + */ + CXInterpreter_Failure = 1, + /** + * More more input is expected. + */ + CXInterpreter_MoreInputExpected = 2, +} CXInterpreter_CompilationResult; + +/** + * Add a search path to the interpreter. + * + * \param I The interpreter. + * + * \param dir The directory to add. + * + * \param isUser Whether the directory is a user directory. + * + * \param prepend Whether to prepend the directory to the search path. + */ +void clang_interpreter_addSearchPath(CXInterpreter I, const char* dir, + bool isUser, bool prepend); + +/** + * Get the resource directory. + */ +const char* clang_interpreter_getResourceDir(CXInterpreter I); + +/** + * Add an include path. + * + * \param I The interpreter. + * + * \param dir The directory to add. + */ +void clang_interpreter_addIncludePath(CXInterpreter I, const char* dir); + +/** + * Declares a code snippet in \c code and does not execute it. + * + * \param I The interpreter. + * + * \param code The code snippet to declare. + * + * \param silent Whether to suppress the diagnostics or not + * + * \returns a \c CXErrorCode. + */ +enum CXErrorCode clang_interpreter_declare(CXInterpreter I, const char* code, + bool silent); + +/** + * Declares and executes a code snippet in \c code. + * + * \param I The interpreter. + * + * \param code The code snippet to execute. + * + * \returns a \c CXErrorCode. + */ +enum CXErrorCode clang_interpreter_process(CXInterpreter I, const char* code); + +/** + * An opaque pointer representing a lightweight struct that is used for carrying + * execution results. + */ +typedef void* CXValue; + +/** + * Create a CXValue. + * + * \returns a \c CXValue. + */ +CXValue clang_createValue(); + +/** + * Dispose of the given CXValue. + * + * \param V The CXValue to dispose. + */ +void clang_value_dispose(CXValue V); + +/** + * Declares, executes and stores the execution result to \c V. + * + * \param[in] I The interpreter. + * + * \param[in] code The code snippet to evaluate. + * + * \param[out] V The value to store the execution result. + * + * \returns a \c CXErrorCode. + */ +enum CXErrorCode clang_interpreter_evaluate(CXInterpreter I, const char* code, + CXValue V); + +/** + * Looks up the library if access is enabled. + * + * \param I The interpreter. + * + * \param lib_name The name of the library to lookup. + * + * \returns the path to the library. + */ +CXString clang_interpreter_lookupLibrary(CXInterpreter I, const char* lib_name); + +/** + * Finds \c lib_stem considering the list of search paths and loads it by + * calling dlopen. + * + * \param I The interpreter. + * + * \param lib_stem The stem of the library to load. + * + * \param lookup Whether to lookup the library or not. + * + * \returns a \c CXInterpreter_CompilationResult. + */ +CXInterpreter_CompilationResult +clang_interpreter_loadLibrary(CXInterpreter I, const char* lib_stem, + bool lookup); + +/** + * Finds \c lib_stem considering the list of search paths and unloads it by + * calling dlclose. + * + * \param I The interpreter. + * + * \param lib_stem The stem of the library to unload. + */ +void clang_interpreter_unloadLibrary(CXInterpreter I, const char* lib_stem); + +/** + * Scans all libraries on the library search path for a given potentially + * mangled symbol name. + * + * \param I The interpreter. + * + * \param mangled_name The mangled name of the symbol to search for. + * + * \param search_system Whether to search the system paths or not. + * + * \returns the path to the first library that contains the symbol definition. + */ +CXString clang_interpreter_searchLibrariesForSymbol(CXInterpreter I, + const char* mangled_name, + bool search_system); + +/** + * Inserts or replaces a symbol in the JIT with the one provided. This is useful + * for providing our own implementations of facilities such as printf. + * + * \param I The interpreter. + * + * \param linker_mangled_name The name of the symbol to be inserted or replaced. + * + * \param address The new address of the symbol. + * + * \returns true on failure. + */ +bool clang_interpreter_insertOrReplaceJitSymbol(CXInterpreter I, + const char* linker_mangled_name, + uint64_t address); + +typedef void* CXFuncAddr; + +/** + * Get the function address from the given mangled name. + * + * \param I The interpreter. + * + * \param mangled_name The mangled name of the function. + * + * \returns the address of the function given its potentially mangled name. + */ +CXFuncAddr +clang_interpreter_getFunctionAddressFromMangledName(CXInterpreter I, + const char* mangled_name); + +/** + * @} + */ + +/** + * \defgroup CPPINTEROP_TYPE_MANIP Type manipulations + * + * @{ + */ + +/** + * Describes the kind of entity that a type refers to. + */ +enum CXQualTypeKind { + CXQualType_Unexposed = 0, + CXQualType_Invalid = 1, + // reserved for future use +}; + +/** + * An opaque pointer representing a type. + */ +typedef struct { + enum CXQualTypeKind kind; + void* data; + const void* meta; +} CXQualType; + +/** + * Checks if it is a "built-in" or a "complex" type. + */ +bool clang_qualtype_isBuiltin(CXQualType type); + +/** + * Checks if the passed value is an enum type or not. + */ +bool clang_qualtype_isEnumType(CXQualType type); + +/** + * We assume that smart pointer types define both operator* and operator->. + */ +bool clang_qualtype_isSmartPtrType(CXQualType type); + +/** + * Checks if the provided parameter is a Record (struct). + */ +bool clang_scope_isRecordType(CXQualType type); + +/** + * Checks if the provided parameter is a Plain Old Data Type (POD). + */ +bool clang_scope_isPODType(CXQualType type); + +/** + * For the given "type", this function gets the integer type that the enum + * represents, so that you can store it properly in your specific language. + */ +CXQualType clang_qualtype_getIntegerTypeFromEnumType(CXQualType type); + +/** + * Gets the pure, Underlying Type (as opposed to the Using Type). + */ +CXQualType clang_qualtype_getUnderlyingType(CXQualType type); + +/** + * Gets the Type (passed as a parameter) as a String value. + */ +CXString clang_qualtype_getTypeAsString(CXQualType type); + +/** + * Gets the Canonical Type string from the std string. A canonical type + * is the type with any typedef names, syntactic sugars or modifiers stripped + * out of it. + */ +CXQualType clang_qualtype_getCanonicalType(CXQualType type); + +/** + * Used to either get the built-in type of the provided string, or + * use the name to lookup the actual type. + */ +CXQualType clang_qualtype_getType(const char* name); + +/** + * Returns the complex of the provided type. + */ +CXQualType clang_qualtype_getComplexType(CXQualType eltype); + +/** + * Gets the size of the "type" that is passed in to this function. + */ +size_t clang_qualtype_getSizeOfType(CXQualType type); + +/** + * Checks if a C++ type derives from another. + */ +bool clang_qualtype_isTypeDerivedFrom(CXQualType derived, CXQualType base); + +/** + * @} + */ + +/** + * \defgroup CPPINTEROP_SCOPE_MANIP Scope manipulations + * + * @{ + */ + +/** + * Describes the kind of entity that a scope refers to. + */ +enum CXScopeKind { + CXScope_Unexposed = 0, + CXScope_Invalid = 1, + /** The global scope. */ + CXScope_Global = 2, + /** Namespaces. */ + CXScope_Namespace = 3, + /** Function, methods, constructor etc. */ + CXScope_Function = 4, + /** Variables. */ + CXScope_Variable = 5, + /** Enum Constants. */ + CXScope_EnumConstant = 6, + /** Fields. */ + CXScope_Field = 7, + // reserved for future use +}; + +/** + * An opaque pointer representing a variable, typedef, function, struct, etc. + */ +typedef struct { + enum CXScopeKind kind; + void* data; + const void* meta; +} CXScope; + +// for debugging purposes +void clang_scope_dump(CXScope S); + +/** + * This will convert a class into its type, so for example, you can use it to + * declare variables in it. + */ +CXQualType clang_scope_getTypeFromScope(CXScope S); + +/** + * Checks if the given class represents an aggregate type. + * + * \returns true if the \c scope supports aggregate initialization. + */ +bool clang_scope_isAggregate(CXScope S); + +/** + * Checks if the scope is a namespace or not. + */ +bool clang_scope_isNamespace(CXScope S); + +/** + * Checks if the scope is a class or not. + */ +bool clang_scope_isClass(CXScope S); + +/** + * Checks if the class definition is present, or not. Performs a template + * instantiation if necessary. + */ +bool clang_scope_isComplete(CXScope S); + +/** + * Get the size of the given type. + */ +size_t clang_scope_sizeOf(CXScope S); + +/** + * Checks if it is a templated class. + */ +bool clang_scope_isTemplate(CXScope S); + +/** + * Checks if it is a class template specialization class. + */ +bool clang_scope_isTemplateSpecialization(CXScope S); + +/** + * Checks if \c handle introduces a typedef name via \c typedef or \c using. + */ +bool clang_scope_isTypedefed(CXScope S); + +bool clang_scope_isAbstract(CXScope S); + +/** + * Checks if it is an enum name (EnumDecl represents an enum name). + */ +bool clang_scope_isEnumScope(CXScope S); + +/** + * Checks if it is an enum's value (EnumConstantDecl represents each enum + * constant that is defined). + */ +bool clang_scope_isEnumConstant(CXScope S); + +/** + * Extracts enum declarations from a specified scope and stores them in vector + */ +CXStringSet* clang_scope_getEnums(CXScope S); + +/** + * For the given "class", get the integer type that the enum represents, so that + * you can store it properly in your specific language. + */ +CXQualType clang_scope_getIntegerTypeFromEnumScope(CXScope S); + +typedef struct { + CXScope* Scopes; + size_t Count; +} CXScopeSet; + +/** + * Free the given scope set. + */ +void clang_disposeScopeSet(CXScopeSet* set); + +/** + * Gets a list of all the enum constants for an enum. + */ +CXScopeSet* clang_scope_getEnumConstants(CXScope S); + +/** + * Gets the enum name when an enum constant is passed. + */ +CXQualType clang_scope_getEnumConstantType(CXScope S); + +/** + * Gets the index value (0,1,2, etcetera) of the enum constant that was passed + * into this function. + */ +size_t clang_scope_getEnumConstantValue(CXScope S); + +/** + * Checks if the passed value is a variable. + */ +bool clang_scope_isVariable(CXScope S); + +/** + * Gets the name of any named decl (a class, namespace, variable, or a + * function). + */ +CXString clang_scope_getName(CXScope S); + +/** + * This is similar to clang_scope_getName() function, but besides the name, it + * also gets the template arguments. + */ +CXString clang_scope_getCompleteName(CXScope S); + +/** + * Gets the "qualified" name (including the namespace) of any + * named decl (a class, namespace, variable, or a function). + */ +CXString clang_scope_getQualifiedName(CXScope S); + +/** + * This is similar to clang_scope_getQualifiedName() function, but besides + * the "qualified" name (including the namespace), it also gets the template + * arguments. + */ +CXString clang_scope_getQualifiedCompleteName(CXScope S); + +/** + * Gets the list of namespaces utilized in the supplied scope. + */ +CXScopeSet* clang_scope_getUsingNamespaces(CXScope S); + +/** + * Gets the global scope of the whole interpreter instance. + */ +CXScope clang_scope_getGlobalScope(CXInterpreter I); + +/** + * Strips the typedef and returns the underlying class, and if the underlying + * decl is not a class it returns the input unchanged. + */ +CXScope clang_scope_getUnderlyingScope(CXScope S); + +/** + * Gets the namespace or class (by stripping typedefs) for the name passed as a + * parameter. \c parent is mandatory, the global scope should be used as + * the default value. + */ +CXScope clang_scope_getScope(const char* name, CXScope parent); + +/** + * This function performs a lookup within the specified parent, + * a specific named entity (functions, enums, etcetera). + */ +CXScope clang_scope_getNamed(const char* name, CXScope parent); + +/** + * Gets the parent of the scope that is passed as a parameter. + */ +CXScope clang_scope_getParentScope(CXScope parent); + +/** + * Gets the scope of the type that is passed as a parameter. + */ +CXScope clang_scope_getScopeFromType(CXQualType type); + +/** + * Gets the number of Base Classes for the Derived Class that + * is passed as a parameter. + */ +size_t clang_scope_getNumBases(CXScope S); + +/** + * Gets a specific Base Class using its index. Typically + * clang_scope_getNumBases() is used to get the number of Base Classes, and then + * that number can be used to iterate through the index value to get each + * specific base class. + */ +CXScope clang_scope_getBaseClass(CXScope S, size_t ibase); + +/** + * Checks if the supplied Derived Class is a sub-class of the provided Base + * Class. + */ +bool clang_scope_isSubclass(CXScope derived, CXScope base); + +/** + * Each base has its own offset in a Derived Class. This offset can be + * used to get to the Base Class fields. + */ +int64_t clang_scope_getBaseClassOffset(CXScope derived, CXScope base); + +/** + * Gets a list of all the Methods that are in the Class that is supplied as a + * parameter. + */ +CXScopeSet* clang_scope_getClassMethods(CXScope S); + +/** + * Template function pointer list to add proxies for + * un-instantiated/non-overloaded templated methods. + */ +CXScopeSet* clang_scope_getFunctionTemplatedDecls(CXScope S); + +/** + * Checks if a class has a default constructor. + */ +bool clang_scope_hasDefaultConstructor(CXScope S); + +/** + * Returns the default constructor of a class, if any. + */ +CXScope clang_scope_getDefaultConstructor(CXScope S); + +/** + * Returns the class destructor, if any. + */ +CXScope clang_scope_getDestructor(CXScope S); + +/** + * Looks up all the functions that have the name that is passed as a parameter + * in this function. + */ +CXScopeSet* clang_scope_getFunctionsUsingName(CXScope S, const char* name); + +/** + * Gets the return type of the provided function. + */ +CXQualType clang_scope_getFunctionReturnType(CXScope func); + +/** + * Gets the number of Arguments for the provided function. + */ +size_t clang_scope_getFunctionNumArgs(CXScope func); + +/** + * Gets the number of Required Arguments for the provided function. + */ +size_t clang_scope_getFunctionRequiredArgs(CXScope func); + +/** + * For each Argument of a function, you can get the Argument Type by providing + * the Argument Index, based on the number of arguments from the + * clang_scope_getFunctionNumArgs() function. + */ +CXQualType clang_scope_getFunctionArgType(CXScope func, size_t iarg); + +/** + * Returns a stringified version of a given function signature in the form: + * void N::f(int i, double d, long l = 0, char ch = 'a'). + */ +CXString clang_scope_getFunctionSignature(CXScope func); + +/** + * Checks if a function was marked as \c =delete. + */ +bool clang_scope_isFunctionDeleted(CXScope func); + +/** + * Checks if a function is a templated function. + */ +bool clang_scope_isTemplatedFunction(CXScope func); + +/** + * This function performs a lookup to check if there is a templated function of + * that type. \c parent is mandatory, the global scope should be used as the + * default value. + */ +bool clang_scope_existsFunctionTemplate(const char* name, CXScope parent); + +/** + * Gets a list of all the Templated Methods that are in the Class that is + * supplied as a parameter. + */ +CXScopeSet* clang_scope_getClassTemplatedMethods(const char* name, + CXScope parent); + +/** + * Checks if the provided parameter is a method. + */ +bool clang_scope_isMethod(CXScope method); + +/** + * Checks if the provided parameter is a 'Public' method. + */ +bool clang_scope_isPublicMethod(CXScope method); + +/** + * Checks if the provided parameter is a 'Protected' method. + */ +bool clang_scope_isProtectedMethod(CXScope method); + +/** + * Checks if the provided parameter is a 'Private' method. + */ +bool clang_scope_isPrivateMethod(CXScope method); + +/** + * Checks if the provided parameter is a 'Private' method. + */ +bool clang_scope_isPrivateMethod(CXScope method); + +/** + * Checks if the provided parameter is a Constructor. + */ +bool clang_scope_isConstructor(CXScope method); + +/** + * Checks if the provided parameter is a Destructor. + */ +bool clang_scope_isDestructor(CXScope method); + +/** + * Checks if the provided parameter is a 'Static' method. + */ +bool clang_scope_isStaticMethod(CXScope method); + +/** + * Returns the address of the function given its function declaration. + */ +CXFuncAddr clang_scope_getFunctionAddress(CXScope method); + +/** + * Checks if the provided parameter is a 'Virtual' method. + */ +bool clang_scope_isVirtualMethod(CXScope method); + +/** + * Checks if a function declared is of const type or not. + */ +bool clang_scope_isConstMethod(CXScope method); + +/** + * Returns the default argument value as string. + */ +CXString clang_scope_getFunctionArgDefault(CXScope func, size_t param_index); + +/** + * Returns the argument name of function as string. + */ +CXString clang_scope_getFunctionArgName(CXScope func, size_t param_index); + +typedef struct { + void* Type; + const char* IntegralValue; +} CXTemplateArgInfo; + +/** + * Builds a template instantiation for a given templated declaration. + * Offers a single interface for instantiation of class, function and variable + * templates. + * + * \param[in] tmpl The uninstantiated template class/function. + * + * \param[in] template_args The pointer to vector of template arguments stored + * in the \c TemplateArgInfo struct + * + * \param[in] template_args_size The size of the vector of template arguments + * passed as \c template_args + * + * \returns a \c CXScope representing the instantiated templated + * class/function/variable. + */ +CXScope clang_scope_instantiateTemplate(CXScope tmpl, + CXTemplateArgInfo* template_args, + size_t template_args_size); + +/** + * Gets all the Fields/Data Members of a Class. For now, it only gets non-static + * data members but in a future update, it may support getting static data + * members as well. + */ +CXScopeSet* clang_scope_getDatamembers(CXScope S); + +/** + * This is a Lookup function to be used specifically for data members. + * \c parent is mandatory, the global scope should be used as the default value. + */ +CXScope clang_scope_lookupDatamember(const char* name, CXScope parent); + +/** + * Gets the type of the variable that is passed as a parameter. + */ +CXQualType clang_scope_getVariableType(CXScope var); + +/** + * Gets the address of the variable, you can use it to get the value stored in + * the variable. + */ +intptr_t clang_scope_getVariableOffset(CXScope var); + +/** + * Checks if the provided variable is a 'Public' variable. + */ +bool clang_scope_isPublicVariable(CXScope var); + +/** + * Checks if the provided variable is a 'Protected' variable. + */ +bool clang_scope_isProtectedVariable(CXScope var); + +/** + * Checks if the provided variable is a 'Private' variable. + */ +bool clang_scope_isPrivateVariable(CXScope var); + +/** + * Checks if the provided variable is a 'Static' variable. + */ +bool clang_scope_isStaticVariable(CXScope var); + +/** + * Checks if the provided variable is a 'Const' variable. + */ +bool clang_scope_isConstVariable(CXScope var); + +/** + * @} + */ + +/** + * \defgroup CPPINTEROP_OBJECT_MANIP Object manipulations + * + * @{ + */ + +/** + * An opaque pointer representing the object of a given type (\c CXScope). + */ +typedef void* CXObject; + +/** + * Allocates memory for the given type. + */ +CXObject clang_allocate(CXScope S); + +/** + * Deallocates memory for a given class. + */ +void clang_deallocate(CXObject address); + +/** + * Creates an object of class \c scope and calls its default constructor. If \c + * arena is set it uses placement new. + */ +CXObject clang_construct(CXScope scope, void* arena); + +/** + * Calls the destructor of object of type \c type. When withFree is true it + * calls operator delete/free. + * + * \param I The interpreter. + * + * \param This The object to destruct. + * + * \param type The type of the object. + * + * \param withFree Whether to call operator delete/free or not. + */ +void clang_destruct(CXObject This, CXScope S, bool withFree); + +/** + * @} + */ + +/** + * \defgroup CPPINTEROP_JITCALL_MANIP JitCall manipulations + * + * @{ + */ + +/** + * An opaque pointer representing CppInterOp's JitCall, a class modeling + * function calls for functions produced by the interpreter in compiled code. + */ +typedef struct CXJitCallImpl* CXJitCall; + +/** + * Dispose of the given CXJitCall. + * + * \param J The CXJitCall to dispose. + */ +void clang_jitcall_dispose(CXJitCall J); + +/** + * The kind of the JitCall. + */ +typedef enum { + CXJitCall_Unknown = 0, + CXJitCall_GenericCall = 1, + CXJitCall_DestructorCall = 2, +} CXJitCallKind; + +/** + * Get the kind of the given CXJitCall. + * + * \param J The CXJitCall. + * + * \returns the kind of the given CXJitCall. + */ +CXJitCallKind clang_jitcall_getKind(CXJitCall J); + +/** + * Check if the given CXJitCall is valid. + * + * \param J The CXJitCall. + * + * \returns true if the given CXJitCall is valid. + */ +bool clang_jitcall_isValid(CXJitCall J); + +typedef struct { + void** data; + size_t numArgs; +} CXJitCallArgList; + +/** + * Makes a call to a generic function or method. + * + * \param[in] J The CXJitCall. + * + * \param[in] result The location where the return result will be placed. + * + * \param[in] args The arguments to pass to the invocation. + * + * \param[in] self The 'this pointer' of the object. + */ +void clang_jitcall_invoke(CXJitCall J, void* result, CXJitCallArgList args, + void* self); + +/** + * Creates a trampoline function by using the interpreter and returns a uniform + * interface to call it from compiled code. + * + * \returns a \c CXJitCall. + */ +CXJitCall clang_jitcall_makeFunctionCallable(CXScope func); + +/** + * @} + */ + +LLVM_CLANG_C_EXTERN_C_END + +#endif // LLVM_CLANG_C_CXCPPINTEROP_H + // NOLINTEND() \ No newline at end of file diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index 2cbb66c61..7d79a87a6 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -78,6 +78,8 @@ namespace Cpp { class JitCall { public: friend CPPINTEROP_API JitCall MakeFunctionCallable(TCppConstFunction_t); + friend JitCall MakeFunctionCallableImpl(TInterp_t I, + TCppConstFunction_t func); enum Kind : char { kUnknown = 0, kGenericCall, @@ -262,16 +264,16 @@ namespace Cpp { /// This is similar to GetName() function, but besides /// the name, it also gets the template arguments. - CPPINTEROP_API std::string GetCompleteName(TCppType_t klass); + CPPINTEROP_API std::string GetCompleteName(TCppScope_t klass); /// Gets the "qualified" name (including the namespace) of any /// named decl (a class, namespace, variable, or a function). - CPPINTEROP_API std::string GetQualifiedName(TCppType_t klass); + CPPINTEROP_API std::string GetQualifiedName(TCppScope_t klass); /// This is similar to GetQualifiedName() function, but besides /// the "qualified" name (including the namespace), it also /// gets the template arguments. - CPPINTEROP_API std::string GetQualifiedCompleteName(TCppType_t klass); + CPPINTEROP_API std::string GetQualifiedCompleteName(TCppScope_t klass); /// Gets the list of namespaces utilized in the supplied scope. CPPINTEROP_API std::vector GetUsingNamespaces(TCppScope_t scope); @@ -307,13 +309,13 @@ namespace Cpp { /// Gets the number of Base Classes for the Derived Class that /// is passed as a parameter. - CPPINTEROP_API TCppIndex_t GetNumBases(TCppType_t klass); + CPPINTEROP_API TCppIndex_t GetNumBases(TCppScope_t klass); /// Gets a specific Base Class using its index. Typically GetNumBases() /// is used to get the number of Base Classes, and then that number /// can be used to iterate through the index value to get each specific /// base class. - CPPINTEROP_API TCppScope_t GetBaseClass(TCppType_t klass, TCppIndex_t ibase); + CPPINTEROP_API TCppScope_t GetBaseClass(TCppScope_t klass, TCppIndex_t ibase); /// Checks if the supplied Derived Class is a sub-class of the /// provided Base Class. diff --git a/lib/Interpreter/CMakeLists.txt b/lib/Interpreter/CMakeLists.txt index 7f4ca53e1..42e878fe2 100644 --- a/lib/Interpreter/CMakeLists.txt +++ b/lib/Interpreter/CMakeLists.txt @@ -97,6 +97,7 @@ endif(LLVM_LINK_LLVM_DYLIB) add_llvm_library(clangCppInterOp DISABLE_LLVM_LINK_LLVM_DYLIB CppInterOp.cpp + CXCppInterOp.cpp ${DLM} LINK_LIBS ${link_libs} diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp new file mode 100644 index 000000000..a5f18ba35 --- /dev/null +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -0,0 +1,1316 @@ +#include "clang-c/CXCppInterOp.h" +#include "Compatibility.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Mangle.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/Type.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/CppInterOp.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/Orc/LLJIT.h" +#include "llvm/Support/Casting.h" +#include +#include +#include "clang-c/CXString.h" + +CXString makeCXString(const std::string& S) { + CXString Str; + if (S.empty()) { + Str.data = ""; + Str.private_flags = 0; // CXS_Unmanaged + } else { + Str.data = strdup(S.c_str()); + Str.private_flags = 1; // CXS_Malloc + } + return Str; +} + +CXStringSet* makeCXStringSet(const std::vector& Strs) { + CXStringSet* Set = new CXStringSet; + Set->Count = Strs.size(); + Set->Strings = new CXString[Set->Count]; + for (auto [Idx, Val] : llvm::enumerate(Strs)) { + Set->Strings[Idx] = makeCXString(Val); + } + return Set; +} + +struct CXInterpreterImpl { + std::unique_ptr Interp; + // reserved for future use +}; + +static inline compat::Interpreter* getInterpreter(const CXInterpreterImpl* I) { + assert(I && "Invalid interpreter"); + return I->Interp.get(); +} + +CXInterpreter clang_createInterpreter(const char* const* argv, int argc) { + auto* I = new CXInterpreterImpl(); + I->Interp = std::make_unique(argc, argv); + // reserved for future use + return I; +} + +CXInterpreter clang_createInterpreterFromPtr(TInterp_t I) { + auto* II = new CXInterpreterImpl(); + II->Interp.reset(reinterpret_cast(I)); // NOLINT(*-cast) + return II; +} + +TInterp_t clang_interpreter_getInterpreterAsPtr(CXInterpreter I) { + return reinterpret_cast(getInterpreter(I)); // NOLINT(*-cast) +} + +void clang_interpreter_dispose(CXInterpreter I) { + delete static_cast(I); // NOLINT(*-owning-memory) +} + +void clang_interpreter_addSearchPath(CXInterpreter I, const char* dir, + bool isUser, bool prepend) { + auto* interp = getInterpreter(I); + interp->getDynamicLibraryManager()->addSearchPath(dir, isUser, prepend); +} + +void clang_interpreter_addIncludePath(CXInterpreter I, const char* dir) { + getInterpreter(I)->AddIncludePath(dir); +} + +const char* clang_interpreter_getResourceDir(CXInterpreter I) { + auto* interp = getInterpreter(I); + return interp->getCI()->getHeaderSearchOpts().ResourceDir.c_str(); +} + +enum CXErrorCode clang_interpreter_declare(CXInterpreter I, const char* code, + bool silent) { + auto* interp = getInterpreter(I); + auto& diag = interp->getSema().getDiagnostics(); + + bool is_silent_old = diag.getSuppressAllDiagnostics(); + + diag.setSuppressAllDiagnostics(silent); + auto result = interp->declare(code); + diag.setSuppressAllDiagnostics(is_silent_old); + + if (result) + return CXError_Failure; + + return CXError_Success; +} + +enum CXErrorCode clang_interpreter_process(CXInterpreter I, const char* code) { + auto result = getInterpreter(I)->process(code); + if (result) + return CXError_Failure; + + return CXError_Success; +} + +CXValue clang_createValue() { +#ifdef USE_CLING + auto val = std::make_unique(); +#else + auto val = std::make_unique(); +#endif // USE_CLING + + return val.release(); +} + +void clang_value_dispose(CXValue V) { +#ifdef USE_CLING + delete static_cast(V); // NOLINT(*-owning-memory) +#else + delete static_cast(V); // NOLINT(*-owning-memory) +#endif // USE_CLING +} + +enum CXErrorCode clang_interpreter_evaluate(CXInterpreter I, const char* code, + CXValue V) { +#ifdef USE_CLING + auto* val = static_cast(V); +#else + auto* val = static_cast(V); +#endif // USE_CLING + + auto result = getInterpreter(I)->evaluate(code, *val); + if (result) + return CXError_Failure; + + return CXError_Success; +} + +CXString clang_interpreter_lookupLibrary(CXInterpreter I, + const char* lib_name) { + auto* interp = getInterpreter(I); + return makeCXString( + interp->getDynamicLibraryManager()->lookupLibrary(lib_name)); +} + +CXInterpreter_CompilationResult +clang_interpreter_loadLibrary(CXInterpreter I, const char* lib_stem, + bool lookup) { + auto* interp = getInterpreter(I); + return static_cast( + interp->loadLibrary(lib_stem, lookup)); +} + +void clang_interpreter_unloadLibrary(CXInterpreter I, const char* lib_stem) { + auto* interp = getInterpreter(I); + interp->getDynamicLibraryManager()->unloadLibrary(lib_stem); +} + +CXString clang_interpreter_searchLibrariesForSymbol(CXInterpreter I, + const char* mangled_name, + bool search_system) { + auto* interp = getInterpreter(I); + return makeCXString( + interp->getDynamicLibraryManager()->searchLibrariesForSymbol( + mangled_name, search_system)); +} + +namespace Cpp { +bool InsertOrReplaceJitSymbolImpl(compat::Interpreter& I, + const char* linker_mangled_name, + uint64_t address); +} // namespace Cpp + +bool clang_interpreter_insertOrReplaceJitSymbol(CXInterpreter I, + const char* linker_mangled_name, + uint64_t address) { + return Cpp::InsertOrReplaceJitSymbolImpl(*getInterpreter(I), + linker_mangled_name, address); +} + +CXFuncAddr +clang_interpreter_getFunctionAddressFromMangledName(CXInterpreter I, + const char* mangled_name) { + auto* interp = getInterpreter(I); + auto FDAorErr = compat::getSymbolAddress(*interp, mangled_name); + if (llvm::Error Err = FDAorErr.takeError()) + llvm::consumeError(std::move(Err)); // nullptr if missing + else + return llvm::jitTargetAddressToPointer(*FDAorErr); + + return nullptr; +} + +static inline CXQualType +makeCXQualType(const CXInterpreterImpl* I, clang::QualType Ty, + CXQualTypeKind K = CXQualType_Unexposed) { + assert(I && "Invalid interpreter"); + return CXQualType{K, Ty.getAsOpaquePtr(), reinterpret_cast(I)}; +} + +static inline clang::QualType getType(CXQualType Ty) { + return clang::QualType::getFromOpaquePtr(Ty.data); +} + +static inline const CXInterpreterImpl* getMeta(CXQualType Ty) { + return reinterpret_cast(Ty.meta); +} + +static inline compat::Interpreter* getInterpreter(CXQualType Ty) { + return getInterpreter(reinterpret_cast(Ty.meta)); +} + +bool clang_qualtype_isBuiltin(CXQualType type) { + return Cpp::IsBuiltin(type.data); +} + +bool clang_qualtype_isEnumType(CXQualType type) { + return getType(type)->isEnumeralType(); +} + +bool clang_qualtype_isSmartPtrType(CXQualType type) { + return Cpp::IsSmartPtrType(type.data); +} + +bool clang_scope_isRecordType(CXQualType type) { + return getType(type)->isRecordType(); +} + +bool clang_scope_isPODType(CXQualType type) { + clang::QualType QT = getType(type); + if (QT.isNull()) + return false; + return QT.isPODType(getInterpreter(type)->getSema().getASTContext()); +} + +CXQualType clang_qualtype_getIntegerTypeFromEnumType(CXQualType type) { + void* Ptr = Cpp::GetIntegerTypeFromEnumType(type.data); + return makeCXQualType(getMeta(type), clang::QualType::getFromOpaquePtr(Ptr)); +} + +CXQualType clang_qualtype_getUnderlyingType(CXQualType type) { + clang::QualType QT = getType(type); + QT = QT->getCanonicalTypeUnqualified(); + + // Recursively remove array dimensions + while (QT->isArrayType()) + QT = clang::QualType(QT->getArrayElementTypeNoTypeQual(), 0); + + // Recursively reduce pointer depth till we are left with a pointerless + // type. + for (auto PT = QT->getPointeeType(); !PT.isNull(); + PT = QT->getPointeeType()) { + QT = PT; + } + QT = QT->getCanonicalTypeUnqualified(); + return makeCXQualType(getMeta(type), QT); +} + +CXString clang_qualtype_getTypeAsString(CXQualType type) { + clang::QualType QT = getType(type); + auto& C = getInterpreter(type)->getSema().getASTContext(); + clang::PrintingPolicy Policy = C.getPrintingPolicy(); + Policy.Bool = true; // Print bool instead of _Bool. + Policy.SuppressTagKeyword = true; // Do not print `class std::string`. + return makeCXString(compat::FixTypeName(QT.getAsString(Policy))); +} + +CXQualType clang_qualtype_getCanonicalType(CXQualType type) { + clang::QualType QT = getType(type); + if (QT.isNull()) + return makeCXQualType(getMeta(type), clang::QualType(), CXQualType_Invalid); + + return makeCXQualType(getMeta(type), QT.getCanonicalType()); +} + +namespace Cpp { +clang::QualType GetType(const std::string& name, clang::Sema& sema); +} // namespace Cpp + +CXQualType clang_qualtype_getType(CXInterpreter I, const char* name) { + auto& S = getInterpreter(I)->getSema(); + clang::QualType QT = Cpp::GetType(std::string(name), S); + if (QT.isNull()) + return makeCXQualType(I, QT, CXQualType_Invalid); + + return makeCXQualType(I, QT); +} + +CXQualType clang_qualtype_getComplexType(CXQualType eltype) { + auto& C = getInterpreter(eltype)->getSema().getASTContext(); + return makeCXQualType(getMeta(eltype), C.getComplexType(getType(eltype))); +} + +static inline CXScope makeCXScope(const CXInterpreterImpl* I, clang::Decl* D, + CXScopeKind K = CXScope_Unexposed) { + assert(I && "Invalid interpreter"); + return CXScope{K, D, reinterpret_cast(I)}; +} + +size_t clang_qualtype_getSizeOfType(CXQualType type) { + clang::QualType QT = getType(type); + if (const clang::TagType* TT = QT->getAs()) + return clang_scope_sizeOf(makeCXScope(getMeta(type), TT->getDecl())); + + // FIXME: Can we get the size of a non-tag type? + auto* I = getInterpreter(type); + auto TI = I->getSema().getASTContext().getTypeInfo(QT); + size_t TypeSize = TI.Width; + return TypeSize / 8; +} + +bool clang_qualtype_isTypeDerivedFrom(CXQualType derived, CXQualType base) { + auto* I = getInterpreter(derived); + auto& SM = I->getSema().getSourceManager(); + auto fakeLoc = SM.getLocForStartOfFile(SM.getMainFileID()); + auto derivedType = getType(derived); + auto baseType = getType(base); + +#ifdef USE_CLING + cling::Interpreter::PushTransactionRAII RAII(I); +#endif + return I->getSema().IsDerivedFrom(fakeLoc, derivedType, baseType); +} + +static inline bool isNull(CXScope S) { return !S.data; } + +static inline clang::Decl* getDecl(CXScope S) { + return static_cast(S.data); +} + +static inline const CXInterpreterImpl* getMeta(CXScope S) { + return reinterpret_cast(S.meta); +} + +static inline CXScopeKind kind(CXScope S) { return S.kind; } + +static inline compat::Interpreter* getInterpreter(CXScope S) { + return getInterpreter(reinterpret_cast(S.meta)); +} + +void clang_scope_dump(CXScope S) { getDecl(S)->dump(); } + +CXQualType clang_scope_getTypeFromScope(CXScope S) { + if (isNull(S)) + return makeCXQualType(getMeta(S), clang::QualType(), CXQualType_Invalid); + + auto* D = getDecl(S); + if (const auto* VD = llvm::dyn_cast(D)) + return makeCXQualType(getMeta(S), VD->getType()); + + auto& Ctx = getInterpreter(S)->getCI()->getASTContext(); + return makeCXQualType(getMeta(S), + Ctx.getTypeDeclType(llvm::cast(D))); +} + +bool clang_scope_isAggregate(CXScope S) { return Cpp::IsAggregate(S.data); } + +bool clang_scope_isNamespace(CXScope S) { + return llvm::isa(getDecl(S)); +} + +bool clang_scope_isClass(CXScope S) { + return llvm::isa(getDecl(S)); +} + +bool clang_scope_isComplete(CXScope S) { + if (isNull(S)) + return false; + + auto* D = getDecl(S); + if (llvm::isa(D)) { + clang::QualType QT = getType(clang_scope_getTypeFromScope(S)); + const auto* CI = getInterpreter(S)->getCI(); + auto& S = CI->getSema(); + auto& SM = S.getSourceManager(); + clang::SourceLocation fakeLoc = SM.getLocForStartOfFile(SM.getMainFileID()); + return S.isCompleteType(fakeLoc, QT); + } + + if (auto* CXXRD = llvm::dyn_cast(D)) + return CXXRD->hasDefinition(); + else if (auto* TD = llvm::dyn_cast(D)) + return TD->getDefinition(); + + // Everything else is considered complete. + return true; +} + +size_t clang_scope_sizeOf(CXScope S) { + if (!clang_scope_isComplete(S)) + return 0; + + if (auto* RD = llvm::dyn_cast(getDecl(S))) { + clang::ASTContext& Context = RD->getASTContext(); + const clang::ASTRecordLayout& Layout = Context.getASTRecordLayout(RD); + return Layout.getSize().getQuantity(); + } + + return 0; +} + +bool clang_scope_isTemplate(CXScope S) { + return llvm::isa_and_nonnull(getDecl(S)); +} + +bool clang_scope_isTemplateSpecialization(CXScope S) { + return llvm::isa_and_nonnull( + getDecl(S)); +} + +bool clang_scope_isTypedefed(CXScope S) { + return llvm::isa_and_nonnull(getDecl(S)); +} + +bool clang_scope_isAbstract(CXScope S) { + if (auto* CXXRD = llvm::dyn_cast_or_null(getDecl(S))) + return CXXRD->isAbstract(); + return false; +} + +bool clang_scope_isEnumScope(CXScope S) { + return llvm::isa_and_nonnull(getDecl(S)); +} + +bool clang_scope_isEnumConstant(CXScope S) { + return llvm::isa_and_nonnull(getDecl(S)); +} + +CXStringSet* clang_scope_getEnums(CXScope S) { + std::vector EnumNames; + Cpp::GetEnums(S.data, EnumNames); + return makeCXStringSet(EnumNames); +} + +CXQualType clang_scope_getIntegerTypeFromEnumScope(CXScope S) { + auto* ED = llvm::dyn_cast_or_null(getDecl(S)); + if (ED) + return makeCXQualType(getMeta(S), ED->getIntegerType()); + + return makeCXQualType(getMeta(S), clang::QualType(), CXQualType_Invalid); +} + +void clang_disposeScopeSet(CXScopeSet* set) { + delete[] set->Scopes; + delete set; +} + +CXScopeSet* clang_scope_getEnumConstants(CXScope S) { + auto* ED = llvm::dyn_cast_or_null(getDecl(S)); + if (!ED || ED->enumerators().empty()) + return nullptr; + + CXScopeSet* Set = new CXScopeSet; + Set->Count = std::distance(ED->enumerator_begin(), ED->enumerator_end()); + Set->Scopes = new CXScope[Set->Count]; + for (auto [Idx, Val] : llvm::enumerate(ED->enumerators())) { + Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_EnumConstant); + } + + return Set; +} + +CXQualType clang_scope_getEnumConstantType(CXScope S) { + if (isNull(S)) + return makeCXQualType(getMeta(S), clang::QualType(), CXQualType_Invalid); + + auto* ECD = llvm::dyn_cast_or_null(getDecl(S)); + if (ECD) + return makeCXQualType(getMeta(S), ECD->getType()); + + return makeCXQualType(getMeta(S), clang::QualType(), CXQualType_Invalid); +} + +size_t clang_scope_getEnumConstantValue(CXScope S) { + auto* ECD = llvm::dyn_cast_or_null(getDecl(S)); + if (ECD) { + const llvm::APSInt& Val = ECD->getInitVal(); + return Val.getExtValue(); + } + return 0; +} + +bool clang_scope_isVariable(CXScope S) { + return llvm::isa_and_nonnull(getDecl(S)); +} + +CXString clang_scope_getName(CXScope S) { + auto* D = getDecl(S); + + if (llvm::isa_and_nonnull(D)) + return makeCXString(""); + + if (auto* ND = llvm::dyn_cast_or_null(D)) + return makeCXString(ND->getNameAsString()); + + return makeCXString(""); +} + +CXString clang_scope_getCompleteName(CXScope S) { + auto& C = getInterpreter(S)->getSema().getASTContext(); + auto* D = getDecl(S); + + if (auto* ND = llvm::dyn_cast_or_null(D)) { + if (auto* TD = llvm::dyn_cast(ND)) { + std::string type_name; + clang::QualType QT = C.getTagDeclType(TD); + clang::PrintingPolicy Policy = C.getPrintingPolicy(); + Policy.SuppressUnwrittenScope = true; + Policy.SuppressScope = true; + Policy.AnonymousTagLocations = false; + QT.getAsStringInternal(type_name, Policy); + + return makeCXString(type_name); + } + + return makeCXString(ND->getNameAsString()); + } + + if (llvm::isa_and_nonnull(D)) + return makeCXString(""); + + return makeCXString(""); +} + +CXString clang_scope_getQualifiedName(CXScope S) { + auto* D = getDecl(S); + if (auto* ND = llvm::dyn_cast_or_null(D)) + return makeCXString(ND->getQualifiedNameAsString()); + + if (llvm::isa_and_nonnull(D)) + return makeCXString(""); + + return makeCXString(""); +} + +CXString clang_scope_getQualifiedCompleteName(CXScope S) { + auto& C = getInterpreter(S)->getSema().getASTContext(); + auto* D = getDecl(S); + + if (auto* ND = llvm::dyn_cast_or_null(D)) { + if (auto* TD = llvm::dyn_cast(ND)) { + std::string type_name; + clang::QualType QT = C.getTagDeclType(TD); + QT.getAsStringInternal(type_name, C.getPrintingPolicy()); + + return makeCXString(type_name); + } + + return makeCXString(ND->getQualifiedNameAsString()); + } + + if (llvm::isa_and_nonnull(D)) { + return makeCXString(""); + } + + return makeCXString(""); +} + +CXScopeSet* clang_scope_getUsingNamespaces(CXScope S) { + auto* DC = llvm::dyn_cast_or_null(getDecl(S)); + if (!DC || DC->using_directives().empty()) + return nullptr; + + CXScopeSet* Set = new CXScopeSet; + Set->Count = std::distance(DC->using_directives().begin(), + DC->using_directives().end()); + Set->Scopes = new CXScope[Set->Count]; + for (auto [Idx, Val] : llvm::enumerate(DC->using_directives())) { + Set->Scopes[Idx] = makeCXScope(getMeta(S), Val->getNominatedNamespace(), + CXScope_Namespace); + } + + return Set; +} + +CXScope clang_scope_getGlobalScope(CXInterpreter I) { + auto& C = getInterpreter(I)->getSema().getASTContext(); + auto* DC = C.getTranslationUnitDecl(); + return makeCXScope(I, DC, CXScope_Global); +} + +CXScope clang_scope_getUnderlyingScope(CXScope S) { + auto* TND = llvm::dyn_cast_or_null(getDecl(S)); + if (!TND) + return makeCXScope(getMeta(S), nullptr, CXScope_Invalid); + + clang::QualType QT = TND->getUnderlyingType(); + auto D = Cpp::GetScopeFromType(QT.getAsOpaquePtr()); + if (!D) + return makeCXScope(getMeta(S), nullptr, CXScope_Invalid); + + return makeCXScope(getMeta(S), static_cast(D)); +} + +CXScope clang_scope_getScope(const char* name, CXScope parent) { + auto S = clang_scope_getNamed(name, parent); + if (kind(S) == CXScope_Invalid) + return S; + + clang::NamedDecl* ND = llvm::dyn_cast(getDecl(S)); + if (llvm::isa(ND) || llvm::isa(ND) || + llvm::isa(ND) || + llvm::isa(ND)) { + return makeCXScope(getMeta(S), ND->getCanonicalDecl()); + } + + return S; +} + +CXScope clang_scope_getNamed(const char* name, CXScope parent) { + clang::DeclContext* Within = 0; + if (kind(parent) != CXScope_Invalid) { + auto US = clang_scope_getUnderlyingScope(parent); + if (kind(US) != CXScope_Invalid) + Within = llvm::dyn_cast(getDecl(US)); + } + + auto& sema = getInterpreter(parent)->getSema(); + auto* ND = Cpp::Cpp_utils::Lookup::Named(&sema, std::string(name), Within); + if (ND && ND != (clang::NamedDecl*)-1) { + return makeCXScope(getMeta(parent), ND->getCanonicalDecl()); + } + + return makeCXScope(getMeta(parent), nullptr, CXScope_Invalid); +} + +CXScope clang_scope_getParentScope(CXScope parent) { + auto* D = getDecl(parent); + + if (llvm::isa_and_nonnull(D)) + return makeCXScope(getMeta(parent), nullptr, CXScope_Invalid); + + auto* ParentDC = D->getDeclContext(); + + if (!ParentDC) + return makeCXScope(getMeta(parent), nullptr, CXScope_Invalid); + + auto* CD = clang::Decl::castFromDeclContext(ParentDC)->getCanonicalDecl(); + + return makeCXScope(getMeta(parent), CD); +} + +CXScope clang_scope_getScopeFromType(CXQualType type) { + auto* D = Cpp::GetScopeFromType(type.data); + return makeCXScope(getMeta(type), static_cast(D)); +} + +size_t clang_scope_getNumBases(CXScope S) { + auto* D = getDecl(S); + + if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { + if (CXXRD->hasDefinition()) + return CXXRD->getNumBases(); + } + + return 0; +} + +CXScope clang_scope_getBaseClass(CXScope S, size_t ibase) { + auto* D = getDecl(S); + auto* CXXRD = llvm::dyn_cast_or_null(D); + if (!CXXRD || CXXRD->getNumBases() <= ibase) + return makeCXScope(getMeta(S), nullptr, CXScope_Invalid); + + auto type = (CXXRD->bases_begin() + ibase)->getType(); + if (auto RT = type->getAs()) + return makeCXScope(getMeta(S), RT->getDecl()); + + return makeCXScope(getMeta(S), nullptr, CXScope_Invalid); +} + +bool clang_scope_isSubclass(CXScope derived, CXScope base) { + if (isNull(derived) || isNull(base)) + return false; + + auto* D = getDecl(derived); + auto* B = getDecl(base); + + if (D == B) + return true; + + if (!llvm::isa(D) || + !llvm::isa(B)) + return false; + + return clang_qualtype_isTypeDerivedFrom(clang_scope_getTypeFromScope(derived), + clang_scope_getTypeFromScope(base)); +} + +namespace Cpp { +unsigned ComputeBaseOffset(const clang::ASTContext& Context, + const clang::CXXRecordDecl* DerivedRD, + const clang::CXXBasePath& Path); +} // namespace Cpp + +int64_t clang_scope_getBaseClassOffset(CXScope derived, CXScope base) { + auto* D = getDecl(derived); + auto* B = getDecl(base); + + if (D == B) + return 0; + + assert(D || B); + + if (!llvm::isa(D) || + !llvm::isa(B)) + return -1; + + auto* DCXXRD = llvm::cast(D); + auto* BCXXRD = llvm::cast(B); + clang::CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + DCXXRD->isDerivedFrom(BCXXRD, Paths); + + auto* I = getInterpreter(derived); + return Cpp::ComputeBaseOffset(I->getSema().getASTContext(), DCXXRD, + Paths.front()); +} + +CXScopeSet* clang_scope_getClassMethods(CXScope S) { + if (kind(S) == CXScope_Invalid) + return nullptr; + + auto US = clang_scope_getUnderlyingScope(S); + if (kind(US) == CXScope_Invalid || !clang_scope_isClass(US)) + return nullptr; + + auto* CXXRD = llvm::dyn_cast(getDecl(US)); + + auto* I = getInterpreter(S); +#ifdef USE_CLING + cling::Interpreter::PushTransactionRAII RAII(I); +#endif // USE_CLING + I->getSema().ForceDeclarationOfImplicitMembers(CXXRD); + llvm::SmallVector Methods; + for (clang::Decl* DI : CXXRD->decls()) { + if (auto* MD = llvm::dyn_cast(DI)) { + Methods.push_back(MD); + } else if (auto* USD = llvm::dyn_cast(DI)) { + auto* MD = llvm::dyn_cast(USD->getTargetDecl()); + if (MD) + Methods.push_back(MD); + } + } + + CXScopeSet* Set = new CXScopeSet; + Set->Count = Methods.size(); + Set->Scopes = new CXScope[Set->Count]; + for (auto [Idx, Val] : llvm::enumerate(Methods)) { + Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); + } + + return Set; +} + +CXScopeSet* clang_scope_getFunctionTemplatedDecls(CXScope S) { + if (kind(S) == CXScope_Invalid) + return nullptr; + + auto US = clang_scope_getUnderlyingScope(S); + if (kind(US) == CXScope_Invalid || !clang_scope_isClass(US)) + return nullptr; + + auto* CXXRD = llvm::dyn_cast(getDecl(US)); + + auto* I = getInterpreter(S); +#ifdef USE_CLING + cling::Interpreter::PushTransactionRAII RAII(I); +#endif // USE_CLING + I->getSema().ForceDeclarationOfImplicitMembers(CXXRD); + llvm::SmallVector Methods; + for (clang::Decl* DI : CXXRD->decls()) { + if (auto* MD = llvm::dyn_cast(DI)) { + Methods.push_back(MD); + } else if (auto* USD = llvm::dyn_cast(DI)) { + auto* MD = + llvm::dyn_cast(USD->getTargetDecl()); + if (MD) + Methods.push_back(MD); + } + } + + CXScopeSet* Set = new CXScopeSet; + Set->Count = Methods.size(); + Set->Scopes = new CXScope[Set->Count]; + for (auto [Idx, Val] : llvm::enumerate(Methods)) { + Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); + } + + return Set; +} + +bool clang_scope_hasDefaultConstructor(CXScope S) { + auto* D = getDecl(S); + + if (auto* CXXRD = llvm::dyn_cast_or_null(D)) + return CXXRD->hasDefaultConstructor(); + + return false; +} + +CXScope clang_scope_getDefaultConstructor(CXScope S) { + if (!clang_scope_hasDefaultConstructor(S)) + return makeCXScope(getMeta(S), nullptr, CXScope_Invalid); + + auto* CXXRD = llvm::dyn_cast_or_null(getDecl(S)); + if (!CXXRD) + return makeCXScope(getMeta(S), nullptr, CXScope_Invalid); + + auto* Res = getInterpreter(S)->getSema().LookupDefaultConstructor(CXXRD); + return makeCXScope(getMeta(S), Res, CXScope_Function); +} + +CXScope clang_scope_getDestructor(CXScope S) { + auto* D = getDecl(S); + + if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { + getInterpreter(S)->getSema().ForceDeclarationOfImplicitMembers(CXXRD); + return makeCXScope(getMeta(S), CXXRD->getDestructor(), CXScope_Function); + } + + return makeCXScope(getMeta(S), nullptr, CXScope_Invalid); +} + +CXScopeSet* clang_scope_getFunctionsUsingName(CXScope S, const char* name) { + auto* D = getDecl(clang_scope_getUnderlyingScope(S)); + + if (!D || !name) + return nullptr; + + llvm::StringRef Name(name); + auto* I = getInterpreter(S); + auto& SM = I->getSema(); + clang::DeclarationName DName = &SM.getASTContext().Idents.get(name); + clang::LookupResult R(SM, DName, clang::SourceLocation(), + clang::Sema::LookupOrdinaryName, + clang::Sema::ForVisibleRedeclaration); + + Cpp::Cpp_utils::Lookup::Named(&SM, R, clang::Decl::castToDeclContext(D)); + + if (R.empty()) + return nullptr; + + R.resolveKind(); + + llvm::SmallVector Funcs; + for (auto* Found : R) + if (llvm::isa(Found)) + Funcs.push_back(Found); + + CXScopeSet* Set = new CXScopeSet; + Set->Count = Funcs.size(); + Set->Scopes = new CXScope[Set->Count]; + for (auto [Idx, Val] : llvm::enumerate(Funcs)) { + Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); + } + + return Set; +} + +CXQualType clang_scope_getFunctionReturnType(CXScope func) { + auto* D = getDecl(func); + if (auto* FD = llvm::dyn_cast_or_null(D)) + return makeCXQualType(getMeta(func), FD->getReturnType()); + + if (auto* FD = llvm::dyn_cast_or_null(D)) { + auto* FTD = FD->getTemplatedDecl(); + return makeCXQualType(getMeta(func), FTD->getReturnType()); + } + + return makeCXQualType(getMeta(func), clang::QualType(), CXQualType_Invalid); +} + +size_t clang_scope_getFunctionNumArgs(CXScope func) { + auto* D = getDecl(func); + if (auto* FD = llvm::dyn_cast_or_null(D)) + return FD->getNumParams(); + + if (auto* FD = llvm::dyn_cast_or_null(D)) + return FD->getTemplatedDecl()->getNumParams(); + + return 0; +} + +size_t clang_scope_getFunctionRequiredArgs(CXScope func) { + auto* D = getDecl(func); + if (auto* FD = llvm::dyn_cast_or_null(D)) + return FD->getMinRequiredArguments(); + + if (auto* FD = llvm::dyn_cast_or_null(D)) + return FD->getTemplatedDecl()->getMinRequiredArguments(); + + return 0; +} + +CXQualType clang_scope_getFunctionArgType(CXScope func, size_t iarg) { + auto* D = getDecl(func); + + if (auto* FD = llvm::dyn_cast_or_null(D)) { + if (iarg < FD->getNumParams()) { + auto* PVD = FD->getParamDecl(iarg); + return makeCXQualType(getMeta(func), PVD->getOriginalType()); + } + } + + return makeCXQualType(getMeta(func), clang::QualType(), CXQualType_Invalid); +} + +CXString clang_scope_getFunctionSignature(CXScope func) { + if (isNull(func)) + return makeCXString(""); + + auto* D = getDecl(func); + if (auto* FD = llvm::dyn_cast(D)) { + std::string Signature; + llvm::raw_string_ostream SS(Signature); + auto& C = getInterpreter(func)->getSema().getASTContext(); + clang::PrintingPolicy Policy = C.getPrintingPolicy(); + // Skip printing the body + Policy.TerseOutput = true; + Policy.FullyQualifiedName = true; + Policy.SuppressDefaultTemplateArgs = false; + FD->print(SS, Policy); + SS.flush(); + return makeCXString(Signature); + } + + return makeCXString(""); +} + +bool clang_scope_isFunctionDeleted(CXScope func) { + auto* FD = llvm::cast(getDecl(func)); + return FD->isDeleted(); +} + +bool clang_scope_isTemplatedFunction(CXScope func) { + auto* D = getDecl(func); + if (llvm::isa_and_nonnull(D)) + return true; + + if (auto* FD = llvm::dyn_cast_or_null(D)) { + auto TK = FD->getTemplatedKind(); + return TK == clang::FunctionDecl::TemplatedKind:: + TK_FunctionTemplateSpecialization || + TK == clang::FunctionDecl::TemplatedKind:: + TK_DependentFunctionTemplateSpecialization || + TK == clang::FunctionDecl::TemplatedKind::TK_FunctionTemplate; + } + + return false; +} + +bool clang_scope_existsFunctionTemplate(const char* name, CXScope parent) { + if (kind(parent) == CXScope_Invalid || !name) + return false; + + auto* Within = llvm::dyn_cast(getDecl(parent)); + + auto& S = getInterpreter(parent)->getSema(); + auto* ND = Cpp::Cpp_utils::Lookup::Named(&S, name, Within); + + if ((intptr_t)ND == (intptr_t)0) + return false; + + if ((intptr_t)ND != (intptr_t)-1) + return clang_scope_isTemplatedFunction(makeCXScope(getMeta(parent), ND)); + + // FIXME: Cycle through the Decls and check if there is a templated function + return true; +} + +CXScopeSet* clang_scope_getClassTemplatedMethods(const char* name, + CXScope parent) { + auto* D = getDecl(clang_scope_getUnderlyingScope(parent)); + + if (!D || !name) + return nullptr; + + llvm::StringRef Name(name); + auto* I = getInterpreter(parent); + auto& SM = I->getSema(); + clang::DeclarationName DName = &SM.getASTContext().Idents.get(name); + clang::LookupResult R(SM, DName, clang::SourceLocation(), + clang::Sema::LookupOrdinaryName, + clang::Sema::ForVisibleRedeclaration); + + Cpp::Cpp_utils::Lookup::Named(&SM, R, clang::Decl::castToDeclContext(D)); + + if (R.empty()) + return nullptr; + + R.resolveKind(); + + llvm::SmallVector Funcs; + for (auto* Found : R) + if (llvm::isa(Found)) + Funcs.push_back(Found); + + CXScopeSet* Set = new CXScopeSet; + Set->Count = Funcs.size(); + Set->Scopes = new CXScope[Set->Count]; + for (auto [Idx, Val] : llvm::enumerate(Funcs)) { + Set->Scopes[Idx] = makeCXScope(getMeta(parent), Val, CXScope_Function); + } + + return Set; +} + +bool clang_scope_isMethod(CXScope method) { + auto* D = getDecl(method); + return llvm::dyn_cast_or_null(D); +} + +bool clang_scope_isPublicMethod(CXScope method) { + auto* D = getDecl(method); + if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + return CXXMD->getAccess() == clang::AccessSpecifier::AS_public; + + return false; +} + +bool clang_scope_isProtectedMethod(CXScope method) { + auto* D = getDecl(method); + if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + return CXXMD->getAccess() == clang::AccessSpecifier::AS_protected; + + return false; +} + +bool clang_scope_isPrivateMethod(CXScope method) { + auto* D = getDecl(method); + if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + return CXXMD->getAccess() == clang::AccessSpecifier::AS_private; + + return false; +} + +bool clang_scope_isConstructor(CXScope method) { + auto* D = getDecl(method); + return llvm::isa_and_nonnull(D); +} + +bool clang_scope_isDestructor(CXScope method) { + auto* D = getDecl(method); + return llvm::isa_and_nonnull(D); +} + +bool clang_scope_isStaticMethod(CXScope method) { + auto* D = getDecl(method); + if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + return CXXMD->isStatic(); + + return false; +} + +CXFuncAddr clang_scope_getFunctionAddress(CXScope method) { + auto* D = getDecl(method); + auto* I = getInterpreter(method); + + const auto get_mangled_name = [I](clang::FunctionDecl* FD) { + auto MangleCtx = I->getSema().getASTContext().createMangleContext(); + + if (!MangleCtx->shouldMangleDeclName(FD)) { + return FD->getNameInfo().getName().getAsString(); + } + + std::string mangled_name; + llvm::raw_string_ostream ostream(mangled_name); + + MangleCtx->mangleName(FD, ostream); + + ostream.flush(); + delete MangleCtx; + + return mangled_name; + }; + + if (auto* FD = llvm::dyn_cast_or_null(D)) { + auto FDAorErr = compat::getSymbolAddress(*I, get_mangled_name(FD).c_str()); + if (llvm::Error Err = FDAorErr.takeError()) + llvm::consumeError(std::move(Err)); // nullptr if missing + else + return llvm::jitTargetAddressToPointer(*FDAorErr); + } + + return nullptr; +} + +bool clang_scope_isVirtualMethod(CXScope method) { + auto* D = getDecl(method); + if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + return CXXMD->isVirtual(); + + return false; +} + +bool clang_scope_isConstMethod(CXScope method) { + auto* D = getDecl(method); + if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + return CXXMD->getMethodQualifiers().hasConst(); + + return false; +} + +CXString clang_scope_getFunctionArgDefault(CXScope func, size_t param_index) { + return makeCXString(Cpp::GetFunctionArgDefault(func.data, param_index)); +} + +CXString clang_scope_getFunctionArgName(CXScope func, size_t param_index) { + return makeCXString(Cpp::GetFunctionArgName(func.data, param_index)); +} + +CXScopeSet* clang_scope_getDatamembers(CXScope S) { + auto* CXXRD = llvm::dyn_cast_or_null(getDecl(S)); + if (!CXXRD) + return nullptr; + + CXScopeSet* Set = new CXScopeSet; + Set->Count = std::distance(CXXRD->field_begin(), CXXRD->field_end()); + Set->Scopes = new CXScope[Set->Count]; + for (auto [Idx, Val] : llvm::enumerate(CXXRD->fields())) { + Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); + } + + return Set; +} + +CXScope clang_scope_lookupDatamember(const char* name, CXScope parent) { + if (kind(parent) == CXScope_Invalid || !name) + return makeCXScope(getMeta(parent), nullptr, CXScope_Invalid); + + clang::DeclContext* Within = + llvm::dyn_cast(getDecl(parent)); + + auto& S = getInterpreter(parent)->getSema(); + auto* ND = Cpp::Cpp_utils::Lookup::Named(&S, name, Within); + if (ND && ND != (clang::NamedDecl*)-1) { + if (llvm::isa_and_nonnull(ND)) { + return makeCXScope(getMeta(parent), ND, CXScope_Field); + } + } + + return makeCXScope(getMeta(parent), nullptr, CXScope_Invalid); +} + +namespace Cpp { +clang::Decl* +InstantiateTemplate(clang::TemplateDecl* TemplateD, + llvm::ArrayRef TemplateArgs, + clang::Sema& S); +} // namespace Cpp + +CXScope clang_scope_instantiateTemplate(CXScope tmpl, + CXTemplateArgInfo* template_args, + size_t template_args_size) { + auto* I = getInterpreter(tmpl); + auto& S = I->getSema(); + auto& C = S.getASTContext(); + + llvm::SmallVector TemplateArgs; + TemplateArgs.reserve(template_args_size); + for (size_t i = 0; i < template_args_size; ++i) { + clang::QualType ArgTy = + clang::QualType::getFromOpaquePtr(template_args[i].Type); + if (template_args[i].IntegralValue) { + // We have a non-type template parameter. Create an integral value from + // the string representation. + auto Res = llvm::APSInt(template_args[i].IntegralValue); + Res = Res.extOrTrunc(C.getIntWidth(ArgTy)); + TemplateArgs.push_back(clang::TemplateArgument(C, Res, ArgTy)); + } else { + TemplateArgs.push_back(ArgTy); + } + } + + clang::TemplateDecl* TmplD = static_cast(getDecl(tmpl)); + + // We will create a new decl, push a transaction. +#ifdef USE_CLING + cling::Interpreter::PushTransactionRAII RAII(I); +#endif + return makeCXScope(getMeta(tmpl), + Cpp::InstantiateTemplate(TmplD, TemplateArgs, S)); +} + +CXQualType clang_scope_getVariableType(CXScope var) { + auto D = getDecl(var); + + if (auto DD = llvm::dyn_cast_or_null(D)) + return makeCXQualType(getMeta(var), DD->getType()); + + return makeCXQualType(getMeta(var), clang::QualType(), CXQualType_Invalid); +} + +namespace Cpp { +intptr_t GetVariableOffsetImpl(compat::Interpreter& I, clang::Decl* D); +} // namespace Cpp + +intptr_t clang_scope_getVariableOffset(CXScope var) { + return Cpp::GetVariableOffsetImpl(*getInterpreter(var), getDecl(var)); +} + +bool clang_scope_isPublicVariable(CXScope var) { + auto* D = getDecl(var); + if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + return CXXMD->getAccess() == clang::AccessSpecifier::AS_public; + + return false; +} + +bool clang_scope_isProtectedVariable(CXScope var) { + auto* D = getDecl(var); + if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + return CXXMD->getAccess() == clang::AccessSpecifier::AS_protected; + + return false; +} + +bool clang_scope_isPrivateVariable(CXScope var) { + auto* D = getDecl(var); + if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + return CXXMD->getAccess() == clang::AccessSpecifier::AS_private; + + return false; +} + +bool clang_scope_isStaticVariable(CXScope var) { + auto* D = getDecl(var); + if (llvm::isa_and_nonnull(D)) + return true; + + return false; +} + +bool clang_scope_isConstVariable(CXScope var) { + auto* D = getDecl(var); + if (auto* VD = llvm::dyn_cast_or_null(D)) { + return VD->getType().isConstQualified(); + } + + return false; +} + +CXObject clang_allocate(CXScope S) { + return ::operator new(clang_scope_sizeOf(S)); +} + +void clang_deallocate(CXObject address) { ::operator delete(address); } + +namespace Cpp { +JitCall MakeFunctionCallableImpl(TInterp_t I, TCppConstFunction_t func); +} // namespace Cpp + +CXObject clang_construct(CXScope scope, void* arena) { + if (!clang_scope_hasDefaultConstructor(scope)) + return nullptr; + + auto Ctor = clang_scope_getDefaultConstructor(scope); + if (kind(Ctor) == CXScope_Invalid) + return nullptr; + + auto* I = getInterpreter(scope); + if (Cpp::JitCall JC = Cpp::MakeFunctionCallableImpl(I, getDecl(Ctor))) { + if (arena) { + JC.Invoke(&arena, {}, (void*)~0); // Tell Invoke to use placement new. + return arena; + } + + void* obj = nullptr; + JC.Invoke(&obj); + return obj; + } + + return nullptr; +} + +namespace Cpp { +void DestructImpl(compat::Interpreter& interp, TCppObject_t This, + clang::Decl* Class, bool withFree); +} // namespace Cpp + +void clang_destruct(CXObject This, CXScope S, bool withFree) { + Cpp::DestructImpl(*getInterpreter(S), This, getDecl(S), withFree); +} + +CXJitCallKind clang_jitcall_getKind(CXJitCall J) { + auto* call = reinterpret_cast(J); // NOLINT(*-cast) + return static_cast(call->getKind()); +} + +bool clang_jitcall_isValid(CXJitCall J) { + return reinterpret_cast(J)->isValid(); // NOLINT(*-cast) +} + +void clang_jitcall_invoke(CXJitCall J, void* result, CXJitCallArgList args, + void* self) { + auto* call = reinterpret_cast(J); // NOLINT(*-cast) + return call->Invoke(result, {args.data, args.numArgs}, self); +} + +CXJitCall clang_jitcall_makeFunctionCallable(CXScope func) { + auto J = Cpp::MakeFunctionCallableImpl(getInterpreter(func), getDecl(func)); + return reinterpret_cast( + std::make_unique(J).release()); // NOLINT(*-cast) +} + +void clang_jitcall_dispose(CXJitCall J) { + delete reinterpret_cast(J); // NOLINT(*-owning-memory, *-cast) +} \ No newline at end of file diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 2b251dea3..ac559432c 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -192,11 +192,11 @@ namespace Cpp { if (!scope) return false; - Decl *D = static_cast(scope); + Decl* D = static_cast(scope); if (isa(D)) { QualType QT = QualType::getFromOpaquePtr(GetTypeFromScope(scope)); - clang::Sema &S = getSema(); + clang::Sema& S = getSema(); SourceLocation fakeLoc = GetValidSLoc(S); #ifdef USE_CLING cling::Interpreter::PushTransactionRAII RAII(&getInterp()); @@ -401,7 +401,7 @@ namespace Cpp { return llvm::isa_and_nonnull(D); } - std::string GetName(TCppType_t klass) { + std::string GetName(TCppScope_t klass) { auto *D = (clang::NamedDecl *) klass; if (llvm::isa_and_nonnull(D)) { @@ -415,10 +415,9 @@ namespace Cpp { return ""; } - std::string GetCompleteName(TCppType_t klass) - { - auto &C = getSema().getASTContext(); - auto *D = (Decl *) klass; + std::string GetCompleteName(TCppScope_t klass) { + auto& C = getSema().getASTContext(); + auto* D = (Decl*)klass; if (auto *ND = llvm::dyn_cast_or_null(D)) { if (auto *TD = llvm::dyn_cast(ND)) { @@ -443,8 +442,7 @@ namespace Cpp { return ""; } - std::string GetQualifiedName(TCppType_t klass) - { + std::string GetQualifiedName(TCppScope_t klass) { auto *D = (Decl *) klass; if (auto *ND = llvm::dyn_cast_or_null(D)) { return ND->getQualifiedNameAsString(); @@ -458,10 +456,9 @@ namespace Cpp { } //FIXME: Figure out how to merge with GetCompleteName. - std::string GetQualifiedCompleteName(TCppType_t klass) - { - auto &C = getSema().getASTContext(); - auto *D = (Decl *) klass; + std::string GetQualifiedCompleteName(TCppScope_t klass) { + auto& C = getSema().getASTContext(); + auto* D = (Decl*)klass; if (auto *ND = llvm::dyn_cast_or_null(D)) { if (auto *TD = llvm::dyn_cast(ND)) { @@ -574,22 +571,27 @@ namespace Cpp { return GetScope(name.substr(start, end), curr_scope); } - TCppScope_t GetNamed(const std::string &name, - TCppScope_t parent /*= nullptr*/) - { + Decl* GetNamedImpl(Sema* sema, const std::string& name, + Decl* parent /*= nullptr*/) { clang::DeclContext *Within = 0; if (parent) { - auto *D = (clang::Decl *)parent; - D = GetUnderlyingScope(D); + Decl* D = GetUnderlyingScope(parent); Within = llvm::dyn_cast(D); } - auto *ND = Cpp_utils::Lookup::Named(&getSema(), name, Within); + auto* ND = Cpp_utils::Lookup::Named(sema, name, Within); if (ND && ND != (clang::NamedDecl*) -1) { - return (TCppScope_t)(ND->getCanonicalDecl()); + return ND->getCanonicalDecl(); } - return 0; + return nullptr; + } + + TCppScope_t GetNamed(const std::string& name, + TCppScope_t parent /*= nullptr*/) { + auto& sema = getSema(); + auto* D = static_cast(parent); + return GetNamedImpl(&sema, name, D); } TCppScope_t GetParentScope(TCppScope_t scope) @@ -660,12 +662,12 @@ namespace Cpp { } // Copied from VTableBuilder.cpp - // This is an internal helper function for the CppInterOp library (as evident - // by the 'static' declaration), while the similar GetBaseClassOffset() + // This is an internal helper function for the CppInterOp library, + // while the similar GetBaseClassOffset() // function below is exposed to library users. - static unsigned ComputeBaseOffset(const ASTContext &Context, - const CXXRecordDecl *DerivedRD, - const CXXBasePath &Path) { + unsigned ComputeBaseOffset(const ASTContext& Context, + const CXXRecordDecl* DerivedRD, + const CXXBasePath& Path) { CharUnits NonVirtualOffset = CharUnits::Zero(); unsigned NonVirtualStart = 0; @@ -705,7 +707,6 @@ namespace Cpp { return (NonVirtualOffset + VirtualOffset).getQuantity(); } return NonVirtualOffset.getQuantity(); - } int64_t GetBaseClassOffset(TCppScope_t derived, TCppScope_t base) { @@ -1207,13 +1208,11 @@ namespace Cpp { return 0; } - intptr_t GetVariableOffset(TCppScope_t var) - { - if (!var) + intptr_t GetVariableOffsetImpl(compat::Interpreter& I, Decl* D) { + if (!D) return 0; - auto *D = (Decl *) var; - auto &C = getASTContext(); + auto& C = I.getSema().getASTContext(); if (auto* FD = llvm::dyn_cast(D)) { const clang::RecordDecl* RD = FD->getParent(); @@ -1242,7 +1241,7 @@ namespace Cpp { compat::maybeMangleDeclName(GD, mangledName); void* address = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol( mangledName.c_str()); - auto &I = getInterp(); + if (!address) address = I.getAddressOfGlobal(GD); if (!address) { @@ -1292,6 +1291,11 @@ namespace Cpp { return 0; } + intptr_t GetVariableOffset(TCppScope_t var) { + auto* D = static_cast(var); + return GetVariableOffsetImpl(getInterp(), D); + } + // Check if the Access Specifier of the variable matches the provided value. bool CheckVariableAccess(TCppScope_t var, AccessSpecifier AS) { @@ -1453,6 +1457,19 @@ namespace Cpp { } } + QualType GetType(const std::string& name, Sema& sema) { + QualType builtin = findBuiltinType(name, sema.getASTContext()); + if (!builtin.isNull()) + return builtin; + + auto* D = (Decl*)GetNamedImpl(&sema, name, /* Within= */ 0); + if (auto* TD = llvm::dyn_cast_or_null(D)) { + return QualType(TD->getTypeForDecl(), 0); + } + + return QualType(); + } + TCppType_t GetType(const std::string &name) { QualType builtin = findBuiltinType(name, getASTContext()); if (!builtin.isNull()) @@ -2574,26 +2591,31 @@ namespace Cpp { } // namespace // End of JitCall Helper Functions - CPPINTEROP_API JitCall MakeFunctionCallable(TCppConstFunction_t func) { - auto* D = (const clang::Decl*)func; - if (!D) - return {}; + JitCall MakeFunctionCallableImpl(TInterp_t I, TCppConstFunction_t func) { + auto* D = (const clang::Decl*)func; + if (!D) + return {}; - auto& I = getInterp(); - // FIXME: Unify with make_wrapper. - if (auto *Dtor = dyn_cast(D)) { - if (auto Wrapper = make_dtor_wrapper(I, Dtor->getParent())) - return {JitCall::kDestructorCall, Wrapper, Dtor}; + auto* interp = static_cast(I); + + // FIXME: Unify with make_wrapper. + if (const auto* Dtor = dyn_cast(D)) { + if (auto Wrapper = make_dtor_wrapper(*interp, Dtor->getParent())) + return {JitCall::kDestructorCall, Wrapper, Dtor}; + // FIXME: else error we failed to compile the wrapper. + return {}; + } + + if (auto Wrapper = make_wrapper(*interp, cast(D))) { + return {JitCall::kGenericCall, Wrapper, cast(D)}; + } // FIXME: else error we failed to compile the wrapper. return {}; } - if (auto Wrapper = make_wrapper(I, cast(D))) { - return {JitCall::kGenericCall, Wrapper, cast(D)}; + CPPINTEROP_API JitCall MakeFunctionCallable(TCppConstFunction_t func) { + return MakeFunctionCallableImpl(&getInterp(), func); } - // FIXME: else error we failed to compile the wrapper. - return {}; - } namespace { static std::string MakeResourcesPath() { @@ -2842,8 +2864,9 @@ namespace Cpp { return DLM->searchLibrariesForSymbol(mangled_name, search_system); } - bool InsertOrReplaceJitSymbol(const char* linker_mangled_name, - uint64_t address) { + bool InsertOrReplaceJitSymbolImpl(compat::Interpreter& I, + const char* linker_mangled_name, + uint64_t address) { // FIXME: This approach is problematic since we could replace a symbol // whose address was already taken by clients. // @@ -2869,7 +2892,6 @@ namespace Cpp { using namespace llvm; using namespace llvm::orc; - auto& I = getInterp(); auto Symbol = compat::getSymbolAddress(I, linker_mangled_name); llvm::orc::LLJIT& Jit = *compat::getExecutionEngine(I); llvm::orc::ExecutionSession& ES = Jit.getExecutionSession(); @@ -2930,6 +2952,12 @@ namespace Cpp { return false; } + bool InsertOrReplaceJitSymbol(const char* linker_mangled_name, + uint64_t address) { + return InsertOrReplaceJitSymbolImpl(getInterp(), linker_mangled_name, + address); + } + std::string ObjToString(const char *type, void *obj) { return getInterp().toString(type, obj); } @@ -2979,9 +3007,8 @@ namespace Cpp { // return C.getElaboratedType(ETK_None, NS, TT); } - static Decl* InstantiateTemplate(TemplateDecl* TemplateD, - ArrayRef TemplateArgs, - Sema& S) { + Decl* InstantiateTemplate(TemplateDecl* TemplateD, + ArrayRef TemplateArgs, Sema& S) { // Create a list of template arguments. TemplateArgumentListInfo TLI{}; for (auto TA : TemplateArgs) @@ -3241,15 +3268,15 @@ namespace Cpp { } // FIXME: Add optional arguments to the operator new. - TCppObject_t Construct(TCppScope_t scope, - void* arena/*=nullptr*/) { + TCppObject_t ConstructImpl(compat::Interpreter& interp, TCppScope_t scope, + void* arena /*=nullptr*/) { auto* Class = (Decl*) scope; // FIXME: Diagnose. if (!HasDefaultConstructor(Class)) return nullptr; auto* const Ctor = GetDefaultConstructor(Class); - if (JitCall JC = MakeFunctionCallable(Ctor)) { + if (JitCall JC = MakeFunctionCallableImpl(&interp, Ctor)) { if (arena) { JC.Invoke(&arena, {}, (void*)~0); // Tell Invoke to use placement new. return arena; @@ -3262,15 +3289,24 @@ namespace Cpp { return nullptr; } - void Destruct(TCppObject_t This, TCppScope_t scope, bool withFree /*=true*/) { - Decl* Class = (Decl*)scope; - if (auto wrapper = make_dtor_wrapper(getInterp(), Class)) { + TCppObject_t Construct(TCppScope_t scope, void* arena /*=nullptr*/) { + return ConstructImpl(getInterp(), scope, arena); + } + + void DestructImpl(compat::Interpreter& interp, TCppObject_t This, Decl* Class, + bool withFree) { + if (auto wrapper = make_dtor_wrapper(interp, Class)) { (*wrapper)(This, /*nary=*/0, withFree); return; } // FIXME: Diagnose. } + void Destruct(TCppObject_t This, TCppScope_t scope, bool withFree /*=true*/) { + auto* Class = static_cast(scope); + DestructImpl(getInterp(), This, Class, withFree); + } + class StreamCaptureInfo { std::unique_ptr m_TempFile; int m_FD = -1; From 84af69c055ebeaa56451d1b9123246f3b629f39e Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sat, 15 Jun 2024 21:44:16 +0900 Subject: [PATCH 02/23] Fix clang-tidy --- include/clang-c/CXCppInterOp.h | 7 +- lib/Interpreter/CXCppInterOp.cpp | 346 +++++++++++++++---------------- 2 files changed, 170 insertions(+), 183 deletions(-) diff --git a/include/clang-c/CXCppInterOp.h b/include/clang-c/CXCppInterOp.h index 71bdd5f06..a8d87a126 100644 --- a/include/clang-c/CXCppInterOp.h +++ b/include/clang-c/CXCppInterOp.h @@ -325,7 +325,7 @@ CXQualType clang_qualtype_getCanonicalType(CXQualType type); * Used to either get the built-in type of the provided string, or * use the name to lookup the actual type. */ -CXQualType clang_qualtype_getType(const char* name); +CXQualType clang_qualtype_getType(CXInterpreter I, const char* name); /** * Returns the complex of the provided type. @@ -684,11 +684,6 @@ bool clang_scope_isProtectedMethod(CXScope method); */ bool clang_scope_isPrivateMethod(CXScope method); -/** - * Checks if the provided parameter is a 'Private' method. - */ -bool clang_scope_isPrivateMethod(CXScope method); - /** * Checks if the provided parameter is a Constructor. */ diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index a5f18ba35..53e8c06b3 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -30,9 +30,9 @@ CXString makeCXString(const std::string& S) { } CXStringSet* makeCXStringSet(const std::vector& Strs) { - CXStringSet* Set = new CXStringSet; + auto* Set = new CXStringSet; // NOLINT(*-owning-memory) Set->Count = Strs.size(); - Set->Strings = new CXString[Set->Count]; + Set->Strings = new CXString[Set->Count]; // NOLINT(*-owning-memory) for (auto [Idx, Val] : llvm::enumerate(Strs)) { Set->Strings[Idx] = makeCXString(Val); } @@ -50,24 +50,24 @@ static inline compat::Interpreter* getInterpreter(const CXInterpreterImpl* I) { } CXInterpreter clang_createInterpreter(const char* const* argv, int argc) { - auto* I = new CXInterpreterImpl(); + auto* I = new CXInterpreterImpl(); // NOLINT(*-owning-memory) I->Interp = std::make_unique(argc, argv); // reserved for future use return I; } CXInterpreter clang_createInterpreterFromPtr(TInterp_t I) { - auto* II = new CXInterpreterImpl(); - II->Interp.reset(reinterpret_cast(I)); // NOLINT(*-cast) + auto* II = new CXInterpreterImpl(); // NOLINT(*-owning-memory) + II->Interp.reset(static_cast(I)); // NOLINT(*-cast) return II; } TInterp_t clang_interpreter_getInterpreterAsPtr(CXInterpreter I) { - return reinterpret_cast(getInterpreter(I)); // NOLINT(*-cast) + return getInterpreter(I); } void clang_interpreter_dispose(CXInterpreter I) { - delete static_cast(I); // NOLINT(*-owning-memory) + delete I; // NOLINT(*-owning-memory) } void clang_interpreter_addSearchPath(CXInterpreter I, const char* dir, @@ -81,7 +81,7 @@ void clang_interpreter_addIncludePath(CXInterpreter I, const char* dir) { } const char* clang_interpreter_getResourceDir(CXInterpreter I) { - auto* interp = getInterpreter(I); + const auto* interp = getInterpreter(I); return interp->getCI()->getHeaderSearchOpts().ResourceDir.c_str(); } @@ -90,10 +90,10 @@ enum CXErrorCode clang_interpreter_declare(CXInterpreter I, const char* code, auto* interp = getInterpreter(I); auto& diag = interp->getSema().getDiagnostics(); - bool is_silent_old = diag.getSuppressAllDiagnostics(); + const bool is_silent_old = diag.getSuppressAllDiagnostics(); diag.setSuppressAllDiagnostics(silent); - auto result = interp->declare(code); + const auto result = interp->declare(code); diag.setSuppressAllDiagnostics(is_silent_old); if (result) @@ -103,8 +103,7 @@ enum CXErrorCode clang_interpreter_declare(CXInterpreter I, const char* code, } enum CXErrorCode clang_interpreter_process(CXInterpreter I, const char* code) { - auto result = getInterpreter(I)->process(code); - if (result) + if (getInterpreter(I)->process(code)) return CXError_Failure; return CXError_Success; @@ -136,8 +135,7 @@ enum CXErrorCode clang_interpreter_evaluate(CXInterpreter I, const char* code, auto* val = static_cast(V); #endif // USE_CLING - auto result = getInterpreter(I)->evaluate(code, *val); - if (result) + if (getInterpreter(I)->evaluate(code, *val)) return CXError_Failure; return CXError_Success; @@ -199,22 +197,22 @@ clang_interpreter_getFunctionAddressFromMangledName(CXInterpreter I, } static inline CXQualType -makeCXQualType(const CXInterpreterImpl* I, clang::QualType Ty, - CXQualTypeKind K = CXQualType_Unexposed) { +makeCXQualType(const CXInterpreterImpl* I, const clang::QualType Ty, + const CXQualTypeKind K = CXQualType_Unexposed) { assert(I && "Invalid interpreter"); - return CXQualType{K, Ty.getAsOpaquePtr(), reinterpret_cast(I)}; + return CXQualType{K, Ty.getAsOpaquePtr(), static_cast(I)}; } -static inline clang::QualType getType(CXQualType Ty) { +static inline clang::QualType getType(const CXQualType& Ty) { return clang::QualType::getFromOpaquePtr(Ty.data); } -static inline const CXInterpreterImpl* getMeta(CXQualType Ty) { - return reinterpret_cast(Ty.meta); +static inline const CXInterpreterImpl* getMeta(const CXQualType& Ty) { + return static_cast(Ty.meta); } -static inline compat::Interpreter* getInterpreter(CXQualType Ty) { - return getInterpreter(reinterpret_cast(Ty.meta)); +static inline compat::Interpreter* getInterpreter(const CXQualType& Ty) { + return getInterpreter(static_cast(Ty.meta)); } bool clang_qualtype_isBuiltin(CXQualType type) { @@ -234,14 +232,14 @@ bool clang_scope_isRecordType(CXQualType type) { } bool clang_scope_isPODType(CXQualType type) { - clang::QualType QT = getType(type); + const clang::QualType QT = getType(type); if (QT.isNull()) return false; return QT.isPODType(getInterpreter(type)->getSema().getASTContext()); } CXQualType clang_qualtype_getIntegerTypeFromEnumType(CXQualType type) { - void* Ptr = Cpp::GetIntegerTypeFromEnumType(type.data); + const void* Ptr = Cpp::GetIntegerTypeFromEnumType(type.data); return makeCXQualType(getMeta(type), clang::QualType::getFromOpaquePtr(Ptr)); } @@ -264,8 +262,8 @@ CXQualType clang_qualtype_getUnderlyingType(CXQualType type) { } CXString clang_qualtype_getTypeAsString(CXQualType type) { - clang::QualType QT = getType(type); - auto& C = getInterpreter(type)->getSema().getASTContext(); + const clang::QualType QT = getType(type); + const auto& C = getInterpreter(type)->getSema().getASTContext(); clang::PrintingPolicy Policy = C.getPrintingPolicy(); Policy.Bool = true; // Print bool instead of _Bool. Policy.SuppressTagKeyword = true; // Do not print `class std::string`. @@ -273,7 +271,7 @@ CXString clang_qualtype_getTypeAsString(CXQualType type) { } CXQualType clang_qualtype_getCanonicalType(CXQualType type) { - clang::QualType QT = getType(type); + const clang::QualType QT = getType(type); if (QT.isNull()) return makeCXQualType(getMeta(type), clang::QualType(), CXQualType_Invalid); @@ -286,7 +284,7 @@ clang::QualType GetType(const std::string& name, clang::Sema& sema); CXQualType clang_qualtype_getType(CXInterpreter I, const char* name) { auto& S = getInterpreter(I)->getSema(); - clang::QualType QT = Cpp::GetType(std::string(name), S); + const clang::QualType QT = Cpp::GetType(std::string(name), S); if (QT.isNull()) return makeCXQualType(I, QT, CXQualType_Invalid); @@ -294,34 +292,34 @@ CXQualType clang_qualtype_getType(CXInterpreter I, const char* name) { } CXQualType clang_qualtype_getComplexType(CXQualType eltype) { - auto& C = getInterpreter(eltype)->getSema().getASTContext(); + const auto& C = getInterpreter(eltype)->getSema().getASTContext(); return makeCXQualType(getMeta(eltype), C.getComplexType(getType(eltype))); } static inline CXScope makeCXScope(const CXInterpreterImpl* I, clang::Decl* D, CXScopeKind K = CXScope_Unexposed) { assert(I && "Invalid interpreter"); - return CXScope{K, D, reinterpret_cast(I)}; + return CXScope{K, D, static_cast(I)}; } size_t clang_qualtype_getSizeOfType(CXQualType type) { - clang::QualType QT = getType(type); - if (const clang::TagType* TT = QT->getAs()) + const clang::QualType QT = getType(type); + if (const auto* TT = QT->getAs()) return clang_scope_sizeOf(makeCXScope(getMeta(type), TT->getDecl())); // FIXME: Can we get the size of a non-tag type? - auto* I = getInterpreter(type); - auto TI = I->getSema().getASTContext().getTypeInfo(QT); - size_t TypeSize = TI.Width; + const auto* I = getInterpreter(type); + const auto TI = I->getSema().getASTContext().getTypeInfo(QT); + const size_t TypeSize = TI.Width; return TypeSize / 8; } bool clang_qualtype_isTypeDerivedFrom(CXQualType derived, CXQualType base) { auto* I = getInterpreter(derived); - auto& SM = I->getSema().getSourceManager(); - auto fakeLoc = SM.getLocForStartOfFile(SM.getMainFileID()); - auto derivedType = getType(derived); - auto baseType = getType(base); + const auto& SM = I->getSema().getSourceManager(); + const auto fakeLoc = SM.getLocForStartOfFile(SM.getMainFileID()); + const auto derivedType = getType(derived); + const auto baseType = getType(base); #ifdef USE_CLING cling::Interpreter::PushTransactionRAII RAII(I); @@ -329,20 +327,20 @@ bool clang_qualtype_isTypeDerivedFrom(CXQualType derived, CXQualType base) { return I->getSema().IsDerivedFrom(fakeLoc, derivedType, baseType); } -static inline bool isNull(CXScope S) { return !S.data; } +static inline bool isNull(const CXScope& S) { return !S.data; } -static inline clang::Decl* getDecl(CXScope S) { +static inline clang::Decl* getDecl(const CXScope& S) { return static_cast(S.data); } -static inline const CXInterpreterImpl* getMeta(CXScope S) { - return reinterpret_cast(S.meta); +static inline const CXInterpreterImpl* getMeta(const CXScope& S) { + return static_cast(S.meta); } -static inline CXScopeKind kind(CXScope S) { return S.kind; } +static inline CXScopeKind kind(const CXScope& S) { return S.kind; } -static inline compat::Interpreter* getInterpreter(CXScope S) { - return getInterpreter(reinterpret_cast(S.meta)); +static inline compat::Interpreter* getInterpreter(const CXScope& S) { + return getInterpreter(static_cast(S.meta)); } void clang_scope_dump(CXScope S) { getDecl(S)->dump(); } @@ -355,7 +353,7 @@ CXQualType clang_scope_getTypeFromScope(CXScope S) { if (const auto* VD = llvm::dyn_cast(D)) return makeCXQualType(getMeta(S), VD->getType()); - auto& Ctx = getInterpreter(S)->getCI()->getASTContext(); + const auto& Ctx = getInterpreter(S)->getCI()->getASTContext(); return makeCXQualType(getMeta(S), Ctx.getTypeDeclType(llvm::cast(D))); } @@ -376,17 +374,18 @@ bool clang_scope_isComplete(CXScope S) { auto* D = getDecl(S); if (llvm::isa(D)) { - clang::QualType QT = getType(clang_scope_getTypeFromScope(S)); + const clang::QualType QT = getType(clang_scope_getTypeFromScope(S)); const auto* CI = getInterpreter(S)->getCI(); - auto& S = CI->getSema(); - auto& SM = S.getSourceManager(); - clang::SourceLocation fakeLoc = SM.getLocForStartOfFile(SM.getMainFileID()); - return S.isCompleteType(fakeLoc, QT); + auto& Sema = CI->getSema(); + const auto& SM = Sema.getSourceManager(); + const clang::SourceLocation fakeLoc = SM.getLocForStartOfFile(SM.getMainFileID()); + return Sema.isCompleteType(fakeLoc, QT); } - if (auto* CXXRD = llvm::dyn_cast(D)) + if (const auto* CXXRD = llvm::dyn_cast(D)) return CXXRD->hasDefinition(); - else if (auto* TD = llvm::dyn_cast(D)) + + if (const auto* TD = llvm::dyn_cast(D)) return TD->getDefinition(); // Everything else is considered complete. @@ -397,8 +396,8 @@ size_t clang_scope_sizeOf(CXScope S) { if (!clang_scope_isComplete(S)) return 0; - if (auto* RD = llvm::dyn_cast(getDecl(S))) { - clang::ASTContext& Context = RD->getASTContext(); + if (const auto* RD = llvm::dyn_cast(getDecl(S))) { + const clang::ASTContext& Context = RD->getASTContext(); const clang::ASTRecordLayout& Layout = Context.getASTRecordLayout(RD); return Layout.getSize().getQuantity(); } @@ -440,26 +439,25 @@ CXStringSet* clang_scope_getEnums(CXScope S) { } CXQualType clang_scope_getIntegerTypeFromEnumScope(CXScope S) { - auto* ED = llvm::dyn_cast_or_null(getDecl(S)); - if (ED) + if (const auto* ED = llvm::dyn_cast_or_null(getDecl(S))) return makeCXQualType(getMeta(S), ED->getIntegerType()); return makeCXQualType(getMeta(S), clang::QualType(), CXQualType_Invalid); } void clang_disposeScopeSet(CXScopeSet* set) { - delete[] set->Scopes; - delete set; + delete[] set->Scopes; // NOLINT(*-owning-memory) + delete set; // NOLINT(*-owning-memory) } CXScopeSet* clang_scope_getEnumConstants(CXScope S) { - auto* ED = llvm::dyn_cast_or_null(getDecl(S)); + const auto* ED = llvm::dyn_cast_or_null(getDecl(S)); if (!ED || ED->enumerators().empty()) return nullptr; - CXScopeSet* Set = new CXScopeSet; + auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = std::distance(ED->enumerator_begin(), ED->enumerator_end()); - Set->Scopes = new CXScope[Set->Count]; + Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto [Idx, Val] : llvm::enumerate(ED->enumerators())) { Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_EnumConstant); } @@ -471,16 +469,15 @@ CXQualType clang_scope_getEnumConstantType(CXScope S) { if (isNull(S)) return makeCXQualType(getMeta(S), clang::QualType(), CXQualType_Invalid); - auto* ECD = llvm::dyn_cast_or_null(getDecl(S)); - if (ECD) + if (const auto* ECD = + llvm::dyn_cast_or_null(getDecl(S))) return makeCXQualType(getMeta(S), ECD->getType()); return makeCXQualType(getMeta(S), clang::QualType(), CXQualType_Invalid); } size_t clang_scope_getEnumConstantValue(CXScope S) { - auto* ECD = llvm::dyn_cast_or_null(getDecl(S)); - if (ECD) { + if (const auto* ECD = llvm::dyn_cast_or_null(getDecl(S))) { const llvm::APSInt& Val = ECD->getInitVal(); return Val.getExtValue(); } @@ -497,20 +494,20 @@ CXString clang_scope_getName(CXScope S) { if (llvm::isa_and_nonnull(D)) return makeCXString(""); - if (auto* ND = llvm::dyn_cast_or_null(D)) + if (const auto* ND = llvm::dyn_cast_or_null(D)) return makeCXString(ND->getNameAsString()); return makeCXString(""); } CXString clang_scope_getCompleteName(CXScope S) { - auto& C = getInterpreter(S)->getSema().getASTContext(); + const auto& C = getInterpreter(S)->getSema().getASTContext(); auto* D = getDecl(S); if (auto* ND = llvm::dyn_cast_or_null(D)) { - if (auto* TD = llvm::dyn_cast(ND)) { + if (const auto* TD = llvm::dyn_cast(ND)) { std::string type_name; - clang::QualType QT = C.getTagDeclType(TD); + const clang::QualType QT = C.getTagDeclType(TD); clang::PrintingPolicy Policy = C.getPrintingPolicy(); Policy.SuppressUnwrittenScope = true; Policy.SuppressScope = true; @@ -531,7 +528,7 @@ CXString clang_scope_getCompleteName(CXScope S) { CXString clang_scope_getQualifiedName(CXScope S) { auto* D = getDecl(S); - if (auto* ND = llvm::dyn_cast_or_null(D)) + if (const auto* ND = llvm::dyn_cast_or_null(D)) return makeCXString(ND->getQualifiedNameAsString()); if (llvm::isa_and_nonnull(D)) @@ -541,13 +538,13 @@ CXString clang_scope_getQualifiedName(CXScope S) { } CXString clang_scope_getQualifiedCompleteName(CXScope S) { - auto& C = getInterpreter(S)->getSema().getASTContext(); + const auto& C = getInterpreter(S)->getSema().getASTContext(); auto* D = getDecl(S); if (auto* ND = llvm::dyn_cast_or_null(D)) { - if (auto* TD = llvm::dyn_cast(ND)) { + if (const auto* TD = llvm::dyn_cast(ND)) { std::string type_name; - clang::QualType QT = C.getTagDeclType(TD); + const clang::QualType QT = C.getTagDeclType(TD); QT.getAsStringInternal(type_name, C.getPrintingPolicy()); return makeCXString(type_name); @@ -564,14 +561,14 @@ CXString clang_scope_getQualifiedCompleteName(CXScope S) { } CXScopeSet* clang_scope_getUsingNamespaces(CXScope S) { - auto* DC = llvm::dyn_cast_or_null(getDecl(S)); + const auto* DC = llvm::dyn_cast_or_null(getDecl(S)); if (!DC || DC->using_directives().empty()) return nullptr; - CXScopeSet* Set = new CXScopeSet; + auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = std::distance(DC->using_directives().begin(), DC->using_directives().end()); - Set->Scopes = new CXScope[Set->Count]; + Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto [Idx, Val] : llvm::enumerate(DC->using_directives())) { Set->Scopes[Idx] = makeCXScope(getMeta(S), Val->getNominatedNamespace(), CXScope_Namespace); @@ -581,18 +578,18 @@ CXScopeSet* clang_scope_getUsingNamespaces(CXScope S) { } CXScope clang_scope_getGlobalScope(CXInterpreter I) { - auto& C = getInterpreter(I)->getSema().getASTContext(); + const auto& C = getInterpreter(I)->getSema().getASTContext(); auto* DC = C.getTranslationUnitDecl(); return makeCXScope(I, DC, CXScope_Global); } CXScope clang_scope_getUnderlyingScope(CXScope S) { - auto* TND = llvm::dyn_cast_or_null(getDecl(S)); + const auto* TND = llvm::dyn_cast_or_null(getDecl(S)); if (!TND) return makeCXScope(getMeta(S), nullptr, CXScope_Invalid); - clang::QualType QT = TND->getUnderlyingType(); - auto D = Cpp::GetScopeFromType(QT.getAsOpaquePtr()); + const clang::QualType QT = TND->getUnderlyingType(); + auto* D = Cpp::GetScopeFromType(QT.getAsOpaquePtr()); if (!D) return makeCXScope(getMeta(S), nullptr, CXScope_Invalid); @@ -600,12 +597,12 @@ CXScope clang_scope_getUnderlyingScope(CXScope S) { } CXScope clang_scope_getScope(const char* name, CXScope parent) { - auto S = clang_scope_getNamed(name, parent); + const auto S = clang_scope_getNamed(name, parent); if (kind(S) == CXScope_Invalid) return S; - clang::NamedDecl* ND = llvm::dyn_cast(getDecl(S)); - if (llvm::isa(ND) || llvm::isa(ND) || + if (auto* ND = llvm::dyn_cast(getDecl(S)); + llvm::isa(ND) || llvm::isa(ND) || llvm::isa(ND) || llvm::isa(ND)) { return makeCXScope(getMeta(S), ND->getCanonicalDecl()); @@ -615,16 +612,17 @@ CXScope clang_scope_getScope(const char* name, CXScope parent) { } CXScope clang_scope_getNamed(const char* name, CXScope parent) { - clang::DeclContext* Within = 0; + const clang::DeclContext* Within = nullptr; if (kind(parent) != CXScope_Invalid) { - auto US = clang_scope_getUnderlyingScope(parent); - if (kind(US) != CXScope_Invalid) + if (const auto US = clang_scope_getUnderlyingScope(parent); + kind(US) != CXScope_Invalid) Within = llvm::dyn_cast(getDecl(US)); } auto& sema = getInterpreter(parent)->getSema(); - auto* ND = Cpp::Cpp_utils::Lookup::Named(&sema, std::string(name), Within); - if (ND && ND != (clang::NamedDecl*)-1) { + if (auto* ND = + Cpp::Cpp_utils::Lookup::Named(&sema, std::string(name), Within); + ND && intptr_t(ND) != (intptr_t)-1) { return makeCXScope(getMeta(parent), ND->getCanonicalDecl()); } @@ -637,8 +635,7 @@ CXScope clang_scope_getParentScope(CXScope parent) { if (llvm::isa_and_nonnull(D)) return makeCXScope(getMeta(parent), nullptr, CXScope_Invalid); - auto* ParentDC = D->getDeclContext(); - + const auto* ParentDC = D->getDeclContext(); if (!ParentDC) return makeCXScope(getMeta(parent), nullptr, CXScope_Invalid); @@ -655,7 +652,7 @@ CXScope clang_scope_getScopeFromType(CXQualType type) { size_t clang_scope_getNumBases(CXScope S) { auto* D = getDecl(S); - if (auto* CXXRD = llvm::dyn_cast_or_null(D)) { + if (const auto* CXXRD = llvm::dyn_cast_or_null(D)) { if (CXXRD->hasDefinition()) return CXXRD->getNumBases(); } @@ -669,8 +666,8 @@ CXScope clang_scope_getBaseClass(CXScope S, size_t ibase) { if (!CXXRD || CXXRD->getNumBases() <= ibase) return makeCXScope(getMeta(S), nullptr, CXScope_Invalid); - auto type = (CXXRD->bases_begin() + ibase)->getType(); - if (auto RT = type->getAs()) + const auto type = (CXXRD->bases_begin() + ibase)->getType(); + if (const auto* RT = type->getAs()) return makeCXScope(getMeta(S), RT->getDecl()); return makeCXScope(getMeta(S), nullptr, CXScope_Invalid); @@ -713,13 +710,13 @@ int64_t clang_scope_getBaseClassOffset(CXScope derived, CXScope base) { !llvm::isa(B)) return -1; - auto* DCXXRD = llvm::cast(D); - auto* BCXXRD = llvm::cast(B); + const auto* DCXXRD = llvm::cast(D); + const auto* BCXXRD = llvm::cast(B); clang::CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, /*DetectVirtual=*/false); DCXXRD->isDerivedFrom(BCXXRD, Paths); - auto* I = getInterpreter(derived); + const auto* I = getInterpreter(derived); return Cpp::ComputeBaseOffset(I->getSema().getASTContext(), DCXXRD, Paths.front()); } @@ -728,7 +725,7 @@ CXScopeSet* clang_scope_getClassMethods(CXScope S) { if (kind(S) == CXScope_Invalid) return nullptr; - auto US = clang_scope_getUnderlyingScope(S); + const auto US = clang_scope_getUnderlyingScope(S); if (kind(US) == CXScope_Invalid || !clang_scope_isClass(US)) return nullptr; @@ -744,15 +741,15 @@ CXScopeSet* clang_scope_getClassMethods(CXScope S) { if (auto* MD = llvm::dyn_cast(DI)) { Methods.push_back(MD); } else if (auto* USD = llvm::dyn_cast(DI)) { - auto* MD = llvm::dyn_cast(USD->getTargetDecl()); - if (MD) - Methods.push_back(MD); + if (auto* TMD = + llvm::dyn_cast(USD->getTargetDecl())) + Methods.push_back(TMD); } } - CXScopeSet* Set = new CXScopeSet; + auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = Methods.size(); - Set->Scopes = new CXScope[Set->Count]; + Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto [Idx, Val] : llvm::enumerate(Methods)) { Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); } @@ -764,7 +761,7 @@ CXScopeSet* clang_scope_getFunctionTemplatedDecls(CXScope S) { if (kind(S) == CXScope_Invalid) return nullptr; - auto US = clang_scope_getUnderlyingScope(S); + const auto US = clang_scope_getUnderlyingScope(S); if (kind(US) == CXScope_Invalid || !clang_scope_isClass(US)) return nullptr; @@ -779,17 +776,16 @@ CXScopeSet* clang_scope_getFunctionTemplatedDecls(CXScope S) { for (clang::Decl* DI : CXXRD->decls()) { if (auto* MD = llvm::dyn_cast(DI)) { Methods.push_back(MD); - } else if (auto* USD = llvm::dyn_cast(DI)) { - auto* MD = - llvm::dyn_cast(USD->getTargetDecl()); - if (MD) - Methods.push_back(MD); + } else if (const auto* USD = llvm::dyn_cast(DI)) { + if (auto* TMD = + llvm::dyn_cast(USD->getTargetDecl())) + Methods.push_back(TMD); } } - CXScopeSet* Set = new CXScopeSet; + auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = Methods.size(); - Set->Scopes = new CXScope[Set->Count]; + Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto [Idx, Val] : llvm::enumerate(Methods)) { Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); } @@ -800,7 +796,7 @@ CXScopeSet* clang_scope_getFunctionTemplatedDecls(CXScope S) { bool clang_scope_hasDefaultConstructor(CXScope S) { auto* D = getDecl(S); - if (auto* CXXRD = llvm::dyn_cast_or_null(D)) + if (const auto* CXXRD = llvm::dyn_cast_or_null(D)) return CXXRD->hasDefaultConstructor(); return false; @@ -830,15 +826,15 @@ CXScope clang_scope_getDestructor(CXScope S) { } CXScopeSet* clang_scope_getFunctionsUsingName(CXScope S, const char* name) { - auto* D = getDecl(clang_scope_getUnderlyingScope(S)); + const auto* D = getDecl(clang_scope_getUnderlyingScope(S)); if (!D || !name) return nullptr; - llvm::StringRef Name(name); - auto* I = getInterpreter(S); + const llvm::StringRef Name(name); + const auto* I = getInterpreter(S); auto& SM = I->getSema(); - clang::DeclarationName DName = &SM.getASTContext().Idents.get(name); + const clang::DeclarationName DName = &SM.getASTContext().Idents.get(Name); clang::LookupResult R(SM, DName, clang::SourceLocation(), clang::Sema::LookupOrdinaryName, clang::Sema::ForVisibleRedeclaration); @@ -855,9 +851,9 @@ CXScopeSet* clang_scope_getFunctionsUsingName(CXScope S, const char* name) { if (llvm::isa(Found)) Funcs.push_back(Found); - CXScopeSet* Set = new CXScopeSet; + auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = Funcs.size(); - Set->Scopes = new CXScope[Set->Count]; + Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto [Idx, Val] : llvm::enumerate(Funcs)) { Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); } @@ -867,11 +863,11 @@ CXScopeSet* clang_scope_getFunctionsUsingName(CXScope S, const char* name) { CXQualType clang_scope_getFunctionReturnType(CXScope func) { auto* D = getDecl(func); - if (auto* FD = llvm::dyn_cast_or_null(D)) + if (const auto* FD = llvm::dyn_cast_or_null(D)) return makeCXQualType(getMeta(func), FD->getReturnType()); - if (auto* FD = llvm::dyn_cast_or_null(D)) { - auto* FTD = FD->getTemplatedDecl(); + if (const auto* FD = llvm::dyn_cast_or_null(D)) { + const auto* FTD = FD->getTemplatedDecl(); return makeCXQualType(getMeta(func), FTD->getReturnType()); } @@ -880,10 +876,10 @@ CXQualType clang_scope_getFunctionReturnType(CXScope func) { size_t clang_scope_getFunctionNumArgs(CXScope func) { auto* D = getDecl(func); - if (auto* FD = llvm::dyn_cast_or_null(D)) + if (const auto* FD = llvm::dyn_cast_or_null(D)) return FD->getNumParams(); - if (auto* FD = llvm::dyn_cast_or_null(D)) + if (const auto* FD = llvm::dyn_cast_or_null(D)) return FD->getTemplatedDecl()->getNumParams(); return 0; @@ -891,10 +887,10 @@ size_t clang_scope_getFunctionNumArgs(CXScope func) { size_t clang_scope_getFunctionRequiredArgs(CXScope func) { auto* D = getDecl(func); - if (auto* FD = llvm::dyn_cast_or_null(D)) + if (const auto* FD = llvm::dyn_cast_or_null(D)) return FD->getMinRequiredArguments(); - if (auto* FD = llvm::dyn_cast_or_null(D)) + if (const auto* FD = llvm::dyn_cast_or_null(D)) return FD->getTemplatedDecl()->getMinRequiredArguments(); return 0; @@ -905,7 +901,7 @@ CXQualType clang_scope_getFunctionArgType(CXScope func, size_t iarg) { if (auto* FD = llvm::dyn_cast_or_null(D)) { if (iarg < FD->getNumParams()) { - auto* PVD = FD->getParamDecl(iarg); + const auto* PVD = FD->getParamDecl(iarg); return makeCXQualType(getMeta(func), PVD->getOriginalType()); } } @@ -918,10 +914,10 @@ CXString clang_scope_getFunctionSignature(CXScope func) { return makeCXString(""); auto* D = getDecl(func); - if (auto* FD = llvm::dyn_cast(D)) { + if (const auto* FD = llvm::dyn_cast(D)) { std::string Signature; llvm::raw_string_ostream SS(Signature); - auto& C = getInterpreter(func)->getSema().getASTContext(); + const auto& C = getInterpreter(func)->getSema().getASTContext(); clang::PrintingPolicy Policy = C.getPrintingPolicy(); // Skip printing the body Policy.TerseOutput = true; @@ -936,7 +932,7 @@ CXString clang_scope_getFunctionSignature(CXScope func) { } bool clang_scope_isFunctionDeleted(CXScope func) { - auto* FD = llvm::cast(getDecl(func)); + const auto* FD = llvm::cast(getDecl(func)); return FD->isDeleted(); } @@ -945,8 +941,8 @@ bool clang_scope_isTemplatedFunction(CXScope func) { if (llvm::isa_and_nonnull(D)) return true; - if (auto* FD = llvm::dyn_cast_or_null(D)) { - auto TK = FD->getTemplatedKind(); + if (const auto* FD = llvm::dyn_cast_or_null(D)) { + const auto TK = FD->getTemplatedKind(); return TK == clang::FunctionDecl::TemplatedKind:: TK_FunctionTemplateSpecialization || TK == clang::FunctionDecl::TemplatedKind:: @@ -961,15 +957,15 @@ bool clang_scope_existsFunctionTemplate(const char* name, CXScope parent) { if (kind(parent) == CXScope_Invalid || !name) return false; - auto* Within = llvm::dyn_cast(getDecl(parent)); + const auto* Within = llvm::dyn_cast(getDecl(parent)); auto& S = getInterpreter(parent)->getSema(); auto* ND = Cpp::Cpp_utils::Lookup::Named(&S, name, Within); - if ((intptr_t)ND == (intptr_t)0) + if (!ND) return false; - if ((intptr_t)ND != (intptr_t)-1) + if (intptr_t(ND) != (intptr_t)-1) return clang_scope_isTemplatedFunction(makeCXScope(getMeta(parent), ND)); // FIXME: Cycle through the Decls and check if there is a templated function @@ -978,15 +974,15 @@ bool clang_scope_existsFunctionTemplate(const char* name, CXScope parent) { CXScopeSet* clang_scope_getClassTemplatedMethods(const char* name, CXScope parent) { - auto* D = getDecl(clang_scope_getUnderlyingScope(parent)); + const auto* D = getDecl(clang_scope_getUnderlyingScope(parent)); if (!D || !name) return nullptr; - llvm::StringRef Name(name); - auto* I = getInterpreter(parent); + const llvm::StringRef Name(name); + const auto* I = getInterpreter(parent); auto& SM = I->getSema(); - clang::DeclarationName DName = &SM.getASTContext().Idents.get(name); + const clang::DeclarationName DName = &SM.getASTContext().Idents.get(Name); clang::LookupResult R(SM, DName, clang::SourceLocation(), clang::Sema::LookupOrdinaryName, clang::Sema::ForVisibleRedeclaration); @@ -1003,9 +999,9 @@ CXScopeSet* clang_scope_getClassTemplatedMethods(const char* name, if (llvm::isa(Found)) Funcs.push_back(Found); - CXScopeSet* Set = new CXScopeSet; + auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = Funcs.size(); - Set->Scopes = new CXScope[Set->Count]; + Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto [Idx, Val] : llvm::enumerate(Funcs)) { Set->Scopes[Idx] = makeCXScope(getMeta(parent), Val, CXScope_Function); } @@ -1020,7 +1016,7 @@ bool clang_scope_isMethod(CXScope method) { bool clang_scope_isPublicMethod(CXScope method) { auto* D = getDecl(method); - if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + if (const auto* CXXMD = llvm::dyn_cast_or_null(D)) return CXXMD->getAccess() == clang::AccessSpecifier::AS_public; return false; @@ -1028,7 +1024,7 @@ bool clang_scope_isPublicMethod(CXScope method) { bool clang_scope_isProtectedMethod(CXScope method) { auto* D = getDecl(method); - if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + if (const auto* CXXMD = llvm::dyn_cast_or_null(D)) return CXXMD->getAccess() == clang::AccessSpecifier::AS_protected; return false; @@ -1036,7 +1032,7 @@ bool clang_scope_isProtectedMethod(CXScope method) { bool clang_scope_isPrivateMethod(CXScope method) { auto* D = getDecl(method); - if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + if (const auto* CXXMD = llvm::dyn_cast_or_null(D)) return CXXMD->getAccess() == clang::AccessSpecifier::AS_private; return false; @@ -1054,7 +1050,7 @@ bool clang_scope_isDestructor(CXScope method) { bool clang_scope_isStaticMethod(CXScope method) { auto* D = getDecl(method); - if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + if (const auto* CXXMD = llvm::dyn_cast_or_null(D)) return CXXMD->isStatic(); return false; @@ -1065,7 +1061,7 @@ CXFuncAddr clang_scope_getFunctionAddress(CXScope method) { auto* I = getInterpreter(method); const auto get_mangled_name = [I](clang::FunctionDecl* FD) { - auto MangleCtx = I->getSema().getASTContext().createMangleContext(); + auto* MangleCtx = I->getSema().getASTContext().createMangleContext(); if (!MangleCtx->shouldMangleDeclName(FD)) { return FD->getNameInfo().getName().getAsString(); @@ -1077,13 +1073,13 @@ CXFuncAddr clang_scope_getFunctionAddress(CXScope method) { MangleCtx->mangleName(FD, ostream); ostream.flush(); - delete MangleCtx; + delete MangleCtx; // NOLINT(*-owning-memory) return mangled_name; }; if (auto* FD = llvm::dyn_cast_or_null(D)) { - auto FDAorErr = compat::getSymbolAddress(*I, get_mangled_name(FD).c_str()); + auto FDAorErr = compat::getSymbolAddress(*I, get_mangled_name(FD)); if (llvm::Error Err = FDAorErr.takeError()) llvm::consumeError(std::move(Err)); // nullptr if missing else @@ -1095,7 +1091,7 @@ CXFuncAddr clang_scope_getFunctionAddress(CXScope method) { bool clang_scope_isVirtualMethod(CXScope method) { auto* D = getDecl(method); - if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + if (const auto* CXXMD = llvm::dyn_cast_or_null(D)) return CXXMD->isVirtual(); return false; @@ -1103,7 +1099,7 @@ bool clang_scope_isVirtualMethod(CXScope method) { bool clang_scope_isConstMethod(CXScope method) { auto* D = getDecl(method); - if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + if (const auto* CXXMD = llvm::dyn_cast_or_null(D)) return CXXMD->getMethodQualifiers().hasConst(); return false; @@ -1118,13 +1114,13 @@ CXString clang_scope_getFunctionArgName(CXScope func, size_t param_index) { } CXScopeSet* clang_scope_getDatamembers(CXScope S) { - auto* CXXRD = llvm::dyn_cast_or_null(getDecl(S)); + const auto* CXXRD = llvm::dyn_cast_or_null(getDecl(S)); if (!CXXRD) return nullptr; - CXScopeSet* Set = new CXScopeSet; + auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = std::distance(CXXRD->field_begin(), CXXRD->field_end()); - Set->Scopes = new CXScope[Set->Count]; + Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto [Idx, Val] : llvm::enumerate(CXXRD->fields())) { Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); } @@ -1136,12 +1132,11 @@ CXScope clang_scope_lookupDatamember(const char* name, CXScope parent) { if (kind(parent) == CXScope_Invalid || !name) return makeCXScope(getMeta(parent), nullptr, CXScope_Invalid); - clang::DeclContext* Within = - llvm::dyn_cast(getDecl(parent)); + const auto* Within = llvm::dyn_cast(getDecl(parent)); auto& S = getInterpreter(parent)->getSema(); auto* ND = Cpp::Cpp_utils::Lookup::Named(&S, name, Within); - if (ND && ND != (clang::NamedDecl*)-1) { + if (ND && intptr_t(ND) != (intptr_t)-1) { if (llvm::isa_and_nonnull(ND)) { return makeCXScope(getMeta(parent), ND, CXScope_Field); } @@ -1167,7 +1162,7 @@ CXScope clang_scope_instantiateTemplate(CXScope tmpl, llvm::SmallVector TemplateArgs; TemplateArgs.reserve(template_args_size); for (size_t i = 0; i < template_args_size; ++i) { - clang::QualType ArgTy = + const clang::QualType ArgTy = clang::QualType::getFromOpaquePtr(template_args[i].Type); if (template_args[i].IntegralValue) { // We have a non-type template parameter. Create an integral value from @@ -1180,7 +1175,7 @@ CXScope clang_scope_instantiateTemplate(CXScope tmpl, } } - clang::TemplateDecl* TmplD = static_cast(getDecl(tmpl)); + auto* TmplD = llvm::dyn_cast(getDecl(tmpl)); // We will create a new decl, push a transaction. #ifdef USE_CLING @@ -1191,9 +1186,9 @@ CXScope clang_scope_instantiateTemplate(CXScope tmpl, } CXQualType clang_scope_getVariableType(CXScope var) { - auto D = getDecl(var); + auto* D = getDecl(var); - if (auto DD = llvm::dyn_cast_or_null(D)) + if (const auto* DD = llvm::dyn_cast_or_null(D)) return makeCXQualType(getMeta(var), DD->getType()); return makeCXQualType(getMeta(var), clang::QualType(), CXQualType_Invalid); @@ -1209,7 +1204,7 @@ intptr_t clang_scope_getVariableOffset(CXScope var) { bool clang_scope_isPublicVariable(CXScope var) { auto* D = getDecl(var); - if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + if (const auto* CXXMD = llvm::dyn_cast_or_null(D)) return CXXMD->getAccess() == clang::AccessSpecifier::AS_public; return false; @@ -1217,7 +1212,7 @@ bool clang_scope_isPublicVariable(CXScope var) { bool clang_scope_isProtectedVariable(CXScope var) { auto* D = getDecl(var); - if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + if (const auto* CXXMD = llvm::dyn_cast_or_null(D)) return CXXMD->getAccess() == clang::AccessSpecifier::AS_protected; return false; @@ -1225,7 +1220,7 @@ bool clang_scope_isProtectedVariable(CXScope var) { bool clang_scope_isPrivateVariable(CXScope var) { auto* D = getDecl(var); - if (auto* CXXMD = llvm::dyn_cast_or_null(D)) + if (const auto* CXXMD = llvm::dyn_cast_or_null(D)) return CXXMD->getAccess() == clang::AccessSpecifier::AS_private; return false; @@ -1233,15 +1228,12 @@ bool clang_scope_isPrivateVariable(CXScope var) { bool clang_scope_isStaticVariable(CXScope var) { auto* D = getDecl(var); - if (llvm::isa_and_nonnull(D)) - return true; - - return false; + return llvm::isa_and_nonnull(D); } bool clang_scope_isConstVariable(CXScope var) { auto* D = getDecl(var); - if (auto* VD = llvm::dyn_cast_or_null(D)) { + if (const auto* VD = llvm::dyn_cast_or_null(D)) { return VD->getType().isConstQualified(); } @@ -1262,19 +1254,19 @@ CXObject clang_construct(CXScope scope, void* arena) { if (!clang_scope_hasDefaultConstructor(scope)) return nullptr; - auto Ctor = clang_scope_getDefaultConstructor(scope); + const auto Ctor = clang_scope_getDefaultConstructor(scope); if (kind(Ctor) == CXScope_Invalid) return nullptr; auto* I = getInterpreter(scope); - if (Cpp::JitCall JC = Cpp::MakeFunctionCallableImpl(I, getDecl(Ctor))) { + if (const Cpp::JitCall JC = Cpp::MakeFunctionCallableImpl(I, getDecl(Ctor))) { if (arena) { - JC.Invoke(&arena, {}, (void*)~0); // Tell Invoke to use placement new. + JC.Invoke(arena, {}, (void*)~0); // Tell Invoke to use placement new. return arena; } void* obj = nullptr; - JC.Invoke(&obj); + JC.Invoke(obj); return obj; } @@ -1291,7 +1283,7 @@ void clang_destruct(CXObject This, CXScope S, bool withFree) { } CXJitCallKind clang_jitcall_getKind(CXJitCall J) { - auto* call = reinterpret_cast(J); // NOLINT(*-cast) + const auto* call = reinterpret_cast(J); // NOLINT(*-cast) return static_cast(call->getKind()); } @@ -1301,14 +1293,14 @@ bool clang_jitcall_isValid(CXJitCall J) { void clang_jitcall_invoke(CXJitCall J, void* result, CXJitCallArgList args, void* self) { - auto* call = reinterpret_cast(J); // NOLINT(*-cast) - return call->Invoke(result, {args.data, args.numArgs}, self); + const auto* call = reinterpret_cast(J); // NOLINT(*-cast) + call->Invoke(result, {args.data, args.numArgs}, self); } CXJitCall clang_jitcall_makeFunctionCallable(CXScope func) { auto J = Cpp::MakeFunctionCallableImpl(getInterpreter(func), getDecl(func)); - return reinterpret_cast( - std::make_unique(J).release()); // NOLINT(*-cast) + auto Ptr = std::make_unique(J); + return reinterpret_cast(Ptr.release()); // NOLINT(*-cast) } void clang_jitcall_dispose(CXJitCall J) { From c8af900c3e9c1e15849c4996c71ee289635adaed Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sat, 15 Jun 2024 21:50:52 +0900 Subject: [PATCH 03/23] Remove structured bindings --- lib/Interpreter/CXCppInterOp.cpp | 43 +++++++++++++++++++------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index 53e8c06b3..a0429ada3 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -33,8 +33,8 @@ CXStringSet* makeCXStringSet(const std::vector& Strs) { auto* Set = new CXStringSet; // NOLINT(*-owning-memory) Set->Count = Strs.size(); Set->Strings = new CXString[Set->Count]; // NOLINT(*-owning-memory) - for (auto [Idx, Val] : llvm::enumerate(Strs)) { - Set->Strings[Idx] = makeCXString(Val); + for (auto En : llvm::enumerate(Strs)) { + Set->Strings[En.index()] = makeCXString(En.value()); } return Set; } @@ -458,8 +458,9 @@ CXScopeSet* clang_scope_getEnumConstants(CXScope S) { auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = std::distance(ED->enumerator_begin(), ED->enumerator_end()); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) - for (auto [Idx, Val] : llvm::enumerate(ED->enumerators())) { - Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_EnumConstant); + for (auto En : llvm::enumerate(ED->enumerators())) { + Set->Scopes[En.index()] = + makeCXScope(getMeta(S), En.value(), CXScope_EnumConstant); } return Set; @@ -477,7 +478,8 @@ CXQualType clang_scope_getEnumConstantType(CXScope S) { } size_t clang_scope_getEnumConstantValue(CXScope S) { - if (const auto* ECD = llvm::dyn_cast_or_null(getDecl(S))) { + if (const auto* ECD = + llvm::dyn_cast_or_null(getDecl(S))) { const llvm::APSInt& Val = ECD->getInitVal(); return Val.getExtValue(); } @@ -569,9 +571,9 @@ CXScopeSet* clang_scope_getUsingNamespaces(CXScope S) { Set->Count = std::distance(DC->using_directives().begin(), DC->using_directives().end()); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) - for (auto [Idx, Val] : llvm::enumerate(DC->using_directives())) { - Set->Scopes[Idx] = makeCXScope(getMeta(S), Val->getNominatedNamespace(), - CXScope_Namespace); + for (auto En : llvm::enumerate(DC->using_directives())) { + Set->Scopes[En.index()] = makeCXScope( + getMeta(S), En.value()->getNominatedNamespace(), CXScope_Namespace); } return Set; @@ -750,8 +752,9 @@ CXScopeSet* clang_scope_getClassMethods(CXScope S) { auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = Methods.size(); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) - for (auto [Idx, Val] : llvm::enumerate(Methods)) { - Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); + for (auto En : llvm::enumerate(Methods)) { + Set->Scopes[En.index()] = + makeCXScope(getMeta(S), En.value(), CXScope_Function); } return Set; @@ -786,8 +789,9 @@ CXScopeSet* clang_scope_getFunctionTemplatedDecls(CXScope S) { auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = Methods.size(); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) - for (auto [Idx, Val] : llvm::enumerate(Methods)) { - Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); + for (auto En : llvm::enumerate(Methods)) { + Set->Scopes[En.index()] = + makeCXScope(getMeta(S), En.value(), CXScope_Function); } return Set; @@ -854,8 +858,9 @@ CXScopeSet* clang_scope_getFunctionsUsingName(CXScope S, const char* name) { auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = Funcs.size(); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) - for (auto [Idx, Val] : llvm::enumerate(Funcs)) { - Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); + for (auto En : llvm::enumerate(Funcs)) { + Set->Scopes[En.index()] = + makeCXScope(getMeta(S), En.value(), CXScope_Function); } return Set; @@ -1002,8 +1007,9 @@ CXScopeSet* clang_scope_getClassTemplatedMethods(const char* name, auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = Funcs.size(); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) - for (auto [Idx, Val] : llvm::enumerate(Funcs)) { - Set->Scopes[Idx] = makeCXScope(getMeta(parent), Val, CXScope_Function); + for (auto En : llvm::enumerate(Funcs)) { + Set->Scopes[En.index()] = + makeCXScope(getMeta(parent), En.value(), CXScope_Function); } return Set; @@ -1121,8 +1127,9 @@ CXScopeSet* clang_scope_getDatamembers(CXScope S) { auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = std::distance(CXXRD->field_begin(), CXXRD->field_end()); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) - for (auto [Idx, Val] : llvm::enumerate(CXXRD->fields())) { - Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); + for (auto En : llvm::enumerate(CXXRD->fields())) { + Set->Scopes[En.index()] = + makeCXScope(getMeta(S), En.value(), CXScope_Function); } return Set; From eab6eb687f649ef72724eb213988ee8bc53582ea Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sun, 16 Jun 2024 00:26:16 +0900 Subject: [PATCH 04/23] Remove init-statement in selection statements --- lib/Interpreter/CXCppInterOp.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index a0429ada3..7df6da4bb 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -378,7 +378,8 @@ bool clang_scope_isComplete(CXScope S) { const auto* CI = getInterpreter(S)->getCI(); auto& Sema = CI->getSema(); const auto& SM = Sema.getSourceManager(); - const clang::SourceLocation fakeLoc = SM.getLocForStartOfFile(SM.getMainFileID()); + const clang::SourceLocation fakeLoc = + SM.getLocForStartOfFile(SM.getMainFileID()); return Sema.isCompleteType(fakeLoc, QT); } @@ -603,8 +604,8 @@ CXScope clang_scope_getScope(const char* name, CXScope parent) { if (kind(S) == CXScope_Invalid) return S; - if (auto* ND = llvm::dyn_cast(getDecl(S)); - llvm::isa(ND) || llvm::isa(ND) || + auto* ND = llvm::dyn_cast(getDecl(S)); + if (llvm::isa(ND) || llvm::isa(ND) || llvm::isa(ND) || llvm::isa(ND)) { return makeCXScope(getMeta(S), ND->getCanonicalDecl()); @@ -616,15 +617,14 @@ CXScope clang_scope_getScope(const char* name, CXScope parent) { CXScope clang_scope_getNamed(const char* name, CXScope parent) { const clang::DeclContext* Within = nullptr; if (kind(parent) != CXScope_Invalid) { - if (const auto US = clang_scope_getUnderlyingScope(parent); - kind(US) != CXScope_Invalid) + const auto US = clang_scope_getUnderlyingScope(parent); + if (kind(US) != CXScope_Invalid) Within = llvm::dyn_cast(getDecl(US)); } auto& sema = getInterpreter(parent)->getSema(); - if (auto* ND = - Cpp::Cpp_utils::Lookup::Named(&sema, std::string(name), Within); - ND && intptr_t(ND) != (intptr_t)-1) { + auto* ND = Cpp::Cpp_utils::Lookup::Named(&sema, std::string(name), Within); + if (ND && intptr_t(ND) != (intptr_t)-1) { return makeCXScope(getMeta(parent), ND->getCanonicalDecl()); } From 7908b5d9bc405a6d1f2a810887475b2e751d029c Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sun, 16 Jun 2024 00:48:53 +0900 Subject: [PATCH 05/23] fix-up --- lib/Interpreter/CXCppInterOp.cpp | 36 +++++++++++++++++++------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index 7df6da4bb..b154fac29 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -460,8 +460,9 @@ CXScopeSet* clang_scope_getEnumConstants(CXScope S) { Set->Count = std::distance(ED->enumerator_begin(), ED->enumerator_end()); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(ED->enumerators())) { - Set->Scopes[En.index()] = - makeCXScope(getMeta(S), En.value(), CXScope_EnumConstant); + auto Idx = En.index(); + auto Val = En.value(); + Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_EnumConstant); } return Set; @@ -573,8 +574,10 @@ CXScopeSet* clang_scope_getUsingNamespaces(CXScope S) { DC->using_directives().end()); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(DC->using_directives())) { - Set->Scopes[En.index()] = makeCXScope( - getMeta(S), En.value()->getNominatedNamespace(), CXScope_Namespace); + auto Idx = En.index(); + auto Val = En.value(); + Set->Scopes[Idx] = makeCXScope(getMeta(S), Val->getNominatedNamespace(), + CXScope_Namespace); } return Set; @@ -753,8 +756,9 @@ CXScopeSet* clang_scope_getClassMethods(CXScope S) { Set->Count = Methods.size(); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(Methods)) { - Set->Scopes[En.index()] = - makeCXScope(getMeta(S), En.value(), CXScope_Function); + auto Idx = En.index(); + auto Val = En.value(); + Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); } return Set; @@ -790,8 +794,9 @@ CXScopeSet* clang_scope_getFunctionTemplatedDecls(CXScope S) { Set->Count = Methods.size(); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(Methods)) { - Set->Scopes[En.index()] = - makeCXScope(getMeta(S), En.value(), CXScope_Function); + auto Idx = En.index(); + auto Val = En.value(); + Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); } return Set; @@ -859,8 +864,9 @@ CXScopeSet* clang_scope_getFunctionsUsingName(CXScope S, const char* name) { Set->Count = Funcs.size(); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(Funcs)) { - Set->Scopes[En.index()] = - makeCXScope(getMeta(S), En.value(), CXScope_Function); + auto Idx = En.index(); + auto Val = En.value(); + Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); } return Set; @@ -1008,8 +1014,9 @@ CXScopeSet* clang_scope_getClassTemplatedMethods(const char* name, Set->Count = Funcs.size(); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(Funcs)) { - Set->Scopes[En.index()] = - makeCXScope(getMeta(parent), En.value(), CXScope_Function); + auto Idx = En.index(); + auto Val = En.value(); + Set->Scopes[Idx] = makeCXScope(getMeta(parent), Val, CXScope_Function); } return Set; @@ -1128,8 +1135,9 @@ CXScopeSet* clang_scope_getDatamembers(CXScope S) { Set->Count = std::distance(CXXRD->field_begin(), CXXRD->field_end()); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(CXXRD->fields())) { - Set->Scopes[En.index()] = - makeCXScope(getMeta(S), En.value(), CXScope_Function); + auto Idx = En.index(); + auto Val = En.value(); + Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); } return Set; From 3afc55d96620024141e821af32ae84db255c1be8 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sun, 16 Jun 2024 01:06:00 +0900 Subject: [PATCH 06/23] Apply clang-tidy suggestions --- lib/Interpreter/CXCppInterOp.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index b154fac29..cd64f89ae 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -461,7 +461,7 @@ CXScopeSet* clang_scope_getEnumConstants(CXScope S) { Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(ED->enumerators())) { auto Idx = En.index(); - auto Val = En.value(); + auto* Val = En.value(); Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_EnumConstant); } @@ -575,7 +575,7 @@ CXScopeSet* clang_scope_getUsingNamespaces(CXScope S) { Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(DC->using_directives())) { auto Idx = En.index(); - auto Val = En.value(); + auto* Val = En.value(); Set->Scopes[Idx] = makeCXScope(getMeta(S), Val->getNominatedNamespace(), CXScope_Namespace); } @@ -757,7 +757,7 @@ CXScopeSet* clang_scope_getClassMethods(CXScope S) { Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(Methods)) { auto Idx = En.index(); - auto Val = En.value(); + auto* Val = En.value(); Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); } @@ -795,7 +795,7 @@ CXScopeSet* clang_scope_getFunctionTemplatedDecls(CXScope S) { Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(Methods)) { auto Idx = En.index(); - auto Val = En.value(); + auto* Val = En.value(); Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); } @@ -865,7 +865,7 @@ CXScopeSet* clang_scope_getFunctionsUsingName(CXScope S, const char* name) { Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(Funcs)) { auto Idx = En.index(); - auto Val = En.value(); + auto* Val = En.value(); Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); } @@ -1015,7 +1015,7 @@ CXScopeSet* clang_scope_getClassTemplatedMethods(const char* name, Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(Funcs)) { auto Idx = En.index(); - auto Val = En.value(); + auto* Val = En.value(); Set->Scopes[Idx] = makeCXScope(getMeta(parent), Val, CXScope_Function); } @@ -1136,7 +1136,7 @@ CXScopeSet* clang_scope_getDatamembers(CXScope S) { Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) for (auto En : llvm::enumerate(CXXRD->fields())) { auto Idx = En.index(); - auto Val = En.value(); + auto* Val = En.value(); Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); } From 1e61b0995e23975c3a6184f2aa0946f04d8a1dd2 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sun, 16 Jun 2024 11:33:28 +0900 Subject: [PATCH 07/23] `CXQualTypeKind` => `CXTypeKind` --- include/clang-c/CXCppInterOp.h | 13 +------ lib/Interpreter/CXCppInterOp.cpp | 67 +++++++++++++++++++------------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/include/clang-c/CXCppInterOp.h b/include/clang-c/CXCppInterOp.h index a8d87a126..e8be717b6 100644 --- a/include/clang-c/CXCppInterOp.h +++ b/include/clang-c/CXCppInterOp.h @@ -5,8 +5,8 @@ #include "clang-c/CXErrorCode.h" #include "clang-c/CXString.h" #include "clang-c/ExternC.h" +#include "clang-c/Index.h" #include "clang-c/Platform.h" -#include "llvm-c/LLJIT.h" #include #include @@ -255,20 +255,11 @@ clang_interpreter_getFunctionAddressFromMangledName(CXInterpreter I, * @{ */ -/** - * Describes the kind of entity that a type refers to. - */ -enum CXQualTypeKind { - CXQualType_Unexposed = 0, - CXQualType_Invalid = 1, - // reserved for future use -}; - /** * An opaque pointer representing a type. */ typedef struct { - enum CXQualTypeKind kind; + enum CXTypeKind kind; void* data; const void* meta; } CXQualType; diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index cd64f89ae..b6a11e057 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -198,7 +198,7 @@ clang_interpreter_getFunctionAddressFromMangledName(CXInterpreter I, static inline CXQualType makeCXQualType(const CXInterpreterImpl* I, const clang::QualType Ty, - const CXQualTypeKind K = CXQualType_Unexposed) { + const CXTypeKind K = CXType_Unexposed) { assert(I && "Invalid interpreter"); return CXQualType{K, Ty.getAsOpaquePtr(), static_cast(I)}; } @@ -273,7 +273,7 @@ CXString clang_qualtype_getTypeAsString(CXQualType type) { CXQualType clang_qualtype_getCanonicalType(CXQualType type) { const clang::QualType QT = getType(type); if (QT.isNull()) - return makeCXQualType(getMeta(type), clang::QualType(), CXQualType_Invalid); + return makeCXQualType(getMeta(type), clang::QualType(), CXType_Invalid); return makeCXQualType(getMeta(type), QT.getCanonicalType()); } @@ -286,7 +286,7 @@ CXQualType clang_qualtype_getType(CXInterpreter I, const char* name) { auto& S = getInterpreter(I)->getSema(); const clang::QualType QT = Cpp::GetType(std::string(name), S); if (QT.isNull()) - return makeCXQualType(I, QT, CXQualType_Invalid); + return makeCXQualType(I, QT, CXType_Invalid); return makeCXQualType(I, QT); } @@ -347,7 +347,7 @@ void clang_scope_dump(CXScope S) { getDecl(S)->dump(); } CXQualType clang_scope_getTypeFromScope(CXScope S) { if (isNull(S)) - return makeCXQualType(getMeta(S), clang::QualType(), CXQualType_Invalid); + return makeCXQualType(getMeta(S), clang::QualType(), CXType_Invalid); auto* D = getDecl(S); if (const auto* VD = llvm::dyn_cast(D)) @@ -443,7 +443,7 @@ CXQualType clang_scope_getIntegerTypeFromEnumScope(CXScope S) { if (const auto* ED = llvm::dyn_cast_or_null(getDecl(S))) return makeCXQualType(getMeta(S), ED->getIntegerType()); - return makeCXQualType(getMeta(S), clang::QualType(), CXQualType_Invalid); + return makeCXQualType(getMeta(S), clang::QualType(), CXType_Invalid); } void clang_disposeScopeSet(CXScopeSet* set) { @@ -453,16 +453,20 @@ void clang_disposeScopeSet(CXScopeSet* set) { CXScopeSet* clang_scope_getEnumConstants(CXScope S) { const auto* ED = llvm::dyn_cast_or_null(getDecl(S)); - if (!ED || ED->enumerators().empty()) + if (!ED) + return nullptr; + + auto EI = ED->enumerator_begin(); + auto EE = ED->enumerator_end(); + if (EI == EE) return nullptr; auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) - Set->Count = std::distance(ED->enumerator_begin(), ED->enumerator_end()); + Set->Count = std::distance(EI, EE); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) - for (auto En : llvm::enumerate(ED->enumerators())) { - auto Idx = En.index(); - auto* Val = En.value(); - Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_EnumConstant); + for (auto I = EI; I != EE; ++I) { + auto Idx = std::distance(EI, I); + Set->Scopes[Idx] = makeCXScope(getMeta(S), *I, CXScope_EnumConstant); } return Set; @@ -470,13 +474,13 @@ CXScopeSet* clang_scope_getEnumConstants(CXScope S) { CXQualType clang_scope_getEnumConstantType(CXScope S) { if (isNull(S)) - return makeCXQualType(getMeta(S), clang::QualType(), CXQualType_Invalid); + return makeCXQualType(getMeta(S), clang::QualType(), CXType_Invalid); if (const auto* ECD = llvm::dyn_cast_or_null(getDecl(S))) return makeCXQualType(getMeta(S), ECD->getType()); - return makeCXQualType(getMeta(S), clang::QualType(), CXQualType_Invalid); + return makeCXQualType(getMeta(S), clang::QualType(), CXType_Invalid); } size_t clang_scope_getEnumConstantValue(CXScope S) { @@ -566,17 +570,20 @@ CXString clang_scope_getQualifiedCompleteName(CXScope S) { CXScopeSet* clang_scope_getUsingNamespaces(CXScope S) { const auto* DC = llvm::dyn_cast_or_null(getDecl(S)); - if (!DC || DC->using_directives().empty()) + if (!DC) + return nullptr; + + auto DI = DC->using_directives().begin(); + auto DE = DC->using_directives().end(); + if (DI == DE) return nullptr; auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) - Set->Count = std::distance(DC->using_directives().begin(), - DC->using_directives().end()); + Set->Count = std::distance(DI, DE); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) - for (auto En : llvm::enumerate(DC->using_directives())) { - auto Idx = En.index(); - auto* Val = En.value(); - Set->Scopes[Idx] = makeCXScope(getMeta(S), Val->getNominatedNamespace(), + for (auto I = DI; I != DE; ++I) { + auto Idx = std::distance(DI, I); + Set->Scopes[Idx] = makeCXScope(getMeta(S), (*I)->getNominatedNamespace(), CXScope_Namespace); } @@ -882,7 +889,7 @@ CXQualType clang_scope_getFunctionReturnType(CXScope func) { return makeCXQualType(getMeta(func), FTD->getReturnType()); } - return makeCXQualType(getMeta(func), clang::QualType(), CXQualType_Invalid); + return makeCXQualType(getMeta(func), clang::QualType(), CXType_Invalid); } size_t clang_scope_getFunctionNumArgs(CXScope func) { @@ -917,7 +924,7 @@ CXQualType clang_scope_getFunctionArgType(CXScope func, size_t iarg) { } } - return makeCXQualType(getMeta(func), clang::QualType(), CXQualType_Invalid); + return makeCXQualType(getMeta(func), clang::QualType(), CXType_Invalid); } CXString clang_scope_getFunctionSignature(CXScope func) { @@ -1131,13 +1138,17 @@ CXScopeSet* clang_scope_getDatamembers(CXScope S) { if (!CXXRD) return nullptr; + auto FI = CXXRD->field_begin(); + auto FE = CXXRD->field_end(); + if (FI == FE) + return nullptr; + auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) - Set->Count = std::distance(CXXRD->field_begin(), CXXRD->field_end()); + Set->Count = std::distance(FI, FE); Set->Scopes = new CXScope[Set->Count]; // NOLINT(*-owning-memory) - for (auto En : llvm::enumerate(CXXRD->fields())) { - auto Idx = En.index(); - auto* Val = En.value(); - Set->Scopes[Idx] = makeCXScope(getMeta(S), Val, CXScope_Function); + for (auto I = FE; I != FE; ++I) { + auto Idx = std::distance(FI, I); + Set->Scopes[Idx] = makeCXScope(getMeta(S), *I, CXScope_Field); } return Set; @@ -1206,7 +1217,7 @@ CXQualType clang_scope_getVariableType(CXScope var) { if (const auto* DD = llvm::dyn_cast_or_null(D)) return makeCXQualType(getMeta(var), DD->getType()); - return makeCXQualType(getMeta(var), clang::QualType(), CXQualType_Invalid); + return makeCXQualType(getMeta(var), clang::QualType(), CXType_Invalid); } namespace Cpp { From bcce36f49cf9f2eaab22382371a7d28a473a6e32 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sun, 16 Jun 2024 12:50:45 +0900 Subject: [PATCH 08/23] Add some test examples --- lib/Interpreter/CXCppInterOp.cpp | 6 +- unittests/CppInterOp/EnumReflectionTest.cpp | 112 +++++++++++++++----- 2 files changed, 87 insertions(+), 31 deletions(-) diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index b6a11e057..b376eb115 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -196,9 +196,9 @@ clang_interpreter_getFunctionAddressFromMangledName(CXInterpreter I, return nullptr; } -static inline CXQualType -makeCXQualType(const CXInterpreterImpl* I, const clang::QualType Ty, - const CXTypeKind K = CXType_Unexposed) { +static inline CXQualType makeCXQualType(const CXInterpreterImpl* I, + const clang::QualType Ty, + const CXTypeKind K = CXType_Unexposed) { assert(I && "Invalid interpreter"); return CXQualType{K, Ty.getAsOpaquePtr(), static_cast(I)}; } diff --git a/unittests/CppInterOp/EnumReflectionTest.cpp b/unittests/CppInterOp/EnumReflectionTest.cpp index 3ec03e136..0a801ee90 100644 --- a/unittests/CppInterOp/EnumReflectionTest.cpp +++ b/unittests/CppInterOp/EnumReflectionTest.cpp @@ -1,9 +1,10 @@ #include "Utils.h" #include "clang/AST/ASTContext.h" -#include "clang/Interpreter/CppInterOp.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/CppInterOp.h" #include "clang/Sema/Sema.h" +#include "clang-c/CXCppInterOp.h" #include "gtest/gtest.h" @@ -12,7 +13,7 @@ using namespace llvm; using namespace clang; TEST(ScopeReflectionTest, IsEnumScope) { - std::vector Decls, SubDecls; + std::vector Decls, SubDecls; std::string code = R"( enum Switch { OFF, @@ -31,10 +32,22 @@ TEST(ScopeReflectionTest, IsEnumScope) { EXPECT_FALSE(Cpp::IsEnumScope(Decls[2])); EXPECT_FALSE(Cpp::IsEnumScope(SubDecls[0])); EXPECT_FALSE(Cpp::IsEnumScope(SubDecls[1])); + + // C API + auto I = Cpp::GetInterpreter(); + EXPECT_TRUE(clang_scope_isEnumScope(CXScope{CXScope_Unexposed, Decls[0], I})); + EXPECT_FALSE( + clang_scope_isEnumScope(CXScope{CXScope_Unexposed, Decls[1], I})); + EXPECT_FALSE( + clang_scope_isEnumScope(CXScope{CXScope_Unexposed, Decls[2], I})); + EXPECT_FALSE( + clang_scope_isEnumScope(CXScope{CXScope_Unexposed, SubDecls[0], I})); + EXPECT_FALSE( + clang_scope_isEnumScope(CXScope{CXScope_Unexposed, SubDecls[1], I})); } TEST(ScopeReflectionTest, IsEnumConstant) { - std::vector Decls, SubDecls; + std::vector Decls, SubDecls; std::string code = R"( enum Switch { OFF, @@ -53,11 +66,24 @@ TEST(ScopeReflectionTest, IsEnumConstant) { EXPECT_FALSE(Cpp::IsEnumConstant(Decls[2])); EXPECT_TRUE(Cpp::IsEnumConstant(SubDecls[0])); EXPECT_TRUE(Cpp::IsEnumConstant(SubDecls[1])); + + // C API + auto I = Cpp::GetInterpreter(); + EXPECT_FALSE( + clang_scope_isEnumConstant(CXScope{CXScope_Unexposed, Decls[0], I})); + EXPECT_FALSE( + clang_scope_isEnumConstant(CXScope{CXScope_Unexposed, Decls[1], I})); + EXPECT_FALSE( + clang_scope_isEnumConstant(CXScope{CXScope_Unexposed, Decls[2], I})); + EXPECT_TRUE( + clang_scope_isEnumConstant(CXScope{CXScope_Unexposed, SubDecls[0], I})); + EXPECT_TRUE( + clang_scope_isEnumConstant(CXScope{CXScope_Unexposed, SubDecls[1], I})); } TEST(EnumReflectionTest, IsEnumType) { - std::vector Decls; - std::string code = R"( + std::vector Decls; + std::string code = R"( enum class E { a, b @@ -81,10 +107,25 @@ TEST(EnumReflectionTest, IsEnumType) { EXPECT_TRUE(Cpp::IsEnumType(Cpp::GetVariableType(Decls[3]))); EXPECT_TRUE(Cpp::IsEnumType(Cpp::GetVariableType(Decls[4]))); EXPECT_TRUE(Cpp::IsEnumType(Cpp::GetVariableType(Decls[5]))); + + // C API + auto I = Cpp::GetInterpreter(); + auto VarTy2 = + clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decls[2], I}); + auto VarTy3 = + clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decls[3], I}); + auto VarTy4 = + clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decls[4], I}); + auto VarTy5 = + clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decls[5], I}); + EXPECT_TRUE(clang_qualtype_isEnumType(VarTy2)); + EXPECT_TRUE(clang_qualtype_isEnumType(VarTy3)); + EXPECT_TRUE(clang_qualtype_isEnumType(VarTy4)); + EXPECT_TRUE(clang_qualtype_isEnumType(VarTy5)); } TEST(EnumReflectionTest, GetIntegerTypeFromEnumScope) { - std::vector Decls; + std::vector Decls; std::string code = R"( enum Switch : bool { OFF, @@ -120,21 +161,27 @@ TEST(EnumReflectionTest, GetIntegerTypeFromEnumScope) { GetAllTopLevelDecls(code, Decls); - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[0])), "bool"); - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[1])), "char"); - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[2])), "int"); - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[3])), "long long"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[0])), + "bool"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[1])), + "char"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[2])), + "int"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[3])), + "long long"); #ifdef _WIN32 EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[4])), "int"); #else - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[4])), "unsigned int"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[4])), + "unsigned int"); #endif - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[5])),"NULL TYPE"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[5])), + "NULL TYPE"); } TEST(EnumReflectionTest, GetIntegerTypeFromEnumType) { - std::vector Decls; + std::vector Decls; std::string code = R"( enum Switch : bool { OFF, @@ -176,11 +223,13 @@ TEST(EnumReflectionTest, GetIntegerTypeFromEnumType) { GetAllTopLevelDecls(code, Decls); - auto get_int_type_from_enum_var = [](Decl *D) { - return Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumType(Cpp::GetVariableType(D))); + auto get_int_type_from_enum_var = [](Decl* D) { + return Cpp::GetTypeAsString( + Cpp::GetIntegerTypeFromEnumType(Cpp::GetVariableType(D))); }; - EXPECT_EQ(get_int_type_from_enum_var(Decls[5]), "NULL TYPE"); // When a nullptr is returned by GetVariableType() + EXPECT_EQ(get_int_type_from_enum_var(Decls[5]), + "NULL TYPE"); // When a nullptr is returned by GetVariableType() EXPECT_EQ(get_int_type_from_enum_var(Decls[6]), "bool"); EXPECT_EQ(get_int_type_from_enum_var(Decls[7]), "char"); EXPECT_EQ(get_int_type_from_enum_var(Decls[8]), "int"); @@ -190,11 +239,12 @@ TEST(EnumReflectionTest, GetIntegerTypeFromEnumType) { #else EXPECT_EQ(get_int_type_from_enum_var(Decls[10]), "unsigned int"); #endif - EXPECT_EQ(get_int_type_from_enum_var(Decls[11]), "NULL TYPE"); // When a non Enum Type variable is used + EXPECT_EQ(get_int_type_from_enum_var(Decls[11]), + "NULL TYPE"); // When a non Enum Type variable is used } TEST(EnumReflectionTest, GetEnumConstants) { - std::vector Decls; + std::vector Decls; std::string code = R"( enum ZeroEnum { }; @@ -238,7 +288,7 @@ TEST(EnumReflectionTest, GetEnumConstants) { } TEST(EnumReflectionTest, GetEnumConstantType) { - std::vector Decls; + std::vector Decls; std::string code = R"( enum Enum0 { Constant0 = 0 @@ -269,7 +319,7 @@ TEST(EnumReflectionTest, GetEnumConstantType) { } TEST(EnumReflectionTest, GetEnumConstantValue) { - std::vector Decls; + std::vector Decls; std::string code = R"( enum Counter { Zero = 0, @@ -293,7 +343,8 @@ TEST(EnumReflectionTest, GetEnumConstantValue) { EXPECT_EQ(Cpp::GetEnumConstantValue(EnumConstants[4]), 54); EXPECT_EQ(Cpp::GetEnumConstantValue(EnumConstants[5]), -10); EXPECT_EQ(Cpp::GetEnumConstantValue(EnumConstants[6]), -9); - EXPECT_EQ(Cpp::GetEnumConstantValue(Decls[1]), 0); // Checking value of non enum constant + EXPECT_EQ(Cpp::GetEnumConstantValue(Decls[1]), + 0); // Checking value of non enum constant } TEST(EnumReflectionTest, GetEnums) { @@ -345,16 +396,21 @@ TEST(EnumReflectionTest, GetEnums) { Cpp::TCppScope_t myClass_scope = Cpp::GetScope("myClass", 0); Cpp::TCppScope_t unsupported_scope = Cpp::GetScope("myVariable", 0); - Cpp::GetEnums(globalscope,enumNames1); - Cpp::GetEnums(Animals_scope,enumNames2); + Cpp::GetEnums(globalscope, enumNames1); + Cpp::GetEnums(Animals_scope, enumNames2); Cpp::GetEnums(myClass_scope, enumNames3); Cpp::GetEnums(unsupported_scope, enumNames4); // Check if the enum names are correctly retrieved - EXPECT_TRUE(std::find(enumNames1.begin(), enumNames1.end(), "Color") != enumNames1.end()); - EXPECT_TRUE(std::find(enumNames1.begin(), enumNames1.end(), "Days") != enumNames1.end()); - EXPECT_TRUE(std::find(enumNames2.begin(), enumNames2.end(), "AnimalType") != enumNames2.end()); - EXPECT_TRUE(std::find(enumNames2.begin(), enumNames2.end(), "Months") != enumNames2.end()); - EXPECT_TRUE(std::find(enumNames3.begin(), enumNames3.end(), "Color") != enumNames3.end()); + EXPECT_TRUE(std::find(enumNames1.begin(), enumNames1.end(), "Color") != + enumNames1.end()); + EXPECT_TRUE(std::find(enumNames1.begin(), enumNames1.end(), "Days") != + enumNames1.end()); + EXPECT_TRUE(std::find(enumNames2.begin(), enumNames2.end(), "AnimalType") != + enumNames2.end()); + EXPECT_TRUE(std::find(enumNames2.begin(), enumNames2.end(), "Months") != + enumNames2.end()); + EXPECT_TRUE(std::find(enumNames3.begin(), enumNames3.end(), "Color") != + enumNames3.end()); EXPECT_TRUE(enumNames4.empty()); } \ No newline at end of file From 23911bf0d2274c206336722ad8796d35e5d715f4 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sun, 16 Jun 2024 19:38:31 +0900 Subject: [PATCH 09/23] Add tests for EnumReflection and misc. fixes --- include/clang-c/CXCppInterOp.h | 6 + lib/Interpreter/CXCppInterOp.cpp | 35 ++-- unittests/CppInterOp/CMakeLists.txt | 1 + unittests/CppInterOp/EnumReflectionTest.cpp | 202 ++++++++++++++++---- 4 files changed, 196 insertions(+), 48 deletions(-) diff --git a/include/clang-c/CXCppInterOp.h b/include/clang-c/CXCppInterOp.h index e8be717b6..c1231dfbc 100644 --- a/include/clang-c/CXCppInterOp.h +++ b/include/clang-c/CXCppInterOp.h @@ -50,6 +50,12 @@ CXInterpreter clang_createInterpreterFromPtr(TInterp_t I); */ TInterp_t clang_interpreter_getInterpreterAsPtr(CXInterpreter I); +/** + * Similar to \c clang_interpreter_getInterpreterAsPtr() but it takes the + * ownership. + */ +TInterp_t clang_interpreter_takeInterpreterAsPtr(CXInterpreter I); + /** * Dispose of the given interpreter context. */ diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index b376eb115..a1f5d8944 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -66,6 +66,10 @@ TInterp_t clang_interpreter_getInterpreterAsPtr(CXInterpreter I) { return getInterpreter(I); } +TInterp_t clang_interpreter_takeInterpreterAsPtr(CXInterpreter I) { + return static_cast(I)->Interp.release(); +} + void clang_interpreter_dispose(CXInterpreter I) { delete I; // NOLINT(*-owning-memory) } @@ -447,6 +451,9 @@ CXQualType clang_scope_getIntegerTypeFromEnumScope(CXScope S) { } void clang_disposeScopeSet(CXScopeSet* set) { + if (!set) + return; + delete[] set->Scopes; // NOLINT(*-owning-memory) delete set; // NOLINT(*-owning-memory) } @@ -454,12 +461,12 @@ void clang_disposeScopeSet(CXScopeSet* set) { CXScopeSet* clang_scope_getEnumConstants(CXScope S) { const auto* ED = llvm::dyn_cast_or_null(getDecl(S)); if (!ED) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) auto EI = ED->enumerator_begin(); auto EE = ED->enumerator_end(); if (EI == EE) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = std::distance(EI, EE); @@ -571,12 +578,12 @@ CXString clang_scope_getQualifiedCompleteName(CXScope S) { CXScopeSet* clang_scope_getUsingNamespaces(CXScope S) { const auto* DC = llvm::dyn_cast_or_null(getDecl(S)); if (!DC) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) auto DI = DC->using_directives().begin(); auto DE = DC->using_directives().end(); if (DI == DE) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = std::distance(DI, DE); @@ -735,11 +742,11 @@ int64_t clang_scope_getBaseClassOffset(CXScope derived, CXScope base) { CXScopeSet* clang_scope_getClassMethods(CXScope S) { if (kind(S) == CXScope_Invalid) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) const auto US = clang_scope_getUnderlyingScope(S); if (kind(US) == CXScope_Invalid || !clang_scope_isClass(US)) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) auto* CXXRD = llvm::dyn_cast(getDecl(US)); @@ -773,11 +780,11 @@ CXScopeSet* clang_scope_getClassMethods(CXScope S) { CXScopeSet* clang_scope_getFunctionTemplatedDecls(CXScope S) { if (kind(S) == CXScope_Invalid) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) const auto US = clang_scope_getUnderlyingScope(S); if (kind(US) == CXScope_Invalid || !clang_scope_isClass(US)) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) auto* CXXRD = llvm::dyn_cast(getDecl(US)); @@ -845,7 +852,7 @@ CXScopeSet* clang_scope_getFunctionsUsingName(CXScope S, const char* name) { const auto* D = getDecl(clang_scope_getUnderlyingScope(S)); if (!D || !name) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) const llvm::StringRef Name(name); const auto* I = getInterpreter(S); @@ -858,7 +865,7 @@ CXScopeSet* clang_scope_getFunctionsUsingName(CXScope S, const char* name) { Cpp::Cpp_utils::Lookup::Named(&SM, R, clang::Decl::castToDeclContext(D)); if (R.empty()) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) R.resolveKind(); @@ -995,7 +1002,7 @@ CXScopeSet* clang_scope_getClassTemplatedMethods(const char* name, const auto* D = getDecl(clang_scope_getUnderlyingScope(parent)); if (!D || !name) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) const llvm::StringRef Name(name); const auto* I = getInterpreter(parent); @@ -1008,7 +1015,7 @@ CXScopeSet* clang_scope_getClassTemplatedMethods(const char* name, Cpp::Cpp_utils::Lookup::Named(&SM, R, clang::Decl::castToDeclContext(D)); if (R.empty()) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) R.resolveKind(); @@ -1136,12 +1143,12 @@ CXString clang_scope_getFunctionArgName(CXScope func, size_t param_index) { CXScopeSet* clang_scope_getDatamembers(CXScope S) { const auto* CXXRD = llvm::dyn_cast_or_null(getDecl(S)); if (!CXXRD) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) auto FI = CXXRD->field_begin(); auto FE = CXXRD->field_end(); if (FI == FE) - return nullptr; + return new CXScopeSet{nullptr, 0}; // NOLINT(*-owning-memory) auto* Set = new CXScopeSet; // NOLINT(*-owning-memory) Set->Count = std::distance(FI, FE); diff --git a/unittests/CppInterOp/CMakeLists.txt b/unittests/CppInterOp/CMakeLists.txt index 0e155f709..80f00861c 100644 --- a/unittests/CppInterOp/CMakeLists.txt +++ b/unittests/CppInterOp/CMakeLists.txt @@ -16,6 +16,7 @@ add_cppinterop_unittest(CppInterOpTests target_link_libraries(CppInterOpTests PRIVATE clangCppInterOp + libclang ) if(NOT WIN32) diff --git a/unittests/CppInterOp/EnumReflectionTest.cpp b/unittests/CppInterOp/EnumReflectionTest.cpp index 0a801ee90..265c50b9c 100644 --- a/unittests/CppInterOp/EnumReflectionTest.cpp +++ b/unittests/CppInterOp/EnumReflectionTest.cpp @@ -5,6 +5,7 @@ #include "clang/Interpreter/CppInterOp.h" #include "clang/Sema/Sema.h" #include "clang-c/CXCppInterOp.h" +#include "clang-c/CXString.h" #include "gtest/gtest.h" @@ -34,16 +35,18 @@ TEST(ScopeReflectionTest, IsEnumScope) { EXPECT_FALSE(Cpp::IsEnumScope(SubDecls[1])); // C API - auto I = Cpp::GetInterpreter(); - EXPECT_TRUE(clang_scope_isEnumScope(CXScope{CXScope_Unexposed, Decls[0], I})); - EXPECT_FALSE( - clang_scope_isEnumScope(CXScope{CXScope_Unexposed, Decls[1], I})); - EXPECT_FALSE( - clang_scope_isEnumScope(CXScope{CXScope_Unexposed, Decls[2], I})); - EXPECT_FALSE( - clang_scope_isEnumScope(CXScope{CXScope_Unexposed, SubDecls[0], I})); - EXPECT_FALSE( - clang_scope_isEnumScope(CXScope{CXScope_Unexposed, SubDecls[1], I})); + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_isEnumScope(CXScope{CXScope_Unexposed, Decl, I}); + }; + EXPECT_TRUE(C_API_SHIM(Decls[0])); + EXPECT_FALSE(C_API_SHIM(Decls[1])); + EXPECT_FALSE(C_API_SHIM(Decls[2])); + EXPECT_FALSE(C_API_SHIM(SubDecls[0])); + EXPECT_FALSE(C_API_SHIM(SubDecls[1])); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, IsEnumConstant) { @@ -68,17 +71,18 @@ TEST(ScopeReflectionTest, IsEnumConstant) { EXPECT_TRUE(Cpp::IsEnumConstant(SubDecls[1])); // C API - auto I = Cpp::GetInterpreter(); - EXPECT_FALSE( - clang_scope_isEnumConstant(CXScope{CXScope_Unexposed, Decls[0], I})); - EXPECT_FALSE( - clang_scope_isEnumConstant(CXScope{CXScope_Unexposed, Decls[1], I})); - EXPECT_FALSE( - clang_scope_isEnumConstant(CXScope{CXScope_Unexposed, Decls[2], I})); - EXPECT_TRUE( - clang_scope_isEnumConstant(CXScope{CXScope_Unexposed, SubDecls[0], I})); - EXPECT_TRUE( - clang_scope_isEnumConstant(CXScope{CXScope_Unexposed, SubDecls[1], I})); + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_isEnumConstant(CXScope{CXScope_Unexposed, Decl, I}); + }; + EXPECT_FALSE(C_API_SHIM(Decls[0])); + EXPECT_FALSE(C_API_SHIM(Decls[1])); + EXPECT_FALSE(C_API_SHIM(Decls[2])); + EXPECT_TRUE(C_API_SHIM(SubDecls[0])); + EXPECT_TRUE(C_API_SHIM(SubDecls[1])); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(EnumReflectionTest, IsEnumType) { @@ -109,19 +113,18 @@ TEST(EnumReflectionTest, IsEnumType) { EXPECT_TRUE(Cpp::IsEnumType(Cpp::GetVariableType(Decls[5]))); // C API - auto I = Cpp::GetInterpreter(); - auto VarTy2 = - clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decls[2], I}); - auto VarTy3 = - clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decls[3], I}); - auto VarTy4 = - clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decls[4], I}); - auto VarTy5 = - clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decls[5], I}); - EXPECT_TRUE(clang_qualtype_isEnumType(VarTy2)); - EXPECT_TRUE(clang_qualtype_isEnumType(VarTy3)); - EXPECT_TRUE(clang_qualtype_isEnumType(VarTy4)); - EXPECT_TRUE(clang_qualtype_isEnumType(VarTy5)); + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + auto Ty = clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decl, I}); + return clang_qualtype_isEnumType(Ty); + }; + EXPECT_TRUE(C_API_SHIM(Decls[2])); + EXPECT_TRUE(C_API_SHIM(Decls[3])); + EXPECT_TRUE(C_API_SHIM(Decls[4])); + EXPECT_TRUE(C_API_SHIM(Decls[5])); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(EnumReflectionTest, GetIntegerTypeFromEnumScope) { @@ -178,6 +181,30 @@ TEST(EnumReflectionTest, GetIntegerTypeFromEnumScope) { #endif EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetIntegerTypeFromEnumScope(Decls[5])), "NULL TYPE"); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + auto Ty = clang_scope_getIntegerTypeFromEnumScope( + CXScope{CXScope_Unexposed, Decl, I}); + auto Str = clang_qualtype_getTypeAsString(Ty); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM(Decls[0]), "bool"); + EXPECT_EQ(C_API_SHIM(Decls[1]), "char"); + EXPECT_EQ(C_API_SHIM(Decls[2]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[3]), "long long"); +#ifdef _WIN32 + EXPECT_EQ(C_API_SHIM(Decls[4]), "int"); +#else + EXPECT_EQ(C_API_SHIM(Decls[4]), "unsigned int"); +#endif + EXPECT_EQ(C_API_SHIM(Decls[5]), "NULL TYPE"); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(EnumReflectionTest, GetIntegerTypeFromEnumType) { @@ -241,6 +268,31 @@ TEST(EnumReflectionTest, GetIntegerTypeFromEnumType) { #endif EXPECT_EQ(get_int_type_from_enum_var(Decls[11]), "NULL TYPE"); // When a non Enum Type variable is used + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + auto Ty = clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decl, I}); + auto IntTy = clang_qualtype_getIntegerTypeFromEnumType(Ty); + auto Str = clang_qualtype_getTypeAsString(IntTy); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM(Decls[5]), "NULL TYPE"); + EXPECT_EQ(C_API_SHIM(Decls[6]), "bool"); + EXPECT_EQ(C_API_SHIM(Decls[7]), "char"); + EXPECT_EQ(C_API_SHIM(Decls[8]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[9]), "long long"); +#ifdef _WIN32 + EXPECT_EQ(C_API_SHIM(Decls[10]), "int"); +#else + EXPECT_EQ(C_API_SHIM(Decls[10]), "unsigned int"); +#endif + EXPECT_EQ(C_API_SHIM(Decls[11]), "NULL TYPE"); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(EnumReflectionTest, GetEnumConstants) { @@ -285,6 +337,25 @@ TEST(EnumReflectionTest, GetEnumConstants) { EXPECT_EQ(Cpp::GetEnumConstants(Decls[3]).size(), 3); EXPECT_EQ(Cpp::GetEnumConstants(Decls[4]).size(), 4); EXPECT_EQ(Cpp::GetEnumConstants(Decls[5]).size(), 0); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + auto ECs = + clang_scope_getEnumConstants(CXScope{CXScope_Unexposed, Decl, I}); + auto Res = ECs->Count; + clang_disposeScopeSet(ECs); + return Res; + }; + EXPECT_EQ(C_API_SHIM(Decls[0]), 0); + EXPECT_EQ(C_API_SHIM(Decls[1]), 1); + EXPECT_EQ(C_API_SHIM(Decls[2]), 2); + EXPECT_EQ(C_API_SHIM(Decls[3]), 3); + EXPECT_EQ(C_API_SHIM(Decls[4]), 4); + EXPECT_EQ(C_API_SHIM(Decls[5]), 0); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(EnumReflectionTest, GetEnumConstantType) { @@ -316,6 +387,24 @@ TEST(EnumReflectionTest, GetEnumConstantType) { EXPECT_EQ(get_enum_constant_type_as_str(Decls[1]), "NULL TYPE"); EXPECT_EQ(get_enum_constant_type_as_str(nullptr), "NULL TYPE"); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + auto ECs = + clang_scope_getEnumConstants(CXScope{CXScope_Unexposed, Decl, I}); + auto Ty = clang_scope_getEnumConstantType(ECs->Scopes[0]); + clang_disposeScopeSet(ECs); + auto Str = clang_qualtype_getTypeAsString(Ty); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM(Decls[0]), "Enum0"); + EXPECT_EQ(C_API_SHIM(Decls[1]), "Enum1"); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(EnumReflectionTest, GetEnumConstantValue) { @@ -345,6 +434,25 @@ TEST(EnumReflectionTest, GetEnumConstantValue) { EXPECT_EQ(Cpp::GetEnumConstantValue(EnumConstants[6]), -9); EXPECT_EQ(Cpp::GetEnumConstantValue(Decls[1]), 0); // Checking value of non enum constant + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto ECs = + clang_scope_getEnumConstants(CXScope{CXScope_Unexposed, Decls[0], I}); + EXPECT_EQ(clang_scope_getEnumConstantValue(ECs->Scopes[0]), 0); + EXPECT_EQ(clang_scope_getEnumConstantValue(ECs->Scopes[1]), 1); + EXPECT_EQ(clang_scope_getEnumConstantValue(ECs->Scopes[2]), 52); + EXPECT_EQ(clang_scope_getEnumConstantValue(ECs->Scopes[3]), 53); + EXPECT_EQ(clang_scope_getEnumConstantValue(ECs->Scopes[4]), 54); + EXPECT_EQ(clang_scope_getEnumConstantValue(ECs->Scopes[5]), -10); + EXPECT_EQ(clang_scope_getEnumConstantValue(ECs->Scopes[6]), -9); + EXPECT_EQ(clang_scope_getEnumConstantValue( + CXScope{CXScope_EnumConstant, Decls[1], I}), + 0); + clang_disposeScopeSet(ECs); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(EnumReflectionTest, GetEnums) { @@ -413,4 +521,30 @@ TEST(EnumReflectionTest, GetEnums) { EXPECT_TRUE(std::find(enumNames3.begin(), enumNames3.end(), "Color") != enumNames3.end()); EXPECT_TRUE(enumNames4.empty()); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto GS = clang_scope_getGlobalScope(I); + auto C_API_SHIM = [](const auto& Scope, auto EnumName) -> bool { + auto EMStrSet = clang_scope_getEnums(Scope); + if (!EMStrSet) + return false; + + std::vector Names; + for (size_t i = 0; i < EMStrSet->Count; ++i) + Names.push_back(clang_getCString(EMStrSet->Strings[i])); + + return std::find(Names.begin(), Names.end(), std::string(EnumName)) != + Names.end(); + }; + EXPECT_TRUE(C_API_SHIM(GS, "Color")); + EXPECT_TRUE(C_API_SHIM(GS, "Days")); + EXPECT_TRUE(C_API_SHIM(clang_scope_getScope("Animals", GS), "AnimalType")); + EXPECT_TRUE(C_API_SHIM(clang_scope_getScope("Animals", GS), "Months")); + EXPECT_TRUE(C_API_SHIM(clang_scope_getScope("myClass", GS), "Color")); + EXPECT_EQ(clang_scope_getEnums(clang_scope_getScope("myVariable", GS))->Count, + 0); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } \ No newline at end of file From 2f3e0c1fe8da8f2e69ee968865c40b51fbab0476 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sun, 16 Jun 2024 20:08:17 +0900 Subject: [PATCH 10/23] Do not link to libclang --- unittests/CppInterOp/CMakeLists.txt | 1 - unittests/CppInterOp/EnumReflectionTest.cpp | 1 - unittests/CppInterOp/Utils.cpp | 9 +++++++++ unittests/CppInterOp/Utils.h | 7 ++++++- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/unittests/CppInterOp/CMakeLists.txt b/unittests/CppInterOp/CMakeLists.txt index 80f00861c..0e155f709 100644 --- a/unittests/CppInterOp/CMakeLists.txt +++ b/unittests/CppInterOp/CMakeLists.txt @@ -16,7 +16,6 @@ add_cppinterop_unittest(CppInterOpTests target_link_libraries(CppInterOpTests PRIVATE clangCppInterOp - libclang ) if(NOT WIN32) diff --git a/unittests/CppInterOp/EnumReflectionTest.cpp b/unittests/CppInterOp/EnumReflectionTest.cpp index 265c50b9c..612c6dff5 100644 --- a/unittests/CppInterOp/EnumReflectionTest.cpp +++ b/unittests/CppInterOp/EnumReflectionTest.cpp @@ -5,7 +5,6 @@ #include "clang/Interpreter/CppInterOp.h" #include "clang/Sema/Sema.h" #include "clang-c/CXCppInterOp.h" -#include "clang-c/CXString.h" #include "gtest/gtest.h" diff --git a/unittests/CppInterOp/Utils.cpp b/unittests/CppInterOp/Utils.cpp index 41389ad30..33401e854 100644 --- a/unittests/CppInterOp/Utils.cpp +++ b/unittests/CppInterOp/Utils.cpp @@ -56,3 +56,12 @@ void TestUtils::GetAllSubDecls(Decl *D, std::vector& SubDecls, SubDecls.push_back(Di); } } + +const char* clang_getCString(CXString string) { + return static_cast(string.data); +} + +void clang_disposeString(CXString string) { + if (string.private_flags == 1 && string.data) + free(const_cast(string.data)); +} \ No newline at end of file diff --git a/unittests/CppInterOp/Utils.h b/unittests/CppInterOp/Utils.h index 8eff16abf..e5e51232a 100644 --- a/unittests/CppInterOp/Utils.h +++ b/unittests/CppInterOp/Utils.h @@ -3,9 +3,10 @@ #include "../../lib/Interpreter/Compatibility.h" +#include "llvm/Support/Valgrind.h" #include #include -#include "llvm/Support/Valgrind.h" +#include "clang-c/CXString.h" using namespace clang; using namespace llvm; @@ -21,4 +22,8 @@ namespace TestUtils { bool filter_implicitGenerated = false); } // end namespace TestUtils +// libclang's string manipulation APIs +const char* clang_getCString(CXString string); +void clang_disposeString(CXString string); + #endif // CPPINTEROP_UNITTESTS_LIBCPPINTEROP_UTILS_H From 0bd100e04c8675cf00219f6d07ffc8e95fd44e3c Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Mon, 17 Jun 2024 00:32:58 +0900 Subject: [PATCH 11/23] Add tests for ScopeReflection and misc. fixes -- Take 1 --- lib/Interpreter/CXCppInterOp.cpp | 9 +- unittests/CppInterOp/ScopeReflectionTest.cpp | 629 +++++++++++++++---- 2 files changed, 529 insertions(+), 109 deletions(-) diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index a1f5d8944..28a91c667 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -543,12 +543,13 @@ CXString clang_scope_getCompleteName(CXScope S) { CXString clang_scope_getQualifiedName(CXScope S) { auto* D = getDecl(S); - if (const auto* ND = llvm::dyn_cast_or_null(D)) - return makeCXString(ND->getQualifiedNameAsString()); if (llvm::isa_and_nonnull(D)) return makeCXString(""); + if (const auto* ND = llvm::dyn_cast_or_null(D)) + return makeCXString(ND->getQualifiedNameAsString()); + return makeCXString(""); } @@ -606,12 +607,12 @@ CXScope clang_scope_getGlobalScope(CXInterpreter I) { CXScope clang_scope_getUnderlyingScope(CXScope S) { const auto* TND = llvm::dyn_cast_or_null(getDecl(S)); if (!TND) - return makeCXScope(getMeta(S), nullptr, CXScope_Invalid); + return S; const clang::QualType QT = TND->getUnderlyingType(); auto* D = Cpp::GetScopeFromType(QT.getAsOpaquePtr()); if (!D) - return makeCXScope(getMeta(S), nullptr, CXScope_Invalid); + return S; return makeCXScope(getMeta(S), static_cast(D)); } diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index d0da1c2f8..d397cb38f 100644 --- a/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -1,14 +1,15 @@ #include "Utils.h" #include "clang/Interpreter/CppInterOp.h" +#include "clang-c/CXCppInterOp.h" #include "clang/AST/ASTContext.h" -#include "clang/Interpreter/CppInterOp.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/CppInterOp.h" #include "clang/Sema/Sema.h" -#include "clang/AST/DeclBase.h" #include "clang/AST/ASTDumper.h" +#include "clang/AST/DeclBase.h" #include "gtest/gtest.h" @@ -17,7 +18,7 @@ using namespace llvm; using namespace clang; TEST(ScopeReflectionTest, IsAggregate) { - std::vector Decls; + std::vector Decls; std::string code = R"( char cv[4] = {}; int x[] = {}; @@ -39,6 +40,20 @@ TEST(ScopeReflectionTest, IsAggregate) { EXPECT_TRUE(Cpp::IsAggregate(Decls[2])); EXPECT_TRUE(Cpp::IsAggregate(Decls[3])); EXPECT_FALSE(Cpp::IsAggregate(Decls[4])); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_isAggregate(CXScope{CXScope_Unexposed, Decl, I}); + }; + EXPECT_TRUE(C_API_SHIM(Decls[0])); + EXPECT_TRUE(C_API_SHIM(Decls[1])); + EXPECT_TRUE(C_API_SHIM(Decls[2])); + EXPECT_TRUE(C_API_SHIM(Decls[3])); + EXPECT_FALSE(C_API_SHIM(Decls[4])); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } // Check that the CharInfo table has been constructed reasonably. @@ -48,6 +63,18 @@ TEST(ScopeReflectionTest, IsNamespace) { EXPECT_TRUE(Cpp::IsNamespace(Decls[0])); EXPECT_FALSE(Cpp::IsNamespace(Decls[1])); EXPECT_FALSE(Cpp::IsNamespace(Decls[2])); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_isNamespace(CXScope{CXScope_Unexposed, Decl, I}); + }; + EXPECT_TRUE(C_API_SHIM(Decls[0])); + EXPECT_FALSE(C_API_SHIM(Decls[1])); + EXPECT_FALSE(C_API_SHIM(Decls[2])); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, IsClass) { @@ -56,6 +83,18 @@ TEST(ScopeReflectionTest, IsClass) { EXPECT_FALSE(Cpp::IsClass(Decls[0])); EXPECT_TRUE(Cpp::IsClass(Decls[1])); EXPECT_FALSE(Cpp::IsClass(Decls[2])); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_isClass(CXScope{CXScope_Unexposed, Decl, I}); + }; + EXPECT_FALSE(C_API_SHIM(Decls[0])); + EXPECT_TRUE(C_API_SHIM(Decls[1])); + EXPECT_FALSE(C_API_SHIM(Decls[2])); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, IsComplete) { @@ -70,8 +109,7 @@ TEST(ScopeReflectionTest, IsComplete) { template struct TemplatedS{ T x; }; TemplatedS templateF() { return {}; }; )"; - GetAllTopLevelDecls(code, - Decls); + GetAllTopLevelDecls(code, Decls); EXPECT_TRUE(Cpp::IsComplete(Decls[0])); EXPECT_TRUE(Cpp::IsComplete(Decls[1])); EXPECT_TRUE(Cpp::IsComplete(Decls[2])); @@ -81,6 +119,26 @@ TEST(ScopeReflectionTest, IsComplete) { Cpp::TCppType_t retTy = Cpp::GetFunctionReturnType(Decls[7]); EXPECT_TRUE(Cpp::IsComplete(Cpp::GetScopeFromType(retTy))); EXPECT_FALSE(Cpp::IsComplete(nullptr)); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_isComplete(CXScope{CXScope_Unexposed, Decl, I}); + }; + EXPECT_TRUE(C_API_SHIM(Decls[0])); + EXPECT_TRUE(C_API_SHIM(Decls[1])); + EXPECT_TRUE(C_API_SHIM(Decls[2])); + EXPECT_FALSE(C_API_SHIM(Decls[3])); + EXPECT_FALSE(C_API_SHIM(Decls[4])); + EXPECT_TRUE(C_API_SHIM(Decls[5])); + auto Ty = + clang_scope_getFunctionReturnType(CXScope{CXScope_Function, Decls[7], I}); + auto Scope = clang_scope_getScopeFromType(Ty); + EXPECT_TRUE(clang_scope_isComplete(Scope)); + EXPECT_FALSE(C_API_SHIM(nullptr)); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, SizeOf) { @@ -98,17 +156,34 @@ TEST(ScopeReflectionTest, SizeOf) { EXPECT_EQ(Cpp::SizeOf(Decls[5]), (size_t)1); EXPECT_EQ(Cpp::SizeOf(Decls[6]), (size_t)4); EXPECT_EQ(Cpp::SizeOf(Decls[7]), (size_t)16); -} + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_sizeOf(CXScope{CXScope_Unexposed, Decl, I}); + }; + EXPECT_EQ(C_API_SHIM(Decls[0]), (size_t)0); + EXPECT_EQ(C_API_SHIM(Decls[1]), (size_t)1); + EXPECT_EQ(C_API_SHIM(Decls[2]), (size_t)0); + EXPECT_EQ(C_API_SHIM(Decls[3]), (size_t)0); + EXPECT_EQ(C_API_SHIM(Decls[4]), (size_t)0); + EXPECT_EQ(C_API_SHIM(Decls[5]), (size_t)1); + EXPECT_EQ(C_API_SHIM(Decls[6]), (size_t)4); + EXPECT_EQ(C_API_SHIM(Decls[7]), (size_t)16); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); +} TEST(ScopeReflectionTest, IsBuiltin) { // static std::set g_builtins = - // {"bool", "char", "signed char", "unsigned char", "wchar_t", "short", "unsigned short", - // "int", "unsigned int", "long", "unsigned long", "long long", "unsigned long long", - // "float", "double", "long double", "void"} + // {"bool", "char", "signed char", "unsigned char", "wchar_t", "short", + // "unsigned short", + // "int", "unsigned int", "long", "unsigned long", "long long", "unsigned + // long long", "float", "double", "long double", "void"} Cpp::CreateInterpreter(); - ASTContext &C = Interp->getCI()->getASTContext(); + ASTContext& C = Interp->getCI()->getASTContext(); EXPECT_TRUE(Cpp::IsBuiltin(C.BoolTy.getAsOpaquePtr())); EXPECT_TRUE(Cpp::IsBuiltin(C.CharTy.getAsOpaquePtr())); EXPECT_TRUE(Cpp::IsBuiltin(C.SignedCharTy.getAsOpaquePtr())); @@ -118,21 +193,22 @@ TEST(ScopeReflectionTest, IsBuiltin) { // complex EXPECT_TRUE(Cpp::IsBuiltin(C.getComplexType(C.FloatTy).getAsOpaquePtr())); EXPECT_TRUE(Cpp::IsBuiltin(C.getComplexType(C.DoubleTy).getAsOpaquePtr())); - EXPECT_TRUE(Cpp::IsBuiltin(C.getComplexType(C.LongDoubleTy).getAsOpaquePtr())); + EXPECT_TRUE( + Cpp::IsBuiltin(C.getComplexType(C.LongDoubleTy).getAsOpaquePtr())); EXPECT_TRUE(Cpp::IsBuiltin(C.getComplexType(C.Float128Ty).getAsOpaquePtr())); // std::complex std::vector Decls; Interp->declare("#include "); - Sema &S = Interp->getCI()->getSema(); + Sema& S = Interp->getCI()->getSema(); auto lookup = S.getStdNamespace()->lookup(&C.Idents.get("complex")); - auto *CTD = cast(lookup.front()); - for (ClassTemplateSpecializationDecl *CTSD : CTD->specializations()) + auto* CTD = cast(lookup.front()); + for (ClassTemplateSpecializationDecl* CTSD : CTD->specializations()) EXPECT_TRUE(Cpp::IsBuiltin(C.getTypeDeclType(CTSD).getAsOpaquePtr())); } TEST(ScopeReflectionTest, IsTemplate) { - std::vector Decls; + std::vector Decls; std::string code = R"(template class A{}; @@ -155,10 +231,23 @@ TEST(ScopeReflectionTest, IsTemplate) { EXPECT_FALSE(Cpp::IsTemplate(Decls[1])); EXPECT_TRUE(Cpp::IsTemplate(Decls[2])); EXPECT_FALSE(Cpp::IsTemplate(Decls[3])); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_isTemplate(CXScope{CXScope_Unexposed, Decl, I}); + }; + EXPECT_TRUE(C_API_SHIM(Decls[0])); + EXPECT_FALSE(C_API_SHIM(Decls[1])); + EXPECT_TRUE(C_API_SHIM(Decls[2])); + EXPECT_FALSE(C_API_SHIM(Decls[3])); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, IsTemplateSpecialization) { - std::vector Decls; + std::vector Decls; std::string code = R"( template class A{}; @@ -170,11 +259,27 @@ TEST(ScopeReflectionTest, IsTemplateSpecialization) { EXPECT_FALSE(Cpp::IsTemplateSpecialization(Decls[0])); EXPECT_FALSE(Cpp::IsTemplateSpecialization(Decls[1])); EXPECT_TRUE(Cpp::IsTemplateSpecialization( - Cpp::GetScopeFromType(Cpp::GetVariableType(Decls[1])))); + Cpp::GetScopeFromType(Cpp::GetVariableType(Decls[1])))); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_isTemplateSpecialization( + CXScope{CXScope_Unexposed, Decl, I}); + }; + EXPECT_FALSE(C_API_SHIM(Decls[0])); + EXPECT_FALSE(C_API_SHIM(Decls[1])); + auto VarType = + clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decls[1], I}); + auto Scope = clang_scope_getScopeFromType(VarType); + EXPECT_TRUE(clang_scope_isTemplateSpecialization(Scope)); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, IsTypedefed) { - std::vector Decls; + std::vector Decls; std::string code = R"( typedef int I; using D = double; @@ -185,10 +290,22 @@ TEST(ScopeReflectionTest, IsTypedefed) { EXPECT_TRUE(Cpp::IsTypedefed(Decls[0])); EXPECT_TRUE(Cpp::IsTypedefed(Decls[1])); EXPECT_FALSE(Cpp::IsTypedefed(Decls[2])); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_isTypedefed(CXScope{CXScope_Unexposed, Decl, I}); + }; + EXPECT_TRUE(C_API_SHIM(Decls[0])); + EXPECT_TRUE(C_API_SHIM(Decls[1])); + EXPECT_FALSE(C_API_SHIM(Decls[2])); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, IsAbstract) { - std::vector Decls; + std::vector Decls; std::string code = R"( class A {}; @@ -205,10 +322,22 @@ TEST(ScopeReflectionTest, IsAbstract) { EXPECT_FALSE(Cpp::IsAbstract(Decls[0])); EXPECT_TRUE(Cpp::IsAbstract(Decls[1])); EXPECT_FALSE(Cpp::IsAbstract(Decls[2])); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_isAbstract(CXScope{CXScope_Unexposed, Decl, I}); + }; + EXPECT_FALSE(C_API_SHIM(Decls[0])); + EXPECT_TRUE(C_API_SHIM(Decls[1])); + EXPECT_FALSE(C_API_SHIM(Decls[2])); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, IsVariable) { - std::vector Decls; + std::vector Decls; std::string code = R"( int i; @@ -223,12 +352,28 @@ TEST(ScopeReflectionTest, IsVariable) { EXPECT_TRUE(Cpp::IsVariable(Decls[0])); EXPECT_FALSE(Cpp::IsVariable(Decls[1])); - std::vector SubDecls; + std::vector SubDecls; GetAllSubDecls(Decls[1], SubDecls); EXPECT_FALSE(Cpp::IsVariable(SubDecls[0])); EXPECT_FALSE(Cpp::IsVariable(SubDecls[1])); EXPECT_FALSE(Cpp::IsVariable(SubDecls[2])); EXPECT_TRUE(Cpp::IsVariable(SubDecls[3])); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_isVariable(CXScope{CXScope_Unexposed, Decl, I}); + }; + EXPECT_TRUE(C_API_SHIM(Decls[0])); + EXPECT_FALSE(C_API_SHIM(Decls[1])); + + EXPECT_FALSE(C_API_SHIM(SubDecls[0])); + EXPECT_FALSE(C_API_SHIM(SubDecls[1])); + EXPECT_FALSE(C_API_SHIM(SubDecls[2])); + EXPECT_TRUE(C_API_SHIM(SubDecls[3])); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetName) { @@ -247,10 +392,31 @@ TEST(ScopeReflectionTest, GetName) { EXPECT_EQ(Cpp::GetName(Decls[6]), "Size4"); EXPECT_EQ(Cpp::GetName(Decls[7]), "Size16"); EXPECT_EQ(Cpp::GetName(nullptr), ""); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + auto Str = clang_scope_getName(CXScope{CXScope_Unexposed, Decl, I}); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM(Decls[0]), "N"); + EXPECT_EQ(C_API_SHIM(Decls[1]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[2]), "I"); + EXPECT_EQ(C_API_SHIM(Decls[3]), "S"); + EXPECT_EQ(C_API_SHIM(Decls[4]), "E"); + EXPECT_EQ(C_API_SHIM(Decls[5]), "U"); + EXPECT_EQ(C_API_SHIM(Decls[6]), "Size4"); + EXPECT_EQ(C_API_SHIM(Decls[7]), "Size16"); + EXPECT_EQ(C_API_SHIM(nullptr), ""); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetCompleteName) { - std::vector Decls; + std::vector Decls; std::string code = R"(namespace N {} class C{}; int I; @@ -277,11 +443,40 @@ TEST(ScopeReflectionTest, GetCompleteName) { EXPECT_EQ(Cpp::GetCompleteName(Decls[6]), "Size4"); EXPECT_EQ(Cpp::GetCompleteName(Decls[7]), "Size16"); EXPECT_EQ(Cpp::GetCompleteName(Decls[8]), "A"); - EXPECT_EQ(Cpp::GetCompleteName(Cpp::GetScopeFromType( - Cpp::GetVariableType( - Decls[9]))), "A"); + EXPECT_EQ(Cpp::GetCompleteName( + Cpp::GetScopeFromType(Cpp::GetVariableType(Decls[9]))), + "A"); EXPECT_EQ(Cpp::GetCompleteName(Decls[10]), "(unnamed)"); EXPECT_EQ(Cpp::GetCompleteName(nullptr), ""); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + auto Str = clang_scope_getCompleteName(CXScope{CXScope_Unexposed, Decl, I}); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM(Decls[0]), "N"); + EXPECT_EQ(C_API_SHIM(Decls[1]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[2]), "I"); + EXPECT_EQ(C_API_SHIM(Decls[3]), "S"); + EXPECT_EQ(C_API_SHIM(Decls[4]), "E"); + EXPECT_EQ(C_API_SHIM(Decls[5]), "U"); + EXPECT_EQ(C_API_SHIM(Decls[6]), "Size4"); + EXPECT_EQ(C_API_SHIM(Decls[7]), "Size16"); + EXPECT_EQ(C_API_SHIM(Decls[8]), "A"); + auto VarType = + clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decls[9], I}); + auto Scope = clang_scope_getScopeFromType(VarType); + auto Str = clang_scope_getCompleteName(Scope); + EXPECT_EQ(std::string(clang_getCString(Str)), "A"); + clang_disposeString(Str); + EXPECT_EQ(C_API_SHIM(Decls[10]), "(unnamed)"); + EXPECT_EQ(C_API_SHIM(nullptr), ""); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetQualifiedName) { @@ -302,6 +497,24 @@ TEST(ScopeReflectionTest, GetQualifiedName) { EXPECT_EQ(Cpp::GetQualifiedName(Decls[1]), "N::C"); EXPECT_EQ(Cpp::GetQualifiedName(Decls[3]), "N::C::i"); EXPECT_EQ(Cpp::GetQualifiedName(Decls[4]), "N::C::E"); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + auto Str = + clang_scope_getQualifiedName(CXScope{CXScope_Unexposed, Decl, I}); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM(nullptr), ""); + EXPECT_EQ(C_API_SHIM(Decls[0]), "N"); + EXPECT_EQ(C_API_SHIM(Decls[1]), "N::C"); + EXPECT_EQ(C_API_SHIM(Decls[3]), "N::C::i"); + EXPECT_EQ(C_API_SHIM(Decls[4]), "N::C::E"); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetQualifiedCompleteName) { @@ -324,13 +537,40 @@ TEST(ScopeReflectionTest, GetQualifiedCompleteName) { EXPECT_EQ(Cpp::GetQualifiedCompleteName(Decls[0]), "N"); EXPECT_EQ(Cpp::GetQualifiedCompleteName(Decls[1]), "N::C"); EXPECT_EQ(Cpp::GetQualifiedCompleteName(Decls[2]), "N::A"); - EXPECT_EQ(Cpp::GetQualifiedCompleteName(Cpp::GetScopeFromType(Cpp::GetVariableType(Decls[3]))), "N::A"); + EXPECT_EQ(Cpp::GetQualifiedCompleteName( + Cpp::GetScopeFromType(Cpp::GetVariableType(Decls[3]))), + "N::A"); EXPECT_EQ(Cpp::GetQualifiedCompleteName(Decls[5]), "N::C::i"); EXPECT_EQ(Cpp::GetQualifiedCompleteName(Decls[6]), "N::C::E"); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + auto Str = clang_scope_getQualifiedCompleteName( + CXScope{CXScope_Unexposed, Decl, I}); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM(nullptr), ""); + EXPECT_EQ(C_API_SHIM(Decls[0]), "N"); + EXPECT_EQ(C_API_SHIM(Decls[1]), "N::C"); + EXPECT_EQ(C_API_SHIM(Decls[2]), "N::A"); + auto VarType = + clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decls[3], I}); + auto Scope = clang_scope_getScopeFromType(VarType); + auto Str = clang_scope_getQualifiedCompleteName(Scope); + EXPECT_EQ(std::string(clang_getCString(Str)), "N::A"); + clang_disposeString(Str); + EXPECT_EQ(C_API_SHIM(Decls[5]), "N::C::i"); + EXPECT_EQ(C_API_SHIM(Decls[6]), "N::C::E"); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetUsingNamespaces) { - std::vector Decls, Decls1; + std::vector Decls, Decls1; std::string code = R"( namespace abc { @@ -344,14 +584,30 @@ TEST(ScopeReflectionTest, GetUsingNamespaces) { )"; GetAllTopLevelDecls(code, Decls); - std::vector usingNamespaces; + std::vector usingNamespaces; usingNamespaces = Cpp::GetUsingNamespaces( - Decls[0]->getASTContext().getTranslationUnitDecl()); + Decls[0]->getASTContext().getTranslationUnitDecl()); + + // EXPECT_EQ(Cpp::GetName(usingNamespaces[0]), "runtime"); + EXPECT_EQ(Cpp::GetName(usingNamespaces[usingNamespaces.size() - 2]), "std"); + EXPECT_EQ(Cpp::GetName(usingNamespaces[usingNamespaces.size() - 1]), "abc"); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](const auto& Scope) { + auto Str = clang_scope_getName(Scope); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; - //EXPECT_EQ(Cpp::GetName(usingNamespaces[0]), "runtime"); - EXPECT_EQ(Cpp::GetName(usingNamespaces[usingNamespaces.size()-2]), "std"); - EXPECT_EQ(Cpp::GetName(usingNamespaces[usingNamespaces.size()-1]), "abc"); + auto* D = Decls[0]->getASTContext().getTranslationUnitDecl(); + auto* NS = clang_scope_getUsingNamespaces(CXScope{CXScope_Unexposed, D, I}); + EXPECT_EQ(C_API_SHIM(NS->Scopes[NS->Count - 2]), "std"); + EXPECT_EQ(C_API_SHIM(NS->Scopes[NS->Count - 1]), "abc"); + clang_disposeScopeSet(NS); + // C++ API std::string code1 = R"( int x; )"; @@ -360,6 +616,16 @@ TEST(ScopeReflectionTest, GetUsingNamespaces) { std::vector usingNamespaces1; usingNamespaces1 = Cpp::GetUsingNamespaces(Decls1[0]); EXPECT_EQ(usingNamespaces1.size(), 0); + + // C API + auto NS1 = + clang_scope_getUsingNamespaces(CXScope{CXScope_Unexposed, Decls1[0], I}); + EXPECT_EQ(NS1->Count, 0); + clang_disposeScopeSet(NS1); + + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetGlobalScope) { @@ -368,7 +634,7 @@ TEST(ScopeReflectionTest, GetGlobalScope) { } TEST(ScopeReflectionTest, GetUnderlyingScope) { - std::vector Decls; + std::vector Decls; std::string code = R"( namespace N { class C {}; @@ -383,7 +649,26 @@ TEST(ScopeReflectionTest, GetUnderlyingScope) { 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[2])), "INT"); - EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetUnderlyingScope(nullptr)), ""); + EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetUnderlyingScope(nullptr)), + ""); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + auto Scope = + clang_scope_getUnderlyingScope(CXScope{CXScope_Unexposed, Decl, I}); + auto Str = clang_scope_getQualifiedName(Scope); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM(Decls[0]), "N"); + EXPECT_EQ(C_API_SHIM(Decls[1]), "N::C"); + EXPECT_EQ(C_API_SHIM(Decls[2]), "INT"); + EXPECT_EQ(C_API_SHIM(nullptr), ""); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetScope) { @@ -410,6 +695,28 @@ TEST(ScopeReflectionTest, GetScope) { EXPECT_EQ(Cpp::GetQualifiedName(cl_C), "N::C"); EXPECT_EQ(Cpp::GetQualifiedName(td_T), "T"); EXPECT_EQ(Cpp::GetQualifiedName(non_existent), ""); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](const auto& Scope) { + auto Str = clang_scope_getQualifiedName(Scope); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + auto GS = clang_scope_getGlobalScope(I); + auto NS_N = clang_scope_getScope("N", GS); + auto CL_C = clang_scope_getScope("C", NS_N); + auto TD_T = clang_scope_getScope("T", GS); + auto NON_EXISTENT = clang_scope_getScope("sum", GS); + EXPECT_EQ(C_API_SHIM(GS), ""); + EXPECT_EQ(C_API_SHIM(NS_N), "N"); + EXPECT_EQ(C_API_SHIM(CL_C), "N::C"); + EXPECT_EQ(C_API_SHIM(TD_T), "T"); + EXPECT_EQ(C_API_SHIM(NON_EXISTENT), ""); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetScopefromCompleteName) { @@ -426,9 +733,13 @@ TEST(ScopeReflectionTest, GetScopefromCompleteName) { 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_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"); } TEST(ScopeReflectionTest, GetNamed) { @@ -460,13 +771,52 @@ 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"); + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](const auto& Scope) { + auto Str = clang_scope_getQualifiedName(Scope); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + auto GS = clang_scope_getGlobalScope(I); + auto NS_N1 = clang_scope_getNamed("N1", GS); + auto NS_N2 = clang_scope_getNamed("N2", NS_N1); + auto CL_C = clang_scope_getNamed("C", NS_N2); + auto EN_E = clang_scope_getScope("E", CL_C); + + EXPECT_EQ(C_API_SHIM(NS_N1), "N1"); + EXPECT_EQ(C_API_SHIM(NS_N2), "N1::N2"); + EXPECT_EQ(C_API_SHIM(CL_C), "N1::N2::C"); + EXPECT_EQ(C_API_SHIM(clang_scope_getNamed("i", CL_C)), "N1::N2::C::i"); + EXPECT_EQ(C_API_SHIM(EN_E), "N1::N2::C::E"); + EXPECT_EQ(C_API_SHIM(clang_scope_getNamed("A", EN_E)), "N1::N2::C::A"); + EXPECT_EQ(C_API_SHIM(clang_scope_getNamed("B", EN_E)), "N1::N2::C::B"); + EXPECT_EQ(C_API_SHIM(clang_scope_getNamed("A", CL_C)), "N1::N2::C::A"); + EXPECT_EQ(C_API_SHIM(clang_scope_getNamed("B", CL_C)), "N1::N2::C::B"); + EXPECT_EQ(C_API_SHIM(clang_scope_getNamed("S", CL_C)), "N1::N2::C::S"); + + // C++ API Interp->process("#include "); 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); + Cpp::TCppScope_t std_string_npos_var = + Cpp::GetNamed("npos", std_string_class); EXPECT_EQ(Cpp::GetQualifiedName(std_ns), "std"); EXPECT_EQ(Cpp::GetQualifiedName(std_string_class), "std::string"); - EXPECT_EQ(Cpp::GetQualifiedName(std_string_npos_var), "std::basic_string::npos"); + EXPECT_EQ(Cpp::GetQualifiedName(std_string_npos_var), + "std::basic_string::npos"); + + // C API + auto STD_NS = clang_scope_getNamed("std", GS); + auto STD_STRING_CLASS = clang_scope_getNamed("string", STD_NS); + auto STD_STRING_NPOS_VAR = clang_scope_getNamed("npos", STD_STRING_CLASS); + EXPECT_EQ(C_API_SHIM(STD_NS), "std"); + EXPECT_EQ(C_API_SHIM(STD_STRING_CLASS), "std::string"); + EXPECT_EQ(C_API_SHIM(STD_STRING_NPOS_VAR), "std::basic_string::npos"); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetParentScope) { @@ -499,10 +849,38 @@ TEST(ScopeReflectionTest, GetParentScope) { 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"); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](const auto& Scope) { + auto Str = clang_scope_getQualifiedName(clang_scope_getParentScope(Scope)); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + auto GS = clang_scope_getGlobalScope(I); + auto NS_N1 = clang_scope_getNamed("N1", GS); + auto NS_N2 = clang_scope_getNamed("N2", NS_N1); + auto CL_C = clang_scope_getNamed("C", NS_N2); + auto INT_I = clang_scope_getNamed("i", CL_C); + auto EN_E = clang_scope_getNamed("E", CL_C); + auto EN_A = clang_scope_getNamed("A", EN_E); + auto EN_B = clang_scope_getNamed("B", EN_E); + + EXPECT_EQ(C_API_SHIM(NS_N1), ""); + EXPECT_EQ(C_API_SHIM(NS_N2), "N1"); + EXPECT_EQ(C_API_SHIM(CL_C), "N1::N2"); + EXPECT_EQ(C_API_SHIM(INT_I), "N1::N2::C"); + EXPECT_EQ(C_API_SHIM(EN_E), "N1::N2::C"); + EXPECT_EQ(C_API_SHIM(EN_A), "N1::N2::C::E"); + EXPECT_EQ(C_API_SHIM(EN_B), "N1::N2::C::E"); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetScopeFromType) { - std::vector Decls; + std::vector Decls; std::string code = R"( namespace N { class C {}; @@ -532,21 +910,40 @@ TEST(ScopeReflectionTest, GetScopeFromType) { QualType QT5 = llvm::dyn_cast(Decls[5])->getType(); QualType QT6 = llvm::dyn_cast(Decls[6])->getReturnType(); EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetScopeFromType(QT1.getAsOpaquePtr())), - "N::C"); + "N::C"); EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetScopeFromType(QT2.getAsOpaquePtr())), - "N::S"); - EXPECT_EQ(Cpp::GetScopeFromType(QT3.getAsOpaquePtr()), - (Cpp::TCppScope_t) 0); + "N::S"); + EXPECT_EQ(Cpp::GetScopeFromType(QT3.getAsOpaquePtr()), (Cpp::TCppScope_t)0); EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetScopeFromType(QT4.getAsOpaquePtr())), - "N::C"); + "N::C"); EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetScopeFromType(QT5.getAsOpaquePtr())), "N::E"); EXPECT_EQ(Cpp::GetQualifiedName(Cpp::GetScopeFromType(QT6.getAsOpaquePtr())), "N::C"); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Type) { + auto Scope = + clang_scope_getScopeFromType(CXQualType{CXType_Unexposed, Type, I}); + auto Str = clang_scope_getQualifiedName(Scope); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM(QT1.getAsOpaquePtr()), "N::C"); + EXPECT_EQ(C_API_SHIM(QT2.getAsOpaquePtr()), "N::S"); + EXPECT_EQ(C_API_SHIM(QT3.getAsOpaquePtr()), ""); + EXPECT_EQ(C_API_SHIM(QT4.getAsOpaquePtr()), "N::C"); + EXPECT_EQ(C_API_SHIM(QT5.getAsOpaquePtr()), "N::E"); + EXPECT_EQ(C_API_SHIM(QT6.getAsOpaquePtr()), "N::C"); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetNumBases) { - std::vector Decls; + std::vector Decls; std::string code = R"( class A {}; class B : virtual public A {}; @@ -569,7 +966,7 @@ TEST(ScopeReflectionTest, GetNumBases) { } TEST(ScopeReflectionTest, GetBaseClass) { - std::vector Decls; + std::vector Decls; std::string code = R"( class A {}; class B : virtual public A {}; @@ -593,8 +990,8 @@ TEST(ScopeReflectionTest, GetBaseClass) { GetAllTopLevelDecls(code, Decls); - auto get_base_class_name = [](Decl *D, int i) { - return Cpp::GetQualifiedName(Cpp::GetBaseClass(D, i)); + auto get_base_class_name = [](Decl* D, int i) { + return Cpp::GetQualifiedName(Cpp::GetBaseClass(D, i)); }; EXPECT_EQ(get_base_class_name(Decls[1], 0), "A"); @@ -604,10 +1001,10 @@ TEST(ScopeReflectionTest, GetBaseClass) { EXPECT_EQ(get_base_class_name(Decls[4], 0), "D"); EXPECT_EQ(get_base_class_name(Decls[10], 0), ""); - auto *VD = Cpp::GetNamed("var"); - auto *VT = Cpp::GetVariableType(VD); - auto *TC2_A_Decl = Cpp::GetScopeFromType(VT); - auto *TC1_A_Decl = Cpp::GetBaseClass(TC2_A_Decl, 0); + auto* VD = Cpp::GetNamed("var"); + auto* VT = Cpp::GetVariableType(VD); + auto* TC2_A_Decl = Cpp::GetScopeFromType(VT); + auto* TC1_A_Decl = Cpp::GetBaseClass(TC2_A_Decl, 0); EXPECT_EQ(Cpp::GetCompleteName(TC1_A_Decl), "TC1"); auto* VD1 = Cpp::GetNamed("var1"); @@ -618,7 +1015,7 @@ TEST(ScopeReflectionTest, GetBaseClass) { } TEST(ScopeReflectionTest, IsSubclass) { - std::vector Decls; + std::vector Decls; std::string code = R"( class A {}; class B : virtual public A {}; @@ -660,44 +1057,66 @@ TEST(ScopeReflectionTest, IsSubclass) { } TEST(ScopeReflectionTest, GetBaseClassOffset) { - std::vector Decls; + std::vector Decls; #define Stringify(s) Stringifyx(s) #define Stringifyx(...) #__VA_ARGS__ -#define CODE \ - struct A { int m_a; }; \ - struct B { int m_b; }; \ - struct C : virtual A, virtual B { int m_c; }; \ - struct D : virtual A, virtual B, public C { int m_d; }; \ - struct E : public A, public B { int m_e; }; \ - struct F : public A { int m_f; }; \ - struct G : public F { int m_g; }; +#define CODE \ + struct A { \ + int m_a; \ + }; \ + struct B { \ + int m_b; \ + }; \ + struct C : virtual A, virtual B { \ + int m_c; \ + }; \ + struct D : virtual A, virtual B, public C { \ + int m_d; \ + }; \ + struct E : public A, public B { \ + int m_e; \ + }; \ + struct F : public A { \ + int m_f; \ + }; \ + struct G : public F { \ + int m_g; \ + }; -CODE; + CODE; GetAllTopLevelDecls(Stringify(CODE), Decls); #undef Stringifyx #undef Stringify #undef CODE - auto *c = new C(); - EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[2], Decls[0]), (char *)(A*)c - (char *)c); - EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[2], Decls[1]), (char *)(B*)c - (char *)c); - - auto *d = new D(); - EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[3], Decls[0]), (char *)(A*)d - (char *)d); - EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[3], Decls[1]), (char *)(B*)d - (char *)d); - EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[3], Decls[2]), (char *)(C*)d - (char *)d); - - auto *e = new E(); - EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[4], Decls[0]), (char *)(A*)e - (char *)e); - EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[4], Decls[1]), (char *)(B*)e - (char *)e); - - auto *g = new G(); - EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[6], Decls[0]), (char *)(A*)g - (char *)g); + auto* c = new C(); + EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[2], Decls[0]), + (char*)(A*)c - (char*)c); + EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[2], Decls[1]), + (char*)(B*)c - (char*)c); + + auto* d = new D(); + EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[3], Decls[0]), + (char*)(A*)d - (char*)d); + EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[3], Decls[1]), + (char*)(B*)d - (char*)d); + EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[3], Decls[2]), + (char*)(C*)d - (char*)d); + + auto* e = new E(); + EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[4], Decls[0]), + (char*)(A*)e - (char*)e); + EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[4], Decls[1]), + (char*)(B*)e - (char*)e); + + auto* g = new G(); + EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[6], Decls[0]), + (char*)(A*)g - (char*)g); } TEST(ScopeReflectionTest, GetAllCppNames) { - std::vector Decls; + std::vector Decls; std::string code = R"( class A { int a; }; class B { int b; }; @@ -716,14 +1135,15 @@ TEST(ScopeReflectionTest, GetAllCppNames) { GetAllTopLevelDecls(code, Decls); - auto test_get_all_cpp_names = [](Decl *D, const std::vector &truth_names) { - auto names = Cpp::GetAllCppNames(D); - EXPECT_EQ(names.size(), truth_names.size()); + auto test_get_all_cpp_names = + [](Decl* D, const std::vector& truth_names) { + auto names = Cpp::GetAllCppNames(D); + EXPECT_EQ(names.size(), truth_names.size()); - for (unsigned i = 0; i < truth_names.size() && i < names.size(); i++) { - EXPECT_EQ(names[i], truth_names[i]); - } - }; + for (unsigned i = 0; i < truth_names.size() && i < names.size(); i++) { + EXPECT_EQ(names[i], truth_names[i]); + } + }; test_get_all_cpp_names(Decls[0], {"a"}); test_get_all_cpp_names(Decls[1], {"b"}); @@ -734,7 +1154,7 @@ TEST(ScopeReflectionTest, GetAllCppNames) { } TEST(ScopeReflectionTest, InstantiateNNTPClassTemplate) { - std::vector Decls; + std::vector Decls; std::string code = R"( template struct Factorial { @@ -748,7 +1168,7 @@ TEST(ScopeReflectionTest, InstantiateNNTPClassTemplate) { GetAllTopLevelDecls(code, Decls); - ASTContext &C = Interp->getCI()->getASTContext(); + ASTContext& C = Interp->getCI()->getASTContext(); Cpp::TCppType_t IntTy = C.IntTy.getAsOpaquePtr(); std::vector args1 = {{IntTy, "5"}}; EXPECT_TRUE(Cpp::InstantiateTemplate(Decls[0], args1.data(), @@ -815,7 +1235,7 @@ TEST(ScopeReflectionTest, InstantiateTemplateFunctionFromString) { } TEST(ScopeReflectionTest, InstantiateTemplate) { - std::vector Decls; + std::vector Decls; std::string code = R"( template class AllDefault { @@ -855,13 +1275,13 @@ TEST(ScopeReflectionTest, InstantiateTemplate) { )"; GetAllTopLevelDecls(code, Decls); - ASTContext &C = Interp->getCI()->getASTContext(); + ASTContext& C = Interp->getCI()->getASTContext(); std::vector args1 = {C.IntTy.getAsOpaquePtr()}; auto Instance1 = Cpp::InstantiateTemplate(Decls[0], args1.data(), /*type_size*/ args1.size()); EXPECT_TRUE(isa((Decl*)Instance1)); - auto *CTSD1 = static_cast(Instance1); + auto* CTSD1 = static_cast(Instance1); EXPECT_TRUE(CTSD1->hasDefinition()); TemplateArgument TA1 = CTSD1->getTemplateArgs().get(0); EXPECT_TRUE(TA1.getAsType()->isIntegerType()); @@ -870,7 +1290,7 @@ TEST(ScopeReflectionTest, InstantiateTemplate) { auto Instance2 = Cpp::InstantiateTemplate(Decls[1], nullptr, /*type_size*/ 0); EXPECT_TRUE(isa((Decl*)Instance2)); - auto *CTSD2 = static_cast(Instance2); + auto* CTSD2 = static_cast(Instance2); EXPECT_TRUE(CTSD2->hasDefinition()); TemplateArgument TA2 = CTSD2->getTemplateArgs().get(0); EXPECT_TRUE(TA2.getAsType()->isIntegerType()); @@ -879,7 +1299,7 @@ TEST(ScopeReflectionTest, InstantiateTemplate) { auto Instance3 = Cpp::InstantiateTemplate(Decls[2], args3.data(), /*type_size*/ args3.size()); EXPECT_TRUE(isa((Decl*)Instance3)); - auto *CTSD3 = static_cast(Instance3); + auto* CTSD3 = static_cast(Instance3); EXPECT_TRUE(CTSD3->hasDefinition()); TemplateArgument TA3_0 = CTSD3->getTemplateArgs().get(0); TemplateArgument TA3_1 = CTSD3->getTemplateArgs().get(1); @@ -892,12 +1312,12 @@ TEST(ScopeReflectionTest, InstantiateTemplate) { "C1::C1(const C0 &val)"); std::vector args4 = {C.IntTy.getAsOpaquePtr(), - {C.IntTy.getAsOpaquePtr(), "3"}}; + {C.IntTy.getAsOpaquePtr(), "3"}}; auto Instance4 = Cpp::InstantiateTemplate(Decls[3], args4.data(), /*type_size*/ args4.size()); EXPECT_TRUE(isa((Decl*)Instance4)); - auto *CTSD4 = static_cast(Instance4); + auto* CTSD4 = static_cast(Instance4); EXPECT_TRUE(CTSD4->hasDefinition()); TemplateArgument TA4_0 = CTSD4->getTemplateArgs().get(0); TemplateArgument TA4_1 = CTSD4->getTemplateArgs().get(1); @@ -906,7 +1326,7 @@ TEST(ScopeReflectionTest, InstantiateTemplate) { } TEST(ScopeReflectionTest, GetClassTemplateInstantiationArgs) { - std::vector Decls; + std::vector Decls; std::string code = R"( template struct __Cppyy_AppendTypesSlow {}; __Cppyy_AppendTypesSlow v1; @@ -916,14 +1336,14 @@ TEST(ScopeReflectionTest, GetClassTemplateInstantiationArgs) { GetAllTopLevelDecls(code, Decls); - auto *v1 = Cpp::GetNamed("v1"); - auto *v2 = Cpp::GetNamed("v2"); - auto *v3 = Cpp::GetNamed("v3"); + auto* v1 = Cpp::GetNamed("v1"); + auto* v2 = Cpp::GetNamed("v2"); + auto* v3 = Cpp::GetNamed("v3"); EXPECT_TRUE(v1 && v2 && v3); - auto *v1_class = Cpp::GetScopeFromType(Cpp::GetVariableType(v1)); - auto *v2_class = Cpp::GetScopeFromType(Cpp::GetVariableType(v2)); - auto *v3_class = Cpp::GetScopeFromType(Cpp::GetVariableType(v3)); + auto* v1_class = Cpp::GetScopeFromType(Cpp::GetVariableType(v1)); + auto* v2_class = Cpp::GetScopeFromType(Cpp::GetVariableType(v2)); + auto* v3_class = Cpp::GetScopeFromType(Cpp::GetVariableType(v3)); EXPECT_TRUE(v1_class && v2_class && v3_class); std::vector instance_types; @@ -942,10 +1362,9 @@ TEST(ScopeReflectionTest, GetClassTemplateInstantiationArgs) { EXPECT_TRUE(instance_types.size() == 0); } - TEST(ScopeReflectionTest, IncludeVector) { if (llvm::sys::RunningOnValgrind()) - GTEST_SKIP() << "XFAIL due to Valgrind report"; + GTEST_SKIP() << "XFAIL due to Valgrind report"; std::string code = R"( #include #include From 3160a20bf7b770034bc502cac9a743591d8ea388 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Tue, 18 Jun 2024 00:01:56 +0900 Subject: [PATCH 12/23] Add more tests for ScopeReflection --- unittests/CppInterOp/ScopeReflectionTest.cpp | 112 +++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index d397cb38f..b4145f4a2 100644 --- a/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -963,6 +963,21 @@ TEST(ScopeReflectionTest, GetNumBases) { // FIXME: Perhaps we should have a special number or error out as this // operation is not well defined if a class has no definition. EXPECT_EQ(Cpp::GetNumBases(Decls[5]), 0); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_getNumBases(CXScope{CXScope_Unexposed, Decl, I}); + }; + EXPECT_EQ(C_API_SHIM(Decls[0]), 0); + EXPECT_EQ(C_API_SHIM(Decls[1]), 1); + EXPECT_EQ(C_API_SHIM(Decls[2]), 1); + EXPECT_EQ(C_API_SHIM(Decls[3]), 2); + EXPECT_EQ(C_API_SHIM(Decls[4]), 1); + EXPECT_EQ(C_API_SHIM(Decls[5]), 0); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetBaseClass) { @@ -1012,6 +1027,40 @@ TEST(ScopeReflectionTest, GetBaseClass) { auto* TC3_A_Decl = Cpp::GetScopeFromType(VT1); auto* A_class = Cpp::GetBaseClass(TC3_A_Decl, 0); EXPECT_EQ(Cpp::GetCompleteName(A_class), "A"); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl, int i) { + auto Scope = + clang_scope_getBaseClass(CXScope{CXScope_Unexposed, Decl, I}, i); + auto Str = clang_scope_getQualifiedName(Scope); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM(Decls[1], 0), "A"); + EXPECT_EQ(C_API_SHIM(Decls[2], 0), "A"); + EXPECT_EQ(C_API_SHIM(Decls[3], 0), "B"); + EXPECT_EQ(C_API_SHIM(Decls[3], 1), "C"); + EXPECT_EQ(C_API_SHIM(Decls[4], 0), "D"); + EXPECT_EQ(C_API_SHIM(Decls[10], 0), ""); + + auto C_API_SHIM2 = [&](const char* name) { + auto GS = clang_scope_getGlobalScope(I); + auto VD = clang_scope_getNamed(name, GS); + auto VT = clang_scope_getVariableType(VD); + auto TC2_A_Decl = clang_scope_getScopeFromType(VT); + auto TC1_A_Decl = clang_scope_getBaseClass(TC2_A_Decl, 0); + auto Str = clang_scope_getCompleteName(TC1_A_Decl); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM2("var"), "TC1"); + EXPECT_EQ(C_API_SHIM2("var1"), "A"); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, IsSubclass) { @@ -1054,6 +1103,38 @@ TEST(ScopeReflectionTest, IsSubclass) { EXPECT_TRUE(Cpp::IsSubclass(Decls[4], Decls[4])); EXPECT_FALSE(Cpp::IsSubclass(Decls[4], Decls[5])); EXPECT_FALSE(Cpp::IsSubclass(Decls[4], nullptr)); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto D, auto B) { + return clang_scope_isSubclass(CXScope{CXScope_Unexposed, D, I}, + CXScope{CXScope_Unexposed, B, I}); + }; + EXPECT_FALSE(C_API_SHIM(Decls[0], Decls[1])); + EXPECT_TRUE(C_API_SHIM(Decls[1], Decls[1])); + EXPECT_FALSE(C_API_SHIM(Decls[2], Decls[1])); + EXPECT_TRUE(C_API_SHIM(Decls[3], Decls[1])); + EXPECT_TRUE(C_API_SHIM(Decls[4], Decls[1])); + EXPECT_FALSE(C_API_SHIM(Decls[0], Decls[2])); + EXPECT_FALSE(C_API_SHIM(Decls[1], Decls[2])); + EXPECT_TRUE(C_API_SHIM(Decls[2], Decls[2])); + EXPECT_TRUE(C_API_SHIM(Decls[3], Decls[2])); + EXPECT_TRUE(C_API_SHIM(Decls[4], Decls[2])); + EXPECT_FALSE(C_API_SHIM(Decls[0], Decls[3])); + EXPECT_FALSE(C_API_SHIM(Decls[1], Decls[3])); + EXPECT_FALSE(C_API_SHIM(Decls[2], Decls[3])); + EXPECT_TRUE(C_API_SHIM(Decls[3], Decls[3])); + EXPECT_TRUE(C_API_SHIM(Decls[4], Decls[3])); + EXPECT_FALSE(C_API_SHIM(Decls[0], Decls[4])); + EXPECT_FALSE(C_API_SHIM(Decls[1], Decls[4])); + EXPECT_FALSE(C_API_SHIM(Decls[2], Decls[4])); + EXPECT_FALSE(C_API_SHIM(Decls[3], Decls[4])); + EXPECT_TRUE(C_API_SHIM(Decls[4], Decls[4])); + EXPECT_FALSE(C_API_SHIM(Decls[4], Decls[5])); + EXPECT_FALSE(C_API_SHIM(Decls[4], nullptr)); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetBaseClassOffset) { @@ -1113,6 +1194,24 @@ TEST(ScopeReflectionTest, GetBaseClassOffset) { auto* g = new G(); EXPECT_EQ(Cpp::GetBaseClassOffset(Decls[6], Decls[0]), (char*)(A*)g - (char*)g); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto D, auto B) { + return clang_scope_getBaseClassOffset(CXScope{CXScope_Unexposed, D, I}, + CXScope{CXScope_Unexposed, B, I}); + }; + EXPECT_EQ(C_API_SHIM(Decls[2], Decls[0]), (char*)(A*)c - (char*)c); + EXPECT_EQ(C_API_SHIM(Decls[2], Decls[1]), (char*)(B*)c - (char*)c); + EXPECT_EQ(C_API_SHIM(Decls[3], Decls[0]), (char*)(A*)d - (char*)d); + EXPECT_EQ(C_API_SHIM(Decls[3], Decls[1]), (char*)(B*)d - (char*)d); + EXPECT_EQ(C_API_SHIM(Decls[3], Decls[2]), (char*)(C*)d - (char*)d); + EXPECT_EQ(C_API_SHIM(Decls[4], Decls[0]), (char*)(A*)e - (char*)e); + EXPECT_EQ(C_API_SHIM(Decls[4], Decls[1]), (char*)(B*)e - (char*)e); + EXPECT_EQ(C_API_SHIM(Decls[6], Decls[0]), (char*)(A*)g - (char*)g); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, GetAllCppNames) { @@ -1173,6 +1272,19 @@ TEST(ScopeReflectionTest, InstantiateNNTPClassTemplate) { std::vector args1 = {{IntTy, "5"}}; EXPECT_TRUE(Cpp::InstantiateTemplate(Decls[0], args1.data(), /*type_size*/ args1.size())); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + CXTemplateArgInfo Args1[] = {{IntTy, "5"}}; + auto C_API_SHIM = [&](auto Decl) { + return clang_scope_instantiateTemplate(CXScope{CXScope_Function, Decl, I}, + Args1, 1) + .data; + }; + EXPECT_NE(C_API_SHIM(Decls[0]), nullptr); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(ScopeReflectionTest, InstantiateVarTemplate) { From e29df37486c9141847b46fd7fd391eb398785bcd Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Tue, 18 Jun 2024 00:25:03 +0900 Subject: [PATCH 13/23] Add tests for TypeReflection --- unittests/CppInterOp/TypeReflectionTest.cpp | 259 ++++++++++++++++---- 1 file changed, 208 insertions(+), 51 deletions(-) diff --git a/unittests/CppInterOp/TypeReflectionTest.cpp b/unittests/CppInterOp/TypeReflectionTest.cpp index 0d286e18f..9d819a233 100644 --- a/unittests/CppInterOp/TypeReflectionTest.cpp +++ b/unittests/CppInterOp/TypeReflectionTest.cpp @@ -1,8 +1,10 @@ #include "Utils.h" +#include "clang-c/CXCppInterOp.h" + #include "clang/AST/ASTContext.h" -#include "clang/Interpreter/CppInterOp.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/CppInterOp.h" #include "clang/Sema/Sema.h" #include "gtest/gtest.h" @@ -12,7 +14,7 @@ using namespace llvm; using namespace clang; TEST(TypeReflectionTest, GetTypeAsString) { - std::vector Decls; + std::vector Decls; std::string code = R"( namespace N { class C {}; @@ -40,20 +42,38 @@ TEST(TypeReflectionTest, GetTypeAsString) { QualType QT5 = llvm::dyn_cast(Decls[5])->getType(); QualType QT6 = llvm::dyn_cast(Decls[6])->getType(); QualType QT7 = llvm::dyn_cast(Decls[7])->getType(); - EXPECT_EQ(Cpp::GetTypeAsString(QT1.getAsOpaquePtr()), - "N::C"); - EXPECT_EQ(Cpp::GetTypeAsString(QT2.getAsOpaquePtr()), - "N::S"); + EXPECT_EQ(Cpp::GetTypeAsString(QT1.getAsOpaquePtr()), "N::C"); + EXPECT_EQ(Cpp::GetTypeAsString(QT2.getAsOpaquePtr()), "N::S"); EXPECT_EQ(Cpp::GetTypeAsString(QT3.getAsOpaquePtr()), "int"); EXPECT_EQ(Cpp::GetTypeAsString(QT4.getAsOpaquePtr()), "char"); EXPECT_EQ(Cpp::GetTypeAsString(QT5.getAsOpaquePtr()), "char &"); EXPECT_EQ(Cpp::GetTypeAsString(QT6.getAsOpaquePtr()), "const char *"); EXPECT_EQ(Cpp::GetTypeAsString(QT7.getAsOpaquePtr()), "char[4]"); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Type) { + auto Ty = CXQualType{CXType_Unexposed, Type.getAsOpaquePtr(), I}; + auto Str = clang_qualtype_getTypeAsString(Ty); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM(QT1), "N::C"); + EXPECT_EQ(C_API_SHIM(QT2), "N::S"); + EXPECT_EQ(C_API_SHIM(QT3), "int"); + EXPECT_EQ(C_API_SHIM(QT4), "char"); + EXPECT_EQ(C_API_SHIM(QT5), "char &"); + EXPECT_EQ(C_API_SHIM(QT6), "const char *"); + EXPECT_EQ(C_API_SHIM(QT7), "char[4]"); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(TypeReflectionTest, GetSizeOfType) { - std::vector Decls; - std::string code = R"( + std::vector Decls; + std::string code = R"( struct S { int a; double b; @@ -75,11 +95,26 @@ TEST(TypeReflectionTest, GetSizeOfType) { EXPECT_EQ(Cpp::GetSizeOfType(Cpp::GetVariableType(Decls[4])), 16); EXPECT_EQ(Cpp::GetSizeOfType(Cpp::GetTypeFromScope(Decls[5])), 0); EXPECT_EQ(Cpp::GetSizeOfType(Cpp::GetVariableType(Decls[6])), 8); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + auto Ty = clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decl, I}); + return clang_qualtype_getSizeOfType(Ty); + }; + EXPECT_EQ(C_API_SHIM(Decls[1]), 1); + EXPECT_EQ(C_API_SHIM(Decls[2]), 4); + EXPECT_EQ(C_API_SHIM(Decls[3]), 8); + EXPECT_EQ(C_API_SHIM(Decls[4]), 16); + EXPECT_EQ(C_API_SHIM(Decls[6]), 8); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(TypeReflectionTest, GetCanonicalType) { - std::vector Decls; - std::string code = R"( + std::vector Decls; + std::string code = R"( typedef int I; typedef double D; @@ -98,12 +133,29 @@ TEST(TypeReflectionTest, GetCanonicalType) { EXPECT_EQ(Cpp::GetTypeAsString(D3), "D"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetCanonicalType(D3)), "double"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetCanonicalType(D4)), "NULL TYPE"); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Type) { + auto Ty = + clang_qualtype_getCanonicalType(CXQualType{CXType_Unexposed, Type, I}); + auto Str = clang_qualtype_getTypeAsString(Ty); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM(D2), "int"); + EXPECT_EQ(C_API_SHIM(D3), "double"); + EXPECT_EQ(C_API_SHIM(D4), "NULL TYPE"); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(TypeReflectionTest, GetType) { Cpp::CreateInterpreter(); - std::string code = R"( + std::string code = R"( class A {}; )"; @@ -112,21 +164,53 @@ TEST(TypeReflectionTest, GetType) { EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("int")), "int"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("double")), "double"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("A")), "A"); - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("unsigned char")), "unsigned char"); - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("signed char")),"signed char"); - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("unsigned short")), "unsigned short"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("unsigned char")), + "unsigned char"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("signed char")), "signed char"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("unsigned short")), + "unsigned short"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("unsigned int")), "unsigned int"); - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("unsigned long")),"unsigned long"); - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("unsigned long long")), "unsigned long long"); - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("signed short")),"short"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("unsigned long")), + "unsigned long"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("unsigned long long")), + "unsigned long long"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("signed short")), "short"); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("signed int")), "int"); - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("signed long")),"long"); - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("signed long long")),"long long"); - EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("struct")),"NULL TYPE"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("signed long")), "long"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("signed long long")), + "long long"); + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetType("struct")), "NULL TYPE"); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](const char* name) { + auto Ty = clang_qualtype_getType(I, name); + auto Str = clang_qualtype_getTypeAsString(Ty); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM("int"), "int"); + EXPECT_EQ(C_API_SHIM("double"), "double"); + EXPECT_EQ(C_API_SHIM("A"), "A"); + EXPECT_EQ(C_API_SHIM("unsigned char"), "unsigned char"); + EXPECT_EQ(C_API_SHIM("signed char"), "signed char"); + EXPECT_EQ(C_API_SHIM("unsigned short"), "unsigned short"); + EXPECT_EQ(C_API_SHIM("unsigned int"), "unsigned int"); + EXPECT_EQ(C_API_SHIM("unsigned long"), "unsigned long"); + EXPECT_EQ(C_API_SHIM("unsigned long long"), "unsigned long long"); + EXPECT_EQ(C_API_SHIM("signed short"), "short"); + EXPECT_EQ(C_API_SHIM("signed int"), "int"); + EXPECT_EQ(C_API_SHIM("signed long"), "long"); + EXPECT_EQ(C_API_SHIM("signed long long"), "long long"); + EXPECT_EQ(C_API_SHIM("struct"), "NULL TYPE"); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(TypeReflectionTest, IsRecordType) { - std::vector Decls; + std::vector Decls; std::string code = R"( const int var0 = 0; @@ -161,7 +245,7 @@ TEST(TypeReflectionTest, IsRecordType) { )"; GetAllTopLevelDecls(code, Decls); - auto is_var_of_record_ty = [] (Decl *D) { + auto is_var_of_record_ty = [](Decl* D) { return Cpp::IsRecordType(Cpp::GetVariableType(D)); }; @@ -190,10 +274,44 @@ TEST(TypeReflectionTest, IsRecordType) { EXPECT_FALSE(is_var_of_record_ty(Decls[22])); EXPECT_FALSE(is_var_of_record_ty(Decls[23])); EXPECT_FALSE(is_var_of_record_ty(Decls[24])); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + auto Ty = clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decl, I}); + return clang_scope_isRecordType(Ty); + }; + EXPECT_FALSE(C_API_SHIM(Decls[0])); + EXPECT_FALSE(C_API_SHIM(Decls[1])); + EXPECT_FALSE(C_API_SHIM(Decls[2])); + EXPECT_FALSE(C_API_SHIM(Decls[3])); + EXPECT_FALSE(C_API_SHIM(Decls[4])); + EXPECT_FALSE(C_API_SHIM(Decls[5])); + EXPECT_FALSE(C_API_SHIM(Decls[6])); + EXPECT_FALSE(C_API_SHIM(Decls[7])); + EXPECT_FALSE(C_API_SHIM(Decls[8])); + EXPECT_FALSE(C_API_SHIM(Decls[9])); + EXPECT_FALSE(C_API_SHIM(Decls[10])); + EXPECT_FALSE(C_API_SHIM(Decls[11])); + EXPECT_TRUE(C_API_SHIM(Decls[13])); + EXPECT_FALSE(C_API_SHIM(Decls[14])); + EXPECT_FALSE(C_API_SHIM(Decls[15])); + EXPECT_FALSE(C_API_SHIM(Decls[16])); + EXPECT_FALSE(C_API_SHIM(Decls[17])); + EXPECT_FALSE(C_API_SHIM(Decls[18])); + EXPECT_TRUE(C_API_SHIM(Decls[19])); + EXPECT_FALSE(C_API_SHIM(Decls[20])); + EXPECT_FALSE(C_API_SHIM(Decls[21])); + EXPECT_FALSE(C_API_SHIM(Decls[22])); + EXPECT_FALSE(C_API_SHIM(Decls[23])); + EXPECT_FALSE(C_API_SHIM(Decls[24])); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(TypeReflectionTest, GetUnderlyingType) { - std::vector Decls; + std::vector Decls; std::string code = R"( const int var0 = 0; @@ -234,8 +352,9 @@ TEST(TypeReflectionTest, GetUnderlyingType) { E evar0 = e1; )"; GetAllTopLevelDecls(code, Decls); - auto get_underly_var_type_as_str = [] (Decl *D) { - return Cpp::GetTypeAsString(Cpp::GetUnderlyingType(Cpp::GetVariableType(D))); + auto get_underly_var_type_as_str = [](Decl* D) { + return Cpp::GetTypeAsString( + Cpp::GetUnderlyingType(Cpp::GetVariableType(D))); }; EXPECT_EQ(get_underly_var_type_as_str(Decls[0]), "int"); EXPECT_EQ(get_underly_var_type_as_str(Decls[1]), "int"); @@ -268,10 +387,55 @@ TEST(TypeReflectionTest, GetUnderlyingType) { EXPECT_EQ(get_underly_var_type_as_str(Decls[28]), "C"); EXPECT_EQ(get_underly_var_type_as_str(Decls[30]), "E"); + + // C API + auto I = clang_createInterpreterFromPtr(Cpp::GetInterpreter()); + auto C_API_SHIM = [&](auto Decl) { + auto Ty = clang_scope_getVariableType(CXScope{CXScope_Unexposed, Decl, I}); + auto Str = + clang_qualtype_getTypeAsString(clang_qualtype_getUnderlyingType(Ty)); + auto Res = std::string(clang_getCString(Str)); + clang_disposeString(Str); + return Res; + }; + EXPECT_EQ(C_API_SHIM(Decls[0]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[1]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[2]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[3]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[4]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[5]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[6]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[7]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[8]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[9]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[10]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[11]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[12]), "int"); + EXPECT_EQ(C_API_SHIM(Decls[13]), "int"); + + EXPECT_EQ(C_API_SHIM(Decls[15]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[16]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[17]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[18]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[19]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[20]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[21]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[22]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[23]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[24]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[25]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[26]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[27]), "C"); + EXPECT_EQ(C_API_SHIM(Decls[28]), "C"); + + EXPECT_EQ(C_API_SHIM(Decls[30]), "E"); + // Clean up resources + clang_interpreter_takeInterpreterAsPtr(I); + clang_interpreter_dispose(I); } TEST(TypeReflectionTest, IsUnderlyingTypeRecordType) { - std::vector Decls; + std::vector Decls; std::string code = R"( const int var0 = 0; @@ -306,7 +470,7 @@ TEST(TypeReflectionTest, IsUnderlyingTypeRecordType) { )"; GetAllTopLevelDecls(code, Decls); - auto is_var_of_underly_record_ty = [] (Decl *D) { + auto is_var_of_underly_record_ty = [](Decl* D) { return Cpp::IsRecordType(Cpp::GetUnderlyingType(Cpp::GetVariableType(D))); }; @@ -340,7 +504,7 @@ TEST(TypeReflectionTest, IsUnderlyingTypeRecordType) { TEST(TypeReflectionTest, GetComplexType) { Cpp::CreateInterpreter(); - auto get_complex_type_as_string = [&](const std::string &element_type) { + auto get_complex_type_as_string = [&](const std::string& element_type) { auto ElementQT = Cpp::GetType(element_type); auto ComplexQT = Cpp::GetComplexType(ElementQT); return Cpp::GetTypeAsString(Cpp::GetCanonicalType(ComplexQT)); @@ -352,14 +516,14 @@ TEST(TypeReflectionTest, GetComplexType) { } TEST(TypeReflectionTest, GetTypeFromScope) { - std::vector Decls; + std::vector Decls; - std::string code = R"( + std::string code = R"( class C {}; struct S {}; int a = 10; )"; - + GetAllTopLevelDecls(code, Decls); EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetTypeFromScope(Decls[0])), "C"); @@ -369,7 +533,7 @@ TEST(TypeReflectionTest, GetTypeFromScope) { } TEST(TypeReflectionTest, IsTypeDerivedFrom) { - std::vector Decls; + std::vector Decls; std::string code = R"( class A {}; @@ -406,7 +570,7 @@ TEST(TypeReflectionTest, IsTypeDerivedFrom) { } TEST(TypeReflectionTest, GetDimensions) { - std::vector Decls, SubDecls; + std::vector Decls, SubDecls; std::string code = R"( int a; @@ -438,8 +602,7 @@ TEST(TypeReflectionTest, GetDimensions) { dims = Cpp::GetDimensions(Cpp::GetVariableType(Decls[0])); truth_dims = std::vector({}); EXPECT_EQ(dims.size(), truth_dims.size()); - for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) - { + for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) { EXPECT_EQ(dims[i], truth_dims[i]); } @@ -447,17 +610,15 @@ TEST(TypeReflectionTest, GetDimensions) { dims = Cpp::GetDimensions(Cpp::GetVariableType(Decls[1])); truth_dims = std::vector({1}); EXPECT_EQ(dims.size(), truth_dims.size()); - for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) - { + for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) { EXPECT_EQ(dims[i], truth_dims[i]); } - + // Variable c dims = Cpp::GetDimensions(Cpp::GetVariableType(Decls[2])); truth_dims = std::vector({1, 2}); EXPECT_EQ(dims.size(), truth_dims.size()); - for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) - { + for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) { EXPECT_EQ(dims[i], truth_dims[i]); } @@ -465,8 +626,7 @@ TEST(TypeReflectionTest, GetDimensions) { dims = Cpp::GetDimensions(Cpp::GetVariableType(Decls[3])); truth_dims = std::vector({1, 2, 3}); EXPECT_EQ(dims.size(), truth_dims.size()); - for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) - { + for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) { EXPECT_EQ(dims[i], truth_dims[i]); } @@ -475,8 +635,7 @@ TEST(TypeReflectionTest, GetDimensions) { dims = Cpp::GetDimensions(Cpp::GetVariableType(SubDecls[1])); truth_dims = std::vector({Cpp::DimensionValue::UNKNOWN_SIZE}); EXPECT_EQ(dims.size(), truth_dims.size()); - for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) - { + for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) { EXPECT_EQ(dims[i], truth_dims[i]); } @@ -485,8 +644,7 @@ TEST(TypeReflectionTest, GetDimensions) { dims = Cpp::GetDimensions(Cpp::GetVariableType(SubDecls[3])); truth_dims = std::vector({Cpp::DimensionValue::UNKNOWN_SIZE, 3, 4}); EXPECT_EQ(dims.size(), truth_dims.size()); - for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) - { + for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) { EXPECT_EQ(dims[i], truth_dims[i]); } @@ -494,14 +652,13 @@ TEST(TypeReflectionTest, GetDimensions) { dims = Cpp::GetDimensions(Cpp::GetVariableType(Decls[7])); truth_dims = std::vector({6}); EXPECT_EQ(dims.size(), truth_dims.size()); - for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) - { + for (unsigned i = 0; i < truth_dims.size() && i < dims.size(); i++) { EXPECT_EQ(dims[i], truth_dims[i]); } } TEST(TypeReflectionTest, IsPODType) { - std::vector Decls; + std::vector Decls; std::string code = R"( struct A {}; @@ -548,11 +705,11 @@ TEST(TypeReflectionTest, IsSmartPtrType) { C object(); )"); - auto get_type_from_varname = [&](const std::string &varname) { + auto get_type_from_varname = [&](const std::string& varname) { return Cpp::GetVariableType(Cpp::GetNamed(varname)); }; - //EXPECT_TRUE(Cpp::IsSmartPtrType(get_type_from_varname("smart_ptr1"))); + // EXPECT_TRUE(Cpp::IsSmartPtrType(get_type_from_varname("smart_ptr1"))); EXPECT_TRUE(Cpp::IsSmartPtrType(get_type_from_varname("smart_ptr2"))); EXPECT_TRUE(Cpp::IsSmartPtrType(get_type_from_varname("smart_ptr3"))); EXPECT_TRUE(Cpp::IsSmartPtrType(get_type_from_varname("smart_ptr4"))); From 561984564e23f2fa311064013539b5956e7b4f6d Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sat, 22 Jun 2024 11:31:40 +0900 Subject: [PATCH 14/23] Add test for `clang_interpreter_dispose` --- unittests/CppInterOp/InterpreterTest.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/unittests/CppInterOp/InterpreterTest.cpp b/unittests/CppInterOp/InterpreterTest.cpp index e72f26d4c..3bf58bdd8 100644 --- a/unittests/CppInterOp/InterpreterTest.cpp +++ b/unittests/CppInterOp/InterpreterTest.cpp @@ -3,6 +3,8 @@ #include "clang/Interpreter/CppInterOp.h" #include "clang/Basic/Version.h" +#include "clang-c/CXCppInterOp.h" + #include "llvm/ADT/SmallString.h" #include "llvm/Support/Path.h" @@ -92,6 +94,12 @@ TEST(InterpreterTest, CreateInterpreter) { "#endif"); EXPECT_TRUE(Cpp::GetNamed("cpp17")); EXPECT_FALSE(Cpp::GetNamed("cppUnknown")); + + // C API + const char* args[] = {"-std=c++14"}; + auto CXI = clang_createInterpreter(args, 1); + EXPECT_TRUE(CXI); + clang_interpreter_dispose(CXI); } #ifdef LLVM_BINARY_DIR From 73175c5d4be9d8807b15238cdc1fe8f88ab8bba4 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sun, 23 Jun 2024 19:39:24 +0900 Subject: [PATCH 15/23] Add wrapper for `Undo` and fix prototype --- include/clang-c/CXCppInterOp.h | 7 ++++++- lib/Interpreter/CXCppInterOp.cpp | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/clang-c/CXCppInterOp.h b/include/clang-c/CXCppInterOp.h index c1231dfbc..a775cd41d 100644 --- a/include/clang-c/CXCppInterOp.h +++ b/include/clang-c/CXCppInterOp.h @@ -56,6 +56,11 @@ TInterp_t clang_interpreter_getInterpreterAsPtr(CXInterpreter I); */ TInterp_t clang_interpreter_takeInterpreterAsPtr(CXInterpreter I); +/** + * Undo N previous incremental inputs. + */ +CXErrorCode clang_interpreter_Undo(CXInterpreter I, unsigned int N); + /** * Dispose of the given interpreter context. */ @@ -144,7 +149,7 @@ typedef void* CXValue; * * \returns a \c CXValue. */ -CXValue clang_createValue(); +CXValue clang_createValue(void); /** * Dispose of the given CXValue. diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index 28a91c667..4868f7581 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -70,6 +70,10 @@ TInterp_t clang_interpreter_takeInterpreterAsPtr(CXInterpreter I) { return static_cast(I)->Interp.release(); } +CXErrorCode clang_interpreter_Undo(CXInterpreter I, unsigned int N) { + return getInterpreter(I)->Undo(N) ? CXError_Failure : CXError_Success; +} + void clang_interpreter_dispose(CXInterpreter I) { delete I; // NOLINT(*-owning-memory) } @@ -113,7 +117,7 @@ enum CXErrorCode clang_interpreter_process(CXInterpreter I, const char* code) { return CXError_Success; } -CXValue clang_createValue() { +CXValue clang_createValue(void) { #ifdef USE_CLING auto val = std::make_unique(); #else From 2a3c103519d7dd727ed26367196452ed30ad9325 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sun, 23 Jun 2024 20:21:39 +0900 Subject: [PATCH 16/23] fix-up --- include/clang-c/CXCppInterOp.h | 2 +- lib/Interpreter/CXCppInterOp.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/clang-c/CXCppInterOp.h b/include/clang-c/CXCppInterOp.h index a775cd41d..bf36c4eaf 100644 --- a/include/clang-c/CXCppInterOp.h +++ b/include/clang-c/CXCppInterOp.h @@ -59,7 +59,7 @@ TInterp_t clang_interpreter_takeInterpreterAsPtr(CXInterpreter I); /** * Undo N previous incremental inputs. */ -CXErrorCode clang_interpreter_Undo(CXInterpreter I, unsigned int N); +enum CXErrorCode clang_interpreter_Undo(CXInterpreter I, unsigned int N); /** * Dispose of the given interpreter context. diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index 4868f7581..9ab2fc1a8 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -70,7 +70,7 @@ TInterp_t clang_interpreter_takeInterpreterAsPtr(CXInterpreter I) { return static_cast(I)->Interp.release(); } -CXErrorCode clang_interpreter_Undo(CXInterpreter I, unsigned int N) { +enum CXErrorCode clang_interpreter_Undo(CXInterpreter I, unsigned int N) { return getInterpreter(I)->Undo(N) ? CXError_Failure : CXError_Success; } From 5dd4bf2f9462a31b7792901bfe9069ee8592f3ba Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Wed, 26 Jun 2024 22:15:23 +0900 Subject: [PATCH 17/23] misc. updates --- include/clang-c/CXCppInterOp.h | 30 +++++----- lib/Interpreter/CXCppInterOp.cpp | 61 ++++++++++++++------ lib/Interpreter/CppInterOp.cpp | 33 +++-------- unittests/CppInterOp/ScopeReflectionTest.cpp | 2 +- 4 files changed, 65 insertions(+), 61 deletions(-) diff --git a/include/clang-c/CXCppInterOp.h b/include/clang-c/CXCppInterOp.h index bf36c4eaf..76b36ee77 100644 --- a/include/clang-c/CXCppInterOp.h +++ b/include/clang-c/CXCppInterOp.h @@ -358,21 +358,19 @@ bool clang_qualtype_isTypeDerivedFrom(CXQualType derived, CXQualType base); * Describes the kind of entity that a scope refers to. */ enum CXScopeKind { - CXScope_Unexposed = 0, - CXScope_Invalid = 1, - /** The global scope. */ - CXScope_Global = 2, - /** Namespaces. */ - CXScope_Namespace = 3, - /** Function, methods, constructor etc. */ - CXScope_Function = 4, - /** Variables. */ - CXScope_Variable = 5, - /** Enum Constants. */ - CXScope_EnumConstant = 6, - /** Fields. */ - CXScope_Field = 7, - // reserved for future use + CXScope_Unexposed = 1, // FIXME: merge with CXCursorKind? + CXScope_Typedef = 20, + CXScope_Namespace = 22, + CXScope_ClassTemplate = 31, + CXScope_TypeAlias = 36, + CXScope_Invalid = 70, + CXScope_TranslationUnit = 350, + + CXScope_Record, + CXScope_Function, + CXScope_Variable, + CXScope_EnumConstant, + CXScope_Field, }; /** @@ -835,8 +833,6 @@ CXObject clang_construct(CXScope scope, void* arena); * Calls the destructor of object of type \c type. When withFree is true it * calls operator delete/free. * - * \param I The interpreter. - * * \param This The object to destruct. * * \param type The type of the object. diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index 9ab2fc1a8..8452c9fad 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -71,7 +71,11 @@ TInterp_t clang_interpreter_takeInterpreterAsPtr(CXInterpreter I) { } enum CXErrorCode clang_interpreter_Undo(CXInterpreter I, unsigned int N) { +#ifdef USE_CLING + return CXError_Failure; +#else return getInterpreter(I)->Undo(N) ? CXError_Failure : CXError_Success; +#endif // USE_CLING } void clang_interpreter_dispose(CXInterpreter I) { @@ -286,19 +290,6 @@ CXQualType clang_qualtype_getCanonicalType(CXQualType type) { return makeCXQualType(getMeta(type), QT.getCanonicalType()); } -namespace Cpp { -clang::QualType GetType(const std::string& name, clang::Sema& sema); -} // namespace Cpp - -CXQualType clang_qualtype_getType(CXInterpreter I, const char* name) { - auto& S = getInterpreter(I)->getSema(); - const clang::QualType QT = Cpp::GetType(std::string(name), S); - if (QT.isNull()) - return makeCXQualType(I, QT, CXType_Invalid); - - return makeCXQualType(I, QT); -} - CXQualType clang_qualtype_getComplexType(CXQualType eltype) { const auto& C = getInterpreter(eltype)->getSema().getASTContext(); return makeCXQualType(getMeta(eltype), C.getComplexType(getType(eltype))); @@ -353,6 +344,28 @@ static inline compat::Interpreter* getInterpreter(const CXScope& S) { void clang_scope_dump(CXScope S) { getDecl(S)->dump(); } +namespace Cpp { +clang::QualType GetBuiltinType(const std::string& name, clang::Sema& sema); +} // namespace Cpp + +CXQualType clang_qualtype_getType(CXInterpreter I, const char* name) { + auto& S = getInterpreter(I)->getSema(); + const clang::QualType builtin = Cpp::GetBuiltinType(std::string(name), S); + if (!builtin.isNull()) + return makeCXQualType(I, builtin); + + auto scope = clang_scope_getNamed(name, clang_scope_getGlobalScope(I)); + if (isNull(scope)) + return makeCXQualType(I, clang::QualType(), CXType_Invalid); + + if (auto* TD = llvm::dyn_cast_or_null(getDecl(scope))) { + auto QT = clang::QualType(TD->getTypeForDecl(), 0); + return makeCXQualType(I, QT); + } + + return makeCXQualType(I, clang::QualType(), CXType_Invalid); +} + CXQualType clang_scope_getTypeFromScope(CXScope S) { if (isNull(S)) return makeCXQualType(getMeta(S), clang::QualType(), CXType_Invalid); @@ -605,7 +618,7 @@ CXScopeSet* clang_scope_getUsingNamespaces(CXScope S) { CXScope clang_scope_getGlobalScope(CXInterpreter I) { const auto& C = getInterpreter(I)->getSema().getASTContext(); auto* DC = C.getTranslationUnitDecl(); - return makeCXScope(I, DC, CXScope_Global); + return makeCXScope(I, DC, CXScope_TranslationUnit); } CXScope clang_scope_getUnderlyingScope(CXScope S) { @@ -627,11 +640,21 @@ CXScope clang_scope_getScope(const char* name, CXScope parent) { return S; auto* ND = llvm::dyn_cast(getDecl(S)); - if (llvm::isa(ND) || llvm::isa(ND) || - llvm::isa(ND) || - llvm::isa(ND)) { - return makeCXScope(getMeta(S), ND->getCanonicalDecl()); - } + if (llvm::isa(ND)) + return makeCXScope(getMeta(S), ND->getCanonicalDecl(), CXScope_Namespace); + + if (llvm::isa(ND)) + return makeCXScope(getMeta(S), ND->getCanonicalDecl(), CXScope_Typedef); + + if (llvm::isa(ND)) + return makeCXScope(getMeta(S), ND->getCanonicalDecl(), CXScope_TypeAlias); + + if (llvm::isa(ND)) + return makeCXScope(getMeta(S), ND->getCanonicalDecl(), CXScope_Record); + + if (llvm::isa(ND)) + return makeCXScope(getMeta(S), ND->getCanonicalDecl(), + CXScope_ClassTemplate); return S; } diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index ac559432c..b77e0997a 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -571,27 +571,21 @@ namespace Cpp { return GetScope(name.substr(start, end), curr_scope); } - Decl* GetNamedImpl(Sema* sema, const std::string& name, - Decl* parent /*= nullptr*/) { + TCppScope_t GetNamed(const std::string& name, + TCppScope_t parent /*= nullptr*/) { clang::DeclContext *Within = 0; if (parent) { - Decl* D = GetUnderlyingScope(parent); + auto* D = (clang::Decl*)parent; + D = GetUnderlyingScope(D); Within = llvm::dyn_cast(D); } - auto* ND = Cpp_utils::Lookup::Named(sema, name, Within); + auto* ND = Cpp_utils::Lookup::Named(&getSema(), name, Within); if (ND && ND != (clang::NamedDecl*) -1) { - return ND->getCanonicalDecl(); + return (TCppScope_t)(ND->getCanonicalDecl()); } - return nullptr; - } - - TCppScope_t GetNamed(const std::string& name, - TCppScope_t parent /*= nullptr*/) { - auto& sema = getSema(); - auto* D = static_cast(parent); - return GetNamedImpl(&sema, name, D); + return 0; } TCppScope_t GetParentScope(TCppScope_t scope) @@ -1457,17 +1451,8 @@ namespace Cpp { } } - QualType GetType(const std::string& name, Sema& sema) { - QualType builtin = findBuiltinType(name, sema.getASTContext()); - if (!builtin.isNull()) - return builtin; - - auto* D = (Decl*)GetNamedImpl(&sema, name, /* Within= */ 0); - if (auto* TD = llvm::dyn_cast_or_null(D)) { - return QualType(TD->getTypeForDecl(), 0); - } - - return QualType(); + QualType GetBuiltinType(const std::string& name, Sema& sema) { + return findBuiltinType(name, sema.getASTContext()); } TCppType_t GetType(const std::string &name) { diff --git a/unittests/CppInterOp/ScopeReflectionTest.cpp b/unittests/CppInterOp/ScopeReflectionTest.cpp index b4145f4a2..6b18a1785 100644 --- a/unittests/CppInterOp/ScopeReflectionTest.cpp +++ b/unittests/CppInterOp/ScopeReflectionTest.cpp @@ -783,7 +783,7 @@ TEST(ScopeReflectionTest, GetNamed) { auto NS_N1 = clang_scope_getNamed("N1", GS); auto NS_N2 = clang_scope_getNamed("N2", NS_N1); auto CL_C = clang_scope_getNamed("C", NS_N2); - auto EN_E = clang_scope_getScope("E", CL_C); + auto EN_E = clang_scope_getNamed("E", CL_C); EXPECT_EQ(C_API_SHIM(NS_N1), "N1"); EXPECT_EQ(C_API_SHIM(NS_N2), "N1::N2"); From c15be21f04f636ebd334bb9225334d8f3ee5d599 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Tue, 2 Jul 2024 21:14:58 +0900 Subject: [PATCH 18/23] fix-up --- include/clang-c/CXCppInterOp.h | 52 ++++++++++----------- lib/Interpreter/CXCppInterOp.cpp | 80 +++++++++++++++++++++----------- 2 files changed, 78 insertions(+), 54 deletions(-) diff --git a/include/clang-c/CXCppInterOp.h b/include/clang-c/CXCppInterOp.h index 76b36ee77..72fc6e180 100644 --- a/include/clang-c/CXCppInterOp.h +++ b/include/clang-c/CXCppInterOp.h @@ -46,13 +46,12 @@ typedef void* TInterp_t; CXInterpreter clang_createInterpreterFromPtr(TInterp_t I); /** - * Returns a \c TInterp_t. + * Returns a pointer to the underlying interpreter. */ -TInterp_t clang_interpreter_getInterpreterAsPtr(CXInterpreter I); +void* clang_interpreter_getUnderlyingInterpreter(CXInterpreter I); /** - * Similar to \c clang_interpreter_getInterpreterAsPtr() but it takes the - * ownership. + * Returns a \c TInterp_t and takes the ownership. */ TInterp_t clang_interpreter_takeInterpreterAsPtr(CXInterpreter I); @@ -359,6 +358,11 @@ bool clang_qualtype_isTypeDerivedFrom(CXQualType derived, CXQualType base); */ enum CXScopeKind { CXScope_Unexposed = 1, // FIXME: merge with CXCursorKind? + CXScope_Enum = 5, + CXScope_Field = 6, + CXScope_EnumConstant = 7, + CXScope_Function = 8, + CXCursor_Var = 9, CXScope_Typedef = 20, CXScope_Namespace = 22, CXScope_ClassTemplate = 31, @@ -366,11 +370,8 @@ enum CXScopeKind { CXScope_Invalid = 70, CXScope_TranslationUnit = 350, - CXScope_Record, - CXScope_Function, - CXScope_Variable, - CXScope_EnumConstant, - CXScope_Field, + CXScope_Record = 999, + CXScope_CXXRecord, }; /** @@ -857,6 +858,14 @@ void clang_destruct(CXObject This, CXScope S, bool withFree); */ typedef struct CXJitCallImpl* CXJitCall; +/** + * Creates a trampoline function by using the interpreter and returns a uniform + * interface to call it from compiled code. + * + * \returns a \c CXJitCall. + */ +CXJitCall clang_jitcall_create(CXScope func); + /** * Dispose of the given CXJitCall. * @@ -891,32 +900,21 @@ CXJitCallKind clang_jitcall_getKind(CXJitCall J); */ bool clang_jitcall_isValid(CXJitCall J); -typedef struct { - void** data; - size_t numArgs; -} CXJitCallArgList; - /** * Makes a call to a generic function or method. * - * \param[in] J The CXJitCall. + * \param J The CXJitCall. * - * \param[in] result The location where the return result will be placed. + * \param result The location where the return result will be placed. * - * \param[in] args The arguments to pass to the invocation. + * \param args The arguments to pass to the invocation. * - * \param[in] self The 'this pointer' of the object. - */ -void clang_jitcall_invoke(CXJitCall J, void* result, CXJitCallArgList args, - void* self); - -/** - * Creates a trampoline function by using the interpreter and returns a uniform - * interface to call it from compiled code. + * \param n The number of arguments. * - * \returns a \c CXJitCall. + * \param self The 'this pointer' of the object. */ -CXJitCall clang_jitcall_makeFunctionCallable(CXScope func); +void clang_jitcall_invoke(CXJitCall J, void* result, void** args, + unsigned int n, void* self); /** * @} diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index 8452c9fad..eabeccc25 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -62,8 +62,14 @@ CXInterpreter clang_createInterpreterFromPtr(TInterp_t I) { return II; } -TInterp_t clang_interpreter_getInterpreterAsPtr(CXInterpreter I) { - return getInterpreter(I); +void* clang_interpreter_getUnderlyingInterpreter(CXInterpreter I) { +#ifdef USE_CLING + return nullptr; +#else + auto* interp = getInterpreter(I); + auto* clInterp = &static_cast(*interp); + return clInterp; +#endif // USE_CLING } TInterp_t clang_interpreter_takeInterpreterAsPtr(CXInterpreter I) { @@ -251,8 +257,16 @@ bool clang_scope_isPODType(CXQualType type) { } CXQualType clang_qualtype_getIntegerTypeFromEnumType(CXQualType type) { - const void* Ptr = Cpp::GetIntegerTypeFromEnumType(type.data); - return makeCXQualType(getMeta(type), clang::QualType::getFromOpaquePtr(Ptr)); + const clang::QualType QT = getType(type); + if (QT.isNull()) + return makeCXQualType(getMeta(type), clang::QualType(), CXType_Invalid); + + if (auto* ET = QT->getAs()) + return makeCXQualType( + getMeta(type), + ET->getDecl()->getIntegerType()); // TODO: expose type kind? + + return makeCXQualType(getMeta(type), clang::QualType(), CXType_Invalid); } CXQualType clang_qualtype_getUnderlyingType(CXQualType type) { @@ -627,11 +641,11 @@ CXScope clang_scope_getUnderlyingScope(CXScope S) { return S; const clang::QualType QT = TND->getUnderlyingType(); - auto* D = Cpp::GetScopeFromType(QT.getAsOpaquePtr()); - if (!D) + auto D = clang_scope_getScopeFromType(makeCXQualType(getMeta(S), QT)); + if (isNull(D)) return S; - return makeCXScope(getMeta(S), static_cast(D)); + return D; } CXScope clang_scope_getScope(const char* name, CXScope parent) { @@ -676,24 +690,36 @@ CXScope clang_scope_getNamed(const char* name, CXScope parent) { return makeCXScope(getMeta(parent), nullptr, CXScope_Invalid); } -CXScope clang_scope_getParentScope(CXScope parent) { - auto* D = getDecl(parent); +CXScope clang_scope_getParentScope(CXScope scope) { + auto* D = getDecl(scope); if (llvm::isa_and_nonnull(D)) - return makeCXScope(getMeta(parent), nullptr, CXScope_Invalid); + return makeCXScope(getMeta(scope), nullptr, CXScope_Invalid); const auto* ParentDC = D->getDeclContext(); if (!ParentDC) - return makeCXScope(getMeta(parent), nullptr, CXScope_Invalid); + return makeCXScope(getMeta(scope), nullptr, CXScope_Invalid); auto* CD = clang::Decl::castFromDeclContext(ParentDC)->getCanonicalDecl(); - return makeCXScope(getMeta(parent), CD); + return makeCXScope(getMeta(scope), CD); } CXScope clang_scope_getScopeFromType(CXQualType type) { - auto* D = Cpp::GetScopeFromType(type.data); - return makeCXScope(getMeta(type), static_cast(D)); + const clang::QualType QT = getType(type); + if (auto* Type = QT.getCanonicalType().getTypePtrOrNull()) { + Type = Type->getPointeeOrArrayElementType(); + Type = Type->getUnqualifiedDesugaredType(); + if (auto* ET = llvm::dyn_cast(Type)) + return makeCXScope(getMeta(type), ET->getDecl(), CXScope_Enum); + + if (auto* FnType = llvm::dyn_cast(Type)) + Type = const_cast(FnType->getReturnType().getTypePtr()); + + auto* CXXRD = Type->getAsCXXRecordDecl(); + return makeCXScope(getMeta(type), CXXRD, CXScope_CXXRecord); + } + return makeCXScope(getMeta(type), nullptr, CXScope_Invalid); } size_t clang_scope_getNumBases(CXScope S) { @@ -1343,6 +1369,16 @@ void clang_destruct(CXObject This, CXScope S, bool withFree) { Cpp::DestructImpl(*getInterpreter(S), This, getDecl(S), withFree); } +CXJitCall clang_jitcall_create(CXScope func) { + auto J = Cpp::MakeFunctionCallableImpl(getInterpreter(func), getDecl(func)); + auto Ptr = std::make_unique(J); + return reinterpret_cast(Ptr.release()); // NOLINT(*-cast) +} + +void clang_jitcall_dispose(CXJitCall J) { + delete reinterpret_cast(J); // NOLINT(*-owning-memory, *-cast) +} + CXJitCallKind clang_jitcall_getKind(CXJitCall J) { const auto* call = reinterpret_cast(J); // NOLINT(*-cast) return static_cast(call->getKind()); @@ -1352,18 +1388,8 @@ bool clang_jitcall_isValid(CXJitCall J) { return reinterpret_cast(J)->isValid(); // NOLINT(*-cast) } -void clang_jitcall_invoke(CXJitCall J, void* result, CXJitCallArgList args, - void* self) { +void clang_jitcall_invoke(CXJitCall J, void* result, void** args, + unsigned int n, void* self) { const auto* call = reinterpret_cast(J); // NOLINT(*-cast) - call->Invoke(result, {args.data, args.numArgs}, self); -} - -CXJitCall clang_jitcall_makeFunctionCallable(CXScope func) { - auto J = Cpp::MakeFunctionCallableImpl(getInterpreter(func), getDecl(func)); - auto Ptr = std::make_unique(J); - return reinterpret_cast(Ptr.release()); // NOLINT(*-cast) -} - -void clang_jitcall_dispose(CXJitCall J) { - delete reinterpret_cast(J); // NOLINT(*-owning-memory, *-cast) + call->Invoke(result, {args, n}, self); } \ No newline at end of file From e3a9c8b60651d4bd1fc558cbd399768a1b628353 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sun, 21 Jul 2024 19:54:03 +0900 Subject: [PATCH 19/23] Tweak `invoke` API and make JitCall internal --- lib/Interpreter/CXCppInterOp.cpp | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index eabeccc25..1f0331f62 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -1360,6 +1360,12 @@ CXObject clang_construct(CXScope scope, void* arena) { return nullptr; } +void clang_invoke(CXScope func, void* result, void** args, size_t n, + void* self) { + Cpp::MakeFunctionCallableImpl(getInterpreter(func), getDecl(func)) + .Invoke(result, {args, n}, self); +} + namespace Cpp { void DestructImpl(compat::Interpreter& interp, TCppObject_t This, clang::Decl* Class, bool withFree); @@ -1367,29 +1373,4 @@ void DestructImpl(compat::Interpreter& interp, TCppObject_t This, void clang_destruct(CXObject This, CXScope S, bool withFree) { Cpp::DestructImpl(*getInterpreter(S), This, getDecl(S), withFree); -} - -CXJitCall clang_jitcall_create(CXScope func) { - auto J = Cpp::MakeFunctionCallableImpl(getInterpreter(func), getDecl(func)); - auto Ptr = std::make_unique(J); - return reinterpret_cast(Ptr.release()); // NOLINT(*-cast) -} - -void clang_jitcall_dispose(CXJitCall J) { - delete reinterpret_cast(J); // NOLINT(*-owning-memory, *-cast) -} - -CXJitCallKind clang_jitcall_getKind(CXJitCall J) { - const auto* call = reinterpret_cast(J); // NOLINT(*-cast) - return static_cast(call->getKind()); -} - -bool clang_jitcall_isValid(CXJitCall J) { - return reinterpret_cast(J)->isValid(); // NOLINT(*-cast) -} - -void clang_jitcall_invoke(CXJitCall J, void* result, void** args, - unsigned int n, void* self) { - const auto* call = reinterpret_cast(J); // NOLINT(*-cast) - call->Invoke(result, {args, n}, self); } \ No newline at end of file From 954fb3892d787e3601b670c3d797fbdc6e559007 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sun, 21 Jul 2024 20:19:03 +0900 Subject: [PATCH 20/23] fix-up --- include/clang-c/CXCppInterOp.h | 87 ++++++---------------------------- 1 file changed, 15 insertions(+), 72 deletions(-) diff --git a/include/clang-c/CXCppInterOp.h b/include/clang-c/CXCppInterOp.h index 72fc6e180..2d5cafc25 100644 --- a/include/clang-c/CXCppInterOp.h +++ b/include/clang-c/CXCppInterOp.h @@ -831,90 +831,33 @@ void clang_deallocate(CXObject address); CXObject clang_construct(CXScope scope, void* arena); /** - * Calls the destructor of object of type \c type. When withFree is true it - * calls operator delete/free. - * - * \param This The object to destruct. - * - * \param type The type of the object. - * - * \param withFree Whether to call operator delete/free or not. - */ -void clang_destruct(CXObject This, CXScope S, bool withFree); - -/** - * @} - */ - -/** - * \defgroup CPPINTEROP_JITCALL_MANIP JitCall manipulations - * - * @{ - */ - -/** - * An opaque pointer representing CppInterOp's JitCall, a class modeling - * function calls for functions produced by the interpreter in compiled code. - */ -typedef struct CXJitCallImpl* CXJitCall; - -/** - * Creates a trampoline function by using the interpreter and returns a uniform - * interface to call it from compiled code. - * - * \returns a \c CXJitCall. - */ -CXJitCall clang_jitcall_create(CXScope func); - -/** - * Dispose of the given CXJitCall. + * Creates a trampoline function and makes a call to a generic function or + * method. * - * \param J The CXJitCall to dispose. - */ -void clang_jitcall_dispose(CXJitCall J); - -/** - * The kind of the JitCall. - */ -typedef enum { - CXJitCall_Unknown = 0, - CXJitCall_GenericCall = 1, - CXJitCall_DestructorCall = 2, -} CXJitCallKind; - -/** - * Get the kind of the given CXJitCall. + * \param func The function or method to call. * - * \param J The CXJitCall. + * \param result The location where the return result will be placed. * - * \returns the kind of the given CXJitCall. - */ -CXJitCallKind clang_jitcall_getKind(CXJitCall J); - -/** - * Check if the given CXJitCall is valid. + * \param args The arguments to pass to the invocation. * - * \param J The CXJitCall. + * \param n The number of arguments. * - * \returns true if the given CXJitCall is valid. + * \param self The 'this pointer' of the object. */ -bool clang_jitcall_isValid(CXJitCall J); +void clang_invoke(CXScope func, void* result, void** args, size_t n, + void* self); /** - * Makes a call to a generic function or method. - * - * \param J The CXJitCall. - * - * \param result The location where the return result will be placed. + * Calls the destructor of object of type \c type. When withFree is true it + * calls operator delete/free. * - * \param args The arguments to pass to the invocation. + * \param This The object to destruct. * - * \param n The number of arguments. + * \param type The type of the object. * - * \param self The 'this pointer' of the object. + * \param withFree Whether to call operator delete/free or not. */ -void clang_jitcall_invoke(CXJitCall J, void* result, void** args, - unsigned int n, void* self); +void clang_destruct(CXObject This, CXScope S, bool withFree); /** * @} From fd550026712fbc90276a1ab6f0a826a6c7b99bec Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Wed, 28 Aug 2024 21:02:07 +0900 Subject: [PATCH 21/23] Fix `clang_construct` --- lib/Interpreter/CXCppInterOp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index 1f0331f62..d10ebd803 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -1348,12 +1348,12 @@ CXObject clang_construct(CXScope scope, void* arena) { auto* I = getInterpreter(scope); if (const Cpp::JitCall JC = Cpp::MakeFunctionCallableImpl(I, getDecl(Ctor))) { if (arena) { - JC.Invoke(arena, {}, (void*)~0); // Tell Invoke to use placement new. + JC.Invoke(&arena, {}, (void*)~0); // Tell Invoke to use placement new. return arena; } void* obj = nullptr; - JC.Invoke(obj); + JC.Invoke(&obj); return obj; } From 98515e213ba551a0f5b3aaec8344c0ccf3c817d7 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sat, 31 Aug 2024 21:49:49 +0900 Subject: [PATCH 22/23] Make `clang_allocate` API a bit more generic --- lib/Interpreter/CXCppInterOp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Interpreter/CXCppInterOp.cpp b/lib/Interpreter/CXCppInterOp.cpp index d10ebd803..c7485dc69 100644 --- a/lib/Interpreter/CXCppInterOp.cpp +++ b/lib/Interpreter/CXCppInterOp.cpp @@ -1327,8 +1327,8 @@ bool clang_scope_isConstVariable(CXScope var) { return false; } -CXObject clang_allocate(CXScope S) { - return ::operator new(clang_scope_sizeOf(S)); +CXObject clang_allocate(unsigned int n) { + return ::operator new(n); } void clang_deallocate(CXObject address) { ::operator delete(address); } From 8d79c1a0cafe5d2ff6c74afbcfbd1be320caa06b Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Sat, 31 Aug 2024 22:36:31 +0900 Subject: [PATCH 23/23] fix-up --- include/clang-c/CXCppInterOp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/clang-c/CXCppInterOp.h b/include/clang-c/CXCppInterOp.h index 2d5cafc25..6c64dc554 100644 --- a/include/clang-c/CXCppInterOp.h +++ b/include/clang-c/CXCppInterOp.h @@ -817,7 +817,7 @@ typedef void* CXObject; /** * Allocates memory for the given type. */ -CXObject clang_allocate(CXScope S); +CXObject clang_allocate(unsigned int n); /** * Deallocates memory for a given class.