1# Copyright 2019 Google LLC 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# https://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"""Tests for emboss.front_end.symbol_resolver.""" 16 17import unittest 18from compiler.front_end import glue 19from compiler.front_end import symbol_resolver 20from compiler.util import error 21from compiler.util import test_util 22 23_HAPPY_EMB = """ 24struct Foo: 25 0 [+4] UInt uint_field 26 4 [+4] Bar bar_field 27 8 [+16] UInt[4] array_field 28 29struct Bar: 30 0 [+4] Qux bar 31 32enum Qux: 33 ABC = 1 34 DEF = 2 35 36struct FieldRef: 37 n-4 [+n] UInt:8[n] data 38 offset-4 [+offset] UInt:8[offset] data2 39 0 [+4] UInt offset (n) 40 41struct VoidLength: 42 0 [+10] UInt:8[] ten_bytes 43 44enum Quux: 45 ABC = 1 46 DEF = ABC 47 48struct UsesParameter(x: UInt:8): 49 0 [+x] UInt:8[] block 50""" 51 52 53class ResolveSymbolsTest(unittest.TestCase): 54 """Tests for symbol_resolver.resolve_symbols().""" 55 56 def _construct_ir_multiple(self, file_dict, primary_emb_name): 57 ir, unused_debug_info, errors = glue.parse_emboss_file( 58 primary_emb_name, 59 test_util.dict_file_reader(file_dict), 60 stop_before_step="resolve_symbols") 61 assert not errors 62 return ir 63 64 def _construct_ir(self, emb_text, name="happy.emb"): 65 return self._construct_ir_multiple({name: emb_text}, name) 66 67 def test_struct_field_atomic_type_resolution(self): 68 ir = self._construct_ir(_HAPPY_EMB) 69 self.assertEqual([], symbol_resolver.resolve_symbols(ir)) 70 struct_ir = ir.module[0].type[0].structure 71 atomic_field1_reference = struct_ir.field[0].type.atomic_type.reference 72 self.assertEqual(atomic_field1_reference.canonical_name.object_path, ["UInt" 73 ]) 74 self.assertEqual(atomic_field1_reference.canonical_name.module_file, "") 75 atomic_field2_reference = struct_ir.field[1].type.atomic_type.reference 76 self.assertEqual(atomic_field2_reference.canonical_name.object_path, ["Bar" 77 ]) 78 self.assertEqual(atomic_field2_reference.canonical_name.module_file, 79 "happy.emb") 80 81 def test_struct_field_enum_type_resolution(self): 82 ir = self._construct_ir(_HAPPY_EMB) 83 self.assertEqual([], symbol_resolver.resolve_symbols(ir)) 84 struct_ir = ir.module[0].type[1].structure 85 atomic_field_reference = struct_ir.field[0].type.atomic_type.reference 86 self.assertEqual(atomic_field_reference.canonical_name.object_path, ["Qux"]) 87 self.assertEqual(atomic_field_reference.canonical_name.module_file, 88 "happy.emb") 89 90 def test_struct_field_array_type_resolution(self): 91 ir = self._construct_ir(_HAPPY_EMB) 92 self.assertEqual([], symbol_resolver.resolve_symbols(ir)) 93 array_field_type = ir.module[0].type[0].structure.field[2].type.array_type 94 array_field_reference = array_field_type.base_type.atomic_type.reference 95 self.assertEqual(array_field_reference.canonical_name.object_path, ["UInt"]) 96 self.assertEqual(array_field_reference.canonical_name.module_file, "") 97 98 def test_inner_type_resolution(self): 99 ir = self._construct_ir(_HAPPY_EMB) 100 self.assertEqual([], symbol_resolver.resolve_symbols(ir)) 101 array_field_type = ir.module[0].type[0].structure.field[2].type.array_type 102 array_field_reference = array_field_type.base_type.atomic_type.reference 103 self.assertEqual(array_field_reference.canonical_name.object_path, ["UInt"]) 104 self.assertEqual(array_field_reference.canonical_name.module_file, "") 105 106 def test_struct_field_resolution_in_expression_in_location(self): 107 ir = self._construct_ir(_HAPPY_EMB) 108 self.assertEqual([], symbol_resolver.resolve_symbols(ir)) 109 struct_ir = ir.module[0].type[3].structure 110 field0_loc = struct_ir.field[0].location 111 abbreviation_reference = field0_loc.size.field_reference.path[0] 112 self.assertEqual(abbreviation_reference.canonical_name.object_path, 113 ["FieldRef", "offset"]) 114 self.assertEqual(abbreviation_reference.canonical_name.module_file, 115 "happy.emb") 116 field0_start_left = field0_loc.start.function.args[0] 117 nested_abbreviation_reference = field0_start_left.field_reference.path[0] 118 self.assertEqual(nested_abbreviation_reference.canonical_name.object_path, 119 ["FieldRef", "offset"]) 120 self.assertEqual(nested_abbreviation_reference.canonical_name.module_file, 121 "happy.emb") 122 field1_loc = struct_ir.field[1].location 123 direct_reference = field1_loc.size.field_reference.path[0] 124 self.assertEqual(direct_reference.canonical_name.object_path, ["FieldRef", 125 "offset"]) 126 self.assertEqual(direct_reference.canonical_name.module_file, "happy.emb") 127 field1_start_left = field1_loc.start.function.args[0] 128 nested_direct_reference = field1_start_left.field_reference.path[0] 129 self.assertEqual(nested_direct_reference.canonical_name.object_path, 130 ["FieldRef", "offset"]) 131 self.assertEqual(nested_direct_reference.canonical_name.module_file, 132 "happy.emb") 133 134 def test_struct_field_resolution_in_expression_in_array_length(self): 135 ir = self._construct_ir(_HAPPY_EMB) 136 self.assertEqual([], symbol_resolver.resolve_symbols(ir)) 137 struct_ir = ir.module[0].type[3].structure 138 field0_array_type = struct_ir.field[0].type.array_type 139 field0_array_element_count = field0_array_type.element_count 140 abbreviation_reference = field0_array_element_count.field_reference.path[0] 141 self.assertEqual(abbreviation_reference.canonical_name.object_path, 142 ["FieldRef", "offset"]) 143 self.assertEqual(abbreviation_reference.canonical_name.module_file, 144 "happy.emb") 145 field1_array_type = struct_ir.field[1].type.array_type 146 direct_reference = field1_array_type.element_count.field_reference.path[0] 147 self.assertEqual(direct_reference.canonical_name.object_path, ["FieldRef", 148 "offset"]) 149 self.assertEqual(direct_reference.canonical_name.module_file, "happy.emb") 150 151 def test_struct_parameter_resolution(self): 152 ir = self._construct_ir(_HAPPY_EMB) 153 self.assertEqual([], symbol_resolver.resolve_symbols(ir)) 154 struct_ir = ir.module[0].type[6].structure 155 size_ir = struct_ir.field[0].location.size 156 self.assertTrue(size_ir.HasField("field_reference")) 157 self.assertEqual(size_ir.field_reference.path[0].canonical_name.object_path, 158 ["UsesParameter", "x"]) 159 160 def test_enum_value_resolution_in_expression_in_enum_field(self): 161 ir = self._construct_ir(_HAPPY_EMB) 162 self.assertEqual([], symbol_resolver.resolve_symbols(ir)) 163 enum_ir = ir.module[0].type[5].enumeration 164 value_reference = enum_ir.value[1].value.constant_reference 165 self.assertEqual(value_reference.canonical_name.object_path, 166 ["Quux", "ABC"]) 167 self.assertEqual(value_reference.canonical_name.module_file, "happy.emb") 168 169 def test_symbol_resolution_in_expression_in_void_array_length(self): 170 ir = self._construct_ir(_HAPPY_EMB) 171 self.assertEqual([], symbol_resolver.resolve_symbols(ir)) 172 struct_ir = ir.module[0].type[4].structure 173 array_type = struct_ir.field[0].type.array_type 174 # The symbol resolver should ignore void fields. 175 self.assertEqual("automatic", array_type.WhichOneof("size")) 176 177 def test_name_definitions_have_correct_canonical_names(self): 178 ir = self._construct_ir(_HAPPY_EMB) 179 self.assertEqual([], symbol_resolver.resolve_symbols(ir)) 180 foo_name = ir.module[0].type[0].name 181 self.assertEqual(foo_name.canonical_name.object_path, ["Foo"]) 182 self.assertEqual(foo_name.canonical_name.module_file, "happy.emb") 183 uint_field_name = ir.module[0].type[0].structure.field[0].name 184 self.assertEqual(uint_field_name.canonical_name.object_path, ["Foo", 185 "uint_field"]) 186 self.assertEqual(uint_field_name.canonical_name.module_file, "happy.emb") 187 foo_name = ir.module[0].type[2].name 188 self.assertEqual(foo_name.canonical_name.object_path, ["Qux"]) 189 self.assertEqual(foo_name.canonical_name.module_file, "happy.emb") 190 191 def test_duplicate_type_name(self): 192 ir = self._construct_ir("struct Foo:\n" 193 " 0 [+4] UInt field\n" 194 "struct Foo:\n" 195 " 0 [+4] UInt bar\n", "duplicate_type.emb") 196 errors = error.filter_errors(symbol_resolver.resolve_symbols(ir)) 197 self.assertEqual([ 198 [error.error("duplicate_type.emb", 199 ir.module[0].type[1].name.source_location, 200 "Duplicate name 'Foo'"), 201 error.note("duplicate_type.emb", 202 ir.module[0].type[0].name.source_location, 203 "Original definition")] 204 ], errors) 205 206 def test_duplicate_field_name_in_struct(self): 207 ir = self._construct_ir("struct Foo:\n" 208 " 0 [+4] UInt field\n" 209 " 4 [+4] UInt field\n", "duplicate_field.emb") 210 errors = error.filter_errors(symbol_resolver.resolve_symbols(ir)) 211 struct = ir.module[0].type[0].structure 212 self.assertEqual([[ 213 error.error("duplicate_field.emb", 214 struct.field[1].name.source_location, 215 "Duplicate name 'field'"), 216 error.note("duplicate_field.emb", 217 struct.field[0].name.source_location, 218 "Original definition") 219 ]], errors) 220 221 def test_duplicate_abbreviation_in_struct(self): 222 ir = self._construct_ir("struct Foo:\n" 223 " 0 [+4] UInt field1 (f)\n" 224 " 4 [+4] UInt field2 (f)\n", 225 "duplicate_field.emb") 226 errors = error.filter_errors(symbol_resolver.resolve_symbols(ir)) 227 struct = ir.module[0].type[0].structure 228 self.assertEqual([[ 229 error.error("duplicate_field.emb", 230 struct.field[1].abbreviation.source_location, 231 "Duplicate name 'f'"), 232 error.note("duplicate_field.emb", 233 struct.field[0].abbreviation.source_location, 234 "Original definition") 235 ]], errors) 236 237 def test_abbreviation_duplicates_field_name_in_struct(self): 238 ir = self._construct_ir("struct Foo:\n" 239 " 0 [+4] UInt field\n" 240 " 4 [+4] UInt field2 (field)\n", 241 "duplicate_field.emb") 242 errors = error.filter_errors(symbol_resolver.resolve_symbols(ir)) 243 struct = ir.module[0].type[0].structure 244 self.assertEqual([[ 245 error.error("duplicate_field.emb", 246 struct.field[1].abbreviation.source_location, 247 "Duplicate name 'field'"), 248 error.note("duplicate_field.emb", 249 struct.field[0].name.source_location, 250 "Original definition") 251 ]], errors) 252 253 def test_field_name_duplicates_abbreviation_in_struct(self): 254 ir = self._construct_ir("struct Foo:\n" 255 " 0 [+4] UInt field (field2)\n" 256 " 4 [+4] UInt field2\n", "duplicate_field.emb") 257 errors = error.filter_errors(symbol_resolver.resolve_symbols(ir)) 258 struct = ir.module[0].type[0].structure 259 self.assertEqual([[ 260 error.error("duplicate_field.emb", 261 struct.field[1].name.source_location, 262 "Duplicate name 'field2'"), 263 error.note("duplicate_field.emb", 264 struct.field[0].abbreviation.source_location, 265 "Original definition") 266 ]], errors) 267 268 def test_duplicate_value_name_in_enum(self): 269 ir = self._construct_ir("enum Foo:\n" 270 " BAR = 1\n" 271 " BAR = 1\n", "duplicate_enum.emb") 272 errors = error.filter_errors(symbol_resolver.resolve_symbols(ir)) 273 self.assertEqual([[ 274 error.error( 275 "duplicate_enum.emb", 276 ir.module[0].type[0].enumeration.value[1].name.source_location, 277 "Duplicate name 'BAR'"), 278 error.note( 279 "duplicate_enum.emb", 280 ir.module[0].type[0].enumeration.value[0].name.source_location, 281 "Original definition") 282 ]], errors) 283 284 def test_ambiguous_name(self): 285 # struct UInt will be ambiguous with the external UInt in the prelude. 286 ir = self._construct_ir("struct UInt:\n" 287 " 0 [+4] Int:8[4] field\n" 288 "struct Foo:\n" 289 " 0 [+4] UInt bar\n", "ambiguous.emb") 290 errors = error.filter_errors(symbol_resolver.resolve_symbols(ir)) 291 # Find the UInt definition in the prelude. 292 for type_ir in ir.module[1].type: 293 if type_ir.name.name.text == "UInt": 294 prelude_uint = type_ir 295 break 296 ambiguous_type_ir = ir.module[0].type[1].structure.field[0].type.atomic_type 297 self.assertEqual([[ 298 error.error("ambiguous.emb", 299 ambiguous_type_ir.reference.source_name[0].source_location, 300 "Ambiguous name 'UInt'"), error.note( 301 "", prelude_uint.name.source_location, 302 "Possible resolution"), 303 error.note("ambiguous.emb", ir.module[0].type[0].name.source_location, 304 "Possible resolution") 305 ]], errors) 306 307 def test_missing_name(self): 308 ir = self._construct_ir("struct Foo:\n" 309 " 0 [+4] Bar field\n", 310 "missing.emb") 311 errors = error.filter_errors(symbol_resolver.resolve_symbols(ir)) 312 missing_type_ir = ir.module[0].type[0].structure.field[0].type.atomic_type 313 self.assertEqual([ 314 [error.error("missing.emb", 315 missing_type_ir.reference.source_name[0].source_location, 316 "No candidate for 'Bar'")] 317 ], errors) 318 319 def test_missing_leading_name(self): 320 ir = self._construct_ir("struct Foo:\n" 321 " 0 [+Num.FOUR] UInt field\n", "missing.emb") 322 errors = error.filter_errors(symbol_resolver.resolve_symbols(ir)) 323 missing_expr_ir = ir.module[0].type[0].structure.field[0].location.size 324 self.assertEqual([ 325 [error.error( 326 "missing.emb", 327 missing_expr_ir.constant_reference.source_name[0].source_location, 328 "No candidate for 'Num'")] 329 ], errors) 330 331 def test_missing_trailing_name(self): 332 ir = self._construct_ir("struct Foo:\n" 333 " 0 [+Num.FOUR] UInt field\n" 334 "enum Num:\n" 335 " THREE = 3\n", "missing.emb") 336 errors = error.filter_errors(symbol_resolver.resolve_symbols(ir)) 337 missing_expr_ir = ir.module[0].type[0].structure.field[0].location.size 338 self.assertEqual([ 339 [error.error( 340 "missing.emb", 341 missing_expr_ir.constant_reference.source_name[1].source_location, 342 "No candidate for 'FOUR'")] 343 ], errors) 344 345 def test_missing_middle_name(self): 346 ir = self._construct_ir("struct Foo:\n" 347 " 0 [+Num.NaN.FOUR] UInt field\n" 348 "enum Num:\n" 349 " FOUR = 4\n", "missing.emb") 350 errors = error.filter_errors(symbol_resolver.resolve_symbols(ir)) 351 missing_expr_ir = ir.module[0].type[0].structure.field[0].location.size 352 self.assertEqual([ 353 [error.error( 354 "missing.emb", 355 missing_expr_ir.constant_reference.source_name[1].source_location, 356 "No candidate for 'NaN'")] 357 ], errors) 358 359 def test_inner_resolution(self): 360 ir = self._construct_ir( 361 "struct OuterStruct:\n" 362 "\n" 363 " struct InnerStruct2:\n" 364 " 0 [+1] InnerStruct.InnerEnum inner_enum\n" 365 "\n" 366 " struct InnerStruct:\n" 367 " enum InnerEnum:\n" 368 " ONE = 1\n" 369 "\n" 370 " 0 [+1] InnerEnum inner_enum\n" 371 "\n" 372 " 0 [+InnerStruct.InnerEnum.ONE] InnerStruct.InnerEnum inner_enum\n", 373 "nested.emb") 374 errors = symbol_resolver.resolve_symbols(ir) 375 self.assertFalse(errors) 376 outer_struct = ir.module[0].type[0] 377 inner_struct = outer_struct.subtype[1] 378 inner_struct_2 = outer_struct.subtype[0] 379 inner_enum = inner_struct.subtype[0] 380 self.assertEqual(["OuterStruct", "InnerStruct"], 381 list(inner_struct.name.canonical_name.object_path)) 382 self.assertEqual(["OuterStruct", "InnerStruct", "InnerEnum"], 383 list(inner_enum.name.canonical_name.object_path)) 384 self.assertEqual(["OuterStruct", "InnerStruct2"], 385 list(inner_struct_2.name.canonical_name.object_path)) 386 outer_field = outer_struct.structure.field[0] 387 outer_field_end_ref = outer_field.location.size.constant_reference 388 self.assertEqual( 389 ["OuterStruct", "InnerStruct", "InnerEnum", "ONE"], list( 390 outer_field_end_ref.canonical_name.object_path)) 391 self.assertEqual( 392 ["OuterStruct", "InnerStruct", "InnerEnum"], 393 list(outer_field.type.atomic_type.reference.canonical_name.object_path)) 394 inner_field_2_type = inner_struct_2.structure.field[0].type.atomic_type 395 self.assertEqual( 396 ["OuterStruct", "InnerStruct", "InnerEnum" 397 ], list(inner_field_2_type.reference.canonical_name.object_path)) 398 399 def test_resolution_against_anonymous_bits(self): 400 ir = self._construct_ir("struct Struct:\n" 401 " 0 [+1] bits:\n" 402 " 7 [+1] Flag last_packet\n" 403 " 5 [+2] enum inline_inner_enum:\n" 404 " AA = 0\n" 405 " BB = 1\n" 406 " CC = 2\n" 407 " DD = 3\n" 408 " 0 [+5] UInt header_size (h)\n" 409 " 0 [+h] UInt:8[] header_bytes\n" 410 "\n" 411 "struct Struct2:\n" 412 " 0 [+1] Struct.InlineInnerEnum value\n", 413 "anonymity.emb") 414 errors = symbol_resolver.resolve_symbols(ir) 415 self.assertFalse(errors) 416 struct1 = ir.module[0].type[0] 417 struct1_bits_field = struct1.structure.field[0] 418 struct1_bits_field_type = struct1_bits_field.type.atomic_type.reference 419 struct1_byte_field = struct1.structure.field[4] 420 inner_bits = struct1.subtype[0] 421 inner_enum = struct1.subtype[1] 422 self.assertTrue(inner_bits.HasField("structure")) 423 self.assertTrue(inner_enum.HasField("enumeration")) 424 self.assertTrue(inner_bits.name.is_anonymous) 425 self.assertFalse(inner_enum.name.is_anonymous) 426 self.assertEqual(["Struct", "InlineInnerEnum"], 427 list(inner_enum.name.canonical_name.object_path)) 428 self.assertEqual( 429 ["Struct", "InlineInnerEnum", "AA"], 430 list(inner_enum.enumeration.value[0].name.canonical_name.object_path)) 431 self.assertEqual( 432 list(inner_bits.name.canonical_name.object_path), 433 list(struct1_bits_field_type.canonical_name.object_path)) 434 self.assertEqual(2, len(inner_bits.name.canonical_name.object_path)) 435 self.assertEqual( 436 ["Struct", "header_size"], 437 list(struct1_byte_field.location.size.field_reference.path[0]. 438 canonical_name.object_path)) 439 440 def test_duplicate_name_in_different_inline_bits(self): 441 ir = self._construct_ir( 442 "struct Struct:\n" 443 " 0 [+1] bits:\n" 444 " 7 [+1] Flag a\n" 445 " 1 [+1] bits:\n" 446 " 0 [+1] Flag a\n", "duplicate_in_anon.emb") 447 errors = error.filter_errors(symbol_resolver.resolve_symbols(ir)) 448 supertype = ir.module[0].type[0] 449 self.assertEqual([[ 450 error.error( 451 "duplicate_in_anon.emb", 452 supertype.structure.field[3].name.source_location, 453 "Duplicate name 'a'"), 454 error.note( 455 "duplicate_in_anon.emb", 456 supertype.structure.field[1].name.source_location, 457 "Original definition") 458 ]], errors) 459 460 def test_duplicate_name_in_same_inline_bits(self): 461 ir = self._construct_ir( 462 "struct Struct:\n" 463 " 0 [+1] bits:\n" 464 " 7 [+1] Flag a\n" 465 " 0 [+1] Flag a\n", "duplicate_in_anon.emb") 466 errors = symbol_resolver.resolve_symbols(ir) 467 supertype = ir.module[0].type[0] 468 self.assertEqual([[ 469 error.error( 470 "duplicate_in_anon.emb", 471 supertype.structure.field[2].name.source_location, 472 "Duplicate name 'a'"), 473 error.note( 474 "duplicate_in_anon.emb", 475 supertype.structure.field[1].name.source_location, 476 "Original definition") 477 ]], error.filter_errors(errors)) 478 479 def test_import_type_resolution(self): 480 importer = ('import "ed.emb" as ed\n' 481 "struct Ff:\n" 482 " 0 [+1] ed.Gg gg\n") 483 imported = ("struct Gg:\n" 484 " 0 [+1] UInt qq\n") 485 ir = self._construct_ir_multiple({"ed.emb": imported, "er.emb": importer}, 486 "er.emb") 487 errors = symbol_resolver.resolve_symbols(ir) 488 self.assertEqual([], errors) 489 490 def test_duplicate_import_name(self): 491 importer = ('import "ed.emb" as ed\n' 492 'import "ed.emb" as ed\n' 493 "struct Ff:\n" 494 " 0 [+1] ed.Gg gg\n") 495 imported = ("struct Gg:\n" 496 " 0 [+1] UInt qq\n") 497 ir = self._construct_ir_multiple({"ed.emb": imported, "er.emb": importer}, 498 "er.emb") 499 errors = symbol_resolver.resolve_symbols(ir) 500 # Note: the error is on import[2] duplicating import[1] because the implicit 501 # prelude import is import[0]. 502 self.assertEqual([ 503 [error.error("er.emb", 504 ir.module[0].foreign_import[2].local_name.source_location, 505 "Duplicate name 'ed'"), 506 error.note("er.emb", 507 ir.module[0].foreign_import[1].local_name.source_location, 508 "Original definition")] 509 ], errors) 510 511 def test_import_enum_resolution(self): 512 importer = ('import "ed.emb" as ed\n' 513 "struct Ff:\n" 514 " if ed.Gg.GG == ed.Gg.GG:\n" 515 " 0 [+1] UInt gg\n") 516 imported = ("enum Gg:\n" 517 " GG = 0\n") 518 ir = self._construct_ir_multiple({"ed.emb": imported, "er.emb": importer}, 519 "er.emb") 520 errors = symbol_resolver.resolve_symbols(ir) 521 self.assertEqual([], errors) 522 523 def test_that_double_import_names_are_syntactically_invalid(self): 524 # There are currently no checks in resolve_symbols that it is not possible 525 # to get to symbols imported by another module, because it is syntactically 526 # invalid. This may change in the future, in which case this test should be 527 # fixed by adding an explicit check to resolve_symbols and checking the 528 # error message here. 529 importer = ('import "ed.emb" as ed\n' 530 "struct Ff:\n" 531 " 0 [+1] ed.ed2.Gg gg\n") 532 imported = 'import "ed2.emb" as ed2\n' 533 imported2 = ("struct Gg:\n" 534 " 0 [+1] UInt qq\n") 535 unused_ir, unused_debug_info, errors = glue.parse_emboss_file( 536 "er.emb", 537 test_util.dict_file_reader({"ed.emb": imported, 538 "ed2.emb": imported2, 539 "er.emb": importer}), 540 stop_before_step="resolve_symbols") 541 assert errors 542 543 def test_no_error_when_inline_name_aliases_outer_name(self): 544 # The inline enum's complete type should be Foo.Foo. During parsing, the 545 # name is set to just "Foo", but symbol resolution should a) select the 546 # correct Foo, and b) not complain that multiple Foos could match. 547 ir = self._construct_ir( 548 "struct Foo:\n" 549 " 0 [+1] enum foo:\n" 550 " BAR = 0\n") 551 errors = symbol_resolver.resolve_symbols(ir) 552 self.assertEqual([], errors) 553 field = ir.module[0].type[0].structure.field[0] 554 self.assertEqual( 555 ["Foo", "Foo"], 556 list(field.type.atomic_type.reference.canonical_name.object_path)) 557 558 def test_no_error_when_inline_name_in_anonymous_bits_aliases_outer_name(self): 559 # There is an extra layer of complexity when an inline type appears inside 560 # of an inline bits. 561 ir = self._construct_ir( 562 "struct Foo:\n" 563 " 0 [+1] bits:\n" 564 " 0 [+4] enum foo:\n" 565 " BAR = 0\n") 566 errors = symbol_resolver.resolve_symbols(ir) 567 self.assertEqual([], error.filter_errors(errors)) 568 field = ir.module[0].type[0].subtype[0].structure.field[0] 569 self.assertEqual( 570 ["Foo", "Foo"], 571 list(field.type.atomic_type.reference.canonical_name.object_path)) 572 573 574class ResolveFieldReferencesTest(unittest.TestCase): 575 """Tests for symbol_resolver.resolve_field_references().""" 576 577 def _construct_ir_multiple(self, file_dict, primary_emb_name): 578 ir, unused_debug_info, errors = glue.parse_emboss_file( 579 primary_emb_name, 580 test_util.dict_file_reader(file_dict), 581 stop_before_step="resolve_field_references") 582 assert not errors 583 return ir 584 585 def _construct_ir(self, emb_text, name="happy.emb"): 586 return self._construct_ir_multiple({name: emb_text}, name) 587 588 def test_subfield_resolution(self): 589 ir = self._construct_ir( 590 "struct Ff:\n" 591 " 0 [+1] Gg gg\n" 592 " 1 [+gg.qq] UInt:8[] data\n" 593 "struct Gg:\n" 594 " 0 [+1] UInt qq\n", "subfield.emb") 595 errors = symbol_resolver.resolve_field_references(ir) 596 self.assertFalse(errors) 597 ff = ir.module[0].type[0] 598 location_end_path = ff.structure.field[1].location.size.field_reference.path 599 self.assertEqual(["Ff", "gg"], 600 list(location_end_path[0].canonical_name.object_path)) 601 self.assertEqual(["Gg", "qq"], 602 list(location_end_path[1].canonical_name.object_path)) 603 604 def test_aliased_subfield_resolution(self): 605 ir = self._construct_ir( 606 "struct Ff:\n" 607 " 0 [+1] Gg real_gg\n" 608 " 1 [+gg.qq] UInt:8[] data\n" 609 " let gg = real_gg\n" 610 "struct Gg:\n" 611 " 0 [+1] UInt real_qq\n" 612 " let qq = real_qq", "subfield.emb") 613 errors = symbol_resolver.resolve_field_references(ir) 614 self.assertFalse(errors) 615 ff = ir.module[0].type[0] 616 location_end_path = ff.structure.field[1].location.size.field_reference.path 617 self.assertEqual(["Ff", "gg"], 618 list(location_end_path[0].canonical_name.object_path)) 619 self.assertEqual(["Gg", "qq"], 620 list(location_end_path[1].canonical_name.object_path)) 621 622 def test_aliased_aliased_subfield_resolution(self): 623 ir = self._construct_ir( 624 "struct Ff:\n" 625 " 0 [+1] Gg really_real_gg\n" 626 " 1 [+gg.qq] UInt:8[] data\n" 627 " let gg = real_gg\n" 628 " let real_gg = really_real_gg\n" 629 "struct Gg:\n" 630 " 0 [+1] UInt qq\n", "subfield.emb") 631 errors = symbol_resolver.resolve_field_references(ir) 632 self.assertFalse(errors) 633 ff = ir.module[0].type[0] 634 location_end_path = ff.structure.field[1].location.size.field_reference.path 635 self.assertEqual(["Ff", "gg"], 636 list(location_end_path[0].canonical_name.object_path)) 637 self.assertEqual(["Gg", "qq"], 638 list(location_end_path[1].canonical_name.object_path)) 639 640 def test_subfield_resolution_fails(self): 641 ir = self._construct_ir( 642 "struct Ff:\n" 643 " 0 [+1] Gg gg\n" 644 " 1 [+gg.rr] UInt:8[] data\n" 645 "struct Gg:\n" 646 " 0 [+1] UInt qq\n", "subfield.emb") 647 errors = error.filter_errors(symbol_resolver.resolve_field_references(ir)) 648 self.assertEqual([ 649 [error.error("subfield.emb", ir.module[0].type[0].structure.field[ 650 1].location.size.field_reference.path[1].source_name[ 651 0].source_location, "No candidate for 'rr'")] 652 ], errors) 653 654 def test_subfield_resolution_failure_shortcuts_further_resolution(self): 655 ir = self._construct_ir( 656 "struct Ff:\n" 657 " 0 [+1] Gg gg\n" 658 " 1 [+gg.rr.qq] UInt:8[] data\n" 659 "struct Gg:\n" 660 " 0 [+1] UInt qq\n", "subfield.emb") 661 errors = error.filter_errors(symbol_resolver.resolve_field_references(ir)) 662 self.assertEqual([ 663 [error.error("subfield.emb", ir.module[0].type[0].structure.field[ 664 1].location.size.field_reference.path[1].source_name[ 665 0].source_location, "No candidate for 'rr'")] 666 ], errors) 667 668 def test_subfield_resolution_failure_with_aliased_name(self): 669 ir = self._construct_ir( 670 "struct Ff:\n" 671 " 0 [+1] Gg gg\n" 672 " 1 [+gg.gg] UInt:8[] data\n" 673 "struct Gg:\n" 674 " 0 [+1] UInt qq\n", "subfield.emb") 675 errors = error.filter_errors(symbol_resolver.resolve_field_references(ir)) 676 self.assertEqual([ 677 [error.error("subfield.emb", ir.module[0].type[0].structure.field[ 678 1].location.size.field_reference.path[1].source_name[ 679 0].source_location, "No candidate for 'gg'")] 680 ], errors) 681 682 def test_subfield_resolution_failure_with_array(self): 683 ir = self._construct_ir( 684 "struct Ff:\n" 685 " 0 [+1] Gg[1] gg\n" 686 " 1 [+gg.qq] UInt:8[] data\n" 687 "struct Gg:\n" 688 " 0 [+1] UInt qq\n", "subfield.emb") 689 errors = error.filter_errors(symbol_resolver.resolve_field_references(ir)) 690 self.assertEqual([ 691 [error.error("subfield.emb", ir.module[0].type[0].structure.field[ 692 1].location.size.field_reference.path[0].source_name[ 693 0].source_location, "Cannot access member of array 'gg'")] 694 ], errors) 695 696 def test_subfield_resolution_failure_with_int(self): 697 ir = self._construct_ir( 698 "struct Ff:\n" 699 " 0 [+1] UInt gg_source\n" 700 " 1 [+gg.qq] UInt:8[] data\n" 701 " let gg = gg_source + 1\n", 702 "subfield.emb") 703 errors = error.filter_errors(symbol_resolver.resolve_field_references(ir)) 704 error_field = ir.module[0].type[0].structure.field[1] 705 error_reference = error_field.location.size.field_reference 706 error_location = error_reference.path[0].source_name[0].source_location 707 self.assertEqual([ 708 [error.error("subfield.emb", error_location, 709 "Cannot access member of noncomposite field 'gg'")] 710 ], errors) 711 712 def test_subfield_resolution_failure_with_int_no_cascade(self): 713 ir = self._construct_ir( 714 "struct Ff:\n" 715 " 0 [+1] UInt gg_source\n" 716 " 1 [+qqx] UInt:8[] data\n" 717 " let gg = gg_source + 1\n" 718 " let yy = gg.no_field\n" 719 " let qqx = yy.x\n" 720 " let qqy = yy.y\n", 721 "subfield.emb") 722 errors = error.filter_errors(symbol_resolver.resolve_field_references(ir)) 723 error_field = ir.module[0].type[0].structure.field[3] 724 error_reference = error_field.read_transform.field_reference 725 error_location = error_reference.path[0].source_name[0].source_location 726 self.assertEqual([ 727 [error.error("subfield.emb", error_location, 728 "Cannot access member of noncomposite field 'gg'")] 729 ], errors) 730 731 def test_subfield_resolution_failure_with_abbreviation(self): 732 ir = self._construct_ir( 733 "struct Ff:\n" 734 " 0 [+1] Gg gg\n" 735 " 1 [+gg.q] UInt:8[] data\n" 736 "struct Gg:\n" 737 " 0 [+1] UInt qq (q)\n", "subfield.emb") 738 errors = error.filter_errors(symbol_resolver.resolve_field_references(ir)) 739 self.assertEqual([ 740 # TODO(bolms): Make the error message clearer, in this case. 741 [error.error("subfield.emb", ir.module[0].type[0].structure.field[ 742 1].location.size.field_reference.path[1].source_name[ 743 0].source_location, "No candidate for 'q'")] 744 ], errors) 745 746 747if __name__ == "__main__": 748 unittest.main() 749