1 //===-- TestClangASTImporter.cpp ------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "gtest/gtest.h"
10
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/Host/FileSystem.h"
18 #include "lldb/Host/HostInfo.h"
19 #include "lldb/Symbol/Declaration.h"
20 #include "clang/AST/DeclCXX.h"
21
22 using namespace clang;
23 using namespace lldb;
24 using namespace lldb_private;
25
26 class TestClangASTImporter : public testing::Test {
27 public:
28 SubsystemRAII<FileSystem, HostInfo> subsystems;
29 };
30
TEST_F(TestClangASTImporter,CanImportInvalidType)31 TEST_F(TestClangASTImporter, CanImportInvalidType) {
32 ClangASTImporter importer;
33 EXPECT_FALSE(importer.CanImport(CompilerType()));
34 }
35
TEST_F(TestClangASTImporter,ImportInvalidType)36 TEST_F(TestClangASTImporter, ImportInvalidType) {
37 ClangASTImporter importer;
38 EXPECT_FALSE(importer.Import(CompilerType()));
39 }
40
TEST_F(TestClangASTImporter,CopyDeclTagDecl)41 TEST_F(TestClangASTImporter, CopyDeclTagDecl) {
42 // Tests that the ClangASTImporter::CopyDecl can copy TagDecls.
43 clang_utils::SourceASTWithRecord source;
44
45 std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
46
47 ClangASTImporter importer;
48 clang::Decl *imported =
49 importer.CopyDecl(&target_ast->getASTContext(), source.record_decl);
50 ASSERT_NE(nullptr, imported);
51
52 // Check that we got the correct decl by just comparing their qualified name.
53 clang::TagDecl *imported_tag_decl = llvm::cast<clang::TagDecl>(imported);
54 EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
55 imported_tag_decl->getQualifiedNameAsString());
56 // We did a minimal import of the tag decl.
57 EXPECT_TRUE(imported_tag_decl->hasExternalLexicalStorage());
58
59 // Check that origin was set for the imported declaration.
60 ClangASTImporter::DeclOrigin origin = importer.GetDeclOrigin(imported);
61 EXPECT_TRUE(origin.Valid());
62 EXPECT_EQ(origin.ctx, &source.ast->getASTContext());
63 EXPECT_EQ(origin.decl, source.record_decl);
64 }
65
TEST_F(TestClangASTImporter,CopyTypeTagDecl)66 TEST_F(TestClangASTImporter, CopyTypeTagDecl) {
67 // Tests that the ClangASTImporter::CopyType can copy TagDecls types.
68 clang_utils::SourceASTWithRecord source;
69
70 std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
71
72 ClangASTImporter importer;
73 CompilerType imported = importer.CopyType(*target_ast, source.record_type);
74 ASSERT_TRUE(imported.IsValid());
75
76 // Check that we got the correct decl by just comparing their qualified name.
77 clang::TagDecl *imported_tag_decl = ClangUtil::GetAsTagDecl(imported);
78 EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
79 imported_tag_decl->getQualifiedNameAsString());
80 // We did a minimal import of the tag decl.
81 EXPECT_TRUE(imported_tag_decl->hasExternalLexicalStorage());
82
83 // Check that origin was set for the imported declaration.
84 ClangASTImporter::DeclOrigin origin =
85 importer.GetDeclOrigin(imported_tag_decl);
86 EXPECT_TRUE(origin.Valid());
87 EXPECT_EQ(origin.ctx, &source.ast->getASTContext());
88 EXPECT_EQ(origin.decl, source.record_decl);
89 }
90
TEST_F(TestClangASTImporter,CompleteFwdDeclWithOtherOrigin)91 TEST_F(TestClangASTImporter, CompleteFwdDeclWithOtherOrigin) {
92 // Create an AST with a full type that is defined.
93 clang_utils::SourceASTWithRecord source_with_definition;
94
95 // Create an AST with a type thst is only a forward declaration with the
96 // same name as the one in the the other source.
97 std::unique_ptr<TypeSystemClang> fwd_decl_source = clang_utils::createAST();
98 CompilerType fwd_decl_type = clang_utils::createRecord(
99 *fwd_decl_source, source_with_definition.record_decl->getName());
100
101 // Create a target and import the forward decl.
102 std::unique_ptr<TypeSystemClang> target = clang_utils::createAST();
103 ClangASTImporter importer;
104 CompilerType imported = importer.CopyType(*target, fwd_decl_type);
105 ASSERT_TRUE(imported.IsValid());
106 EXPECT_FALSE(imported.IsDefined());
107
108 // Now complete the forward decl with the definition from the other source.
109 // This should define the decl and give it the fields of the other origin.
110 clang::TagDecl *imported_tag_decl = ClangUtil::GetAsTagDecl(imported);
111 importer.CompleteTagDeclWithOrigin(imported_tag_decl,
112 source_with_definition.record_decl);
113 ASSERT_TRUE(imported.IsValid());
114 EXPECT_TRUE(imported.IsDefined());
115 EXPECT_EQ(1U, imported.GetNumFields());
116 }
117
TEST_F(TestClangASTImporter,DeportDeclTagDecl)118 TEST_F(TestClangASTImporter, DeportDeclTagDecl) {
119 // Tests that the ClangASTImporter::DeportDecl completely copies TagDecls.
120 clang_utils::SourceASTWithRecord source;
121
122 std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
123
124 ClangASTImporter importer;
125 clang::Decl *imported =
126 importer.DeportDecl(&target_ast->getASTContext(), source.record_decl);
127 ASSERT_NE(nullptr, imported);
128
129 // Check that we got the correct decl by just comparing their qualified name.
130 clang::TagDecl *imported_tag_decl = llvm::cast<clang::TagDecl>(imported);
131 EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
132 imported_tag_decl->getQualifiedNameAsString());
133 // The record should be completed as we deported it.
134 EXPECT_FALSE(imported_tag_decl->hasExternalLexicalStorage());
135
136 // Deporting doesn't update the origin map.
137 EXPECT_FALSE(importer.GetDeclOrigin(imported_tag_decl).Valid());
138 }
139
TEST_F(TestClangASTImporter,DeportTypeTagDecl)140 TEST_F(TestClangASTImporter, DeportTypeTagDecl) {
141 // Tests that the ClangASTImporter::CopyType can deport TagDecl types.
142 clang_utils::SourceASTWithRecord source;
143
144 std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
145
146 ClangASTImporter importer;
147 CompilerType imported = importer.DeportType(*target_ast, source.record_type);
148 ASSERT_TRUE(imported.IsValid());
149
150 // Check that we got the correct decl by just comparing their qualified name.
151 clang::TagDecl *imported_tag_decl = ClangUtil::GetAsTagDecl(imported);
152 EXPECT_EQ(source.record_decl->getQualifiedNameAsString(),
153 imported_tag_decl->getQualifiedNameAsString());
154 // The record should be completed as we deported it.
155 EXPECT_FALSE(imported_tag_decl->hasExternalLexicalStorage());
156
157 // Deporting doesn't update the origin map.
158 EXPECT_FALSE(importer.GetDeclOrigin(imported_tag_decl).Valid());
159 }
160
TEST_F(TestClangASTImporter,MetadataPropagation)161 TEST_F(TestClangASTImporter, MetadataPropagation) {
162 // Tests that AST metadata is propagated when copying declarations.
163
164 clang_utils::SourceASTWithRecord source;
165
166 const lldb::user_id_t metadata = 123456;
167 source.ast->SetMetadataAsUserID(source.record_decl, metadata);
168
169 std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
170
171 ClangASTImporter importer;
172 clang::Decl *imported =
173 importer.CopyDecl(&target_ast->getASTContext(), source.record_decl);
174 ASSERT_NE(nullptr, imported);
175
176 // Check that we got the same Metadata.
177 ASSERT_NE(nullptr, importer.GetDeclMetadata(imported));
178 EXPECT_EQ(metadata, importer.GetDeclMetadata(imported)->GetUserID());
179 }
180
TEST_F(TestClangASTImporter,MetadataPropagationIndirectImport)181 TEST_F(TestClangASTImporter, MetadataPropagationIndirectImport) {
182 // Tests that AST metadata is propagated when copying declarations when
183 // importing one declaration into a temporary context and then to the
184 // actual destination context.
185
186 clang_utils::SourceASTWithRecord source;
187
188 const lldb::user_id_t metadata = 123456;
189 source.ast->SetMetadataAsUserID(source.record_decl, metadata);
190
191 std::unique_ptr<TypeSystemClang> temporary_ast = clang_utils::createAST();
192
193 ClangASTImporter importer;
194 clang::Decl *temporary_imported =
195 importer.CopyDecl(&temporary_ast->getASTContext(), source.record_decl);
196 ASSERT_NE(nullptr, temporary_imported);
197
198 std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
199 clang::Decl *imported =
200 importer.CopyDecl(&target_ast->getASTContext(), temporary_imported);
201 ASSERT_NE(nullptr, imported);
202
203 // Check that we got the same Metadata.
204 ASSERT_NE(nullptr, importer.GetDeclMetadata(imported));
205 EXPECT_EQ(metadata, importer.GetDeclMetadata(imported)->GetUserID());
206 }
207
TEST_F(TestClangASTImporter,MetadataPropagationAfterCopying)208 TEST_F(TestClangASTImporter, MetadataPropagationAfterCopying) {
209 // Tests that AST metadata is propagated when copying declarations even
210 // when the metadata was set after the declaration has already been copied.
211
212 clang_utils::SourceASTWithRecord source;
213 const lldb::user_id_t metadata = 123456;
214
215 std::unique_ptr<TypeSystemClang> target_ast = clang_utils::createAST();
216
217 ClangASTImporter importer;
218 clang::Decl *imported =
219 importer.CopyDecl(&target_ast->getASTContext(), source.record_decl);
220 ASSERT_NE(nullptr, imported);
221
222 // The TagDecl has been imported. Now set the metadata of the source and
223 // make sure the imported one will directly see it.
224 source.ast->SetMetadataAsUserID(source.record_decl, metadata);
225
226 // Check that we got the same Metadata.
227 ASSERT_NE(nullptr, importer.GetDeclMetadata(imported));
228 EXPECT_EQ(metadata, importer.GetDeclMetadata(imported)->GetUserID());
229 }
230
TEST_F(TestClangASTImporter,RecordLayout)231 TEST_F(TestClangASTImporter, RecordLayout) {
232 // Test that it is possible to register RecordDecl layouts and then later
233 // correctly retrieve them.
234
235 clang_utils::SourceASTWithRecord source;
236
237 ClangASTImporter importer;
238 ClangASTImporter::LayoutInfo layout_info;
239 layout_info.bit_size = 15;
240 layout_info.alignment = 2;
241 layout_info.field_offsets[source.field_decl] = 1;
242 importer.SetRecordLayout(source.record_decl, layout_info);
243
244 uint64_t bit_size;
245 uint64_t alignment;
246 llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
247 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> base_offsets;
248 llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> vbase_offsets;
249 importer.LayoutRecordType(source.record_decl, bit_size, alignment,
250 field_offsets, base_offsets, vbase_offsets);
251
252 EXPECT_EQ(15U, bit_size);
253 EXPECT_EQ(2U, alignment);
254 EXPECT_EQ(1U, field_offsets.size());
255 EXPECT_EQ(1U, field_offsets[source.field_decl]);
256 EXPECT_EQ(0U, base_offsets.size());
257 EXPECT_EQ(0U, vbase_offsets.size());
258 }
259