llvm-project/lldb/unittests/Symbol/TestClangASTContext.cpp
Chandler Carruth 2946cd7010 Update the file headers across all of the LLVM projects in the monorepo
to reflect the new license.

We understand that people may be surprised that we're moving the header
entirely to discuss the new license. We checked this carefully with the
Foundation's lawyer and we believe this is the correct approach.

Essentially, all code in the project is now made available by the LLVM
project under our new license, so you will see that the license headers
include that license only. Some of our contributors have contributed
code under our old license, and accordingly, we have retained a copy of
our old license notice in the top-level files in each project and
repository.

llvm-svn: 351636
2019-01-19 08:50:56 +00:00

451 lines
20 KiB
C++

//===-- TestClangASTContext.cpp ---------------------------------------*- C++
//-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "gtest/gtest.h"
#include "clang/AST/DeclCXX.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/Declaration.h"
using namespace clang;
using namespace lldb;
using namespace lldb_private;
class TestClangASTContext : public testing::Test {
public:
static void SetUpTestCase() {
FileSystem::Initialize();
HostInfo::Initialize();
}
static void TearDownTestCase() {
HostInfo::Terminate();
FileSystem::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, unsigned 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());
switch (encoding) {
case eEncodingSint:
EXPECT_TRUE(type_ptr->isSignedIntegerType());
break;
case eEncodingUint:
EXPECT_TRUE(type_ptr->isUnsignedIntegerType());
break;
case eEncodingIEEE754:
EXPECT_TRUE(type_ptr->isFloatingType());
break;
default:
FAIL() << "Unexpected encoding";
break;
}
}
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()));
}
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(0u, qt.getLocalFastQualifiers());
record_type = record_type.AddConstModifier();
record_type = record_type.AddVolatileModifier();
record_type = record_type.AddRestrictModifier();
qt = ClangUtil::GetQualType(record_type);
EXPECT_NE(0u, qt.getLocalFastQualifiers());
record_type = ClangUtil::RemoveFastQualifiers(record_type);
qt = ClangUtil::GetQualType(record_type);
EXPECT_EQ(0u, 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));
std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases;
// 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);
std::unique_ptr<clang::CXXBaseSpecifier> non_empty_base_spec =
m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(),
lldb::eAccessPublic, false, false);
bases.push_back(std::move(non_empty_base_spec));
bool result = m_ast->TransferBaseClasses(empty_derived.GetOpaqueQualType(),
std::move(bases));
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(1u, 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);
std::unique_ptr<CXXBaseSpecifier> non_empty_vbase_spec =
m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(),
lldb::eAccessPublic, true, false);
bases.push_back(std::move(non_empty_vbase_spec));
result = m_ast->TransferBaseClasses(empty_derived2.GetOpaqueQualType(),
std::move(bases));
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(1u, ClangASTContext::GetNumBaseClasses(
empty_derived_non_empty_vbase_cxx_decl, false));
EXPECT_TRUE(
ClangASTContext::RecordHasFields(empty_derived_non_empty_vbase_decl));
}
TEST_F(TestClangASTContext, TemplateArguments) {
ClangASTContext::TemplateParameterInfos infos;
infos.names.push_back("T");
infos.args.push_back(TemplateArgument(m_ast->getASTContext()->IntTy));
infos.names.push_back("I");
llvm::APSInt arg(llvm::APInt(8, 47));
infos.args.push_back(TemplateArgument(*m_ast->getASTContext(), arg,
m_ast->getASTContext()->IntTy));
// template<typename T, int I> struct foo;
ClassTemplateDecl *decl = m_ast->CreateClassTemplateDecl(
m_ast->GetTranslationUnitDecl(), eAccessPublic, "foo", TTK_Struct, infos);
ASSERT_NE(decl, nullptr);
// foo<int, 47>
ClassTemplateSpecializationDecl *spec_decl =
m_ast->CreateClassTemplateSpecializationDecl(
m_ast->GetTranslationUnitDecl(), decl, TTK_Struct, infos);
ASSERT_NE(spec_decl, nullptr);
CompilerType type = m_ast->CreateClassTemplateSpecializationType(spec_decl);
ASSERT_TRUE(type);
m_ast->StartTagDeclarationDefinition(type);
m_ast->CompleteTagDeclarationDefinition(type);
// typedef foo<int, 47> foo_def;
CompilerType typedef_type = m_ast->CreateTypedefType(
type, "foo_def",
CompilerDeclContext(m_ast.get(), m_ast->GetTranslationUnitDecl()));
CompilerType auto_type(m_ast->getASTContext(),
m_ast->getASTContext()->getAutoType(
ClangUtil::GetCanonicalQualType(typedef_type),
clang::AutoTypeKeyword::Auto, false));
CompilerType int_type(m_ast->getASTContext(), m_ast->getASTContext()->IntTy);
for (CompilerType t : {type, typedef_type, auto_type}) {
SCOPED_TRACE(t.GetTypeName().AsCString());
EXPECT_EQ(m_ast->GetTemplateArgumentKind(t.GetOpaqueQualType(), 0),
eTemplateArgumentKindType);
EXPECT_EQ(m_ast->GetTypeTemplateArgument(t.GetOpaqueQualType(), 0),
int_type);
EXPECT_EQ(llvm::None,
m_ast->GetIntegralTemplateArgument(t.GetOpaqueQualType(), 0));
EXPECT_EQ(m_ast->GetTemplateArgumentKind(t.GetOpaqueQualType(), 1),
eTemplateArgumentKindIntegral);
EXPECT_EQ(m_ast->GetTypeTemplateArgument(t.GetOpaqueQualType(), 1),
CompilerType());
auto result = m_ast->GetIntegralTemplateArgument(t.GetOpaqueQualType(), 1);
ASSERT_NE(llvm::None, result);
EXPECT_EQ(arg, result->value);
EXPECT_EQ(int_type, result->type);
}
}