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