diff --git a/include/clang/Interpreter/CppInterOp.h b/include/clang/Interpreter/CppInterOp.h index 7d1fdb12a..4e9df493b 100644 --- a/include/clang/Interpreter/CppInterOp.h +++ b/include/clang/Interpreter/CppInterOp.h @@ -88,6 +88,8 @@ namespace Cpp { enum OperatorArity { kUnary = 1, kBinary, kBoth }; + enum Signedness { kSigned = 1, kUnsigned, kAny }; + /// A class modeling function calls for functions produced by the interpreter /// in compiled code. It provides an information if we are calling a standard /// function, constructor or destructor. @@ -523,15 +525,32 @@ namespace Cpp { /// Checks if the provided parameter is a Plain Old Data Type (POD). CPPINTEROP_API bool IsPODType(TCppType_t type); + /// Checks if type has an integer representation + CPPINTEROP_API bool IsIntegerType(TCppType_t type, + Signedness s = Signedness::kAny); + + /// Checks if type has a floating representation + CPPINTEROP_API bool IsFloatingType(TCppType_t type); + + /// Checks if two types are the equivalent + /// i.e. have the same canonical type + CPPINTEROP_API bool IsSameType(TCppType_t type_a, TCppType_t type_b); + /// Checks if type is a pointer CPPINTEROP_API bool IsPointerType(TCppType_t type); + /// Checks if type is a void pointer + CPPINTEROP_API bool IsVoidPointerType(TCppType_t type); + /// Get the underlying pointee type CPPINTEROP_API TCppType_t GetPointeeType(TCppType_t type); /// Checks if type is a reference CPPINTEROP_API bool IsReferenceType(TCppType_t type); + /// Get the type handle to the unqualified type + CPPINTEROP_API TCppType_t GetUnqualifiedType(TCppType_t type); + /// Get the type that the reference refers to CPPINTEROP_API TCppType_t GetNonReferenceType(TCppType_t type); diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index 1b9fa943e..5bbe68175 100755 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -1597,11 +1597,44 @@ namespace Cpp { return QT.isPODType(getASTContext()); } + bool IsIntegerType(TCppType_t type, Signedness s) { + if (!type) + return false; + QualType QT = QualType::getFromOpaquePtr(type); + switch (s) { + case Signedness::kAny: + return QT->hasIntegerRepresentation(); + + case Signedness::kSigned: + return QT->hasSignedIntegerRepresentation(); + + case Signedness::kUnsigned: + return QT->hasUnsignedIntegerRepresentation(); + } + return false; + } + + bool IsFloatingType(TCppType_t type) { + QualType QT = QualType::getFromOpaquePtr(type); + return QT->hasFloatingRepresentation(); + } + + bool IsSameType(TCppType_t type_a, TCppType_t type_b) { + clang::QualType QT1 = clang::QualType::getFromOpaquePtr(type_a); + clang::QualType QT2 = clang::QualType::getFromOpaquePtr(type_b); + return getASTContext().hasSameType(QT1, QT2); + } + bool IsPointerType(TCppType_t type) { QualType QT = QualType::getFromOpaquePtr(type); return QT->isPointerType(); } + bool IsVoidPointerType(TCppType_t type) { + QualType QT = QualType::getFromOpaquePtr(type); + return QT->isVoidPointerType(); + } + TCppType_t GetPointeeType(TCppType_t type) { if (!IsPointerType(type)) return nullptr; @@ -1621,8 +1654,17 @@ namespace Cpp { return QT.getNonReferenceType().getAsOpaquePtr(); } + TCppType_t GetUnqualifiedType(TCppType_t type) { + if (!type) + return nullptr; + QualType QT = QualType::getFromOpaquePtr(type); + return QT.getUnqualifiedType().getAsOpaquePtr(); + } + TCppType_t GetUnderlyingType(TCppType_t type) { + if (!type) + return nullptr; QualType QT = QualType::getFromOpaquePtr(type); QT = QT->getCanonicalTypeUnqualified(); diff --git a/unittests/CppInterOp/TypeReflectionTest.cpp b/unittests/CppInterOp/TypeReflectionTest.cpp index 37d884839..2fc2c5a7c 100644 --- a/unittests/CppInterOp/TypeReflectionTest.cpp +++ b/unittests/CppInterOp/TypeReflectionTest.cpp @@ -605,3 +605,111 @@ TEST(TypeReflectionTest, IsFunctionPointerType) { EXPECT_FALSE( Cpp::IsFunctionPointerType(Cpp::GetVariableType(Cpp::GetNamed("i")))); } + +TEST(TypeReflectionTest, IntegerTypes) { + Cpp::CreateInterpreter(); + std::vector Decls; + std::string code = R"( + int a; + int *b; + double c; + enum A { x, y }; + A evar = x; + char k; + long int l; + unsigned int m; + unsigned long n; + )"; + + GetAllTopLevelDecls(code, Decls); + + // Signedness defaults to Any and returns true for both signed and unsigned + // types. + EXPECT_TRUE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[0]))); + EXPECT_FALSE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[1]))); + EXPECT_FALSE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[2]))); + EXPECT_TRUE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[4]))); + EXPECT_TRUE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[5]))); + EXPECT_TRUE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[6]))); + EXPECT_TRUE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[7]), + Cpp::Signedness::kUnsigned)); + EXPECT_FALSE(Cpp::IsIntegerType(Cpp::GetVariableType(Decls[8]), + Cpp::Signedness::kSigned)); +} + +TEST(TypeReflectionTest, VoidPtrType) { + Cpp::CreateInterpreter(); + std::vector Decls; + std::string code = R"( + class A {}; + using VoidPtrType = void*; + VoidPtrType a = nullptr; + void * b = nullptr; + A *pa = nullptr; + )"; + + GetAllTopLevelDecls(code, Decls); + + EXPECT_EQ(Cpp::GetTypeAsString(Cpp::GetVariableType(Decls[2])), + "VoidPtrType"); + EXPECT_TRUE(Cpp::IsVoidPointerType(Cpp::GetVariableType(Decls[2]))); + EXPECT_TRUE(Cpp::IsVoidPointerType(Cpp::GetVariableType(Decls[3]))); + EXPECT_FALSE(Cpp::IsVoidPointerType(Cpp::GetVariableType(Decls[4]))); +} + +TEST(TypeReflectionTest, IsSameType) { + Cpp::CreateInterpreter(); + std::vector Decls; + + std::string code = R"( + #include + #include + + typedef std::va_list VaListAlias; + std::va_list va1; + VaListAlias va2; + + const int ci = 0; + int const ic = 0; + + signed int si1 = 0; + int si2 = 0; + + void *x; + )"; + + GetAllTopLevelDecls(code, Decls); + +#include + + ASTContext& Ctxt = Interp->getCI()->getASTContext(); + + Decls.assign(Decls.end() - 8, Decls.end()); + + EXPECT_TRUE( + Cpp::IsSameType(Cpp::GetType("bool"), Ctxt.BoolTy.getAsOpaquePtr())); + EXPECT_TRUE( + Cpp::IsSameType(Cpp::GetType("float"), Ctxt.FloatTy.getAsOpaquePtr())); + EXPECT_TRUE( + Cpp::IsSameType(Cpp::GetType("long"), Ctxt.LongTy.getAsOpaquePtr())); + EXPECT_TRUE(Cpp::IsSameType(Cpp::GetType("long long"), + Ctxt.LongLongTy.getAsOpaquePtr())); + EXPECT_TRUE( + Cpp::IsSameType(Cpp::GetType("short"), Ctxt.ShortTy.getAsOpaquePtr())); + EXPECT_TRUE(Cpp::IsSameType(Cpp::GetType("char"), + Ctxt.SignedCharTy.getAsOpaquePtr())); + EXPECT_TRUE(Cpp::IsSameType(Cpp::GetType("unsigned char"), + Ctxt.UnsignedCharTy.getAsOpaquePtr())); + EXPECT_TRUE(Cpp::IsSameType(Cpp::GetType("unsigned int"), + Ctxt.UnsignedIntTy.getAsOpaquePtr())); + EXPECT_TRUE(Cpp::IsSameType(Cpp::GetVariableType(Decls[7]), + Ctxt.VoidPtrTy.getAsOpaquePtr())); + + // Expect the typedef to std::va_list to be the same type + EXPECT_TRUE(Cpp::IsSameType(Cpp::GetVariableType(Decls[1]), + Cpp::GetVariableType(Decls[2]))); + EXPECT_TRUE(Cpp::IsSameType(Cpp::GetVariableType(Decls[3]), + Cpp::GetVariableType(Decls[4]))); + EXPECT_TRUE(Cpp::IsSameType(Cpp::GetVariableType(Decls[5]), + Cpp::GetVariableType(Decls[6]))); +}