• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Unwind(const std::deque<std::string> * type_queue)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 
TypeQueueCheckAndPushBack(std::deque<std::string> * type_queue,const std::string & str)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 
TypeQueueCheckAndPop(std::deque<std::string> * type_queue)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 
IsAccessDownGraded(abi_util::AccessSpecifierIR old_access,abi_util::AccessSpecifierIR new_access)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 
ConvertTypeIdToString(const AbiElementMap<const TypeIR * > & type_graph,const std::string & type_id)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>
ReplaceReferencesOtherTypeIdWithName(const AbiElementMap<const TypeIR * > & type_graph,Container & to_fix_elements)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 
ReplaceEnumTypeIRTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,EnumTypeIR * enum_type_ir)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 
ReplaceRecordTypeIRTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,RecordTypeIR * record_type_ir)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 
ReplaceGlobalVarTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,GlobalVarIR * global_var_ir)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 
ReplaceFunctionTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,FunctionIR * function_ir)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 
ReplaceTypeIdsWithTypeNames(const AbiElementMap<const TypeIR * > & type_graph,LinkableMessageIR * lm)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 
CompareEnumFields(const std::vector<abi_util::EnumFieldIR> & old_fields,const std::vector<abi_util::EnumFieldIR> & new_fields,abi_util::EnumTypeDiffIR * enum_type_diff_ir)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 
CompareEnumTypes(const abi_util::EnumTypeIR * old_type,const abi_util::EnumTypeIR * new_type,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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 
CompareVTableComponents(const abi_util::VTableComponentIR & old_component,const abi_util::VTableComponentIR & new_component)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 
CompareVTables(const abi_util::RecordTypeIR * old_record,const abi_util::RecordTypeIR * new_record)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 
CompareSizeAndAlignment(const abi_util::TypeIR * old_type,const abi_util::TypeIR * new_type)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>>
CompareCommonRecordFields(const abi_util::RecordFieldIR * old_field,const abi_util::RecordFieldIR * new_field,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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>
CompareRecordFields(const std::vector<abi_util::RecordFieldIR> & old_fields,const std::vector<abi_util::RecordFieldIR> & new_fields,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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 
CompareBaseSpecifiers(const std::vector<abi_util::CXXBaseSpecifierIR> & old_base_specifiers,const std::vector<abi_util::CXXBaseSpecifierIR> & new_base_specifiers,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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 
CompareTemplateInfo(const std::vector<abi_util::TemplateElementIR> & old_template_elements,const std::vector<abi_util::TemplateElementIR> & new_template_elements,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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>
ConvertToDiffContainerVector(std::vector<std::pair<T,T>> & nc_vector)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>
ConvertToConstPtrVector(std::vector<T> & nc_vector)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 
FixupRemovedFieldTypeIds(const std::vector<const abi_util::RecordFieldIR * > & removed_fields,const AbiElementMap<const abi_util::TypeIR * > & old_types)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>>
FixupDiffedFieldTypeIds(const std::vector<abi_util::RecordFieldDiffIR> & field_diffs)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 
CompareFunctionTypes(const abi_util::FunctionTypeIR * old_type,const abi_util::FunctionTypeIR * new_type,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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 
CompareRecordTypes(const abi_util::RecordTypeIR * old_type,const abi_util::RecordTypeIR * new_type,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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 
CompareLvalueReferenceTypes(const abi_util::LvalueReferenceTypeIR * old_type,const abi_util::LvalueReferenceTypeIR * new_type,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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 
CompareRvalueReferenceTypes(const abi_util::RvalueReferenceTypeIR * old_type,const abi_util::RvalueReferenceTypeIR * new_type,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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 
CompareQualifiedTypes(const abi_util::QualifiedTypeIR * old_type,const abi_util::QualifiedTypeIR * new_type,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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 
ComparePointerTypes(const abi_util::PointerTypeIR * old_type,const abi_util::PointerTypeIR * new_type,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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 
CompareBuiltinTypes(const abi_util::BuiltinTypeIR * old_type,const abi_util::BuiltinTypeIR * new_type)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 
CompareFunctionParameters(const std::vector<abi_util::ParamIR> & old_parameters,const std::vector<abi_util::ParamIR> & new_parameters,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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 
CompareAndDumpTypeDiff(const abi_util::TypeIR * old_type,const abi_util::TypeIR * new_type,abi_util::LinkableMessageKind kind,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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 
CompareDistinctKindMessages(const abi_util::TypeIR * old_type,const abi_util::TypeIR * new_type)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 
CompareAndDumpTypeDiff(const std::string & old_type_id,const std::string & new_type_id,std::deque<std::string> * type_queue,abi_util::DiffMessageIR::DiffKind diff_kind)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