From 22caa3cfbcf5762a47acc40c425d9fe0c40da621 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Mon, 16 Dec 2019 10:06:38 +0100 Subject: [PATCH] [lldb] Add unit test for ClangASTImporter --- lldb/unittests/Symbol/CMakeLists.txt | 1 + .../unittests/Symbol/TestClangASTImporter.cpp | 220 ++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 lldb/unittests/Symbol/TestClangASTImporter.cpp diff --git a/lldb/unittests/Symbol/CMakeLists.txt b/lldb/unittests/Symbol/CMakeLists.txt index aa86986f4e0e87..02875b8b53c1fe 100644 --- a/lldb/unittests/Symbol/CMakeLists.txt +++ b/lldb/unittests/Symbol/CMakeLists.txt @@ -2,6 +2,7 @@ add_lldb_unittest(SymbolTests LocateSymbolFileTest.cpp PostfixExpressionTest.cpp TestClangASTContext.cpp + TestClangASTImporter.cpp TestDWARFCallFrameInfo.cpp TestType.cpp TestLineEntry.cpp diff --git a/lldb/unittests/Symbol/TestClangASTImporter.cpp b/lldb/unittests/Symbol/TestClangASTImporter.cpp new file mode 100644 index 00000000000000..17a0dfb6a3487d --- /dev/null +++ b/lldb/unittests/Symbol/TestClangASTImporter.cpp @@ -0,0 +1,220 @@ +//===-- TestClangASTImporter.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 "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangASTImporter.h" +#include "lldb/Symbol/ClangASTMetadata.h" +#include "lldb/Symbol/ClangUtil.h" +#include "lldb/Symbol/Declaration.h" +#include "clang/AST/DeclCXX.h" + +using namespace clang; +using namespace lldb; +using namespace lldb_private; + +class TestClangASTImporter : public testing::Test { +public: + static void SetUpTestCase() { + FileSystem::Initialize(); + HostInfo::Initialize(); + } + + static void TearDownTestCase() { + HostInfo::Terminate(); + FileSystem::Terminate(); + } + +protected: + std::unique_ptr createAST() { + return std::make_unique(HostInfo::GetTargetTriple()); + } + + CompilerType createRecord(ClangASTContext &ast, const char *name) { + return ast.CreateRecordType(ast.getASTContext()->getTranslationUnitDecl(), + lldb::AccessType::eAccessPublic, name, 0, + lldb::LanguageType::eLanguageTypeC); + } +}; + +TEST_F(TestClangASTImporter, CanImportInvalidType) { + ClangASTImporter importer; + EXPECT_FALSE(importer.CanImport(CompilerType())); +} + +TEST_F(TestClangASTImporter, ImportInvalidType) { + ClangASTImporter importer; + EXPECT_FALSE(importer.Import(CompilerType())); +} + +TEST_F(TestClangASTImporter, CopyDeclTagDecl) { + // Tests that the ClangASTImporter::CopyDecl can copy TagDecls. + std::unique_ptr source_ast = createAST(); + CompilerType source_type = createRecord(*source_ast, "Source"); + clang::TagDecl *source = ClangUtil::GetAsTagDecl(source_type); + + std::unique_ptr target_ast = createAST(); + + ClangASTImporter importer; + clang::Decl *imported = importer.CopyDecl( + target_ast->getASTContext(), source_ast->getASTContext(), source); + ASSERT_NE(nullptr, imported); + + // Check that we got the correct decl by just comparing their qualified name. + clang::TagDecl *imported_tag_decl = llvm::cast(imported); + EXPECT_EQ(source->getQualifiedNameAsString(), + imported_tag_decl->getQualifiedNameAsString()); + + // Check that origin was set for the imported declaration. + ClangASTImporter::DeclOrigin origin = importer.GetDeclOrigin(imported); + EXPECT_TRUE(origin.Valid()); + EXPECT_EQ(origin.ctx, source_ast->getASTContext()); + EXPECT_EQ(origin.decl, source); +} + +TEST_F(TestClangASTImporter, CopyTypeTagDecl) { + // Tests that the ClangASTImporter::CopyType can copy TagDecls types. + std::unique_ptr source_ast = createAST(); + CompilerType source_type = createRecord(*source_ast, "Source"); + clang::TagDecl *source = ClangUtil::GetAsTagDecl(source_type); + + std::unique_ptr target_ast = createAST(); + + ClangASTImporter importer; + CompilerType imported = importer.CopyType(*target_ast, source_type); + ASSERT_TRUE(imported.IsValid()); + + // Check that we got the correct decl by just comparing their qualified name. + clang::TagDecl *imported_tag_decl = ClangUtil::GetAsTagDecl(imported); + EXPECT_EQ(source->getQualifiedNameAsString(), + imported_tag_decl->getQualifiedNameAsString()); + + // Check that origin was set for the imported declaration. + ClangASTImporter::DeclOrigin origin = + importer.GetDeclOrigin(imported_tag_decl); + EXPECT_TRUE(origin.Valid()); + EXPECT_EQ(origin.ctx, source_ast->getASTContext()); + EXPECT_EQ(origin.decl, source); +} + +TEST_F(TestClangASTImporter, MetadataPropagation) { + // Tests that AST metadata is propagated when copying declarations. + + std::unique_ptr source_ast = createAST(); + CompilerType source_type = createRecord(*source_ast, "Source"); + clang::TagDecl *source = ClangUtil::GetAsTagDecl(source_type); + const lldb::user_id_t metadata = 123456; + source_ast->SetMetadataAsUserID(source, metadata); + + std::unique_ptr target_ast = createAST(); + + ClangASTImporter importer; + clang::Decl *imported = importer.CopyDecl( + target_ast->getASTContext(), source_ast->getASTContext(), source); + ASSERT_NE(nullptr, imported); + + // Check that we got the same Metadata. + ASSERT_NE(nullptr, importer.GetDeclMetadata(imported)); + EXPECT_EQ(metadata, importer.GetDeclMetadata(imported)->GetUserID()); +} + +TEST_F(TestClangASTImporter, MetadataPropagationIndirectImport) { + // Tests that AST metadata is propagated when copying declarations when + // importing one declaration into a temporary context and then to the + // actual destination context. + + std::unique_ptr source_ast = createAST(); + CompilerType source_type = createRecord(*source_ast, "Source"); + clang::TagDecl *source = ClangUtil::GetAsTagDecl(source_type); + const lldb::user_id_t metadata = 123456; + source_ast->SetMetadataAsUserID(source, metadata); + + std::unique_ptr temporary_ast = createAST(); + + ClangASTImporter importer; + clang::Decl *temporary_imported = importer.CopyDecl( + temporary_ast->getASTContext(), source_ast->getASTContext(), source); + ASSERT_NE(nullptr, temporary_imported); + + std::unique_ptr target_ast = createAST(); + clang::Decl *imported = + importer.CopyDecl(target_ast->getASTContext(), + temporary_ast->getASTContext(), temporary_imported); + ASSERT_NE(nullptr, imported); + + // Check that we got the same Metadata. + ASSERT_NE(nullptr, importer.GetDeclMetadata(imported)); + EXPECT_EQ(metadata, importer.GetDeclMetadata(imported)->GetUserID()); +} + +TEST_F(TestClangASTImporter, MetadataPropagationAfterCopying) { + // Tests that AST metadata is propagated when copying declarations even + // when the metadata was set after the declaration has already been copied. + + std::unique_ptr source_ast = createAST(); + CompilerType source_type = createRecord(*source_ast, "Source"); + clang::TagDecl *source = ClangUtil::GetAsTagDecl(source_type); + const lldb::user_id_t metadata = 123456; + + std::unique_ptr target_ast = createAST(); + + ClangASTImporter importer; + clang::Decl *imported = importer.CopyDecl( + target_ast->getASTContext(), source_ast->getASTContext(), source); + ASSERT_NE(nullptr, imported); + + // The TagDecl has been imported. Now set the metadata of the source and + // make sure the imported one will directly see it. + source_ast->SetMetadataAsUserID(source, metadata); + + // Check that we got the same Metadata. + ASSERT_NE(nullptr, importer.GetDeclMetadata(imported)); + EXPECT_EQ(metadata, importer.GetDeclMetadata(imported)->GetUserID()); +} + +TEST_F(TestClangASTImporter, RecordLayout) { + // Test that it is possible to register RecordDecl layouts and then later + // correctly retrieve them. + + std::unique_ptr source_ast = createAST(); + CompilerType source_type = createRecord(*source_ast, "Source"); + ClangASTContext::StartTagDeclarationDefinition(source_type); + clang::FieldDecl *field = source_ast->AddFieldToRecordType( + source_type, "a_field", + source_ast->GetBasicType(lldb::BasicType::eBasicTypeChar), + lldb::AccessType::eAccessPublic, 7); + ClangASTContext::CompleteTagDeclarationDefinition(source_type); + + clang::TagDecl *source_tag = ClangUtil::GetAsTagDecl(source_type); + clang::RecordDecl *source_record = llvm::cast(source_tag); + + ClangASTImporter importer; + ClangASTImporter::LayoutInfo layout_info; + layout_info.bit_size = 15; + layout_info.alignment = 2; + layout_info.field_offsets[field] = 1; + importer.InsertRecordDecl(source_record, layout_info); + + uint64_t bit_size; + uint64_t alignment; + llvm::DenseMap field_offsets; + llvm::DenseMap base_offsets; + llvm::DenseMap vbase_offsets; + importer.LayoutRecordType(source_record, bit_size, alignment, field_offsets, + base_offsets, vbase_offsets); + + EXPECT_EQ(15U, bit_size); + EXPECT_EQ(2U, alignment); + EXPECT_EQ(1U, field_offsets.size()); + EXPECT_EQ(1U, field_offsets[field]); + EXPECT_EQ(0U, base_offsets.size()); + EXPECT_EQ(0U, vbase_offsets.size()); +}