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