brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.7 KiB · f1b3d79 Raw
333 lines · cpp
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-exception6//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/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"22 23using namespace clang;24using namespace lldb;25using namespace lldb_private;26 27class TestClangASTImporter : public testing::Test {28public:29  SubsystemRAII<FileSystem, HostInfo> subsystems;30};31 32TEST_F(TestClangASTImporter, CanImportInvalidType) {33  ClangASTImporter importer;34  EXPECT_FALSE(importer.CanImport(CompilerType()));35}36 37TEST_F(TestClangASTImporter, ImportInvalidType) {38  ClangASTImporter importer;39  EXPECT_FALSE(importer.Import(CompilerType()));40}41 42TEST_F(TestClangASTImporter, CopyDeclTagDecl) {43  // Tests that the ClangASTImporter::CopyDecl can copy TagDecls.44  clang_utils::SourceASTWithRecord source;45 46  auto holder =47      std::make_unique<clang_utils::TypeSystemClangHolder>("target ast");48  auto *target_ast = holder->GetAST();49 50  ClangASTImporter importer;51  clang::Decl *imported =52      importer.CopyDecl(&target_ast->getASTContext(), source.record_decl);53  ASSERT_NE(nullptr, imported);54 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());61 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);67}68 69TEST_F(TestClangASTImporter, CopyTypeTagDecl) {70  // Tests that the ClangASTImporter::CopyType can copy TagDecls types.71  clang_utils::SourceASTWithRecord source;72 73  auto holder =74      std::make_unique<clang_utils::TypeSystemClangHolder>("target ast");75  auto *target_ast = holder->GetAST();76 77  ClangASTImporter importer;78  CompilerType imported = importer.CopyType(*target_ast, source.record_type);79  ASSERT_TRUE(imported.IsValid());80 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());87 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);94}95 96TEST_F(TestClangASTImporter, CompleteFwdDeclWithOtherOrigin) {97  // Create an AST with a full type that is defined.98  clang_utils::SourceASTWithRecord source_with_definition;99 100  // Create an AST with a type thst is only a forward declaration with the101  // same name as the one in the other source.102  auto holder =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());107 108  // Create a target and import the forward decl.109  auto target_holder =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());116 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());125}126 127TEST_F(TestClangASTImporter, DeportDeclTagDecl) {128  // Tests that the ClangASTImporter::DeportDecl completely copies TagDecls.129  clang_utils::SourceASTWithRecord source;130 131  auto holder =132      std::make_unique<clang_utils::TypeSystemClangHolder>("target ast");133  auto *target_ast = holder->GetAST();134 135  ClangASTImporter importer;136  clang::Decl *imported =137      importer.DeportDecl(&target_ast->getASTContext(), source.record_decl);138  ASSERT_NE(nullptr, imported);139 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());146 147  // Deporting doesn't update the origin map.148  EXPECT_FALSE(importer.GetDeclOrigin(imported_tag_decl).Valid());149}150 151TEST_F(TestClangASTImporter, DeportTypeTagDecl) {152  // Tests that the ClangASTImporter::CopyType can deport TagDecl types.153  clang_utils::SourceASTWithRecord source;154 155  auto holder =156      std::make_unique<clang_utils::TypeSystemClangHolder>("target ast");157  auto *target_ast = holder->GetAST();158 159  ClangASTImporter importer;160  CompilerType imported = importer.DeportType(*target_ast, source.record_type);161  ASSERT_TRUE(imported.IsValid());162 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());169 170  // Deporting doesn't update the origin map.171  EXPECT_FALSE(importer.GetDeclOrigin(imported_tag_decl).Valid());172}173 174TEST_F(TestClangASTImporter, MetadataPropagation) {175  // Tests that AST metadata is propagated when copying declarations.176 177  clang_utils::SourceASTWithRecord source;178 179  const lldb::user_id_t metadata = 123456;180  source.ast->SetMetadataAsUserID(source.record_decl, metadata);181 182  auto holder =183      std::make_unique<clang_utils::TypeSystemClangHolder>("target ast");184  auto *target_ast = holder->GetAST();185 186  ClangASTImporter importer;187  clang::Decl *imported =188      importer.CopyDecl(&target_ast->getASTContext(), source.record_decl);189  ASSERT_NE(nullptr, imported);190 191  // Check that we got the same Metadata.192  ASSERT_NE(std::nullopt, importer.GetDeclMetadata(imported));193  EXPECT_EQ(metadata, importer.GetDeclMetadata(imported)->GetUserID());194}195 196TEST_F(TestClangASTImporter, MetadataPropagationIndirectImport) {197  // Tests that AST metadata is propagated when copying declarations when198  // importing one declaration into a temporary context and then to the199  // actual destination context.200 201  clang_utils::SourceASTWithRecord source;202 203  const lldb::user_id_t metadata = 123456;204  source.ast->SetMetadataAsUserID(source.record_decl, metadata);205 206  auto tmp_holder =207      std::make_unique<clang_utils::TypeSystemClangHolder>("tmp ast");208  auto *temporary_ast = tmp_holder->GetAST();209 210  ClangASTImporter importer;211  clang::Decl *temporary_imported =212      importer.CopyDecl(&temporary_ast->getASTContext(), source.record_decl);213  ASSERT_NE(nullptr, temporary_imported);214 215  auto holder =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);221 222  // Check that we got the same Metadata.223  ASSERT_NE(std::nullopt, importer.GetDeclMetadata(imported));224  EXPECT_EQ(metadata, importer.GetDeclMetadata(imported)->GetUserID());225}226 227TEST_F(TestClangASTImporter, MetadataPropagationAfterCopying) {228  // Tests that AST metadata is propagated when copying declarations even229  // when the metadata was set after the declaration has already been copied.230 231  clang_utils::SourceASTWithRecord source;232  const lldb::user_id_t metadata = 123456;233 234  auto holder =235      std::make_unique<clang_utils::TypeSystemClangHolder>("target ast");236  auto *target_ast = holder->GetAST();237 238  ClangASTImporter importer;239  clang::Decl *imported =240      importer.CopyDecl(&target_ast->getASTContext(), source.record_decl);241  ASSERT_NE(nullptr, imported);242 243  // The TagDecl has been imported. Now set the metadata of the source and244  // make sure the imported one will directly see it.245  source.ast->SetMetadataAsUserID(source.record_decl, metadata);246 247  // Check that we got the same Metadata.248  ASSERT_NE(std::nullopt, importer.GetDeclMetadata(imported));249  EXPECT_EQ(metadata, importer.GetDeclMetadata(imported)->GetUserID());250}251 252TEST_F(TestClangASTImporter, RecordLayout) {253  // Test that it is possible to register RecordDecl layouts and then later254  // correctly retrieve them.255 256  clang_utils::SourceASTWithRecord source;257 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);264 265  uint64_t bit_size;266  uint64_t alignment;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);272 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());279}280 281TEST_F(TestClangASTImporter, RecordLayoutFromOrigin) {282  // Tests that we can retrieve the layout of a record that has283  // an origin with an already existing LayoutInfo. We expect284  // the layout to be retrieved from the ClangASTImporter of the285  // origin decl.286 287  clang_utils::SourceASTWithRecord source;288 289  auto *dwarf_parser =290      static_cast<DWARFASTParserClang *>(source.ast->GetDWARFParser());291  auto &importer = dwarf_parser->GetClangASTImporter();292 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);299 300  auto holder =301      std::make_unique<clang_utils::TypeSystemClangHolder>("target ast");302  auto *target_ast = holder->GetAST();303 304  // Import the decl into a new TypeSystemClang.305  CompilerType imported = importer.CopyType(*target_ast, source.record_type);306  ASSERT_TRUE(imported.IsValid());307 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);312 313  uint64_t bit_size;314  uint64_t alignment;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;318 319  // Make sure we correctly read out the layout (despite not Having320  // called SetRecordLayout on the new TypeSystem's ClangASTImporter).321  auto success =322      importer.LayoutRecordType(imported_decl, bit_size, alignment,323                                field_offsets, base_offsets, vbase_offsets);324  EXPECT_TRUE(success);325 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());332}333