1 : // Copyright 2015 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/refinery/types/type.h"
16 :
17 : #include "base/memory/ref_counted.h"
18 : #include "gtest/gtest.h"
19 : #include "syzygy/refinery/types/type_repository.h"
20 :
21 : namespace refinery {
22 :
23 : namespace {
24 :
25 : class TypesTest : public testing::Test {
26 : protected:
27 E : void SetUp() override {
28 E : Test::SetUp();
29 E : repo_ = new TypeRepository();
30 E : }
31 :
32 : TypePtr CreatePointerType(const wchar_t* name,
33 : size_t size,
34 : PointerType::Mode ptr_mode,
35 : Type::Flags flags,
36 E : TypeId content_type_id) {
37 E : PointerTypePtr ptr = new PointerType(size, ptr_mode);
38 E : ptr->Finalize(flags, content_type_id);
39 E : ptr->SetName(name);
40 E : return ptr;
41 E : }
42 :
43 : scoped_refptr<TypeRepository> repo_;
44 : };
45 :
46 : } // namespace
47 :
48 E : TEST_F(TypesTest, BasicType) {
49 : // Create a BasicType and store in a supertype pointer.
50 E : TypePtr type = new BasicType(L"foo", 10);
51 :
52 E : ASSERT_TRUE(type.get());
53 : // Verify the kind and fields.
54 E : EXPECT_EQ(Type::BASIC_TYPE_KIND, type->kind());
55 E : EXPECT_EQ(L"foo", type->name());
56 E : EXPECT_EQ(L"foo", type->decorated_name());
57 E : EXPECT_EQ(10U, type->size());
58 :
59 : // Down-cast it.
60 E : BasicTypePtr basic_type;
61 E : ASSERT_TRUE(type->CastTo(&basic_type));
62 E : ASSERT_TRUE(basic_type);
63 :
64 : // Verify that it can't be cast to a PointerType.
65 E : PointerTypePtr ptr;
66 E : EXPECT_FALSE(basic_type->CastTo(&ptr));
67 E : EXPECT_FALSE(ptr.get());
68 E : }
69 :
70 : // This test will eventually be deleted with the no-decorated-name constructor.
71 E : TEST_F(TypesTest, UserDefinedType) {
72 : // Build a UDT instance.
73 E : UserDefinedType::Fields fields;
74 :
75 E : const TypeId kBasicTypeId = repo_->AddType(new BasicType(L"int", 4));
76 : fields.push_back(
77 E : UserDefinedType::Field(L"one", 0, Type::FLAG_CONST, 0, 0, kBasicTypeId));
78 : fields.push_back(UserDefinedType::Field(L"two", 4, Type::FLAG_VOLATILE, 0, 0,
79 E : kBasicTypeId));
80 E : const TypeId kShortTypeId = repo_->AddType(new BasicType(L"short", 2));
81 E : fields.push_back(UserDefinedType::Field(L"three", 8, 0, 0, 0, kShortTypeId));
82 : UserDefinedTypePtr udt =
83 E : new UserDefinedType(L"foo", 10, UserDefinedType::UDT_CLASS);
84 :
85 E : const TypeId kClassId = repo_->AddType(udt);
86 :
87 : // Set up a member function.
88 E : FunctionTypePtr function = new FunctionType(FunctionType::CALL_NEAR_C);
89 : function->Finalize(FunctionType::ArgumentType(kNoTypeFlags, kShortTypeId),
90 E : FunctionType::Arguments(), kClassId);
91 E : function->SetName(L"short (foo::)()");
92 E : const TypeId kFunctionId = repo_->AddType(function);
93 :
94 E : UserDefinedType::Functions functions;
95 : functions.push_back(
96 E : UserDefinedType::Function(L"memberFunction", kFunctionId));
97 :
98 E : udt->Finalize(fields, functions);
99 :
100 : // Up-cast it.
101 E : TypePtr type(udt);
102 E : udt = nullptr;
103 :
104 E : ASSERT_EQ(Type::USER_DEFINED_TYPE_KIND, type->kind());
105 E : EXPECT_EQ(L"foo", type->name());
106 E : EXPECT_EQ(L"foo", type->decorated_name());
107 E : EXPECT_EQ(10, type->size());
108 :
109 E : ASSERT_TRUE(type->CastTo(&udt));
110 E : ASSERT_EQ(type.get(), udt.get());
111 :
112 E : EXPECT_FALSE(udt->is_fwd_decl());
113 E : EXPECT_EQ(UserDefinedType::UDT_CLASS, udt->udt_kind());
114 :
115 : // Verify the fields set up above.
116 E : ASSERT_EQ(3U, udt->fields().size());
117 :
118 E : EXPECT_EQ(0U, udt->fields()[0].offset());
119 E : EXPECT_TRUE(udt->fields()[0].is_const());
120 E : EXPECT_FALSE(udt->fields()[0].is_volatile());
121 E : EXPECT_EQ(kBasicTypeId, udt->fields()[0].type_id());
122 E : BasicTypePtr basic_type;
123 E : ASSERT_TRUE(udt->GetFieldType(0)->CastTo(&basic_type));
124 E : EXPECT_EQ(L"int", basic_type->name());
125 E : EXPECT_EQ(4, basic_type->size());
126 :
127 E : EXPECT_EQ(4U, udt->fields()[1].offset());
128 E : EXPECT_FALSE(udt->fields()[1].is_const());
129 E : EXPECT_TRUE(udt->fields()[1].is_volatile());
130 E : EXPECT_EQ(kBasicTypeId, udt->fields()[1].type_id());
131 E : ASSERT_TRUE(udt->GetFieldType(1)->CastTo(&basic_type));
132 E : EXPECT_EQ(L"int", basic_type->name());
133 E : EXPECT_EQ(4, basic_type->size());
134 :
135 E : EXPECT_EQ(8U, udt->fields()[2].offset());
136 E : EXPECT_FALSE(udt->fields()[2].is_const());
137 E : EXPECT_FALSE(udt->fields()[2].is_volatile());
138 E : EXPECT_EQ(kShortTypeId, udt->fields()[2].type_id());
139 E : ASSERT_TRUE(udt->GetFieldType(2)->CastTo(&basic_type));
140 E : EXPECT_EQ(L"short", basic_type->name());
141 E : EXPECT_EQ(2, basic_type->size());
142 :
143 E : EXPECT_EQ(1, udt->functions().size());
144 E : EXPECT_EQ(L"memberFunction", udt->functions()[0].name());
145 E : EXPECT_EQ(kFunctionId, udt->functions()[0].type_id());
146 E : ASSERT_TRUE(udt->GetFunctionType(0)->CastTo(&function));
147 E : EXPECT_EQ(L"short (foo::)()", function->name());
148 E : EXPECT_EQ(function->containing_class_id(), udt->type_id());
149 E : }
150 :
151 E : TEST_F(TypesTest, UserDefineTypeWithDecoratedName) {
152 : // Build a UDT instance.
153 E : UserDefinedType::Fields fields;
154 E : const TypeId kBasicTypeId = repo_->AddType(new BasicType(L"int", 4));
155 : fields.push_back(
156 E : UserDefinedType::Field(L"one", 0, Type::FLAG_CONST, 0, 0, kBasicTypeId));
157 : fields.push_back(UserDefinedType::Field(L"two", 4, Type::FLAG_VOLATILE, 0, 0,
158 E : kBasicTypeId));
159 E : const TypeId kShortTypeId = repo_->AddType(new BasicType(L"short", 2));
160 E : fields.push_back(UserDefinedType::Field(L"three", 8, 0, 0, 0, kShortTypeId));
161 : UserDefinedTypePtr udt = new UserDefinedType(L"foo", L"decorated_foo", 10,
162 E : UserDefinedType::UDT_STRUCT);
163 E : udt->Finalize(fields, UserDefinedType::Functions());
164 :
165 E : repo_->AddType(udt);
166 :
167 : // Up-cast it.
168 E : TypePtr type(udt);
169 E : udt = nullptr;
170 :
171 E : ASSERT_EQ(Type::USER_DEFINED_TYPE_KIND, type->kind());
172 E : EXPECT_EQ(L"foo", type->name());
173 E : EXPECT_EQ(L"decorated_foo", type->decorated_name());
174 E : EXPECT_EQ(10, type->size());
175 :
176 E : ASSERT_TRUE(type->CastTo(&udt));
177 E : ASSERT_EQ(type.get(), udt.get());
178 :
179 E : EXPECT_FALSE(udt->is_fwd_decl());
180 E : EXPECT_EQ(UserDefinedType::UDT_STRUCT, udt->udt_kind());
181 :
182 : // Verify the fields set up above.
183 E : ASSERT_EQ(3U, udt->fields().size());
184 :
185 E : EXPECT_EQ(0U, udt->fields()[0].offset());
186 E : EXPECT_TRUE(udt->fields()[0].is_const());
187 E : EXPECT_FALSE(udt->fields()[0].is_volatile());
188 E : EXPECT_EQ(kBasicTypeId, udt->fields()[0].type_id());
189 E : BasicTypePtr basic_type;
190 E : ASSERT_TRUE(udt->GetFieldType(0)->CastTo(&basic_type));
191 E : EXPECT_EQ(L"int", basic_type->name());
192 E : EXPECT_EQ(4, basic_type->size());
193 :
194 E : EXPECT_EQ(4U, udt->fields()[1].offset());
195 E : EXPECT_FALSE(udt->fields()[1].is_const());
196 E : EXPECT_TRUE(udt->fields()[1].is_volatile());
197 E : EXPECT_EQ(kBasicTypeId, udt->fields()[1].type_id());
198 E : ASSERT_TRUE(udt->GetFieldType(1)->CastTo(&basic_type));
199 E : EXPECT_EQ(L"int", basic_type->name());
200 E : EXPECT_EQ(4, basic_type->size());
201 :
202 E : EXPECT_EQ(8U, udt->fields()[2].offset());
203 E : EXPECT_FALSE(udt->fields()[2].is_const());
204 E : EXPECT_FALSE(udt->fields()[2].is_volatile());
205 E : EXPECT_EQ(kShortTypeId, udt->fields()[2].type_id());
206 E : ASSERT_TRUE(udt->GetFieldType(2)->CastTo(&basic_type));
207 E : EXPECT_EQ(L"short", basic_type->name());
208 E : EXPECT_EQ(2, basic_type->size());
209 E : }
210 :
211 E : TEST_F(TypesTest, UserDefineTypeForwardDeclaration) {
212 : // Build a UDT instance.
213 : UserDefinedTypePtr udt = new UserDefinedType(L"fwd", L"decorated_fwd", 0,
214 E : UserDefinedType::UDT_STRUCT);
215 E : udt->SetIsForwardDeclaration();
216 :
217 E : repo_->AddType(udt);
218 :
219 : // Up-cast it.
220 E : TypePtr type(udt);
221 E : udt = nullptr;
222 :
223 E : ASSERT_EQ(Type::USER_DEFINED_TYPE_KIND, type->kind());
224 E : EXPECT_EQ(L"fwd", type->name());
225 E : EXPECT_EQ(L"decorated_fwd", type->decorated_name());
226 E : EXPECT_EQ(0, type->size());
227 :
228 E : ASSERT_TRUE(type->CastTo(&udt));
229 E : ASSERT_EQ(type.get(), udt.get());
230 :
231 E : EXPECT_TRUE(udt->is_fwd_decl());
232 :
233 E : EXPECT_EQ(0, udt->fields().size());
234 E : EXPECT_EQ(0, udt->functions().size());
235 E : }
236 :
237 E : TEST_F(TypesTest, PointerType) {
238 : // Build a Pointer instance.
239 E : const TypeId kPtrTypeId = repo_->AddType(new BasicType(L"void", 0));
240 : TypePtr type = CreatePointerType(L"void*", 4, PointerType::PTR_MODE_PTR,
241 E : Type::FLAG_VOLATILE, kPtrTypeId);
242 E : repo_->AddType(type);
243 :
244 : // Test the basic properties.
245 E : ASSERT_TRUE(type);
246 E : EXPECT_EQ(L"void*", type->name());
247 E : EXPECT_EQ(4U, type->size());
248 :
249 E : EXPECT_EQ(Type::POINTER_TYPE_KIND, type->kind());
250 :
251 : // Downcast and test its fields.
252 E : PointerTypePtr pointer;
253 E : ASSERT_TRUE(type->CastTo(&pointer));
254 E : ASSERT_TRUE(pointer);
255 E : EXPECT_FALSE(pointer->is_const());
256 E : EXPECT_TRUE(pointer->is_volatile());
257 E : EXPECT_EQ(PointerType::PTR_MODE_PTR, pointer->ptr_mode());
258 E : ASSERT_EQ(kPtrTypeId, pointer->content_type_id());
259 :
260 E : ASSERT_TRUE(pointer->GetContentType());
261 E : EXPECT_EQ(L"void", pointer->GetContentType()->name());
262 E : EXPECT_EQ(0U, pointer->GetContentType()->size());
263 E : }
264 :
265 E : TEST_F(TypesTest, PointerTypeWithDecoratedName) {
266 : // Build a Pointer instance.
267 E : const TypeId kPtrTypeId = repo_->AddType(new BasicType(L"void", 0));
268 E : PointerTypePtr ptr_type = new PointerType(4, PointerType::PTR_MODE_PTR);
269 E : ptr_type->SetName(L"void*");
270 E : ptr_type->SetDecoratedName(L"decorated_void*");
271 E : ptr_type->Finalize(Type::FLAG_VOLATILE, kPtrTypeId);
272 :
273 E : TypePtr type = ptr_type;
274 E : repo_->AddType(type);
275 :
276 : // Test the basic properties.
277 E : ASSERT_TRUE(type);
278 E : EXPECT_EQ(L"void*", type->name());
279 E : EXPECT_EQ(L"decorated_void*", type->decorated_name());
280 E : EXPECT_EQ(4U, type->size());
281 :
282 E : EXPECT_EQ(Type::POINTER_TYPE_KIND, type->kind());
283 :
284 : // Downcast and test its fields.
285 E : PointerTypePtr pointer;
286 E : ASSERT_TRUE(type->CastTo(&pointer));
287 E : ASSERT_TRUE(pointer);
288 E : EXPECT_FALSE(pointer->is_const());
289 E : EXPECT_TRUE(pointer->is_volatile());
290 E : EXPECT_EQ(PointerType::PTR_MODE_PTR, pointer->ptr_mode());
291 E : ASSERT_EQ(kPtrTypeId, pointer->content_type_id());
292 :
293 E : ASSERT_TRUE(pointer->GetContentType());
294 E : EXPECT_EQ(L"void", pointer->GetContentType()->name());
295 E : EXPECT_EQ(L"void", pointer->GetContentType()->decorated_name());
296 E : EXPECT_EQ(0U, pointer->GetContentType()->size());
297 E : }
298 :
299 E : TEST_F(TypesTest, ArrayType) {
300 E : TypePtr int_type = new BasicType(L"int32_t", 0);
301 E : const TypeId kIntTypeId = repo_->AddType(int_type);
302 E : PointerTypePtr ptr_type = new PointerType(4, PointerType::PTR_MODE_PTR);
303 E : ptr_type->SetName(L"aName");
304 E : ptr_type->SetDecoratedName(L"aDecoratedName");
305 E : ptr_type->Finalize(Type::FLAG_VOLATILE, kIntTypeId);
306 E : const TypeId kPtrTypeId = repo_->AddType(ptr_type);
307 :
308 E : ArrayTypePtr array = new ArrayType(10 * ptr_type->size());
309 E : repo_->AddType(array);
310 E : array->Finalize(Type::FLAG_CONST, kIntTypeId, 10, kPtrTypeId);
311 E : ASSERT_EQ(L"", array->name());
312 E : array->SetName(L"ArrayName");
313 E : array->SetDecoratedName(L"decorated@@ArrayName");
314 :
315 E : ASSERT_EQ(kIntTypeId, array->index_type_id());
316 E : ASSERT_EQ(10, array->num_elements());
317 E : ASSERT_EQ(kPtrTypeId, array->element_type_id());
318 E : ASSERT_EQ(int_type, array->GetIndexType());
319 E : ASSERT_EQ(ptr_type, array->GetElementType());
320 E : ASSERT_EQ(ptr_type, array->GetElementType());
321 E : ASSERT_EQ(L"ArrayName", array->name());
322 E : ASSERT_EQ(L"decorated@@ArrayName", array->decorated_name());
323 E : ASSERT_FALSE(array->is_volatile());
324 E : }
325 :
326 E : TEST_F(TypesTest, FunctionType) {
327 : // Build a UDT instance.
328 E : FunctionType::Arguments args;
329 E : const TypeId kBasicTypeId = repo_->AddType(new BasicType(L"uint32_t", 4));
330 E : args.push_back(FunctionType::ArgumentType(Type::FLAG_CONST, kBasicTypeId));
331 E : args.push_back(FunctionType::ArgumentType(Type::FLAG_VOLATILE, kBasicTypeId));
332 E : const TypeId kShortTypeId = repo_->AddType(new BasicType(L"short", 2));
333 E : args.push_back(FunctionType::ArgumentType(kNoTypeFlags, kShortTypeId));
334 :
335 E : const TypeId kBoolTypeId = repo_->AddType(new BasicType(L"bool", 1));
336 E : FunctionType::ArgumentType ret_value(Type::FLAG_CONST, kBoolTypeId);
337 :
338 : const TypeId kClassType = repo_->AddType(new UserDefinedType(
339 E : L"foo", L"decorated_foo", 10, UserDefinedType::UDT_CLASS));
340 :
341 E : FunctionTypePtr function = new FunctionType(FunctionType::CALL_NEAR_C);
342 E : function->Finalize(ret_value, args, kClassType);
343 E : function->SetName(L"FunctionName");
344 E : function->SetDecoratedName(L"decorated@@FunctionName");
345 :
346 E : repo_->AddType(function);
347 :
348 : // Up-cast it.
349 E : TypePtr type(function);
350 E : function = nullptr;
351 :
352 E : ASSERT_EQ(Type::FUNCTION_TYPE_KIND, type->kind());
353 E : EXPECT_EQ(L"FunctionName", type->name());
354 E : EXPECT_EQ(L"decorated@@FunctionName", type->decorated_name());
355 E : EXPECT_EQ(0, type->size());
356 :
357 E : ASSERT_TRUE(type->CastTo(&function));
358 E : ASSERT_EQ(type.get(), function.get());
359 :
360 : // Verify the arguments set up above.
361 E : ASSERT_EQ(3U, function->argument_types().size());
362 :
363 E : EXPECT_EQ(FunctionType::CALL_NEAR_C, function->call_convention());
364 E : EXPECT_TRUE(function->IsMemberFunction());
365 E : EXPECT_EQ(kClassType, function->containing_class_id());
366 :
367 E : UserDefinedTypePtr udt;
368 E : EXPECT_TRUE(function->GetContainingClassType()->CastTo(&udt));
369 E : EXPECT_EQ(L"foo", udt->name());
370 E : EXPECT_EQ(L"decorated_foo", udt->decorated_name());
371 :
372 E : EXPECT_TRUE(function->argument_types()[0].is_const());
373 E : EXPECT_FALSE(function->argument_types()[0].is_volatile());
374 E : EXPECT_EQ(kBasicTypeId, function->argument_types()[0].type_id());
375 E : BasicTypePtr basic_type;
376 E : ASSERT_TRUE(function->GetArgumentType(0)->CastTo(&basic_type));
377 E : EXPECT_EQ(L"uint32_t", basic_type->name());
378 E : EXPECT_EQ(4, basic_type->size());
379 :
380 E : EXPECT_FALSE(function->argument_types()[1].is_const());
381 E : EXPECT_TRUE(function->argument_types()[1].is_volatile());
382 E : EXPECT_EQ(kBasicTypeId, function->argument_types()[1].type_id());
383 E : ASSERT_TRUE(function->GetArgumentType(1)->CastTo(&basic_type));
384 E : EXPECT_EQ(L"uint32_t", basic_type->name());
385 E : EXPECT_EQ(4, basic_type->size());
386 :
387 E : EXPECT_FALSE(function->argument_types()[2].is_const());
388 E : EXPECT_FALSE(function->argument_types()[2].is_volatile());
389 E : EXPECT_EQ(kShortTypeId, function->argument_types()[2].type_id());
390 E : ASSERT_TRUE(function->GetArgumentType(2)->CastTo(&basic_type));
391 E : EXPECT_EQ(L"short", basic_type->name());
392 E : EXPECT_EQ(2, basic_type->size());
393 :
394 E : EXPECT_TRUE(function->return_type().is_const());
395 E : EXPECT_FALSE(function->return_type().is_volatile());
396 E : EXPECT_EQ(kBoolTypeId, function->return_type().type_id());
397 E : ASSERT_TRUE(function->GetReturnType()->CastTo(&basic_type));
398 E : EXPECT_EQ(L"bool", basic_type->name());
399 E : EXPECT_EQ(1, basic_type->size());
400 E : }
401 :
402 E : TEST_F(TypesTest, GlobalType) {
403 E : const TypeId kBasicTypeId = repo_->AddType(new BasicType(L"int", 4));
404 E : uint64_t kRVA = 0xCAFEBABE;
405 E : TypePtr type = new GlobalType(L"foo", kRVA, kBasicTypeId, 4);
406 E : EXPECT_EQ(Type::GLOBAL_TYPE_KIND, type->kind());
407 E : EXPECT_EQ(L"foo", type->name());
408 E : EXPECT_EQ(4, type->size());
409 :
410 E : ASSERT_NE(0U, repo_->AddType(type));
411 :
412 : // Cast it down.
413 E : GlobalTypePtr global;
414 E : ASSERT_TRUE(type->CastTo(&global));
415 :
416 E : EXPECT_EQ(kRVA, global->rva());
417 E : EXPECT_EQ(kBasicTypeId, global->data_type_id());
418 :
419 E : TypePtr data_type = global->GetDataType();
420 E : ASSERT_NE(nullptr, data_type);
421 E : EXPECT_EQ(L"int", data_type->name());
422 E : }
423 :
424 E : TEST_F(TypesTest, WildcardType) {
425 : // Build a wildcard instance.
426 E : TypePtr type = new WildcardType(L"Wildcard", 4);
427 E : repo_->AddType(type);
428 :
429 : // Test the basic properties.
430 E : ASSERT_TRUE(type);
431 E : EXPECT_EQ(L"Wildcard", type->name());
432 E : EXPECT_EQ(L"Wildcard", type->decorated_name());
433 E : EXPECT_EQ(4U, type->size());
434 :
435 : // Downcast and test its fields.
436 E : WildcardTypePtr wildcard;
437 E : ASSERT_TRUE(type->CastTo(&wildcard));
438 E : ASSERT_TRUE(wildcard);
439 E : }
440 :
441 : } // namespace refinery
|