1 //===-- TestClangASTImporter.cpp ------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "gtest/gtest.h"
11 #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
12 #include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h"
13 #include "Plugins/ExpressionParser/Clang/ClangUtil.h"
14 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
15 #include "TestingSupport/SubsystemRAII.h"
16 #include "TestingSupport/Symbol/ClangTestUtils.h"
17 #include "lldb/Core/Declaration.h"
18 #include "lldb/Host/FileSystem.h"
19 #include "lldb/Host/HostInfo.h"
20 #include "clang/AST/DeclCXX.h"
22 using namespace clang
;
24 using namespace lldb_private
;
26 class TestClangASTImporter
: public testing::Test
{
28 SubsystemRAII
<FileSystem
, HostInfo
> subsystems
;
31 TEST_F(TestClangASTImporter
, CanImportInvalidType
) {
32 ClangASTImporter importer
;
33 EXPECT_FALSE(importer
.CanImport(CompilerType()));
36 TEST_F(TestClangASTImporter
, ImportInvalidType
) {
37 ClangASTImporter importer
;
38 EXPECT_FALSE(importer
.Import(CompilerType()));
41 TEST_F(TestClangASTImporter
, CopyDeclTagDecl
) {
42 // Tests that the ClangASTImporter::CopyDecl can copy TagDecls.
43 clang_utils::SourceASTWithRecord source
;
46 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
47 auto *target_ast
= holder
->GetAST();
49 ClangASTImporter importer
;
50 clang::Decl
*imported
=
51 importer
.CopyDecl(&target_ast
->getASTContext(), source
.record_decl
);
52 ASSERT_NE(nullptr, imported
);
54 // Check that we got the correct decl by just comparing their qualified name.
55 clang::TagDecl
*imported_tag_decl
= llvm::cast
<clang::TagDecl
>(imported
);
56 EXPECT_EQ(source
.record_decl
->getQualifiedNameAsString(),
57 imported_tag_decl
->getQualifiedNameAsString());
58 // We did a minimal import of the tag decl.
59 EXPECT_TRUE(imported_tag_decl
->hasExternalLexicalStorage());
61 // Check that origin was set for the imported declaration.
62 ClangASTImporter::DeclOrigin origin
= importer
.GetDeclOrigin(imported
);
63 EXPECT_TRUE(origin
.Valid());
64 EXPECT_EQ(origin
.ctx
, &source
.ast
->getASTContext());
65 EXPECT_EQ(origin
.decl
, source
.record_decl
);
68 TEST_F(TestClangASTImporter
, CopyTypeTagDecl
) {
69 // Tests that the ClangASTImporter::CopyType can copy TagDecls types.
70 clang_utils::SourceASTWithRecord source
;
73 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
74 auto *target_ast
= holder
->GetAST();
76 ClangASTImporter importer
;
77 CompilerType imported
= importer
.CopyType(*target_ast
, source
.record_type
);
78 ASSERT_TRUE(imported
.IsValid());
80 // Check that we got the correct decl by just comparing their qualified name.
81 clang::TagDecl
*imported_tag_decl
= ClangUtil::GetAsTagDecl(imported
);
82 EXPECT_EQ(source
.record_decl
->getQualifiedNameAsString(),
83 imported_tag_decl
->getQualifiedNameAsString());
84 // We did a minimal import of the tag decl.
85 EXPECT_TRUE(imported_tag_decl
->hasExternalLexicalStorage());
87 // Check that origin was set for the imported declaration.
88 ClangASTImporter::DeclOrigin origin
=
89 importer
.GetDeclOrigin(imported_tag_decl
);
90 EXPECT_TRUE(origin
.Valid());
91 EXPECT_EQ(origin
.ctx
, &source
.ast
->getASTContext());
92 EXPECT_EQ(origin
.decl
, source
.record_decl
);
95 TEST_F(TestClangASTImporter
, CompleteFwdDeclWithOtherOrigin
) {
96 // Create an AST with a full type that is defined.
97 clang_utils::SourceASTWithRecord source_with_definition
;
99 // Create an AST with a type thst is only a forward declaration with the
100 // same name as the one in the other source.
102 std::make_unique
<clang_utils::TypeSystemClangHolder
>("ast");
103 auto *fwd_decl_source
= holder
->GetAST();
104 CompilerType fwd_decl_type
= clang_utils::createRecord(
105 *fwd_decl_source
, source_with_definition
.record_decl
->getName());
107 // Create a target and import the forward decl.
109 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
110 auto *target
= target_holder
->GetAST();
111 ClangASTImporter importer
;
112 CompilerType imported
= importer
.CopyType(*target
, fwd_decl_type
);
113 ASSERT_TRUE(imported
.IsValid());
114 EXPECT_FALSE(imported
.IsDefined());
116 // Now complete the forward decl with the definition from the other source.
117 // This should define the decl and give it the fields of the other origin.
118 clang::TagDecl
*imported_tag_decl
= ClangUtil::GetAsTagDecl(imported
);
119 importer
.CompleteTagDeclWithOrigin(imported_tag_decl
,
120 source_with_definition
.record_decl
);
121 ASSERT_TRUE(imported
.IsValid());
122 EXPECT_TRUE(imported
.IsDefined());
123 EXPECT_EQ(1U, imported
.GetNumFields());
126 TEST_F(TestClangASTImporter
, DeportDeclTagDecl
) {
127 // Tests that the ClangASTImporter::DeportDecl completely copies TagDecls.
128 clang_utils::SourceASTWithRecord source
;
131 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
132 auto *target_ast
= holder
->GetAST();
134 ClangASTImporter importer
;
135 clang::Decl
*imported
=
136 importer
.DeportDecl(&target_ast
->getASTContext(), source
.record_decl
);
137 ASSERT_NE(nullptr, imported
);
139 // Check that we got the correct decl by just comparing their qualified name.
140 clang::TagDecl
*imported_tag_decl
= llvm::cast
<clang::TagDecl
>(imported
);
141 EXPECT_EQ(source
.record_decl
->getQualifiedNameAsString(),
142 imported_tag_decl
->getQualifiedNameAsString());
143 // The record should be completed as we deported it.
144 EXPECT_FALSE(imported_tag_decl
->hasExternalLexicalStorage());
146 // Deporting doesn't update the origin map.
147 EXPECT_FALSE(importer
.GetDeclOrigin(imported_tag_decl
).Valid());
150 TEST_F(TestClangASTImporter
, DeportTypeTagDecl
) {
151 // Tests that the ClangASTImporter::CopyType can deport TagDecl types.
152 clang_utils::SourceASTWithRecord source
;
155 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
156 auto *target_ast
= holder
->GetAST();
158 ClangASTImporter importer
;
159 CompilerType imported
= importer
.DeportType(*target_ast
, source
.record_type
);
160 ASSERT_TRUE(imported
.IsValid());
162 // Check that we got the correct decl by just comparing their qualified name.
163 clang::TagDecl
*imported_tag_decl
= ClangUtil::GetAsTagDecl(imported
);
164 EXPECT_EQ(source
.record_decl
->getQualifiedNameAsString(),
165 imported_tag_decl
->getQualifiedNameAsString());
166 // The record should be completed as we deported it.
167 EXPECT_FALSE(imported_tag_decl
->hasExternalLexicalStorage());
169 // Deporting doesn't update the origin map.
170 EXPECT_FALSE(importer
.GetDeclOrigin(imported_tag_decl
).Valid());
173 TEST_F(TestClangASTImporter
, MetadataPropagation
) {
174 // Tests that AST metadata is propagated when copying declarations.
176 clang_utils::SourceASTWithRecord source
;
178 const lldb::user_id_t metadata
= 123456;
179 source
.ast
->SetMetadataAsUserID(source
.record_decl
, metadata
);
182 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
183 auto *target_ast
= holder
->GetAST();
185 ClangASTImporter importer
;
186 clang::Decl
*imported
=
187 importer
.CopyDecl(&target_ast
->getASTContext(), source
.record_decl
);
188 ASSERT_NE(nullptr, imported
);
190 // Check that we got the same Metadata.
191 ASSERT_NE(nullptr, importer
.GetDeclMetadata(imported
));
192 EXPECT_EQ(metadata
, importer
.GetDeclMetadata(imported
)->GetUserID());
195 TEST_F(TestClangASTImporter
, MetadataPropagationIndirectImport
) {
196 // Tests that AST metadata is propagated when copying declarations when
197 // importing one declaration into a temporary context and then to the
198 // actual destination context.
200 clang_utils::SourceASTWithRecord source
;
202 const lldb::user_id_t metadata
= 123456;
203 source
.ast
->SetMetadataAsUserID(source
.record_decl
, metadata
);
206 std::make_unique
<clang_utils::TypeSystemClangHolder
>("tmp ast");
207 auto *temporary_ast
= tmp_holder
->GetAST();
209 ClangASTImporter importer
;
210 clang::Decl
*temporary_imported
=
211 importer
.CopyDecl(&temporary_ast
->getASTContext(), source
.record_decl
);
212 ASSERT_NE(nullptr, temporary_imported
);
215 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
216 auto *target_ast
= holder
->GetAST();
217 clang::Decl
*imported
=
218 importer
.CopyDecl(&target_ast
->getASTContext(), temporary_imported
);
219 ASSERT_NE(nullptr, imported
);
221 // Check that we got the same Metadata.
222 ASSERT_NE(nullptr, importer
.GetDeclMetadata(imported
));
223 EXPECT_EQ(metadata
, importer
.GetDeclMetadata(imported
)->GetUserID());
226 TEST_F(TestClangASTImporter
, MetadataPropagationAfterCopying
) {
227 // Tests that AST metadata is propagated when copying declarations even
228 // when the metadata was set after the declaration has already been copied.
230 clang_utils::SourceASTWithRecord source
;
231 const lldb::user_id_t metadata
= 123456;
234 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
235 auto *target_ast
= holder
->GetAST();
237 ClangASTImporter importer
;
238 clang::Decl
*imported
=
239 importer
.CopyDecl(&target_ast
->getASTContext(), source
.record_decl
);
240 ASSERT_NE(nullptr, imported
);
242 // The TagDecl has been imported. Now set the metadata of the source and
243 // make sure the imported one will directly see it.
244 source
.ast
->SetMetadataAsUserID(source
.record_decl
, metadata
);
246 // Check that we got the same Metadata.
247 ASSERT_NE(nullptr, importer
.GetDeclMetadata(imported
));
248 EXPECT_EQ(metadata
, importer
.GetDeclMetadata(imported
)->GetUserID());
251 TEST_F(TestClangASTImporter
, RecordLayout
) {
252 // Test that it is possible to register RecordDecl layouts and then later
253 // correctly retrieve them.
255 clang_utils::SourceASTWithRecord source
;
257 ClangASTImporter importer
;
258 ClangASTImporter::LayoutInfo layout_info
;
259 layout_info
.bit_size
= 15;
260 layout_info
.alignment
= 2;
261 layout_info
.field_offsets
[source
.field_decl
] = 1;
262 importer
.SetRecordLayout(source
.record_decl
, layout_info
);
266 llvm::DenseMap
<const clang::FieldDecl
*, uint64_t> field_offsets
;
267 llvm::DenseMap
<const clang::CXXRecordDecl
*, clang::CharUnits
> base_offsets
;
268 llvm::DenseMap
<const clang::CXXRecordDecl
*, clang::CharUnits
> vbase_offsets
;
269 importer
.LayoutRecordType(source
.record_decl
, bit_size
, alignment
,
270 field_offsets
, base_offsets
, vbase_offsets
);
272 EXPECT_EQ(15U, bit_size
);
273 EXPECT_EQ(2U, alignment
);
274 EXPECT_EQ(1U, field_offsets
.size());
275 EXPECT_EQ(1U, field_offsets
[source
.field_decl
]);
276 EXPECT_EQ(0U, base_offsets
.size());
277 EXPECT_EQ(0U, vbase_offsets
.size());