diff --git a/include/CppInterOp/CppInterOp.h b/include/CppInterOp/CppInterOp.h index 95f8a8b8b..d279c6936 100644 --- a/include/CppInterOp/CppInterOp.h +++ b/include/CppInterOp/CppInterOp.h @@ -93,6 +93,18 @@ enum Operator : unsigned char { enum OperatorArity : unsigned char { kUnary = 1, kBinary, kBoth }; +/// Enum modelling CVR qualifiers. +enum QualKind : unsigned char { + Const = 1 << 0, + Volatile = 1 << 1, + Restrict = 1 << 2 +}; + +inline QualKind operator|(QualKind a, QualKind b) { + return static_cast(static_cast(a) | + static_cast(b)); +} + /// 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. @@ -263,6 +275,18 @@ CPPINTEROP_API bool IsEnumConstant(TCppScope_t handle); /// Checks if the passed value is an enum type or not. CPPINTEROP_API bool IsEnumType(TCppType_t type); +/// Checks if the passed type has qual Qualifiers +/// qual can be ORed value of enum QualKind +CPPINTEROP_API bool HasTypeQualifier(TCppType_t type, QualKind qual); + +/// Returns type with the qual Qualifiers removed +/// qual can be ORed value of enum QualKind +CPPINTEROP_API TCppType_t RemoveTypeQualifier(TCppType_t type, QualKind qual); + +/// Returns type with the qual Qualifiers added +/// qual can be ORed value of enum QualKind +CPPINTEROP_API TCppType_t AddTypeQualifier(TCppType_t type, QualKind qual); + /// Extracts enum declarations from a specified scope and stores them in /// vector CPPINTEROP_API void GetEnums(TCppScope_t scope, diff --git a/lib/CppInterOp/CppInterOp.cpp b/lib/CppInterOp/CppInterOp.cpp index 0656a425d..0c2602fc9 100755 --- a/lib/CppInterOp/CppInterOp.cpp +++ b/lib/CppInterOp/CppInterOp.cpp @@ -1612,6 +1612,60 @@ TCppType_t GetCanonicalType(TCppType_t type) { return QT.getCanonicalType().getAsOpaquePtr(); } +bool HasTypeQualifier(TCppType_t type, QualKind qual) { + if (!type) + return false; + + QualType QT = QualType::getFromOpaquePtr(type); + if (qual & QualKind::Const) { + if (!QT.isConstQualified()) + return false; + } + if (qual & QualKind::Volatile) { + if (!QT.isVolatileQualified()) + return false; + } + if (qual & QualKind::Restrict) { + if (!QT.isRestrictQualified()) + return false; + } + return true; +} + +TCppType_t RemoveTypeQualifier(TCppType_t type, QualKind qual) { + if (!type) + return type; + + auto QT = QualType(QualType::getFromOpaquePtr(type)); + if (qual & QualKind::Const) + QT.removeLocalConst(); + if (qual & QualKind::Volatile) + QT.removeLocalVolatile(); + if (qual & QualKind::Restrict) + QT.removeLocalRestrict(); + return QT.getAsOpaquePtr(); +} + +TCppType_t AddTypeQualifier(TCppType_t type, QualKind qual) { + if (!type) + return type; + + auto QT = QualType(QualType::getFromOpaquePtr(type)); + if (qual & QualKind::Const) { + if (!QT.isConstQualified()) + QT.addConst(); + } + if (qual & QualKind::Volatile) { + if (!QT.isVolatileQualified()) + QT.addVolatile(); + } + if (qual & QualKind::Restrict) { + if (!QT.isRestrictQualified()) + QT.addRestrict(); + } + return QT.getAsOpaquePtr(); +} + // Internal functions that are not needed outside the library are // encompassed in an anonymous namespace as follows. This function converts // from a string to the actual type. It is used in the GetType() function. diff --git a/unittests/CppInterOp/TypeReflectionTest.cpp b/unittests/CppInterOp/TypeReflectionTest.cpp index f011899c8..75afefdcb 100644 --- a/unittests/CppInterOp/TypeReflectionTest.cpp +++ b/unittests/CppInterOp/TypeReflectionTest.cpp @@ -611,3 +611,69 @@ TEST(TypeReflectionTest, IsFunctionPointerType) { EXPECT_FALSE( Cpp::IsFunctionPointerType(Cpp::GetVariableType(Cpp::GetNamed("i")))); } + +TEST(TypeReflectionTest, TypeQualifiers) { + Cpp::CreateInterpreter(); + Cpp::Declare(R"( + int *a; + int *__restrict b; + int *const c = 0; + int *volatile d; + int *const volatile e = nullptr; + int *__restrict const f = nullptr; + int *__restrict volatile g; + int *__restrict const volatile h = nullptr; + )"); + + Cpp::TCppType_t a = Cpp::GetVariableType(Cpp::GetNamed("a")); + Cpp::TCppType_t b = Cpp::GetVariableType(Cpp::GetNamed("b")); + Cpp::TCppType_t c = Cpp::GetVariableType(Cpp::GetNamed("c")); + Cpp::TCppType_t d = Cpp::GetVariableType(Cpp::GetNamed("d")); + Cpp::TCppType_t e = Cpp::GetVariableType(Cpp::GetNamed("e")); + Cpp::TCppType_t f = Cpp::GetVariableType(Cpp::GetNamed("f")); + Cpp::TCppType_t g = Cpp::GetVariableType(Cpp::GetNamed("g")); + Cpp::TCppType_t h = Cpp::GetVariableType(Cpp::GetNamed("h")); + + EXPECT_FALSE(Cpp::HasTypeQualifier(nullptr, Cpp::QualKind::Const)); + EXPECT_FALSE(Cpp::RemoveTypeQualifier(nullptr, Cpp::QualKind::Const)); + EXPECT_FALSE(Cpp::AddTypeQualifier(nullptr, Cpp::QualKind::Const)); + + EXPECT_FALSE(Cpp::HasTypeQualifier(a, Cpp::QualKind::Const)); + EXPECT_FALSE(Cpp::HasTypeQualifier(a, Cpp::QualKind::Volatile)); + EXPECT_FALSE(Cpp::HasTypeQualifier(a, Cpp::QualKind::Restrict)); + EXPECT_TRUE(Cpp::HasTypeQualifier(b, Cpp::QualKind::Restrict)); + EXPECT_TRUE(Cpp::HasTypeQualifier(c, Cpp::QualKind::Const)); + EXPECT_TRUE(Cpp::HasTypeQualifier(d, Cpp::QualKind::Volatile)); + EXPECT_TRUE( + Cpp::HasTypeQualifier(e, Cpp::QualKind::Const | Cpp::QualKind::Volatile)); + EXPECT_TRUE( + Cpp::HasTypeQualifier(f, Cpp::QualKind::Const | Cpp::QualKind::Restrict)); + EXPECT_TRUE(Cpp::HasTypeQualifier(g, Cpp::QualKind::Volatile | + Cpp::QualKind::Restrict)); + EXPECT_TRUE(Cpp::HasTypeQualifier(h, Cpp::QualKind::Const | + Cpp::QualKind::Volatile | + Cpp::QualKind::Restrict)); + + EXPECT_EQ(a, Cpp::RemoveTypeQualifier(b, Cpp::QualKind::Restrict)); + EXPECT_EQ(a, Cpp::RemoveTypeQualifier(c, Cpp::QualKind::Const)); + EXPECT_EQ(a, Cpp::RemoveTypeQualifier(d, Cpp::QualKind::Volatile)); + EXPECT_EQ(a, Cpp::RemoveTypeQualifier(e, Cpp::QualKind::Const | + Cpp::QualKind::Volatile)); + EXPECT_EQ(a, Cpp::RemoveTypeQualifier(f, Cpp::QualKind::Const | + Cpp::QualKind::Restrict)); + EXPECT_EQ(a, Cpp::RemoveTypeQualifier(g, Cpp::QualKind::Volatile | + Cpp::QualKind::Restrict)); + EXPECT_EQ(a, Cpp::RemoveTypeQualifier(h, Cpp::QualKind::Const | + Cpp::QualKind::Volatile | + Cpp::QualKind::Restrict)); + EXPECT_EQ(e, Cpp::RemoveTypeQualifier(h, Cpp::QualKind::Restrict)); + EXPECT_EQ(b, Cpp::RemoveTypeQualifier(h, Cpp::QualKind::Const | + Cpp::QualKind::Volatile)); + + EXPECT_EQ(c, Cpp::AddTypeQualifier(a, Cpp::QualKind::Const)); + EXPECT_EQ(d, Cpp::AddTypeQualifier(a, Cpp::QualKind::Volatile)); + EXPECT_EQ(b, Cpp::AddTypeQualifier(a, Cpp::QualKind::Restrict)); + EXPECT_EQ(h, Cpp::AddTypeQualifier(a, Cpp::QualKind::Const | + Cpp::QualKind::Volatile | + Cpp::QualKind::Restrict)); +}