forked from OSchip/llvm-project
453 lines
20 KiB
C++
453 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();
|
|
}
|
|
|
|
void SetUp() override {
|
|
std::string triple = HostInfo::GetTargetTriple();
|
|
m_ast.reset(new ClangASTContext(triple.c_str()));
|
|
}
|
|
|
|
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.get(),
|
|
m_ast->getASTContext()
|
|
->getAutoType(ClangUtil::GetCanonicalQualType(typedef_type),
|
|
clang::AutoTypeKeyword::Auto, false)
|
|
.getAsOpaquePtr());
|
|
|
|
CompilerType int_type(m_ast.get(), m_ast->getASTContext()->IntTy.getAsOpaquePtr());
|
|
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);
|
|
}
|
|
}
|