xref: /aosp_15_r20/development/vndk/tools/header-checker/src/repr/protobuf/ir_diff_dumper.cpp (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "repr/protobuf/ir_diff_dumper.h"
16 
17 #include "repr/ir_diff_representation.h"
18 #include "repr/protobuf/api.h"
19 #include "repr/protobuf/converter.h"
20 
21 #include <fstream>
22 #include <memory>
23 #include <string>
24 
25 #include <llvm/Support/raw_ostream.h>
26 
27 #include <google/protobuf/io/zero_copy_stream_impl.h>
28 #include <google/protobuf/text_format.h>
29 
30 
31 namespace header_checker {
32 namespace repr {
33 
AddTypeInfoDiff(abi_diff::TypeInfoDiff * type_info_diff_protobuf,const TypeDiffIR * type_diff_ir)34 static bool AddTypeInfoDiff(abi_diff::TypeInfoDiff *type_info_diff_protobuf,
35                             const TypeDiffIR *type_diff_ir) {
36   abi_diff::TypeInfo *old_type_info_protobuf =
37       type_info_diff_protobuf->mutable_old_type_info();
38   abi_diff::TypeInfo *new_type_info_protobuf =
39       type_info_diff_protobuf->mutable_new_type_info();
40   if (old_type_info_protobuf == nullptr || new_type_info_protobuf == nullptr) {
41     return false;
42   }
43   const std::pair<uint64_t, uint64_t> &sizes = type_diff_ir->GetSizes();
44   const std::pair<uint32_t, uint32_t> &alignments =
45       type_diff_ir->GetAlignments();
46   old_type_info_protobuf->set_size(sizes.first);
47   new_type_info_protobuf->set_size(sizes.second);
48 
49   old_type_info_protobuf->set_alignment(alignments.first);
50   new_type_info_protobuf->set_alignment(alignments.second);
51   return true;
52 }
53 
AddVTableLayoutDiff(abi_diff::VTableLayoutDiff * vtable_layout_diff_protobuf,const VTableLayoutDiffIR * vtable_layout_diff_ir)54 static bool AddVTableLayoutDiff(
55     abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf,
56     const VTableLayoutDiffIR *vtable_layout_diff_ir) {
57   abi_dump::VTableLayout *old_vtable =
58       vtable_layout_diff_protobuf->mutable_old_vtable();
59   abi_dump::VTableLayout *new_vtable =
60       vtable_layout_diff_protobuf->mutable_new_vtable();
61   if (old_vtable == nullptr || new_vtable == nullptr ||
62       !ConvertVTableLayoutIR(old_vtable,
63                              vtable_layout_diff_ir->GetOldVTable()) ||
64       !ConvertVTableLayoutIR(new_vtable,
65                              vtable_layout_diff_ir->GetNewVTable())) {
66     return false;
67   }
68   return true;
69 }
70 
CopyBaseSpecifiersDiffIRToProtobuf(google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> * dst,const std::vector<CXXBaseSpecifierIR> & bases_ir)71 static bool CopyBaseSpecifiersDiffIRToProtobuf(
72     google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> *dst,
73     const std::vector<CXXBaseSpecifierIR> &bases_ir) {
74   for (auto &&base_ir : bases_ir) {
75     abi_dump::CXXBaseSpecifier *added_base = dst->Add();
76     if (!ConvertCXXBaseSpecifierIR(added_base, base_ir)) {
77       return false;
78     }
79   }
80   return true;
81 }
82 
AddBaseSpecifierDiffs(abi_diff::CXXBaseSpecifierDiff * base_specifiers_diff_protobuf,const CXXBaseSpecifierDiffIR * base_specifiers_diff_ir)83 static bool AddBaseSpecifierDiffs(
84     abi_diff::CXXBaseSpecifierDiff *base_specifiers_diff_protobuf,
85     const CXXBaseSpecifierDiffIR *base_specifiers_diff_ir) {
86   if (!CopyBaseSpecifiersDiffIRToProtobuf(
87           base_specifiers_diff_protobuf->mutable_old_bases(),
88           base_specifiers_diff_ir->GetOldBases()) ||
89       !CopyBaseSpecifiersDiffIRToProtobuf(
90           base_specifiers_diff_protobuf->mutable_new_bases(),
91           base_specifiers_diff_ir->GetNewBases())) {
92     return false;
93   }
94   return true;
95 }
96 
AddRecordFields(abi_diff::RecordTypeDiff * record_diff_protobuf,const std::vector<const RecordFieldIR * > & record_fields_ir,bool field_removed)97 static bool AddRecordFields(
98     abi_diff::RecordTypeDiff *record_diff_protobuf,
99     const std::vector<const RecordFieldIR *> &record_fields_ir,
100     bool field_removed) {
101   for (auto &&record_field_ir : record_fields_ir) {
102     abi_dump::RecordFieldDecl *field = nullptr;
103     if (field_removed) {
104       field = record_diff_protobuf->add_fields_removed();
105     } else {
106       field = record_diff_protobuf->add_fields_added();
107     }
108     if (!ConvertRecordFieldIR(field, record_field_ir)) {
109       return false;
110     }
111   }
112   return true;
113 }
114 
AddRecordFieldDiffs(abi_diff::RecordTypeDiff * record_diff_protobuf,const std::vector<RecordFieldDiffIR> & record_field_diffs_ir)115 static bool AddRecordFieldDiffs(
116     abi_diff::RecordTypeDiff *record_diff_protobuf,
117     const std::vector<RecordFieldDiffIR> &record_field_diffs_ir) {
118   for (auto &&record_field_diff_ir : record_field_diffs_ir) {
119     abi_diff::RecordFieldDeclDiff *record_field_diff =
120         record_diff_protobuf->add_fields_diff();
121     if (record_field_diff == nullptr) {
122       return false;
123     }
124     abi_dump::RecordFieldDecl *old_field =
125         record_field_diff->mutable_old_field();
126     abi_dump::RecordFieldDecl *new_field =
127         record_field_diff->mutable_new_field();
128     if (old_field == nullptr || new_field == nullptr) {
129       return false;
130     }
131     ConvertRecordFieldIR(old_field, record_field_diff_ir.GetOldField());
132     ConvertRecordFieldIR(new_field, record_field_diff_ir.GetNewField());
133   }
134   return true;
135 }
136 
ConvertRecordTypeDiffIR(const RecordTypeDiffIR * record_type_diff_ir)137 static abi_diff::RecordTypeDiff ConvertRecordTypeDiffIR(
138     const RecordTypeDiffIR *record_type_diff_ir) {
139   abi_diff::RecordTypeDiff record_type_diff_protobuf;
140   record_type_diff_protobuf.set_name(record_type_diff_ir->GetName());
141   record_type_diff_protobuf.set_linker_set_key(
142       record_type_diff_ir->GetLinkerSetKey());
143   // If a type_info diff exists
144   const TypeDiffIR *type_diff_ir = record_type_diff_ir->GetTypeDiff();
145   if (type_diff_ir != nullptr) {
146     abi_diff::TypeInfoDiff *type_info_diff =
147         record_type_diff_protobuf.mutable_type_info_diff();
148     if (!AddTypeInfoDiff(type_info_diff, type_diff_ir)) {
149       llvm::errs() << "RecordType could not be converted\n";
150       ::exit(1);
151     }
152   }
153   // If vtables differ.
154   const VTableLayoutDiffIR *vtable_layout_diff_ir =
155       record_type_diff_ir->GetVTableLayoutDiff();
156   if (vtable_layout_diff_ir != nullptr) {
157     abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf =
158         record_type_diff_protobuf.mutable_vtable_layout_diff();
159     if (!AddVTableLayoutDiff(vtable_layout_diff_protobuf,
160                              vtable_layout_diff_ir)) {
161       llvm::errs() << "VTable layout diff could not be added\n";
162       ::exit(1);
163     }
164   }
165   // If base specifiers differ.
166   const CXXBaseSpecifierDiffIR *base_specifier_diff_ir =
167       record_type_diff_ir->GetBaseSpecifiers();
168   if (base_specifier_diff_ir != nullptr) {
169     abi_diff::CXXBaseSpecifierDiff *base_specifier_diff_protobuf =
170         record_type_diff_protobuf.mutable_bases_diff();
171     if (!AddBaseSpecifierDiffs(base_specifier_diff_protobuf,
172                                base_specifier_diff_ir)) {
173       llvm::errs() << "Base Specifier diff could not be added\n";
174       ::exit(1);
175     }
176   }
177   // Field diffs
178   if (!AddRecordFields(&record_type_diff_protobuf,
179                        record_type_diff_ir->GetFieldsRemoved(), true) ||
180       !AddRecordFields(&record_type_diff_protobuf,
181                        record_type_diff_ir->GetFieldsAdded(), false) ||
182       !AddRecordFieldDiffs(&record_type_diff_protobuf,
183                            record_type_diff_ir->GetFieldDiffs())) {
184     llvm::errs() << "Record Field diff could not be added\n";
185     ::exit(1);
186   }
187   return record_type_diff_protobuf;
188 }
189 
AddEnumUnderlyingTypeDiff(abi_diff::UnderlyingTypeDiff * underlying_type_diff_protobuf,const std::pair<std::string,std::string> * underlying_type_diff_ir)190 static bool AddEnumUnderlyingTypeDiff(
191     abi_diff::UnderlyingTypeDiff *underlying_type_diff_protobuf,
192     const std::pair<std::string, std::string> *underlying_type_diff_ir) {
193   if (underlying_type_diff_protobuf == nullptr) {
194     return false;
195   }
196   underlying_type_diff_protobuf->set_old_type(underlying_type_diff_ir->first);
197   underlying_type_diff_protobuf->set_new_type(underlying_type_diff_ir->second);
198   return true;
199 }
200 
AddEnumFields(google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> * dst,const std::vector<const EnumFieldIR * > & enum_fields)201 static bool AddEnumFields(
202     google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> *dst,
203     const std::vector<const EnumFieldIR *> &enum_fields) {
204   for (auto &&enum_field : enum_fields) {
205     abi_dump::EnumFieldDecl *added_enum_field = dst->Add();
206     if (!ConvertEnumFieldIR(added_enum_field, enum_field)) {
207       return false;
208     }
209   }
210   return true;
211 }
212 
AddEnumFieldDiffs(google::protobuf::RepeatedPtrField<abi_diff::EnumFieldDeclDiff> * dst,const std::vector<EnumFieldDiffIR> & fields_diff_ir)213 static bool AddEnumFieldDiffs(
214     google::protobuf::RepeatedPtrField<abi_diff::EnumFieldDeclDiff> *dst,
215     const std::vector<EnumFieldDiffIR> &fields_diff_ir) {
216   for (auto &&field_diff_ir : fields_diff_ir) {
217     abi_diff::EnumFieldDeclDiff *field_diff_protobuf = dst->Add();
218     if (field_diff_protobuf == nullptr) {
219       return false;
220     }
221     if (!ConvertEnumFieldIR(field_diff_protobuf->mutable_old_field(),
222                             field_diff_ir.GetOldField()) ||
223         !ConvertEnumFieldIR(field_diff_protobuf->mutable_new_field(),
224                             field_diff_ir.GetNewField())) {
225       return false;
226     }
227   }
228   return true;
229 }
230 
ConvertEnumTypeDiffIR(const EnumTypeDiffIR * enum_type_diff_ir)231 static abi_diff::EnumTypeDiff ConvertEnumTypeDiffIR(
232     const EnumTypeDiffIR *enum_type_diff_ir) {
233   abi_diff::EnumTypeDiff enum_type_diff_protobuf;
234   enum_type_diff_protobuf.set_name(enum_type_diff_ir->GetName());
235   enum_type_diff_protobuf.set_linker_set_key(
236       enum_type_diff_ir->GetLinkerSetKey());
237   const std::pair<std::string, std::string> *underlying_type_diff =
238       enum_type_diff_ir->GetUnderlyingTypeDiff();
239   if ((underlying_type_diff != nullptr &&
240        !AddEnumUnderlyingTypeDiff(
241            enum_type_diff_protobuf.mutable_underlying_type_diff(),
242            underlying_type_diff)) ||
243       !AddEnumFields(enum_type_diff_protobuf.mutable_fields_removed(),
244                      enum_type_diff_ir->GetFieldsRemoved()) ||
245       !AddEnumFields(enum_type_diff_protobuf.mutable_fields_added(),
246                      enum_type_diff_ir->GetFieldsAdded()) ||
247       !AddEnumFieldDiffs(enum_type_diff_protobuf.mutable_fields_diff(),
248                          enum_type_diff_ir->GetFieldsDiff())) {
249     llvm::errs() << "Enum field diff could not be added\n";
250     ::exit(1);
251   }
252   return enum_type_diff_protobuf;
253 }
254 
ConvertGlobalVarDiffIR(const GlobalVarDiffIR * global_var_diff_ir)255 static abi_diff::GlobalVarDeclDiff ConvertGlobalVarDiffIR(
256     const GlobalVarDiffIR *global_var_diff_ir) {
257   abi_diff::GlobalVarDeclDiff global_var_diff;
258   global_var_diff.set_name(global_var_diff_ir->GetName());
259   abi_dump::GlobalVarDecl *old_global_var = global_var_diff.mutable_old();
260   abi_dump::GlobalVarDecl *new_global_var = global_var_diff.mutable_new_();
261   if (old_global_var == nullptr || new_global_var == nullptr) {
262     llvm::errs() << "Globar Var diff could not be added\n";
263     ::exit(1);
264   }
265   *old_global_var = ConvertGlobalVarIR(global_var_diff_ir->GetOldGlobalVar());
266   *new_global_var = ConvertGlobalVarIR(global_var_diff_ir->GetNewGlobalVar());
267   return global_var_diff;
268 }
269 
ConvertFunctionDiffIR(const FunctionDiffIR * function_diff_ir)270 static abi_diff::FunctionDeclDiff ConvertFunctionDiffIR(
271     const FunctionDiffIR *function_diff_ir) {
272   abi_diff::FunctionDeclDiff function_diff;
273   function_diff.set_name(function_diff_ir->GetName());
274   abi_dump::FunctionDecl *old_function = function_diff.mutable_old();
275   abi_dump::FunctionDecl *new_function = function_diff.mutable_new_();
276   if (old_function == nullptr || new_function == nullptr) {
277     llvm::errs() << "Function diff could not be added\n";
278     ::exit(1);
279   }
280   *old_function = ConvertFunctionIR(function_diff_ir->GetOldFunction());
281   *new_function = ConvertFunctionIR(function_diff_ir->GetNewFunction());
282   return function_diff;
283 }
284 
AddLibNameIR(const std::string & name)285 void ProtobufIRDiffDumper::AddLibNameIR(const std::string &name) {
286   diff_tu_->set_lib_name(name);
287 }
288 
AddArchIR(const std::string & arch)289 void ProtobufIRDiffDumper::AddArchIR(const std::string &arch) {
290   diff_tu_->set_arch(arch);
291 }
292 
GetCompatibilityStatusIR()293 CompatibilityStatusIR ProtobufIRDiffDumper::GetCompatibilityStatusIR() {
294   if (diff_tu_->functions_removed().size() != 0 ||
295       diff_tu_->global_vars_removed().size() != 0 ||
296       diff_tu_->function_diffs().size() != 0 ||
297       diff_tu_->global_var_diffs().size() != 0 ||
298       diff_tu_->enum_type_diffs().size() != 0 ||
299       diff_tu_->record_type_diffs().size() != 0) {
300     return CompatibilityStatusIR::Incompatible;
301   }
302 
303   CompatibilityStatusIR combined_status = CompatibilityStatusIR::Compatible;
304 
305   if (diff_tu_->enum_type_extension_diffs().size() != 0 ||
306       diff_tu_->functions_added().size() != 0 ||
307       diff_tu_->global_vars_added().size() != 0 ||
308       diff_tu_->record_type_extension_diffs().size() != 0 ||
309       diff_tu_->function_extension_diffs().size() != 0) {
310     combined_status = combined_status | CompatibilityStatusIR::Extension;
311   }
312 
313   if (diff_tu_->unreferenced_enum_type_diffs().size() != 0 ||
314       diff_tu_->unreferenced_enum_type_extension_diffs().size() != 0 ||
315       diff_tu_->unreferenced_enum_types_added().size() != 0 ||
316       diff_tu_->unreferenced_enum_types_removed().size() != 0 ||
317       diff_tu_->unreferenced_record_type_diffs().size() != 0 ||
318       diff_tu_->unreferenced_record_type_extension_diffs().size() != 0 ||
319       diff_tu_->unreferenced_record_types_added().size() != 0 ||
320       diff_tu_->unreferenced_record_types_removed().size() != 0) {
321     combined_status =
322         combined_status | CompatibilityStatusIR::UnreferencedChanges;
323   }
324 
325   if (diff_tu_->removed_elf_functions().size() != 0 ||
326       diff_tu_->removed_elf_objects().size() != 0) {
327     combined_status = combined_status | CompatibilityStatusIR::ElfIncompatible;
328   }
329 
330   if (diff_tu_->added_elf_functions().size() != 0 ||
331       diff_tu_->added_elf_objects().size() != 0) {
332     combined_status = combined_status | CompatibilityStatusIR::ElfExtension;
333   }
334 
335   return combined_status;
336 }
337 
AddCompatibilityStatusIR(CompatibilityStatusIR status)338 void ProtobufIRDiffDumper::AddCompatibilityStatusIR(
339     CompatibilityStatusIR status) {
340   diff_tu_->set_compatibility_status(CompatibilityStatusIRToProtobuf(status));
341 }
342 
AddDiffMessageIR(const DiffMessageIR * message,const std::string & type_stack,DiffKind diff_kind)343 bool ProtobufIRDiffDumper::AddDiffMessageIR(const DiffMessageIR *message,
344                                             const std::string &type_stack,
345                                             DiffKind diff_kind) {
346   switch (message->Kind()) {
347     case RecordTypeKind:
348       return AddRecordTypeDiffIR(
349           static_cast<const RecordTypeDiffIR *>(message), type_stack,
350           diff_kind);
351     case EnumTypeKind:
352       return AddEnumTypeDiffIR(
353           static_cast<const EnumTypeDiffIR *>(message), type_stack, diff_kind);
354     case GlobalVarKind:
355       return AddGlobalVarDiffIR(
356           static_cast<const GlobalVarDiffIR*>(message), type_stack, diff_kind);
357     case FunctionKind:
358       return AddFunctionDiffIR(
359           static_cast<const FunctionDiffIR*>(message), type_stack, diff_kind);
360     default:
361       break;
362   }
363   llvm::errs() << "Dump Diff attempted on something not a user defined type / "
364                << "function / global variable\n";
365   return false;
366 }
367 
AddLinkableMessageIR(const LinkableMessageIR * message,DiffKind diff_kind)368 bool ProtobufIRDiffDumper::AddLinkableMessageIR(
369     const LinkableMessageIR *message, DiffKind diff_kind) {
370   switch (message->GetKind()) {
371     case RecordTypeKind:
372       return AddLoneRecordTypeDiffIR(
373           static_cast<const RecordTypeIR *>(message), diff_kind);
374     case EnumTypeKind:
375       return AddLoneEnumTypeDiffIR(
376           static_cast<const EnumTypeIR *>(message), diff_kind);
377     case GlobalVarKind:
378       return AddLoneGlobalVarDiffIR(
379           static_cast<const GlobalVarIR*>(message), diff_kind);
380     case FunctionKind:
381       return AddLoneFunctionDiffIR(
382           static_cast<const FunctionIR*>(message), diff_kind);
383     default:
384       break;
385   }
386   llvm::errs() << "Dump Diff attempted on something not a user defined type / "
387                << "function / global variable\n";
388   return false;
389 }
390 
AddElfSymbolMessageIR(const ElfSymbolIR * elf_symbol,DiffKind diff_kind)391 bool ProtobufIRDiffDumper::AddElfSymbolMessageIR(const ElfSymbolIR *elf_symbol,
392                                                  DiffKind diff_kind) {
393   switch (elf_symbol->GetKind()) {
394     case ElfSymbolIR::ElfFunctionKind:
395       return AddElfFunctionIR(static_cast<const ElfFunctionIR *>(elf_symbol),
396                               diff_kind);
397       break;
398     case ElfSymbolIR::ElfObjectKind:
399       return AddElfObjectIR(static_cast<const ElfObjectIR *>(elf_symbol),
400                             diff_kind);
401       break;
402   }
403   // Any other kind is invalid
404   return false;
405 }
406 
AddElfFunctionIR(const ElfFunctionIR * elf_function_ir,DiffKind diff_kind)407 bool ProtobufIRDiffDumper::AddElfFunctionIR(
408     const ElfFunctionIR *elf_function_ir, DiffKind diff_kind) {
409   abi_dump::ElfFunction *added_elf_function = nullptr;
410   switch (diff_kind) {
411     case DiffKind::Removed:
412       added_elf_function = diff_tu_->add_removed_elf_functions();
413       break;
414     case DiffKind::Added:
415       added_elf_function = diff_tu_->add_added_elf_functions();
416       break;
417     default:
418       llvm::errs() << "Invalid call to AddElfFunctionIR\n";
419       return false;
420   }
421   if (added_elf_function == nullptr) {
422     return false;
423   }
424   *added_elf_function = ConvertElfFunctionIR(elf_function_ir);
425   return true;
426 }
427 
AddElfObjectIR(const ElfObjectIR * elf_object_ir,DiffKind diff_kind)428 bool ProtobufIRDiffDumper::AddElfObjectIR(
429     const ElfObjectIR *elf_object_ir, DiffKind diff_kind) {
430   abi_dump::ElfObject *added_elf_object = nullptr;
431   switch (diff_kind) {
432     case DiffKind::Removed:
433       added_elf_object = diff_tu_->add_removed_elf_objects();
434       break;
435     case DiffKind::Added:
436       added_elf_object = diff_tu_->add_added_elf_objects();
437       break;
438     default:
439       llvm::errs() << "Invalid call to AddElfObjectIR\n";
440       return false;
441   }
442   if (added_elf_object == nullptr) {
443     return false;
444   }
445   *added_elf_object = ConvertElfObjectIR(elf_object_ir);
446   return true;
447 }
448 
AddLoneRecordTypeDiffIR(const RecordTypeIR * record_type_ir,DiffKind diff_kind)449 bool ProtobufIRDiffDumper::AddLoneRecordTypeDiffIR(
450     const RecordTypeIR *record_type_ir, DiffKind diff_kind) {
451   abi_dump::RecordType *added_record_type = nullptr;
452   switch (diff_kind) {
453     case DiffKind::Removed:
454       // Referenced record types do not get reported as added / removed,
455       // the diff shows up in the parent type / function/ global variable
456       // referencing the record.
457       added_record_type = diff_tu_->add_unreferenced_record_types_removed();
458       break;
459     case DiffKind::Added:
460       added_record_type = diff_tu_->add_unreferenced_record_types_added();
461       break;
462     default:
463       llvm::errs() << "Invalid call to AddLoneRecordTypeDiffIR\n";
464       return false;
465   }
466   if (added_record_type == nullptr) {
467     return false;
468   }
469   *added_record_type = ConvertRecordTypeIR(record_type_ir);
470   return true;
471 }
472 
AddLoneFunctionDiffIR(const FunctionIR * function_ir,DiffKind diff_kind)473 bool ProtobufIRDiffDumper::AddLoneFunctionDiffIR(
474     const FunctionIR *function_ir, DiffKind diff_kind) {
475   abi_dump::FunctionDecl *added_function = nullptr;
476   switch (diff_kind) {
477     case DiffKind::Removed:
478       added_function = diff_tu_->add_functions_removed();
479       break;
480     case DiffKind::Added:
481       added_function = diff_tu_->add_functions_added();
482       break;
483     default:
484       llvm::errs() << "Invalid call to AddLoneFunctionDiffIR\n";
485       return false;
486   }
487   *added_function = ConvertFunctionIR(function_ir);
488   return true;
489 }
490 
AddLoneEnumTypeDiffIR(const EnumTypeIR * enum_type_ir,DiffKind diff_kind)491 bool ProtobufIRDiffDumper::AddLoneEnumTypeDiffIR(
492     const EnumTypeIR *enum_type_ir, DiffKind diff_kind) {
493   abi_dump::EnumType *added_enum_type = nullptr;
494   switch (diff_kind) {
495     case DiffKind::Removed:
496       // Referenced enum types do not get reported as added / removed,
497       // the diff shows up in the parent type / function/ global variable
498       // referencing the enum.
499       added_enum_type = diff_tu_->add_unreferenced_enum_types_removed();
500       break;
501     case DiffKind::Added:
502       added_enum_type = diff_tu_->add_unreferenced_enum_types_added();
503       break;
504     default:
505       llvm::errs() << "Invalid call to AddLoneRecordTypeDiffIR\n";
506       return false;
507   }
508   if (added_enum_type == nullptr) {
509     return false;
510   }
511   *added_enum_type = ConvertEnumTypeIR(enum_type_ir);
512   return true;
513 }
514 
AddLoneGlobalVarDiffIR(const GlobalVarIR * global_var_ir,DiffKind diff_kind)515 bool ProtobufIRDiffDumper::AddLoneGlobalVarDiffIR(
516     const GlobalVarIR *global_var_ir, DiffKind diff_kind) {
517   abi_dump::GlobalVarDecl *added_global_var = nullptr;
518   switch (diff_kind) {
519     case DiffKind::Removed:
520       added_global_var = diff_tu_->add_global_vars_removed();
521       break;
522     case DiffKind::Added:
523       added_global_var = diff_tu_->add_global_vars_added();
524       break;
525     default:
526       llvm::errs() << "Invalid call to AddLoneFunctionDiffIR\n";
527       return false;
528   }
529   *added_global_var = ConvertGlobalVarIR(global_var_ir);
530   return true;
531 }
532 
AddRecordTypeDiffIR(const RecordTypeDiffIR * record_diff_ir,const std::string & type_stack,DiffKind diff_kind)533 bool ProtobufIRDiffDumper::AddRecordTypeDiffIR(
534     const RecordTypeDiffIR *record_diff_ir, const std::string &type_stack,
535     DiffKind diff_kind) {
536   abi_diff::RecordTypeDiff *added_record_type_diff = nullptr;
537   bool is_extended = record_diff_ir->IsExtended();
538   switch (diff_kind) {
539     case DiffKind::Unreferenced:
540       if (is_extended) {
541         added_record_type_diff =
542             diff_tu_->add_unreferenced_record_type_extension_diffs();
543       } else {
544         added_record_type_diff = diff_tu_->add_unreferenced_record_type_diffs();
545       }
546       break;
547     case DiffKind::Referenced:
548       if (is_extended) {
549         added_record_type_diff = diff_tu_->add_record_type_extension_diffs();
550       } else {
551         added_record_type_diff = diff_tu_->add_record_type_diffs();
552       }
553       break;
554     default:
555       break;
556   }
557   if (!added_record_type_diff) {
558     return false;
559   }
560 
561   *added_record_type_diff = ConvertRecordTypeDiffIR(record_diff_ir);
562   added_record_type_diff->set_type_stack(type_stack);
563   return true;
564 }
565 
AddFunctionDiffIR(const FunctionDiffIR * function_diff_ir,const std::string & type_stack,DiffKind diff_kind)566 bool ProtobufIRDiffDumper::AddFunctionDiffIR(
567     const FunctionDiffIR *function_diff_ir, const std::string &type_stack,
568     DiffKind diff_kind) {
569   abi_diff::FunctionDeclDiff *added_function_diff =
570       function_diff_ir->IsExtended() ? diff_tu_->add_function_extension_diffs()
571                                      : diff_tu_->add_function_diffs();
572   if (!added_function_diff) {
573     return false;
574   }
575   *added_function_diff = ConvertFunctionDiffIR(function_diff_ir);
576   return true;
577 }
578 
AddEnumTypeDiffIR(const EnumTypeDiffIR * enum_diff_ir,const std::string & type_stack,DiffKind diff_kind)579 bool ProtobufIRDiffDumper::AddEnumTypeDiffIR(const EnumTypeDiffIR *enum_diff_ir,
580                                              const std::string &type_stack,
581                                              DiffKind diff_kind) {
582   abi_diff::EnumTypeDiff *added_enum_type_diff = nullptr;
583   switch (diff_kind) {
584     case DiffKind::Unreferenced:
585       if (enum_diff_ir->IsExtended()) {
586         added_enum_type_diff =
587             diff_tu_->add_unreferenced_enum_type_extension_diffs();
588       } else {
589         added_enum_type_diff =
590             diff_tu_->add_unreferenced_enum_type_diffs();
591       }
592       break;
593     case DiffKind::Referenced:
594       if (enum_diff_ir->IsExtended()) {
595         added_enum_type_diff =
596             diff_tu_->add_enum_type_extension_diffs();
597       } else {
598         added_enum_type_diff =
599             diff_tu_->add_enum_type_diffs();
600       }
601       break;
602     default:
603       break;
604   }
605   if (!added_enum_type_diff) {
606     return false;
607   }
608   *added_enum_type_diff = ConvertEnumTypeDiffIR(enum_diff_ir);
609   added_enum_type_diff->set_type_stack(type_stack);
610   return true;
611 }
612 
AddGlobalVarDiffIR(const GlobalVarDiffIR * global_var_diff_ir,const std::string & type_stack,DiffKind diff_kind)613 bool ProtobufIRDiffDumper::AddGlobalVarDiffIR(
614     const GlobalVarDiffIR *global_var_diff_ir, const std::string &type_stack,
615     DiffKind diff_kind) {
616   abi_diff::GlobalVarDeclDiff *added_global_var_diff =
617       diff_tu_->add_global_var_diffs();
618   if (!added_global_var_diff) {
619     return false;
620   }
621   *added_global_var_diff = ConvertGlobalVarDiffIR(global_var_diff_ir);
622   return true;
623 }
624 
Dump()625 bool ProtobufIRDiffDumper::Dump() {
626   GOOGLE_PROTOBUF_VERIFY_VERSION;
627   assert(diff_tu_.get() != nullptr);
628   std::ofstream text_output(dump_path_);
629   {
630     google::protobuf::io::OstreamOutputStream text_os(&text_output);
631     if (!google::protobuf::TextFormat::Print(*diff_tu_.get(), &text_os)) {
632       return false;
633     }
634   }
635   return text_output.flush().good();
636 }
637 
CreateProtobufIRDiffDumper(const std::string & dump_path)638 std::unique_ptr<IRDiffDumper> CreateProtobufIRDiffDumper(
639     const std::string &dump_path) {
640   return std::make_unique<ProtobufIRDiffDumper>(dump_path);
641 }
642 
643 
644 }  // namespace repr
645 }  // namespace header_checker
646