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 31 TEST_F(TestClangASTImporter, CanImportInvalidType) { 32 ClangASTImporter importer; 33 EXPECT_FALSE(importer.CanImport(CompilerType())); 34 } 35 36 TEST_F(TestClangASTImporter, ImportInvalidType) { 37 ClangASTImporter importer; 38 EXPECT_FALSE(importer.Import(CompilerType())); 39 } 40 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 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 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 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 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 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 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 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 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