Home | History | Annotate | Download | only in src
      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