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