diff options
Diffstat (limited to 'unittests/Symbol')
-rw-r--r-- | unittests/Symbol/CMakeLists.txt | 3 | ||||
-rw-r--r-- | unittests/Symbol/TestClangASTContext.cpp | 315 |
2 files changed, 318 insertions, 0 deletions
diff --git a/unittests/Symbol/CMakeLists.txt b/unittests/Symbol/CMakeLists.txt new file mode 100644 index 000000000000..ef41f3fd62a8 --- /dev/null +++ b/unittests/Symbol/CMakeLists.txt @@ -0,0 +1,3 @@ +add_lldb_unittest(SymbolTests + TestClangASTContext.cpp + ) diff --git a/unittests/Symbol/TestClangASTContext.cpp b/unittests/Symbol/TestClangASTContext.cpp new file mode 100644 index 000000000000..3f166ab9cc72 --- /dev/null +++ b/unittests/Symbol/TestClangASTContext.cpp @@ -0,0 +1,315 @@ +//===-- TestClangASTContext.cpp ---------------------------------------*- C++ -*-===// + +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" + +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangUtil.h" +#include "lldb/Symbol/Declaration.h" +#include "lldb/Symbol/GoASTContext.h" + +using namespace clang; +using namespace lldb; +using namespace lldb_private; + +class TestClangASTContext : public testing::Test +{ +public: + static void + SetUpTestCase() + { + HostInfo::Initialize(); + } + + static void + TearDownTestCase() + { + HostInfo::Terminate(); + } + + virtual void + SetUp() override + { + std::string triple = HostInfo::GetTargetTriple(); + m_ast.reset(new ClangASTContext(triple.c_str())); + } + + virtual void + TearDown() override + { + m_ast.reset(); + } + +protected: + std::unique_ptr<ClangASTContext> m_ast; + + QualType + GetBasicQualType(BasicType type) const + { + return ClangUtil::GetQualType(m_ast->GetBasicTypeFromAST(type)); + } + + QualType + GetBasicQualType(const char *name) const + { + return ClangUtil::GetQualType(m_ast->GetBuiltinTypeByName(ConstString(name))); + } +}; + +TEST_F(TestClangASTContext, TestGetBasicTypeFromEnum) +{ + clang::ASTContext *context = m_ast->getASTContext(); + + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeBool), context->BoolTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeChar), context->CharTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeChar16), context->Char16Ty)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeChar32), context->Char32Ty)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeDouble), context->DoubleTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeDoubleComplex), context->DoubleComplexTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeFloat), context->FloatTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeFloatComplex), context->FloatComplexTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeHalf), context->HalfTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeInt), context->IntTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeInt128), context->Int128Ty)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLong), context->LongTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLongDouble), context->LongDoubleTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLongDoubleComplex), context->LongDoubleComplexTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeLongLong), context->LongLongTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeNullPtr), context->NullPtrTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeObjCClass), context->getObjCClassType())); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeObjCID), context->getObjCIdType())); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeObjCSel), context->getObjCSelType())); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeShort), context->ShortTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeSignedChar), context->SignedCharTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedChar), context->UnsignedCharTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedInt), context->UnsignedIntTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedInt128), context->UnsignedInt128Ty)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedLong), context->UnsignedLongTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedLongLong), context->UnsignedLongLongTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeUnsignedShort), context->UnsignedShortTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeVoid), context->VoidTy)); + EXPECT_TRUE(context->hasSameType(GetBasicQualType(eBasicTypeWChar), context->WCharTy)); +} + +TEST_F(TestClangASTContext, TestGetBasicTypeFromName) +{ + EXPECT_EQ(GetBasicQualType(eBasicTypeChar), GetBasicQualType("char")); + EXPECT_EQ(GetBasicQualType(eBasicTypeSignedChar), GetBasicQualType("signed char")); + EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedChar), GetBasicQualType("unsigned char")); + EXPECT_EQ(GetBasicQualType(eBasicTypeWChar), GetBasicQualType("wchar_t")); + EXPECT_EQ(GetBasicQualType(eBasicTypeSignedWChar), GetBasicQualType("signed wchar_t")); + EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedWChar), GetBasicQualType("unsigned wchar_t")); + EXPECT_EQ(GetBasicQualType(eBasicTypeShort), GetBasicQualType("short")); + EXPECT_EQ(GetBasicQualType(eBasicTypeShort), GetBasicQualType("short int")); + EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedShort), GetBasicQualType("unsigned short")); + EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedShort), GetBasicQualType("unsigned short int")); + EXPECT_EQ(GetBasicQualType(eBasicTypeInt), GetBasicQualType("int")); + EXPECT_EQ(GetBasicQualType(eBasicTypeInt), GetBasicQualType("signed int")); + EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt), GetBasicQualType("unsigned int")); + EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt), GetBasicQualType("unsigned")); + EXPECT_EQ(GetBasicQualType(eBasicTypeLong), GetBasicQualType("long")); + EXPECT_EQ(GetBasicQualType(eBasicTypeLong), GetBasicQualType("long int")); + EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLong), GetBasicQualType("unsigned long")); + EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLong), GetBasicQualType("unsigned long int")); + EXPECT_EQ(GetBasicQualType(eBasicTypeLongLong), GetBasicQualType("long long")); + EXPECT_EQ(GetBasicQualType(eBasicTypeLongLong), GetBasicQualType("long long int")); + EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLongLong), GetBasicQualType("unsigned long long")); + EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedLongLong), GetBasicQualType("unsigned long long int")); + EXPECT_EQ(GetBasicQualType(eBasicTypeInt128), GetBasicQualType("__int128_t")); + EXPECT_EQ(GetBasicQualType(eBasicTypeUnsignedInt128), GetBasicQualType("__uint128_t")); + EXPECT_EQ(GetBasicQualType(eBasicTypeVoid), GetBasicQualType("void")); + EXPECT_EQ(GetBasicQualType(eBasicTypeBool), GetBasicQualType("bool")); + EXPECT_EQ(GetBasicQualType(eBasicTypeFloat), GetBasicQualType("float")); + EXPECT_EQ(GetBasicQualType(eBasicTypeDouble), GetBasicQualType("double")); + EXPECT_EQ(GetBasicQualType(eBasicTypeLongDouble), GetBasicQualType("long double")); + EXPECT_EQ(GetBasicQualType(eBasicTypeObjCID), GetBasicQualType("id")); + EXPECT_EQ(GetBasicQualType(eBasicTypeObjCSel), GetBasicQualType("SEL")); + EXPECT_EQ(GetBasicQualType(eBasicTypeNullPtr), GetBasicQualType("nullptr")); +} + +void +VerifyEncodingAndBitSize(clang::ASTContext *context, lldb::Encoding encoding, int bit_size) +{ + CompilerType type = ClangASTContext::GetBuiltinTypeForEncodingAndBitSize(context, encoding, bit_size); + EXPECT_TRUE(type.IsValid()); + + QualType qtype = ClangUtil::GetQualType(type); + EXPECT_FALSE(qtype.isNull()); + if (qtype.isNull()) + return; + + uint64_t actual_size = context->getTypeSize(qtype); + EXPECT_EQ(bit_size, actual_size); + + const clang::Type *type_ptr = qtype.getTypePtr(); + EXPECT_NE(nullptr, type_ptr); + if (!type_ptr) + return; + + EXPECT_TRUE(type_ptr->isBuiltinType()); + if (encoding == eEncodingSint) + EXPECT_TRUE(type_ptr->isSignedIntegerType()); + else if (encoding == eEncodingUint) + EXPECT_TRUE(type_ptr->isUnsignedIntegerType()); + else if (encoding == eEncodingIEEE754) + EXPECT_TRUE(type_ptr->isFloatingType()); +} + +TEST_F(TestClangASTContext, TestBuiltinTypeForEncodingAndBitSize) +{ + clang::ASTContext *context = m_ast->getASTContext(); + + // Make sure we can get types of every possible size in every possible encoding. + // We can't make any guarantee about which specific type we get, because the standard + // isn't that specific. We only need to make sure the compiler hands us some type that + // is both a builtin type and matches the requested bit size. + VerifyEncodingAndBitSize(context, eEncodingSint, 8); + VerifyEncodingAndBitSize(context, eEncodingSint, 16); + VerifyEncodingAndBitSize(context, eEncodingSint, 32); + VerifyEncodingAndBitSize(context, eEncodingSint, 64); + VerifyEncodingAndBitSize(context, eEncodingSint, 128); + + VerifyEncodingAndBitSize(context, eEncodingUint, 8); + VerifyEncodingAndBitSize(context, eEncodingUint, 16); + VerifyEncodingAndBitSize(context, eEncodingUint, 32); + VerifyEncodingAndBitSize(context, eEncodingUint, 64); + VerifyEncodingAndBitSize(context, eEncodingUint, 128); + + VerifyEncodingAndBitSize(context, eEncodingIEEE754, 32); + VerifyEncodingAndBitSize(context, eEncodingIEEE754, 64); +} + +TEST_F(TestClangASTContext, TestIsClangType) +{ + clang::ASTContext *context = m_ast->getASTContext(); + lldb::opaque_compiler_type_t bool_ctype = ClangASTContext::GetOpaqueCompilerType(context, lldb::eBasicTypeBool); + CompilerType bool_type(m_ast.get(), bool_ctype); + CompilerType record_type = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "FooRecord", clang::TTK_Struct, + lldb::eLanguageTypeC_plus_plus, nullptr); + // Clang builtin type and record type should pass + EXPECT_TRUE(ClangUtil::IsClangType(bool_type)); + EXPECT_TRUE(ClangUtil::IsClangType(record_type)); + + // Default constructed type should fail + EXPECT_FALSE(ClangUtil::IsClangType(CompilerType())); + + // Go type should fail + GoASTContext go_ast; + CompilerType go_type(&go_ast, bool_ctype); + EXPECT_FALSE(ClangUtil::IsClangType(go_type)); +} + +TEST_F(TestClangASTContext, TestRemoveFastQualifiers) +{ + CompilerType record_type = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "FooRecord", clang::TTK_Struct, + lldb::eLanguageTypeC_plus_plus, nullptr); + QualType qt; + + qt = ClangUtil::GetQualType(record_type); + EXPECT_EQ(0, qt.getLocalFastQualifiers()); + record_type = record_type.AddConstModifier(); + record_type = record_type.AddVolatileModifier(); + record_type = record_type.AddRestrictModifier(); + qt = ClangUtil::GetQualType(record_type); + EXPECT_NE(0, qt.getLocalFastQualifiers()); + record_type = ClangUtil::RemoveFastQualifiers(record_type); + qt = ClangUtil::GetQualType(record_type); + EXPECT_EQ(0, qt.getLocalFastQualifiers()); +} + +TEST_F(TestClangASTContext, TestConvertAccessTypeToAccessSpecifier) +{ + EXPECT_EQ(AS_none, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessNone)); + EXPECT_EQ(AS_none, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessPackage)); + EXPECT_EQ(AS_public, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessPublic)); + EXPECT_EQ(AS_private, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessPrivate)); + EXPECT_EQ(AS_protected, ClangASTContext::ConvertAccessTypeToAccessSpecifier(eAccessProtected)); +} + +TEST_F(TestClangASTContext, TestUnifyAccessSpecifiers) +{ + // Unifying two of the same type should return the same type + EXPECT_EQ(AS_public, ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_public)); + EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_private)); + EXPECT_EQ(AS_protected, ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_protected)); + + // Otherwise the result should be the strictest of the two. + EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_public)); + EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_protected)); + EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_private)); + EXPECT_EQ(AS_private, ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_private)); + EXPECT_EQ(AS_protected, ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_public)); + EXPECT_EQ(AS_protected, ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_protected)); + + // None is stricter than everything (by convention) + EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_none, AS_public)); + EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_none, AS_protected)); + EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_none, AS_private)); + EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_public, AS_none)); + EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_protected, AS_none)); + EXPECT_EQ(AS_none, ClangASTContext::UnifyAccessSpecifiers(AS_private, AS_none)); +} + +TEST_F(TestClangASTContext, TestRecordHasFields) +{ + CompilerType int_type = ClangASTContext::GetBasicType(m_ast->getASTContext(), eBasicTypeInt); + + // Test that a record with no fields returns false + CompilerType empty_base = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "EmptyBase", clang::TTK_Struct, + lldb::eLanguageTypeC_plus_plus, nullptr); + ClangASTContext::StartTagDeclarationDefinition(empty_base); + ClangASTContext::CompleteTagDeclarationDefinition(empty_base); + + RecordDecl *empty_base_decl = ClangASTContext::GetAsRecordDecl(empty_base); + EXPECT_NE(nullptr, empty_base_decl); + EXPECT_FALSE(ClangASTContext::RecordHasFields(empty_base_decl)); + + // Test that a record with direct fields returns true + CompilerType non_empty_base = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "NonEmptyBase", + clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); + ClangASTContext::StartTagDeclarationDefinition(non_empty_base); + FieldDecl *non_empty_base_field_decl = + m_ast->AddFieldToRecordType(non_empty_base, "MyField", int_type, eAccessPublic, 0); + ClangASTContext::CompleteTagDeclarationDefinition(non_empty_base); + RecordDecl *non_empty_base_decl = ClangASTContext::GetAsRecordDecl(non_empty_base); + EXPECT_NE(nullptr, non_empty_base_decl); + EXPECT_NE(nullptr, non_empty_base_field_decl); + EXPECT_TRUE(ClangASTContext::RecordHasFields(non_empty_base_decl)); + + // Test that a record with no direct fields, but fields in a base returns true + CompilerType empty_derived = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "EmptyDerived", + clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); + ClangASTContext::StartTagDeclarationDefinition(empty_derived); + CXXBaseSpecifier *non_empty_base_spec = + m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(), lldb::eAccessPublic, false, false); + bool result = m_ast->SetBaseClassesForClassType(empty_derived.GetOpaqueQualType(), &non_empty_base_spec, 1); + ClangASTContext::CompleteTagDeclarationDefinition(empty_derived); + EXPECT_TRUE(result); + CXXRecordDecl *empty_derived_non_empty_base_cxx_decl = m_ast->GetAsCXXRecordDecl(empty_derived.GetOpaqueQualType()); + RecordDecl *empty_derived_non_empty_base_decl = ClangASTContext::GetAsRecordDecl(empty_derived); + EXPECT_EQ(1, ClangASTContext::GetNumBaseClasses(empty_derived_non_empty_base_cxx_decl, false)); + EXPECT_TRUE(ClangASTContext::RecordHasFields(empty_derived_non_empty_base_decl)); + + // Test that a record with no direct fields, but fields in a virtual base returns true + CompilerType empty_derived2 = m_ast->CreateRecordType(nullptr, lldb::eAccessPublic, "EmptyDerived2", + clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); + ClangASTContext::StartTagDeclarationDefinition(empty_derived2); + CXXBaseSpecifier *non_empty_vbase_spec = + m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(), lldb::eAccessPublic, true, false); + result = m_ast->SetBaseClassesForClassType(empty_derived2.GetOpaqueQualType(), &non_empty_vbase_spec, 1); + ClangASTContext::CompleteTagDeclarationDefinition(empty_derived2); + EXPECT_TRUE(result); + CXXRecordDecl *empty_derived_non_empty_vbase_cxx_decl = + m_ast->GetAsCXXRecordDecl(empty_derived2.GetOpaqueQualType()); + RecordDecl *empty_derived_non_empty_vbase_decl = ClangASTContext::GetAsRecordDecl(empty_derived2); + EXPECT_EQ(1, ClangASTContext::GetNumBaseClasses(empty_derived_non_empty_vbase_cxx_decl, false)); + EXPECT_TRUE(ClangASTContext::RecordHasFields(empty_derived_non_empty_vbase_decl)); +} |