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/SymbolFile/DWARF/DWARFASTParserClang.h"
15 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
16 #include "TestingSupport/SubsystemRAII.h"
17 #include "TestingSupport/Symbol/ClangTestUtils.h"
18 #include "lldb/Core/Declaration.h"
19 #include "lldb/Host/FileSystem.h"
20 #include "lldb/Host/HostInfo.h"
21 #include "clang/AST/DeclCXX.h"
23 using namespace clang
;
25 using namespace lldb_private
;
27 class TestClangASTImporter
: public testing::Test
{
29 SubsystemRAII
<FileSystem
, HostInfo
> subsystems
;
32 TEST_F(TestClangASTImporter
, CanImportInvalidType
) {
33 ClangASTImporter importer
;
34 EXPECT_FALSE(importer
.CanImport(CompilerType()));
37 TEST_F(TestClangASTImporter
, ImportInvalidType
) {
38 ClangASTImporter importer
;
39 EXPECT_FALSE(importer
.Import(CompilerType()));
42 TEST_F(TestClangASTImporter
, CopyDeclTagDecl
) {
43 // Tests that the ClangASTImporter::CopyDecl can copy TagDecls.
44 clang_utils::SourceASTWithRecord source
;
47 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
48 auto *target_ast
= holder
->GetAST();
50 ClangASTImporter importer
;
51 clang::Decl
*imported
=
52 importer
.CopyDecl(&target_ast
->getASTContext(), source
.record_decl
);
53 ASSERT_NE(nullptr, imported
);
55 // Check that we got the correct decl by just comparing their qualified name.
56 clang::TagDecl
*imported_tag_decl
= llvm::cast
<clang::TagDecl
>(imported
);
57 EXPECT_EQ(source
.record_decl
->getQualifiedNameAsString(),
58 imported_tag_decl
->getQualifiedNameAsString());
59 // We did a minimal import of the tag decl.
60 EXPECT_TRUE(imported_tag_decl
->hasExternalLexicalStorage());
62 // Check that origin was set for the imported declaration.
63 ClangASTImporter::DeclOrigin origin
= importer
.GetDeclOrigin(imported
);
64 EXPECT_TRUE(origin
.Valid());
65 EXPECT_EQ(origin
.ctx
, &source
.ast
->getASTContext());
66 EXPECT_EQ(origin
.decl
, source
.record_decl
);
69 TEST_F(TestClangASTImporter
, CopyTypeTagDecl
) {
70 // Tests that the ClangASTImporter::CopyType can copy TagDecls types.
71 clang_utils::SourceASTWithRecord source
;
74 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
75 auto *target_ast
= holder
->GetAST();
77 ClangASTImporter importer
;
78 CompilerType imported
= importer
.CopyType(*target_ast
, source
.record_type
);
79 ASSERT_TRUE(imported
.IsValid());
81 // Check that we got the correct decl by just comparing their qualified name.
82 clang::TagDecl
*imported_tag_decl
= ClangUtil::GetAsTagDecl(imported
);
83 EXPECT_EQ(source
.record_decl
->getQualifiedNameAsString(),
84 imported_tag_decl
->getQualifiedNameAsString());
85 // We did a minimal import of the tag decl.
86 EXPECT_TRUE(imported_tag_decl
->hasExternalLexicalStorage());
88 // Check that origin was set for the imported declaration.
89 ClangASTImporter::DeclOrigin origin
=
90 importer
.GetDeclOrigin(imported_tag_decl
);
91 EXPECT_TRUE(origin
.Valid());
92 EXPECT_EQ(origin
.ctx
, &source
.ast
->getASTContext());
93 EXPECT_EQ(origin
.decl
, source
.record_decl
);
96 TEST_F(TestClangASTImporter
, CompleteFwdDeclWithOtherOrigin
) {
97 // Create an AST with a full type that is defined.
98 clang_utils::SourceASTWithRecord source_with_definition
;
100 // Create an AST with a type thst is only a forward declaration with the
101 // same name as the one in the other source.
103 std::make_unique
<clang_utils::TypeSystemClangHolder
>("ast");
104 auto *fwd_decl_source
= holder
->GetAST();
105 CompilerType fwd_decl_type
= clang_utils::createRecord(
106 *fwd_decl_source
, source_with_definition
.record_decl
->getName());
108 // Create a target and import the forward decl.
110 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
111 auto *target
= target_holder
->GetAST();
112 ClangASTImporter importer
;
113 CompilerType imported
= importer
.CopyType(*target
, fwd_decl_type
);
114 ASSERT_TRUE(imported
.IsValid());
115 EXPECT_FALSE(imported
.IsDefined());
117 // Now complete the forward decl with the definition from the other source.
118 // This should define the decl and give it the fields of the other origin.
119 clang::TagDecl
*imported_tag_decl
= ClangUtil::GetAsTagDecl(imported
);
120 importer
.CompleteTagDeclWithOrigin(imported_tag_decl
,
121 source_with_definition
.record_decl
);
122 ASSERT_TRUE(imported
.IsValid());
123 EXPECT_TRUE(imported
.IsDefined());
124 EXPECT_EQ(1U, imported
.GetNumFields());
127 TEST_F(TestClangASTImporter
, DeportDeclTagDecl
) {
128 // Tests that the ClangASTImporter::DeportDecl completely copies TagDecls.
129 clang_utils::SourceASTWithRecord source
;
132 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
133 auto *target_ast
= holder
->GetAST();
135 ClangASTImporter importer
;
136 clang::Decl
*imported
=
137 importer
.DeportDecl(&target_ast
->getASTContext(), source
.record_decl
);
138 ASSERT_NE(nullptr, imported
);
140 // Check that we got the correct decl by just comparing their qualified name.
141 clang::TagDecl
*imported_tag_decl
= llvm::cast
<clang::TagDecl
>(imported
);
142 EXPECT_EQ(source
.record_decl
->getQualifiedNameAsString(),
143 imported_tag_decl
->getQualifiedNameAsString());
144 // The record should be completed as we deported it.
145 EXPECT_FALSE(imported_tag_decl
->hasExternalLexicalStorage());
147 // Deporting doesn't update the origin map.
148 EXPECT_FALSE(importer
.GetDeclOrigin(imported_tag_decl
).Valid());
151 TEST_F(TestClangASTImporter
, DeportTypeTagDecl
) {
152 // Tests that the ClangASTImporter::CopyType can deport TagDecl types.
153 clang_utils::SourceASTWithRecord source
;
156 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
157 auto *target_ast
= holder
->GetAST();
159 ClangASTImporter importer
;
160 CompilerType imported
= importer
.DeportType(*target_ast
, source
.record_type
);
161 ASSERT_TRUE(imported
.IsValid());
163 // Check that we got the correct decl by just comparing their qualified name.
164 clang::TagDecl
*imported_tag_decl
= ClangUtil::GetAsTagDecl(imported
);
165 EXPECT_EQ(source
.record_decl
->getQualifiedNameAsString(),
166 imported_tag_decl
->getQualifiedNameAsString());
167 // The record should be completed as we deported it.
168 EXPECT_FALSE(imported_tag_decl
->hasExternalLexicalStorage());
170 // Deporting doesn't update the origin map.
171 EXPECT_FALSE(importer
.GetDeclOrigin(imported_tag_decl
).Valid());
174 TEST_F(TestClangASTImporter
, MetadataPropagation
) {
175 // Tests that AST metadata is propagated when copying declarations.
177 clang_utils::SourceASTWithRecord source
;
179 const lldb::user_id_t metadata
= 123456;
180 source
.ast
->SetMetadataAsUserID(source
.record_decl
, metadata
);
183 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
184 auto *target_ast
= holder
->GetAST();
186 ClangASTImporter importer
;
187 clang::Decl
*imported
=
188 importer
.CopyDecl(&target_ast
->getASTContext(), source
.record_decl
);
189 ASSERT_NE(nullptr, imported
);
191 // Check that we got the same Metadata.
192 ASSERT_NE(std::nullopt
, importer
.GetDeclMetadata(imported
));
193 EXPECT_EQ(metadata
, importer
.GetDeclMetadata(imported
)->GetUserID());
196 TEST_F(TestClangASTImporter
, MetadataPropagationIndirectImport
) {
197 // Tests that AST metadata is propagated when copying declarations when
198 // importing one declaration into a temporary context and then to the
199 // actual destination context.
201 clang_utils::SourceASTWithRecord source
;
203 const lldb::user_id_t metadata
= 123456;
204 source
.ast
->SetMetadataAsUserID(source
.record_decl
, metadata
);
207 std::make_unique
<clang_utils::TypeSystemClangHolder
>("tmp ast");
208 auto *temporary_ast
= tmp_holder
->GetAST();
210 ClangASTImporter importer
;
211 clang::Decl
*temporary_imported
=
212 importer
.CopyDecl(&temporary_ast
->getASTContext(), source
.record_decl
);
213 ASSERT_NE(nullptr, temporary_imported
);
216 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
217 auto *target_ast
= holder
->GetAST();
218 clang::Decl
*imported
=
219 importer
.CopyDecl(&target_ast
->getASTContext(), temporary_imported
);
220 ASSERT_NE(nullptr, imported
);
222 // Check that we got the same Metadata.
223 ASSERT_NE(std::nullopt
, importer
.GetDeclMetadata(imported
));
224 EXPECT_EQ(metadata
, importer
.GetDeclMetadata(imported
)->GetUserID());
227 TEST_F(TestClangASTImporter
, MetadataPropagationAfterCopying
) {
228 // Tests that AST metadata is propagated when copying declarations even
229 // when the metadata was set after the declaration has already been copied.
231 clang_utils::SourceASTWithRecord source
;
232 const lldb::user_id_t metadata
= 123456;
235 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
236 auto *target_ast
= holder
->GetAST();
238 ClangASTImporter importer
;
239 clang::Decl
*imported
=
240 importer
.CopyDecl(&target_ast
->getASTContext(), source
.record_decl
);
241 ASSERT_NE(nullptr, imported
);
243 // The TagDecl has been imported. Now set the metadata of the source and
244 // make sure the imported one will directly see it.
245 source
.ast
->SetMetadataAsUserID(source
.record_decl
, metadata
);
247 // Check that we got the same Metadata.
248 ASSERT_NE(std::nullopt
, importer
.GetDeclMetadata(imported
));
249 EXPECT_EQ(metadata
, importer
.GetDeclMetadata(imported
)->GetUserID());
252 TEST_F(TestClangASTImporter
, RecordLayout
) {
253 // Test that it is possible to register RecordDecl layouts and then later
254 // correctly retrieve them.
256 clang_utils::SourceASTWithRecord source
;
258 ClangASTImporter importer
;
259 ClangASTImporter::LayoutInfo layout_info
;
260 layout_info
.bit_size
= 15;
261 layout_info
.alignment
= 2;
262 layout_info
.field_offsets
[source
.field_decl
] = 1;
263 importer
.SetRecordLayout(source
.record_decl
, layout_info
);
267 llvm::DenseMap
<const clang::FieldDecl
*, uint64_t> field_offsets
;
268 llvm::DenseMap
<const clang::CXXRecordDecl
*, clang::CharUnits
> base_offsets
;
269 llvm::DenseMap
<const clang::CXXRecordDecl
*, clang::CharUnits
> vbase_offsets
;
270 importer
.LayoutRecordType(source
.record_decl
, bit_size
, alignment
,
271 field_offsets
, base_offsets
, vbase_offsets
);
273 EXPECT_EQ(15U, bit_size
);
274 EXPECT_EQ(2U, alignment
);
275 EXPECT_EQ(1U, field_offsets
.size());
276 EXPECT_EQ(1U, field_offsets
[source
.field_decl
]);
277 EXPECT_EQ(0U, base_offsets
.size());
278 EXPECT_EQ(0U, vbase_offsets
.size());
281 TEST_F(TestClangASTImporter
, RecordLayoutFromOrigin
) {
282 // Tests that we can retrieve the layout of a record that has
283 // an origin with an already existing LayoutInfo. We expect
284 // the layout to be retrieved from the ClangASTImporter of the
287 clang_utils::SourceASTWithRecord source
;
290 static_cast<DWARFASTParserClang
*>(source
.ast
->GetDWARFParser());
291 auto &importer
= dwarf_parser
->GetClangASTImporter();
293 // Set the layout for the origin decl in the origin ClangASTImporter.
294 ClangASTImporter::LayoutInfo layout_info
;
295 layout_info
.bit_size
= 32;
296 layout_info
.alignment
= 16;
297 layout_info
.field_offsets
[source
.field_decl
] = 1;
298 importer
.SetRecordLayout(source
.record_decl
, layout_info
);
301 std::make_unique
<clang_utils::TypeSystemClangHolder
>("target ast");
302 auto *target_ast
= holder
->GetAST();
304 // Import the decl into a new TypeSystemClang.
305 CompilerType imported
= importer
.CopyType(*target_ast
, source
.record_type
);
306 ASSERT_TRUE(imported
.IsValid());
308 auto *imported_decl
= cast
<CXXRecordDecl
>(ClangUtil::GetAsTagDecl(imported
));
309 ClangASTImporter::DeclOrigin origin
= importer
.GetDeclOrigin(imported_decl
);
310 ASSERT_TRUE(origin
.Valid());
311 ASSERT_EQ(origin
.decl
, source
.record_decl
);
315 llvm::DenseMap
<const clang::FieldDecl
*, uint64_t> field_offsets
;
316 llvm::DenseMap
<const clang::CXXRecordDecl
*, clang::CharUnits
> base_offsets
;
317 llvm::DenseMap
<const clang::CXXRecordDecl
*, clang::CharUnits
> vbase_offsets
;
319 // Make sure we correctly read out the layout (despite not Having
320 // called SetRecordLayout on the new TypeSystem's ClangASTImporter).
322 importer
.LayoutRecordType(imported_decl
, bit_size
, alignment
,
323 field_offsets
, base_offsets
, vbase_offsets
);
324 EXPECT_TRUE(success
);
326 EXPECT_EQ(32U, bit_size
);
327 EXPECT_EQ(16U, alignment
);
328 EXPECT_EQ(1U, field_offsets
.size());
329 EXPECT_EQ(1U, field_offsets
[*imported_decl
->field_begin()]);
330 EXPECT_EQ(0U, base_offsets
.size());
331 EXPECT_EQ(0U, vbase_offsets
.size());