1 #include <abi_diff_helpers.h> 2 #include <header_abi_util.h> 3 4 #include <llvm/Support/raw_ostream.h> 5 6 namespace abi_util { 7 8 std::string Unwind(const std::deque<std::string> *type_queue) { 9 if (!type_queue) { 10 return ""; 11 } 12 std::string stack_str; 13 std::deque<std::string> type_queue_copy = *type_queue; 14 while (!type_queue_copy.empty()) { 15 stack_str += type_queue_copy.front() + "-> "; 16 type_queue_copy.pop_front(); 17 } 18 return stack_str; 19 } 20 21 static void TypeQueueCheckAndPushBack(std::deque<std::string> *type_queue, 22 const std::string &str) { 23 if (type_queue) { 24 type_queue->push_back(str); 25 } 26 } 27 28 static void TypeQueueCheckAndPop(std::deque<std::string> *type_queue) { 29 if (type_queue && !type_queue->empty()) { 30 type_queue->pop_back(); 31 } 32 } 33 34 static bool IsAccessDownGraded(abi_util::AccessSpecifierIR old_access, 35 abi_util::AccessSpecifierIR new_access) { 36 bool access_downgraded = false; 37 switch (old_access) { 38 case abi_util::AccessSpecifierIR::ProtectedAccess: 39 if (new_access == abi_util::AccessSpecifierIR::PrivateAccess) { 40 access_downgraded = true; 41 } 42 break; 43 case abi_util::AccessSpecifierIR::PublicAccess: 44 if (new_access != abi_util::AccessSpecifierIR::PublicAccess) { 45 access_downgraded = true; 46 } 47 break; 48 default: 49 break; 50 } 51 return access_downgraded; 52 } 53 54 static std::string ConvertTypeIdToString( 55 const AbiElementMap<const TypeIR *> &type_graph, 56 const std::string &type_id) { 57 auto it = type_graph.find(type_id); 58 if (it != type_graph.end()) { 59 return it->second->GetName(); 60 } 61 return "type-unexported"; 62 } 63 64 template <typename Container> 65 static void ReplaceReferencesOtherTypeIdWithName( 66 const AbiElementMap<const TypeIR *> &type_graph, 67 Container &to_fix_elements) { 68 for (auto &element : to_fix_elements) { 69 element.SetReferencedType( 70 ConvertTypeIdToString(type_graph, element.GetReferencedType())); 71 } 72 } 73 74 static void ReplaceEnumTypeIRTypeIdsWithTypeNames( 75 const AbiElementMap<const TypeIR *> &type_graph, 76 EnumTypeIR *enum_type_ir) { 77 // Replace underlying type. 78 enum_type_ir->SetUnderlyingType( 79 ConvertTypeIdToString(type_graph, enum_type_ir->GetUnderlyingType())); 80 } 81 82 static void ReplaceRecordTypeIRTypeIdsWithTypeNames( 83 const AbiElementMap<const TypeIR *> &type_graph, 84 RecordTypeIR *record_type_ir) { 85 // Replace Fields 86 ReplaceReferencesOtherTypeIdWithName(type_graph, 87 record_type_ir->GetFields()); 88 // Replace template parameters 89 ReplaceReferencesOtherTypeIdWithName(type_graph, 90 record_type_ir->GetTemplateElements()); 91 // Replace bases 92 ReplaceReferencesOtherTypeIdWithName(type_graph, 93 record_type_ir->GetBases()); 94 } 95 96 static void ReplaceGlobalVarTypeIdsWithTypeNames( 97 const AbiElementMap<const TypeIR *> &type_graph, 98 GlobalVarIR *global_var_ir) { 99 // Replace referenced type id. 100 global_var_ir->SetReferencedType( 101 ConvertTypeIdToString(type_graph, global_var_ir->GetReferencedType())); 102 } 103 104 static void ReplaceFunctionTypeIdsWithTypeNames( 105 const AbiElementMap<const TypeIR *> &type_graph, FunctionIR *function_ir) { 106 // Replace return type 107 function_ir->SetReturnType( 108 ConvertTypeIdToString(type_graph, function_ir->GetReturnType())); 109 // Replace function parameters 110 ReplaceReferencesOtherTypeIdWithName(type_graph, 111 function_ir->GetParameters()); 112 // Replace function template parameters 113 ReplaceReferencesOtherTypeIdWithName(type_graph, 114 function_ir->GetTemplateElements()); 115 } 116 117 void ReplaceTypeIdsWithTypeNames( 118 const AbiElementMap<const TypeIR *> &type_graph, 119 LinkableMessageIR *lm) { 120 switch (lm->GetKind()) { 121 case FunctionKind: 122 ReplaceFunctionTypeIdsWithTypeNames(type_graph, 123 static_cast<FunctionIR *>(lm)); 124 break; 125 case GlobalVarKind: 126 ReplaceGlobalVarTypeIdsWithTypeNames(type_graph, 127 static_cast<GlobalVarIR *>(lm)); 128 break; 129 case RecordTypeKind: 130 ReplaceRecordTypeIRTypeIdsWithTypeNames(type_graph, 131 static_cast<RecordTypeIR *>(lm)); 132 133 break; 134 case EnumTypeKind: 135 ReplaceEnumTypeIRTypeIdsWithTypeNames(type_graph, 136 static_cast<EnumTypeIR *>(lm)); 137 break; 138 default: 139 // This method should not be called on any other LinkableMessage 140 assert(0); 141 } 142 } 143 144 void AbiDiffHelper::CompareEnumFields( 145 const std::vector<abi_util::EnumFieldIR> &old_fields, 146 const std::vector<abi_util::EnumFieldIR> &new_fields, 147 abi_util::EnumTypeDiffIR *enum_type_diff_ir) { 148 AbiElementMap<const abi_util::EnumFieldIR *> old_fields_map; 149 AbiElementMap<const abi_util::EnumFieldIR *> new_fields_map; 150 abi_util::AddToMap(&old_fields_map, old_fields, 151 [](const abi_util::EnumFieldIR *f) {return f->GetName();}, 152 [](const abi_util::EnumFieldIR *f) {return f;}); 153 154 abi_util::AddToMap(&new_fields_map, new_fields, 155 [](const abi_util::EnumFieldIR *f) {return f->GetName();}, 156 [](const abi_util::EnumFieldIR *f) {return f;}); 157 158 std::vector<const abi_util::EnumFieldIR *> removed_fields = 159 abi_util::FindRemovedElements(old_fields_map, new_fields_map); 160 161 std::vector<const abi_util::EnumFieldIR *> added_fields = 162 abi_util::FindRemovedElements(new_fields_map, old_fields_map); 163 164 enum_type_diff_ir->SetFieldsAdded(std::move(added_fields)); 165 166 enum_type_diff_ir->SetFieldsRemoved(std::move(removed_fields)); 167 168 std::vector<std::pair< 169 const abi_util::EnumFieldIR *, const abi_util::EnumFieldIR *>> cf = 170 abi_util::FindCommonElements(old_fields_map, new_fields_map); 171 std::vector<abi_util::EnumFieldDiffIR> enum_field_diffs; 172 for (auto &&common_fields : cf) { 173 if (common_fields.first->GetValue() != common_fields.second->GetValue()) { 174 abi_util::EnumFieldDiffIR enum_field_diff_ir(common_fields.first, 175 common_fields.second); 176 enum_field_diffs.emplace_back(std::move(enum_field_diff_ir)); 177 } 178 } 179 enum_type_diff_ir->SetFieldsDiff(std::move(enum_field_diffs)); 180 } 181 182 DiffStatus AbiDiffHelper::CompareEnumTypes( 183 const abi_util::EnumTypeIR *old_type, const abi_util::EnumTypeIR *new_type, 184 std::deque<std::string> *type_queue, 185 abi_util::DiffMessageIR::DiffKind diff_kind) { 186 if (old_type->GetUniqueId() != new_type->GetUniqueId()) { 187 return DiffStatus::direct_diff; 188 } 189 auto enum_type_diff_ir = std::make_unique<abi_util::EnumTypeDiffIR>(); 190 enum_type_diff_ir->SetName(old_type->GetName()); 191 const std::string &old_underlying_type = 192 ConvertTypeIdToString(old_types_, old_type->GetUnderlyingType()); 193 const std::string &new_underlying_type = 194 ConvertTypeIdToString(new_types_, new_type->GetUnderlyingType()); 195 if (old_underlying_type != new_underlying_type) { 196 enum_type_diff_ir->SetUnderlyingTypeDiff( 197 std::make_unique<std::pair<std::string, std::string>>( 198 old_underlying_type, new_underlying_type)); 199 } 200 CompareEnumFields(old_type->GetFields(), new_type->GetFields(), 201 enum_type_diff_ir.get()); 202 if ((enum_type_diff_ir->IsExtended() || 203 enum_type_diff_ir->IsIncompatible()) && 204 (ir_diff_dumper_ && !ir_diff_dumper_->AddDiffMessageIR( 205 enum_type_diff_ir.get(), Unwind(type_queue), diff_kind))) { 206 llvm::errs() << "AddDiffMessage on EnumTypeDiffIR failed\n"; 207 ::exit(1); 208 } 209 return DiffStatus::no_diff; 210 } 211 212 bool AbiDiffHelper::CompareVTableComponents( 213 const abi_util::VTableComponentIR &old_component, 214 const abi_util::VTableComponentIR &new_component) { 215 return old_component.GetName() == new_component.GetName() && 216 old_component.GetValue() == new_component.GetValue() && 217 old_component.GetKind() == new_component.GetKind(); 218 } 219 220 bool AbiDiffHelper::CompareVTables( 221 const abi_util::RecordTypeIR *old_record, 222 const abi_util::RecordTypeIR *new_record) { 223 224 const std::vector<abi_util::VTableComponentIR> &old_components = 225 old_record->GetVTableLayout().GetVTableComponents(); 226 const std::vector<abi_util::VTableComponentIR> &new_components = 227 new_record->GetVTableLayout().GetVTableComponents(); 228 if (old_components.size() > new_components.size()) { 229 // Something in the vtable got deleted. 230 return false; 231 } 232 uint32_t i = 0; 233 while (i < old_components.size()) { 234 auto &old_element = old_components.at(i); 235 auto &new_element = new_components.at(i); 236 if (!CompareVTableComponents(old_element, new_element)) { 237 return false; 238 } 239 i++; 240 } 241 return true; 242 } 243 244 bool AbiDiffHelper::CompareSizeAndAlignment( 245 const abi_util::TypeIR *old_type, 246 const abi_util::TypeIR *new_type) { 247 return old_type->GetSize() == new_type->GetSize() && 248 old_type->GetAlignment() == new_type->GetAlignment(); 249 } 250 251 DiffStatusPair<std::unique_ptr<abi_util::RecordFieldDiffIR>> 252 AbiDiffHelper::CompareCommonRecordFields( 253 const abi_util::RecordFieldIR *old_field, 254 const abi_util::RecordFieldIR *new_field, 255 std::deque<std::string> *type_queue, 256 abi_util::DiffMessageIR::DiffKind diff_kind) { 257 258 DiffStatus field_diff_status = 259 CompareAndDumpTypeDiff(old_field->GetReferencedType(), 260 new_field->GetReferencedType(), 261 type_queue, diff_kind); 262 263 if (old_field->GetOffset() != new_field->GetOffset() || 264 // TODO: Should this be an inquality check instead ? Some compilers can 265 // make signatures dependant on absolute values of access specifiers. 266 IsAccessDownGraded(old_field->GetAccess(), new_field->GetAccess()) || 267 (field_diff_status == DiffStatus::direct_diff)) { 268 return std::make_pair( 269 DiffStatus::direct_diff, 270 std::make_unique<abi_util::RecordFieldDiffIR>(old_field, new_field) 271 ); 272 } 273 return std::make_pair(field_diff_status, nullptr); 274 } 275 276 277 GenericFieldDiffInfo<RecordFieldIR, RecordFieldDiffIR> 278 AbiDiffHelper::CompareRecordFields( 279 const std::vector<abi_util::RecordFieldIR> &old_fields, 280 const std::vector<abi_util::RecordFieldIR> &new_fields, 281 std::deque<std::string> *type_queue, 282 abi_util::DiffMessageIR::DiffKind diff_kind) { 283 GenericFieldDiffInfo<RecordFieldIR, RecordFieldDiffIR> 284 diffed_removed_added_fields; 285 AbiElementMap<const abi_util::RecordFieldIR *> old_fields_map; 286 AbiElementMap<const abi_util::RecordFieldIR *> new_fields_map; 287 std::map<uint64_t, const abi_util::RecordFieldIR *> old_fields_offset_map; 288 std::map<uint64_t, const abi_util::RecordFieldIR *> new_fields_offset_map; 289 290 abi_util::AddToMap( 291 &old_fields_map, old_fields, 292 [](const abi_util::RecordFieldIR *f) {return f->GetName();}, 293 [](const abi_util::RecordFieldIR *f) {return f;}); 294 abi_util::AddToMap( 295 &new_fields_map, new_fields, 296 [](const abi_util::RecordFieldIR *f) {return f->GetName();}, 297 [](const abi_util::RecordFieldIR *f) {return f;}); 298 abi_util::AddToMap( 299 &old_fields_offset_map, old_fields, 300 [](const abi_util::RecordFieldIR *f) {return f->GetOffset();}, 301 [](const abi_util::RecordFieldIR *f) {return f;}); 302 abi_util::AddToMap( 303 &new_fields_offset_map, new_fields, 304 [](const abi_util::RecordFieldIR *f) {return f->GetOffset();}, 305 [](const abi_util::RecordFieldIR *f) {return f;}); 306 // If a field is removed from the map field_name -> offset see if another 307 // field is present at the same offset and compare the size and type etc, 308 // remove it from the removed fields if they're compatible. 309 DiffStatus final_diff_status = DiffStatus::no_diff; 310 std::vector<const abi_util::RecordFieldIR *> removed_fields = 311 abi_util::FindRemovedElements(old_fields_map, new_fields_map); 312 313 std::vector<const abi_util::RecordFieldIR *> added_fields = 314 abi_util::FindRemovedElements(new_fields_map, old_fields_map); 315 316 auto predicate = 317 [&](const abi_util::RecordFieldIR *removed_field, 318 std::map<uint64_t, const abi_util::RecordFieldIR *> &field_off_map) { 319 uint64_t old_field_offset = removed_field->GetOffset(); 320 auto corresponding_field_at_same_offset = 321 field_off_map.find(old_field_offset); 322 // Correctly reported as removed, so do not remove. 323 if (corresponding_field_at_same_offset == field_off_map.end()) { 324 return false; 325 } 326 327 auto comparison_result = CompareCommonRecordFields( 328 removed_field, corresponding_field_at_same_offset->second, 329 type_queue, diff_kind); 330 // No actual diff, so remove it. 331 return (comparison_result.second == nullptr); 332 }; 333 334 removed_fields.erase( 335 std::remove_if( 336 removed_fields.begin(), removed_fields.end(), 337 std::bind(predicate, std::placeholders::_1, new_fields_offset_map)), 338 removed_fields.end()); 339 added_fields.erase( 340 std::remove_if( 341 added_fields.begin(), added_fields.end(), 342 std::bind(predicate, std::placeholders::_1, old_fields_offset_map)), 343 added_fields.end()); 344 345 diffed_removed_added_fields.removed_fields_ = std::move(removed_fields); 346 diffed_removed_added_fields.added_fields_ = std::move(added_fields); 347 348 std::vector<std::pair< 349 const abi_util::RecordFieldIR *, const abi_util::RecordFieldIR *>> cf = 350 abi_util::FindCommonElements(old_fields_map, new_fields_map); 351 bool common_field_diff_exists = false; 352 for (auto &&common_fields : cf) { 353 auto diffed_field_ptr = CompareCommonRecordFields(common_fields.first, 354 common_fields.second, 355 type_queue, diff_kind); 356 if (!common_field_diff_exists && 357 (diffed_field_ptr.first & 358 (DiffStatus::direct_diff | DiffStatus::indirect_diff))) { 359 common_field_diff_exists = true; 360 } 361 if (diffed_field_ptr.second != nullptr) { 362 diffed_removed_added_fields.diffed_fields_.emplace_back( 363 std::move(*(diffed_field_ptr.second.release()))); 364 } 365 } 366 if (diffed_removed_added_fields.diffed_fields_.size() != 0 || 367 diffed_removed_added_fields.removed_fields_.size() != 0) { 368 final_diff_status = DiffStatus::direct_diff; 369 } else if (common_field_diff_exists) { 370 final_diff_status = DiffStatus::indirect_diff; 371 } 372 diffed_removed_added_fields.diff_status_ = final_diff_status; 373 return diffed_removed_added_fields; 374 } 375 376 bool AbiDiffHelper::CompareBaseSpecifiers( 377 const std::vector<abi_util::CXXBaseSpecifierIR> &old_base_specifiers, 378 const std::vector<abi_util::CXXBaseSpecifierIR> &new_base_specifiers, 379 std::deque<std::string> *type_queue, 380 abi_util::DiffMessageIR::DiffKind diff_kind) { 381 if (old_base_specifiers.size() != new_base_specifiers.size()) { 382 return false; 383 } 384 int i = 0; 385 while (i < old_base_specifiers.size()) { 386 if (CompareAndDumpTypeDiff(old_base_specifiers.at(i).GetReferencedType(), 387 new_base_specifiers.at(i).GetReferencedType(), 388 type_queue, diff_kind) == 389 DiffStatus::direct_diff || 390 (old_base_specifiers.at(i).GetAccess() != 391 new_base_specifiers.at(i).GetAccess())) { 392 return false; 393 } 394 i++; 395 } 396 return true; 397 } 398 399 DiffStatus AbiDiffHelper::CompareTemplateInfo( 400 const std::vector<abi_util::TemplateElementIR> &old_template_elements, 401 const std::vector<abi_util::TemplateElementIR> &new_template_elements, 402 std::deque<std::string> *type_queue, 403 abi_util::DiffMessageIR::DiffKind diff_kind) { 404 uint32_t old_template_size = old_template_elements.size(); 405 uint32_t i = 0; 406 if (old_template_size != new_template_elements.size()) { 407 return DiffStatus::direct_diff; 408 } 409 DiffStatus final_diff_status = DiffStatus::no_diff; 410 while (i < old_template_size) { 411 const abi_util::TemplateElementIR &old_template_element = 412 old_template_elements[i]; 413 const abi_util::TemplateElementIR &new_template_element = 414 new_template_elements[i]; 415 auto template_element_diff = 416 CompareAndDumpTypeDiff(old_template_element.GetReferencedType(), 417 new_template_element.GetReferencedType(), 418 type_queue, diff_kind); 419 if (template_element_diff & 420 (DiffStatus::direct_diff | DiffStatus::indirect_diff)) { 421 final_diff_status = template_element_diff; 422 } 423 i++; 424 } 425 return final_diff_status; 426 } 427 428 template <typename DiffContainer, typename T> 429 static std::vector<DiffContainer> ConvertToDiffContainerVector( 430 std::vector<std::pair<T, T>> &nc_vector) { 431 std::vector<DiffContainer> cptr_vec; 432 for (auto &e : nc_vector) { 433 cptr_vec.emplace_back(&e.first, &e.second); 434 } 435 return cptr_vec; 436 } 437 438 template <typename T> 439 static std::vector<const T*> ConvertToConstPtrVector( 440 std::vector<T> &nc_vector) { 441 std::vector<const T*> cptr_vec; 442 for (auto &e : nc_vector) { 443 cptr_vec.emplace_back(&e); 444 } 445 return cptr_vec; 446 } 447 448 static std::vector<abi_util::RecordFieldIR> FixupRemovedFieldTypeIds( 449 const std::vector<const abi_util::RecordFieldIR *> &removed_fields, 450 const AbiElementMap<const abi_util::TypeIR *> &old_types) { 451 std::vector<abi_util::RecordFieldIR> removed_fields_dup; 452 for (auto &removed_field : removed_fields) { 453 removed_fields_dup.emplace_back(*removed_field); 454 RecordFieldIR &it = removed_fields_dup[removed_fields_dup.size() -1]; 455 it.SetReferencedType( 456 ConvertTypeIdToString(old_types, it.GetReferencedType())); 457 } 458 return removed_fields_dup; 459 } 460 461 std::vector<std::pair<abi_util::RecordFieldIR, abi_util::RecordFieldIR>> 462 AbiDiffHelper::FixupDiffedFieldTypeIds( 463 const std::vector<abi_util::RecordFieldDiffIR> &field_diffs) { 464 std::vector<std::pair<abi_util::RecordFieldIR, abi_util::RecordFieldIR>> 465 diffed_fields_dup; 466 for (auto &field_diff : field_diffs) { 467 diffed_fields_dup.emplace_back(*(field_diff.old_field_), 468 *(field_diff.new_field_)); 469 auto &it = diffed_fields_dup[diffed_fields_dup.size() - 1]; 470 abi_util::RecordFieldIR &old_field = it.first; 471 abi_util::RecordFieldIR &new_field = it.second; 472 old_field.SetReferencedType( 473 ConvertTypeIdToString(old_types_, old_field.GetReferencedType())); 474 new_field.SetReferencedType( 475 ConvertTypeIdToString(new_types_, new_field.GetReferencedType())); 476 } 477 return diffed_fields_dup; 478 } 479 480 DiffStatus AbiDiffHelper::CompareFunctionTypes( 481 const abi_util::FunctionTypeIR *old_type, 482 const abi_util::FunctionTypeIR *new_type, 483 std::deque<std::string> *type_queue, 484 abi_util::DiffMessageIR::DiffKind diff_kind) { 485 DiffStatus param_diffs = CompareFunctionParameters(old_type->GetParameters(), 486 new_type->GetParameters(), 487 type_queue, diff_kind); 488 DiffStatus return_type_diff = 489 CompareAndDumpTypeDiff(old_type->GetReturnType(), 490 new_type->GetReturnType(), 491 type_queue, diff_kind); 492 493 if (param_diffs == DiffStatus::direct_diff || 494 return_type_diff == DiffStatus::direct_diff) { 495 return DiffStatus::direct_diff; 496 } 497 498 if (param_diffs == DiffStatus::indirect_diff || 499 return_type_diff == DiffStatus::indirect_diff) { 500 return DiffStatus::indirect_diff; 501 } 502 503 return DiffStatus::no_diff; 504 } 505 506 DiffStatus AbiDiffHelper::CompareRecordTypes( 507 const abi_util::RecordTypeIR *old_type, 508 const abi_util::RecordTypeIR *new_type, 509 std::deque<std::string> *type_queue, 510 abi_util::DiffMessageIR::DiffKind diff_kind) { 511 auto record_type_diff_ir = std::make_unique<abi_util::RecordTypeDiffIR>(); 512 // Compare names. 513 if (!old_type->IsAnonymous() && !new_type->IsAnonymous() && 514 old_type->GetUniqueId() != new_type->GetUniqueId()) { 515 // Do not dump anything since the record types themselves are fundamentally 516 // different. 517 return DiffStatus::direct_diff; 518 } 519 DiffStatus final_diff_status = DiffStatus::no_diff; 520 record_type_diff_ir->SetName(old_type->GetName()); 521 if (old_type->GetAccess() != new_type->GetAccess()) { 522 final_diff_status = DiffStatus::indirect_diff; 523 record_type_diff_ir->SetAccessDiff( 524 std::make_unique<abi_util::AccessSpecifierDiffIR>( 525 old_type->GetAccess(), new_type->GetAccess())); 526 } 527 528 if (!CompareSizeAndAlignment(old_type, new_type)) { 529 final_diff_status = DiffStatus::indirect_diff; 530 record_type_diff_ir->SetTypeDiff( 531 std::make_unique<abi_util::TypeDiffIR>( 532 std::make_pair(old_type->GetSize(), new_type->GetSize()), 533 std::make_pair(old_type->GetAlignment(), 534 new_type->GetAlignment()))); 535 } 536 if (!CompareVTables(old_type, new_type)) { 537 final_diff_status = DiffStatus::indirect_diff; 538 record_type_diff_ir->SetVTableLayoutDiff( 539 std::make_unique<abi_util::VTableLayoutDiffIR>( 540 old_type->GetVTableLayout(), new_type->GetVTableLayout())); 541 } 542 auto &old_fields_dup = old_type->GetFields(); 543 auto &new_fields_dup = new_type->GetFields(); 544 auto field_status_and_diffs = 545 CompareRecordFields(old_fields_dup, new_fields_dup, 546 type_queue, diff_kind); 547 // TODO: combine this with base class diffs as well. 548 final_diff_status = final_diff_status | field_status_and_diffs.diff_status_; 549 550 std::vector<abi_util::CXXBaseSpecifierIR> old_bases = old_type->GetBases(); 551 std::vector<abi_util::CXXBaseSpecifierIR> new_bases = new_type->GetBases(); 552 553 if (!CompareBaseSpecifiers(old_bases, new_bases, type_queue, diff_kind) && 554 ir_diff_dumper_) { 555 ReplaceReferencesOtherTypeIdWithName(old_types_, old_bases); 556 ReplaceReferencesOtherTypeIdWithName(new_types_, new_bases); 557 record_type_diff_ir->SetBaseSpecifierDiffs ( 558 std::make_unique<abi_util::CXXBaseSpecifierDiffIR>(old_bases, 559 new_bases)); 560 } 561 if (ir_diff_dumper_) { 562 // Make copies of the fields removed and diffed, since we have to change 563 // type ids -> type strings. 564 std::vector<std::pair<RecordFieldIR, RecordFieldIR>> field_diff_dups = 565 FixupDiffedFieldTypeIds(field_status_and_diffs.diffed_fields_); 566 std::vector<abi_util::RecordFieldDiffIR> field_diffs_fixed = 567 ConvertToDiffContainerVector<abi_util::RecordFieldDiffIR, 568 abi_util::RecordFieldIR>(field_diff_dups); 569 570 std::vector<abi_util::RecordFieldIR> field_removed_dups = 571 FixupRemovedFieldTypeIds(field_status_and_diffs.removed_fields_, 572 old_types_); 573 std::vector<const abi_util::RecordFieldIR *> fields_removed_fixed = 574 ConvertToConstPtrVector(field_removed_dups); 575 576 std::vector<abi_util::RecordFieldIR> field_added_dups = 577 FixupRemovedFieldTypeIds(field_status_and_diffs.added_fields_, 578 new_types_); 579 std::vector<const abi_util::RecordFieldIR *> fields_added_fixed = 580 ConvertToConstPtrVector(field_added_dups); 581 582 record_type_diff_ir->SetFieldDiffs(std::move(field_diffs_fixed)); 583 record_type_diff_ir->SetFieldsRemoved(std::move(fields_removed_fixed)); 584 record_type_diff_ir->SetFieldsAdded(std::move(fields_added_fixed)); 585 586 if (record_type_diff_ir->DiffExists() && 587 !ir_diff_dumper_->AddDiffMessageIR(record_type_diff_ir.get(), 588 Unwind(type_queue), diff_kind)) { 589 llvm::errs() << "AddDiffMessage on record type failed\n"; 590 ::exit(1); 591 } 592 } // Records cannot be 'extended' compatibly, without a certain amount of 593 // risk. 594 final_diff_status = final_diff_status | 595 CompareTemplateInfo(old_type->GetTemplateElements(), 596 new_type->GetTemplateElements(), 597 type_queue, diff_kind); 598 599 return 600 (final_diff_status & 601 (DiffStatus::direct_diff | DiffStatus::indirect_diff)) ? 602 DiffStatus::indirect_diff : DiffStatus::no_diff; 603 } 604 605 DiffStatus AbiDiffHelper::CompareLvalueReferenceTypes( 606 const abi_util::LvalueReferenceTypeIR *old_type, 607 const abi_util::LvalueReferenceTypeIR *new_type, 608 std::deque<std::string> *type_queue, 609 abi_util::DiffMessageIR::DiffKind diff_kind) { 610 return CompareAndDumpTypeDiff(old_type->GetReferencedType(), 611 new_type->GetReferencedType(), 612 type_queue, diff_kind); 613 } 614 615 DiffStatus AbiDiffHelper::CompareRvalueReferenceTypes( 616 const abi_util::RvalueReferenceTypeIR *old_type, 617 const abi_util::RvalueReferenceTypeIR *new_type, 618 std::deque<std::string> *type_queue, 619 abi_util::DiffMessageIR::DiffKind diff_kind) { 620 return CompareAndDumpTypeDiff(old_type->GetReferencedType(), 621 new_type->GetReferencedType(), 622 type_queue, diff_kind); 623 } 624 625 DiffStatus AbiDiffHelper::CompareQualifiedTypes( 626 const abi_util::QualifiedTypeIR *old_type, 627 const abi_util::QualifiedTypeIR *new_type, 628 std::deque<std::string> *type_queue, 629 abi_util::DiffMessageIR::DiffKind diff_kind) { 630 // If all the qualifiers are not the same, return direct_diff, else 631 // recursively compare the unqualified types. 632 if (old_type->IsConst() != new_type->IsConst() || 633 old_type->IsVolatile() != new_type->IsVolatile() || 634 old_type->IsRestricted() != new_type->IsRestricted()) { 635 return DiffStatus::direct_diff; 636 } 637 return CompareAndDumpTypeDiff(old_type->GetReferencedType(), 638 new_type->GetReferencedType(), 639 type_queue, diff_kind); 640 } 641 642 DiffStatus AbiDiffHelper::ComparePointerTypes( 643 const abi_util::PointerTypeIR *old_type, 644 const abi_util::PointerTypeIR *new_type, 645 std::deque<std::string> *type_queue, 646 abi_util::DiffMessageIR::DiffKind diff_kind) { 647 // The following need to be the same for two pointer types to be considered 648 // equivalent: 649 // 1) Number of pointer indirections are the same. 650 // 2) The ultimate pointee is the same. 651 assert(CompareSizeAndAlignment(old_type, new_type)); 652 return CompareAndDumpTypeDiff(old_type->GetReferencedType(), 653 new_type->GetReferencedType(), 654 type_queue, diff_kind); 655 } 656 657 DiffStatus AbiDiffHelper::CompareBuiltinTypes( 658 const abi_util::BuiltinTypeIR *old_type, 659 const abi_util::BuiltinTypeIR *new_type) { 660 // If the size, alignment and is_unsigned are the same, return no_diff 661 // else return direct_diff. 662 uint64_t old_signedness = old_type->IsUnsigned(); 663 uint64_t new_signedness = new_type->IsUnsigned(); 664 665 if (!CompareSizeAndAlignment(old_type, new_type) || 666 old_signedness != new_signedness || 667 old_type->IsIntegralType() != new_type->IsIntegralType()) { 668 return DiffStatus::direct_diff; 669 } 670 return DiffStatus::no_diff; 671 } 672 673 DiffStatus AbiDiffHelper::CompareFunctionParameters( 674 const std::vector<abi_util::ParamIR> &old_parameters, 675 const std::vector<abi_util::ParamIR> &new_parameters, 676 std::deque<std::string> *type_queue, 677 abi_util::DiffMessageIR::DiffKind diff_kind) { 678 size_t old_parameters_size = old_parameters.size(); 679 if (old_parameters_size != new_parameters.size()) { 680 return DiffStatus::direct_diff; 681 } 682 uint64_t i = 0; 683 while (i < old_parameters_size) { 684 const abi_util::ParamIR &old_parameter = old_parameters.at(i); 685 const abi_util::ParamIR &new_parameter = new_parameters.at(i); 686 if ((CompareAndDumpTypeDiff(old_parameter.GetReferencedType(), 687 new_parameter.GetReferencedType(), 688 type_queue, diff_kind) == 689 DiffStatus::direct_diff) || 690 (old_parameter.GetIsDefault() != new_parameter.GetIsDefault())) { 691 return DiffStatus::direct_diff; 692 } 693 i++; 694 } 695 return DiffStatus::no_diff; 696 } 697 698 DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff( 699 const abi_util::TypeIR *old_type, const abi_util::TypeIR *new_type, 700 abi_util::LinkableMessageKind kind, std::deque<std::string> *type_queue, 701 abi_util::DiffMessageIR::DiffKind diff_kind) { 702 if (kind == abi_util::LinkableMessageKind::BuiltinTypeKind) { 703 return CompareBuiltinTypes( 704 static_cast<const abi_util::BuiltinTypeIR *>(old_type), 705 static_cast<const abi_util::BuiltinTypeIR *>(new_type)); 706 } 707 708 if (kind == abi_util::LinkableMessageKind::QualifiedTypeKind) { 709 return CompareQualifiedTypes( 710 static_cast<const abi_util::QualifiedTypeIR *>(old_type), 711 static_cast<const abi_util::QualifiedTypeIR *>(new_type), 712 type_queue, diff_kind); 713 } 714 715 if (kind == abi_util::LinkableMessageKind::EnumTypeKind) { 716 return CompareEnumTypes( 717 static_cast<const abi_util::EnumTypeIR *>(old_type), 718 static_cast<const abi_util::EnumTypeIR *>(new_type), 719 type_queue, diff_kind); 720 721 } 722 723 if (kind == abi_util::LinkableMessageKind::LvalueReferenceTypeKind) { 724 return CompareLvalueReferenceTypes( 725 static_cast<const abi_util::LvalueReferenceTypeIR *>(old_type), 726 static_cast<const abi_util::LvalueReferenceTypeIR *>(new_type), 727 type_queue, diff_kind); 728 729 } 730 731 if (kind == abi_util::LinkableMessageKind::RvalueReferenceTypeKind) { 732 return CompareRvalueReferenceTypes( 733 static_cast<const abi_util::RvalueReferenceTypeIR *>(old_type), 734 static_cast<const abi_util::RvalueReferenceTypeIR *>(new_type), 735 type_queue, diff_kind); 736 } 737 738 if (kind == abi_util::LinkableMessageKind::PointerTypeKind) { 739 return ComparePointerTypes( 740 static_cast<const abi_util::PointerTypeIR *>(old_type), 741 static_cast<const abi_util::PointerTypeIR *>(new_type), 742 type_queue, diff_kind); 743 } 744 745 if (kind == abi_util::LinkableMessageKind::RecordTypeKind) { 746 return CompareRecordTypes( 747 static_cast<const abi_util::RecordTypeIR *>(old_type), 748 static_cast<const abi_util::RecordTypeIR *>(new_type), 749 type_queue, diff_kind); 750 } 751 752 if (kind == abi_util::LinkableMessageKind::FunctionTypeKind) { 753 return CompareFunctionTypes( 754 static_cast<const abi_util::FunctionTypeIR *>(old_type), 755 static_cast<const abi_util::FunctionTypeIR *>(new_type), 756 type_queue, diff_kind); 757 } 758 return DiffStatus::no_diff; 759 } 760 761 static DiffStatus CompareDistinctKindMessages( 762 const abi_util::TypeIR *old_type, const abi_util::TypeIR *new_type) { 763 // For these types to be considered ABI compatible, the very least requirement 764 // is that their sizes and alignments should be equal. 765 // TODO: Fill in 766 return DiffStatus::direct_diff; 767 } 768 769 DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff( 770 const std::string &old_type_id, const std::string &new_type_id, 771 std::deque<std::string> *type_queue, 772 abi_util::DiffMessageIR::DiffKind diff_kind) { 773 774 // Check the map for type ids which have already been compared 775 // These types have already been diffed, return without further comparison. 776 if (!type_cache_->insert(old_type_id + new_type_id).second) { 777 return DiffStatus::no_diff; 778 } else { 779 TypeQueueCheckAndPushBack(type_queue, 780 ConvertTypeIdToString(old_types_,old_type_id)); 781 } 782 AbiElementMap<const abi_util::TypeIR *>::const_iterator old_it = 783 old_types_.find(old_type_id); 784 AbiElementMap<const abi_util::TypeIR *>::const_iterator new_it = 785 new_types_.find(new_type_id); 786 if (old_it == old_types_.end() || new_it == new_types_.end()) { 787 TypeQueueCheckAndPop(type_queue); 788 // One of the types were hidden, we cannot compare further. 789 return DiffStatus::no_diff; 790 } 791 abi_util::LinkableMessageKind old_kind = 792 old_it->second->GetKind(); 793 abi_util::LinkableMessageKind new_kind = 794 new_it->second->GetKind(); 795 DiffStatus diff_status = DiffStatus::no_diff; 796 if (old_kind != new_kind) { 797 diff_status = CompareDistinctKindMessages(old_it->second, new_it->second); 798 } else { 799 diff_status = CompareAndDumpTypeDiff(old_it->second , new_it->second , 800 old_kind, type_queue, diff_kind); 801 } 802 TypeQueueCheckAndPop(type_queue); 803 return diff_status; 804 } 805 806 } // namespace abi_util 807