Skip to content

Add type info interfaces motivated by numba #534

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions include/clang/Interpreter/CppInterOp.h
Original file line number Diff line number Diff line change
Expand Up @@ -509,15 +509,40 @@ 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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably we should have an enum instead of many interfaces..


/// Checks if type is an integral type
CPPINTEROP_API bool IsIntegralType(TCppType_t type);

/// Checks if type is a signed integer
CPPINTEROP_API bool IsSignedIntegerType(TCppType_t type);

/// Checks if type has an unsigned integer
CPPINTEROP_API bool IsUnsignedIntegerType(TCppType_t type);

/// 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);

Expand Down
45 changes: 45 additions & 0 deletions lib/Interpreter/CppInterOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1549,11 +1549,47 @@ namespace Cpp {
return QT.isPODType(getASTContext());
}

bool IsIntegerType(TCppType_t type) {
QualType QT = QualType::getFromOpaquePtr(type);
return QT->hasIntegerRepresentation();
}

bool IsIntegralType(TCppType_t type) {
QualType QT = QualType::getFromOpaquePtr(type);
return QT->isIntegralType(getASTContext());
}

bool IsSignedIntegerType(TCppType_t type) {
QualType QT = QualType::getFromOpaquePtr(type);
return QT->hasSignedIntegerRepresentation();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    auto *D = (Decl *) var;
              ^


bool IsUnsignedIntegerType(TCppType_t type) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: redundant boolean literal in conditional return statement [readability-simplify-boolean-expr]

lib/Interpreter/CppInterOp.cpp:1565:

-     if (llvm::isa_and_nonnull<VarDecl>(D)) {
-       return true;
-     }
- 
-     return false;
+     return llvm::isa_and_nonnull<VarDecl>(D);

QualType QT = QualType::getFromOpaquePtr(type);
return QT->hasUnsignedIntegerRepresentation();
}

bool IsFloatingType(TCppType_t type) {
QualType QT = QualType::getFromOpaquePtr(type);
return QT->hasFloatingRepresentation();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]

    auto *D = (clang::Decl *) var;
              ^


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;
Expand All @@ -1573,8 +1609,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();

Expand Down
124 changes: 124 additions & 0 deletions unittests/CppInterOp/TypeReflectionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -600,3 +600,127 @@ TEST(TypeReflectionTest, IsFunctionPointerType) {
EXPECT_FALSE(
Cpp::IsFunctionPointerType(Cpp::GetVariableType(Cpp::GetNamed("i"))));
}

TEST(TypeReflectionTest, IntegerTypes) {
Cpp::CreateInterpreter();
std::vector<Decl*> Decls;
std::string code = R"(
int a;
int *b;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'TEST' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
int *b;
TESTstatic (TypeReflectionTest, IntegerTypes) {

double c;
enum A { x, y };
A evar = x;
char k;
long int l;
unsigned int m;
unsigned long n;
)";

GetAllTopLevelDecls(code, Decls);

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::IsIntegralType(Cpp::GetVariableType(Decls[5])));
EXPECT_TRUE(Cpp::IsIntegralType(Cpp::GetVariableType(Decls[6])));
EXPECT_TRUE(Cpp::IsUnsignedIntegerType(Cpp::GetVariableType(Decls[7])));
EXPECT_FALSE(Cpp::IsSignedIntegerType(Cpp::GetVariableType(Decls[8])));
}

TEST(TypeReflectionTest, VoidPtrType) {
Cpp::CreateInterpreter();
std::vector<Decl*> Decls;
std::string code = R"(
class A {};
using VoidPtrType = void*;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'TEST' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
using VoidPtrType = void*;
TESTstatic (TypeReflectionTest, VoidPtrType) {

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<Decl*> Decls;

std::string code = R"(
#include <cstdarg>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'TEST' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
#include <cstdarg>
TESTstatic (TypeReflectionTest, IsSameType) {

#include <iostream>

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 <iostream>

ASTContext &Ctxt = Interp->getCI()->getASTContext();

Decls.assign(Decls.end() - 8, Decls.end());

EXPECT_TRUE(Cpp::IsSameType(Cpp::GetType("bool"), Ctxt.BoolTy.getAsOpaquePtr()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: included header iostream is not used directly [misc-include-cleaner]

Suggested change
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])));
}

TEST(VariableReflectionTest, Is_Get_Reference) {
Cpp::CreateInterpreter();
std::vector<Decl*> Decls;
std::string code = R"(
class A {};
int a;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'TEST' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
int a;
TESTstatic (VariableReflectionTest, Is_Get_Reference) {

int &b = a;
double c;
double &d = c;
A e;
A &f = e;
)";

GetAllTopLevelDecls(code, Decls);

EXPECT_FALSE(Cpp::IsReferenceType(Cpp::GetVariableType(Decls[1])));
EXPECT_TRUE(Cpp::IsReferenceType(Cpp::GetVariableType(Decls[2])));
EXPECT_FALSE(Cpp::IsReferenceType(Cpp::GetVariableType(Decls[3])));
EXPECT_TRUE(Cpp::IsReferenceType(Cpp::GetVariableType(Decls[4])));
EXPECT_FALSE(Cpp::IsReferenceType(Cpp::GetVariableType(Decls[5])));
EXPECT_TRUE(Cpp::IsReferenceType(Cpp::GetVariableType(Decls[6])));

EXPECT_EQ(Cpp::GetNonReferenceType(Cpp::GetVariableType(Decls[2])),
Cpp::GetVariableType(Decls[1]));
EXPECT_EQ(Cpp::GetNonReferenceType(Cpp::GetVariableType(Decls[4])),
Cpp::GetVariableType(Decls[3]));
EXPECT_EQ(Cpp::GetNonReferenceType(Cpp::GetVariableType(Decls[6])),
Cpp::GetVariableType(Decls[5]));

EXPECT_FALSE(Cpp::GetNonReferenceType(Cpp::GetVariableType(Decls[5])));
}
Loading