forked from OSchip/llvm-project
259 lines
10 KiB
C++
259 lines
10 KiB
C++
//===-- TestClangASTImporter.cpp ------------------------------------------===//
|
|
//
|
|
// 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 "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
|
|
#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
|
|
#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
|
|
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
|
|
#include "TestingSupport/SubsystemRAII.h"
|
|
#include "TestingSupport/Symbol/ClangTestUtils.h"
|
|
#include "lldb/Core/Declaration.h"
|
|
#include "lldb/Host/FileSystem.h"
|
|
#include "lldb/Host/HostInfo.h"
|
|
#include "clang/AST/DeclCXX.h"
|
|
|
|
using namespace clang;
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
class TestClangASTImporter : public testing::Test {
|
|
public:
|
|
SubsystemRAII<FileSystem, HostInfo> subsystems;
|
|
};
|
|
|
|
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.
|
|
clang_utils::SourceASTWithRecord source;
|
|
|
|
std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
|
|
|
|
ClangASTImporter importer;
|
|
clang::Decl *imported =
|
|
importer.CopyDecl(&target_ast->getASTContext(), source.record_decl);
|
|
ASSERT_NE(nullptr, imported);
|
|
|
|
// Check that we got the correct decl by just comparing their qualified name.
|
|
clang::TagDecl *imported_tag_decl = llvm::cast<clang::TagDecl>(imported);
|
|
EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
|
|
imported_tag_decl->getQualifiedNameAsString());
|
|
// We did a minimal import of the tag decl.
|
|
EXPECT_TRUE(imported_tag_decl->hasExternalLexicalStorage());
|
|
|
|
// 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.record_decl);
|
|
}
|
|
|
|
TEST_F(TestClangASTImporter, CopyTypeTagDecl) {
|
|
// Tests that the ClangASTImporter::CopyType can copy TagDecls types.
|
|
clang_utils::SourceASTWithRecord source;
|
|
|
|
std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
|
|
|
|
ClangASTImporter importer;
|
|
CompilerType imported = importer.CopyType(*target_ast, source.record_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.record_decl->getQualifiedNameAsString(),
|
|
imported_tag_decl->getQualifiedNameAsString());
|
|
// We did a minimal import of the tag decl.
|
|
EXPECT_TRUE(imported_tag_decl->hasExternalLexicalStorage());
|
|
|
|
// 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.record_decl);
|
|
}
|
|
|
|
TEST_F(TestClangASTImporter, CompleteFwdDeclWithOtherOrigin) {
|
|
// Create an AST with a full type that is defined.
|
|
clang_utils::SourceASTWithRecord source_with_definition;
|
|
|
|
// Create an AST with a type thst is only a forward declaration with the
|
|
// same name as the one in the other source.
|
|
std::unique_ptr<TypeSystemClang> fwd_decl_source = clang_utils::createAST();
|
|
CompilerType fwd_decl_type = clang_utils::createRecord(
|
|
*fwd_decl_source, source_with_definition.record_decl->getName());
|
|
|
|
// Create a target and import the forward decl.
|
|
std::unique_ptr<TypeSystemClang> target = clang_utils::createAST();
|
|
ClangASTImporter importer;
|
|
CompilerType imported = importer.CopyType(*target, fwd_decl_type);
|
|
ASSERT_TRUE(imported.IsValid());
|
|
EXPECT_FALSE(imported.IsDefined());
|
|
|
|
// Now complete the forward decl with the definition from the other source.
|
|
// This should define the decl and give it the fields of the other origin.
|
|
clang::TagDecl *imported_tag_decl = ClangUtil::GetAsTagDecl(imported);
|
|
importer.CompleteTagDeclWithOrigin(imported_tag_decl,
|
|
source_with_definition.record_decl);
|
|
ASSERT_TRUE(imported.IsValid());
|
|
EXPECT_TRUE(imported.IsDefined());
|
|
EXPECT_EQ(1U, imported.GetNumFields());
|
|
}
|
|
|
|
TEST_F(TestClangASTImporter, DeportDeclTagDecl) {
|
|
// Tests that the ClangASTImporter::DeportDecl completely copies TagDecls.
|
|
clang_utils::SourceASTWithRecord source;
|
|
|
|
std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
|
|
|
|
ClangASTImporter importer;
|
|
clang::Decl *imported =
|
|
importer.DeportDecl(&target_ast->getASTContext(), source.record_decl);
|
|
ASSERT_NE(nullptr, imported);
|
|
|
|
// Check that we got the correct decl by just comparing their qualified name.
|
|
clang::TagDecl *imported_tag_decl = llvm::cast<clang::TagDecl>(imported);
|
|
EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
|
|
imported_tag_decl->getQualifiedNameAsString());
|
|
// The record should be completed as we deported it.
|
|
EXPECT_FALSE(imported_tag_decl->hasExternalLexicalStorage());
|
|
|
|
// Deporting doesn't update the origin map.
|
|
EXPECT_FALSE(importer.GetDeclOrigin(imported_tag_decl).Valid());
|
|
}
|
|
|
|
TEST_F(TestClangASTImporter, DeportTypeTagDecl) {
|
|
// Tests that the ClangASTImporter::CopyType can deport TagDecl types.
|
|
clang_utils::SourceASTWithRecord source;
|
|
|
|
std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
|
|
|
|
ClangASTImporter importer;
|
|
CompilerType imported = importer.DeportType(*target_ast, source.record_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.record_decl->getQualifiedNameAsString(),
|
|
imported_tag_decl->getQualifiedNameAsString());
|
|
// The record should be completed as we deported it.
|
|
EXPECT_FALSE(imported_tag_decl->hasExternalLexicalStorage());
|
|
|
|
// Deporting doesn't update the origin map.
|
|
EXPECT_FALSE(importer.GetDeclOrigin(imported_tag_decl).Valid());
|
|
}
|
|
|
|
TEST_F(TestClangASTImporter, MetadataPropagation) {
|
|
// Tests that AST metadata is propagated when copying declarations.
|
|
|
|
clang_utils::SourceASTWithRecord source;
|
|
|
|
const lldb::user_id_t metadata = 123456;
|
|
source.ast->SetMetadataAsUserID(source.record_decl, metadata);
|
|
|
|
std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
|
|
|
|
ClangASTImporter importer;
|
|
clang::Decl *imported =
|
|
importer.CopyDecl(&target_ast->getASTContext(), source.record_decl);
|
|
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.
|
|
|
|
clang_utils::SourceASTWithRecord source;
|
|
|
|
const lldb::user_id_t metadata = 123456;
|
|
source.ast->SetMetadataAsUserID(source.record_decl, metadata);
|
|
|
|
std::unique_ptr<TypeSystemClang> temporary_ast = clang_utils::createAST();
|
|
|
|
ClangASTImporter importer;
|
|
clang::Decl *temporary_imported =
|
|
importer.CopyDecl(&temporary_ast->getASTContext(), source.record_decl);
|
|
ASSERT_NE(nullptr, temporary_imported);
|
|
|
|
std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
|
|
clang::Decl *imported =
|
|
importer.CopyDecl(&target_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.
|
|
|
|
clang_utils::SourceASTWithRecord source;
|
|
const lldb::user_id_t metadata = 123456;
|
|
|
|
std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
|
|
|
|
ClangASTImporter importer;
|
|
clang::Decl *imported =
|
|
importer.CopyDecl(&target_ast->getASTContext(), source.record_decl);
|
|
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.record_decl, 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.
|
|
|
|
clang_utils::SourceASTWithRecord source;
|
|
|
|
ClangASTImporter importer;
|
|
ClangASTImporter::LayoutInfo layout_info;
|
|
layout_info.bit_size = 15;
|
|
layout_info.alignment = 2;
|
|
layout_info.field_offsets[source.field_decl] = 1;
|
|
importer.SetRecordLayout(source.record_decl, layout_info);
|
|
|
|
uint64_t bit_size;
|
|
uint64_t alignment;
|
|
llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
|
|
llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> base_offsets;
|
|
llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> vbase_offsets;
|
|
importer.LayoutRecordType(source.record_decl, 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[source.field_decl]);
|
|
EXPECT_EQ(0U, base_offsets.size());
|
|
EXPECT_EQ(0U, vbase_offsets.size());
|
|
}
|