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/ir_reader.h"
16 
17 #include "repr/abi_diff_helpers.h"
18 #include "repr/ir_representation.h"
19 #include "repr/ir_representation_internal.h"
20 #include "repr/json/api.h"
21 #include "repr/protobuf/api.h"
22 
23 #include <list>
24 #include <memory>
25 #include <set>
26 #include <string>
27 
28 #include <llvm/Support/raw_ostream.h>
29 
30 
31 namespace header_checker {
32 namespace repr {
33 
34 
35 using MergeStatus = IRReader::MergeStatus;
36 
37 
38 std::unique_ptr<IRReader>
CreateIRReader(TextFormatIR text_format,const std::set<std::string> * exported_headers)39 IRReader::CreateIRReader(
40     TextFormatIR text_format, const std::set<std::string> *exported_headers) {
41   switch (text_format) {
42     case TextFormatIR::ProtobufTextFormat:
43       return CreateProtobufIRReader(exported_headers);
44     case TextFormatIR::Json:
45       return CreateJsonIRReader(exported_headers);
46     default:
47       llvm::errs() << "Text format not supported yet\n";
48       return nullptr;
49   }
50 }
51 
52 
ReadDump(const std::string & dump_file)53 bool IRReader::ReadDump(const std::string &dump_file) {
54   module_->SetCompilationUnitPath(dump_file);
55   return ReadDumpImpl(dump_file);
56 }
57 
58 
MergeBuiltinType(const BuiltinTypeIR * builtin_type,const IRReader & addend,AbiElementMap<MergeStatus> * local_to_global_type_id_map)59 MergeStatus IRReader::MergeBuiltinType(
60     const BuiltinTypeIR *builtin_type, const IRReader &addend,
61     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
62   std::string linker_set_key = builtin_type->GetLinkerSetKey();
63   auto builtin_it = module_->builtin_types_.find(linker_set_key);
64   if (builtin_it != module_->builtin_types_.end()) {
65     return MergeStatus(false, builtin_it->second.GetSelfType());
66   }
67 
68   // Add this builtin type to the parent graph's builtin_types_ map.
69   const std::string &type_id = builtin_type->GetSelfType();
70   auto p = module_->builtin_types_.emplace(linker_set_key, *builtin_type);
71   module_->type_graph_.emplace(type_id, &p.first->second);
72 
73   MergeStatus merge_status(true, type_id);
74   local_to_global_type_id_map->emplace(type_id, merge_status);
75   return merge_status;
76 }
77 
78 
LookupUserDefinedType(const TypeIR * ud_type,const IRReader & addend,const std::string & ud_type_unique_id_and_source,AbiElementMap<MergeStatus> * local_to_global_type_id_map_)79 MergeStatus IRReader::LookupUserDefinedType(
80     const TypeIR *ud_type, const IRReader &addend,
81     const std::string &ud_type_unique_id_and_source,
82     AbiElementMap<MergeStatus> *local_to_global_type_id_map_) {
83   auto it = module_->odr_list_map_.find(ud_type_unique_id_and_source);
84   if (it == module_->odr_list_map_.end()) {
85     // Calling this an ODR violation even though it means no UD with the same
86     // name + source combination was seen in the parent graph. The type-id
87     // passed does not matter since was_newly_added_ is true, the type will get
88     // allocated a new type id.
89     return MergeStatus(true, "");
90   }
91 
92   // Initialize type comparator (which will compare the referenced types
93   // recursively).
94   std::set<std::string> type_cache;
95   DiffPolicyOptions diff_policy_options(false) ;
96   AbiDiffHelper diff_helper(module_->type_graph_, addend.module_->type_graph_,
97                             diff_policy_options, &type_cache,
98                             nullptr, local_to_global_type_id_map_);
99 
100   // Compare each user-defined type with the latest input user-defined type.
101   // If there is a match, re-use the existing user-defined type.
102   for (auto &contender_ud : it->second) {
103     DiffStatus result = diff_helper.CompareAndDumpTypeDiff(
104         contender_ud->GetSelfType(), ud_type->GetSelfType());
105     if (result == DiffStatus::no_diff) {
106       local_to_global_type_id_map_->emplace(
107           ud_type->GetSelfType(),
108           MergeStatus(false, contender_ud->GetSelfType()));
109       return MergeStatus(false, contender_ud->GetSelfType());
110     }
111   }
112 
113 #ifdef DEBUG
114   llvm::errs() << "ODR violation detected for: " << ud_type->GetName() << "\n";
115 #endif
116   return MergeStatus(true, (*(it->second.begin()))->GetSelfType());
117 }
118 
119 
LookupType(const TypeIR * addend_node,const IRReader & addend,AbiElementMap<MergeStatus> * local_to_global_type_id_map)120 MergeStatus IRReader::LookupType(
121     const TypeIR *addend_node, const IRReader &addend,
122     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
123   std::string unique_type_id;
124   switch (addend_node->GetKind()) {
125     case RecordTypeKind:
126       unique_type_id =
127           GetODRListMapKey(static_cast<const RecordTypeIR *>(addend_node));
128       break;
129     case EnumTypeKind:
130       unique_type_id =
131           GetODRListMapKey(static_cast<const EnumTypeIR *>(addend_node));
132       break;
133     case FunctionTypeKind:
134       unique_type_id =
135           GetODRListMapKey(static_cast<const FunctionTypeIR *>(addend_node));
136       break;
137     default:
138       // Other kinds (e.g. PointerTypeKind, QualifiedTypeKind, ArrayTypeKind,
139       // LvalueReferenceTypeKind, RvalueReferenceTypeKind, or BuiltinTypeKind)
140       // should be proactively added by returning MergeStatus with
141       // was_newly_added_ = true.
142       return MergeStatus(true, "type-hidden");
143   }
144 
145   return LookupUserDefinedType(
146       addend_node, addend, unique_type_id, local_to_global_type_id_map);
147 }
148 
149 
150 // This method merges the type referenced by 'references_type' into the parent
151 // graph. It also corrects the referenced_type field in the references_type
152 // object passed and returns the merge status of the *referenced type*.
MergeReferencingTypeInternal(const IRReader & addend,ReferencesOtherType * references_type,AbiElementMap<MergeStatus> * local_to_global_type_id_map)153 MergeStatus IRReader::MergeReferencingTypeInternal(
154     const IRReader &addend, ReferencesOtherType *references_type,
155     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
156   // First look in the local_to_global_type_id_map for the referenced type's
157   // id.
158   const std::string &referenced_type_id = references_type->GetReferencedType();
159   auto local_to_global_it = local_to_global_type_id_map->find(
160       referenced_type_id);
161   if (local_to_global_it != local_to_global_type_id_map->end()) {
162     // The type was already added to the parent graph. So change the
163     // referenced type to the global type id.
164     references_type->SetReferencedType(local_to_global_it->second.type_id_);
165     return local_to_global_it->second;
166   }
167 
168   // If that did not go through, look at the addend's type_map_ and get the
169   // TypeIR* and call MergeType on it.
170   auto local_type_it = addend.module_->type_graph_.find(referenced_type_id);
171   if (local_type_it != addend.module_->type_graph_.end()) {
172     // We don't care about merge_status.was_newly_added since we wouldn't have
173     // gotten this far if we weren't adding this.
174     MergeStatus merge_status =
175         MergeType(local_type_it->second, addend, local_to_global_type_id_map);
176     const std::string &global_type_id = merge_status.type_id_;
177     references_type->SetReferencedType(global_type_id);
178     return merge_status;
179   }
180 
181   // If the referenced type was hidden, create the name reference type in the
182   // parent module and keep the referenced type_id as-is.
183   return MergeStatus(true, referenced_type_id);
184 }
185 
186 
MergeRecordFields(const IRReader & addend,RecordTypeIR * added_node,AbiElementMap<MergeStatus> * local_to_global_type_id_map)187 void IRReader::MergeRecordFields(
188     const IRReader &addend, RecordTypeIR *added_node,
189     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
190   for (auto &field : added_node->GetFields()) {
191     MergeReferencingTypeInternal(addend, &field, local_to_global_type_id_map);
192   }
193 }
194 
195 
MergeRecordCXXBases(const IRReader & addend,RecordTypeIR * added_node,AbiElementMap<MergeStatus> * local_to_global_type_id_map)196 void IRReader::MergeRecordCXXBases(
197     const IRReader &addend, RecordTypeIR *added_node,
198     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
199   for (auto &base : added_node->GetBases()) {
200     MergeReferencingTypeInternal(addend, &base, local_to_global_type_id_map);
201   }
202 }
203 
204 
MergeRecordTemplateElements(const IRReader & addend,RecordTypeIR * added_node,AbiElementMap<MergeStatus> * local_to_global_type_id_map)205 void IRReader::MergeRecordTemplateElements(
206     const IRReader &addend, RecordTypeIR *added_node,
207     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
208   for (auto &template_element : added_node->GetTemplateElements()) {
209     MergeReferencingTypeInternal(
210         addend, &template_element, local_to_global_type_id_map);
211   }
212 }
213 
214 
MergeRecordDependencies(const IRReader & addend,RecordTypeIR * added_node,AbiElementMap<MergeStatus> * local_to_global_type_id_map)215 void IRReader::MergeRecordDependencies(
216     const IRReader &addend, RecordTypeIR *added_node,
217     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
218   // First call MergeType on all its fields.
219   MergeRecordFields(addend, added_node, local_to_global_type_id_map);
220 
221   // Call MergeType on CXXBases of the record.
222   MergeRecordCXXBases(addend, added_node, local_to_global_type_id_map);
223 
224   MergeRecordTemplateElements(addend, added_node, local_to_global_type_id_map);
225 }
226 
227 
228 template <typename T>
229 std::pair<MergeStatus, typename AbiElementMap<T>::iterator>
UpdateUDTypeAccounting(const T * addend_node,const IRReader & addend,AbiElementMap<MergeStatus> * local_to_global_type_id_map,AbiElementMap<T> * specific_type_map)230 IRReader::UpdateUDTypeAccounting(
231     const T *addend_node, const IRReader &addend,
232     AbiElementMap<MergeStatus> *local_to_global_type_id_map,
233     AbiElementMap<T> *specific_type_map) {
234   std::string added_type_id = addend_node->GetSelfType();
235   auto type_id_it = module_->type_graph_.find(added_type_id);
236   if (type_id_it != module_->type_graph_.end()) {
237     added_type_id = AllocateNewTypeId(added_type_id, *addend.module_);
238   }
239 
240   // Add the ud-type with type-id to the type_graph_, since if there are generic
241   // reference types which refer to the record being added, they'll need to find
242   // it's id in the map.
243   // Add ud-type to the parent graph.
244   T added_type_ir = *addend_node;
245   added_type_ir.SetSelfType(added_type_id);
246   added_type_ir.SetReferencedType(added_type_id);
247   auto it = AddToMapAndTypeGraph(std::move(added_type_ir), specific_type_map,
248                                  &module_->type_graph_);
249   // Add to faciliate ODR checking.
250   const std::string &key = GetODRListMapKey(&(it->second));
251   MergeStatus type_merge_status = MergeStatus(true, added_type_id);
252   module_->AddToODRListMap(key, &(it->second));
253   local_to_global_type_id_map->emplace(addend_node->GetSelfType(),
254                                        type_merge_status);
255   return {type_merge_status, it};
256 }
257 
258 
259 // This method is necessarily going to have a was_newly_merged_ = true in its
260 // MergeStatus return. So it necessarily merges a new RecordType.
MergeRecordAndDependencies(const RecordTypeIR * addend_node,const IRReader & addend,AbiElementMap<MergeStatus> * local_to_global_type_id_map)261 MergeStatus IRReader::MergeRecordAndDependencies(
262     const RecordTypeIR *addend_node, const IRReader &addend,
263     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
264   auto p = UpdateUDTypeAccounting(
265       addend_node, addend, local_to_global_type_id_map,
266       &module_->record_types_);
267   MergeRecordDependencies(addend, &p.second->second,
268                           local_to_global_type_id_map);
269   return p.first;
270 }
271 
272 
MergeEnumDependencies(const IRReader & addend,EnumTypeIR * added_node,AbiElementMap<MergeStatus> * local_to_global_type_id_map)273 void IRReader::MergeEnumDependencies(
274     const IRReader &addend, EnumTypeIR *added_node,
275     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
276   const std::string underlying_type_id = added_node->GetUnderlyingType();
277   // Get the underlying type, it nessarily has to be present in the addend's
278   // type graph since builtin types can't be hidden. Call MergeType on it and
279   // change the underlying type to that.
280   auto it = addend.module_->type_graph_.find(underlying_type_id);
281   if (it == addend.module_->type_graph_.end()) {
282     llvm::errs() << "Enum underlying types should not be hidden\n";
283     ::exit(1);
284   }
285   MergeStatus merge_status = MergeType(
286       it->second, addend, local_to_global_type_id_map);
287   added_node->SetUnderlyingType(merge_status.type_id_);
288 }
289 
290 
291 // This method is necessarily going to have a was_newly_merged_ = true in its
292 // MergeStatus return. So it necessarily merges a new EnumType.
MergeEnumType(const EnumTypeIR * addend_node,const IRReader & addend,AbiElementMap<MergeStatus> * local_to_global_type_id_map)293 MergeStatus IRReader::MergeEnumType(
294     const EnumTypeIR *addend_node, const IRReader &addend,
295     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
296   auto p = UpdateUDTypeAccounting(
297       addend_node, addend, local_to_global_type_id_map, &module_->enum_types_);
298   MergeEnumDependencies(addend, &p.second->second, local_to_global_type_id_map);
299   return p.first;
300 }
301 
302 
MergeFunctionType(const FunctionTypeIR * addend_node,const IRReader & addend,AbiElementMap<MergeStatus> * local_to_global_type_id_map)303 MergeStatus IRReader::MergeFunctionType(
304     const FunctionTypeIR *addend_node, const IRReader &addend,
305     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
306   auto p = UpdateUDTypeAccounting(
307       addend_node, addend, local_to_global_type_id_map,
308       &module_->function_types_);
309   MergeCFunctionLikeDeps(addend, &p.second->second,
310                          local_to_global_type_id_map);
311   return p.first;
312 }
313 
314 
315 template <typename T>
MergeReferencingTypeInternalAndUpdateParent(const IRReader & addend,const T * addend_node,AbiElementMap<MergeStatus> * local_to_global_type_id_map,AbiElementMap<T> * parent_map,const std::string & updated_self_type_id)316 MergeStatus IRReader::MergeReferencingTypeInternalAndUpdateParent(
317     const IRReader &addend, const T *addend_node,
318     AbiElementMap<MergeStatus> *local_to_global_type_id_map,
319     AbiElementMap<T> *parent_map, const std::string &updated_self_type_id) {
320   MergeStatus merge_status;
321   uint64_t old_max_type_id = max_type_id_;
322 
323   // Create copy of addend_node
324   T added_node = *addend_node;
325   added_node.SetSelfType(updated_self_type_id);
326 
327   // The merge status returned is the merge status of the referenced type.
328   merge_status = MergeReferencingTypeInternal(addend, &added_node,
329                                               local_to_global_type_id_map);
330   if (merge_status.was_newly_added_) {
331     // Emplace to map (type-referenced -> Referencing type)
332     AddToMapAndTypeGraph(std::move(added_node), parent_map,
333                          &module_->type_graph_);
334     return MergeStatus(true, updated_self_type_id);
335   }
336 
337   // The type that the added_node references was not newly added to the parent
338   // graph. However, we still might need to add the added_node to the parent
339   // graph, since for the particular 'Kind' of the added_node, it may not be
340   // present in the parent graph. This will be determined by looking at the
341   // appropriate 'type-referenced' -> TypeElement map in the parent for the
342   // type-id returned by the MergeStatus. If the map doesn't have an entry for
343   // the type-id returned by the MergeStatus, the added_type is not present in
344   // the parent graph and needs to be 'newly' added. We also need to modify the
345   // global type id in the local_to_global_type_id map. The added_node should
346   // already have it's self_type and referenced_type fields fixed up.
347   // We maintain a rollback id to have contiguous type ids.
348   max_type_id_ = old_max_type_id;
349 
350   // Try finding the referenced_type is referred to by any referencing type
351   // of the same kind in the parent graph. It is safe to call this on the
352   // added_node, since the referenced_type in the added_node would have been
353   // modified by the MergeReferencingTypeInternal call.
354   auto it = parent_map->find(GetReferencedTypeMapKey(added_node));
355   if (it == parent_map->end()) {
356     // There was no counterpart found for the added_node's type Kind referencing
357     // the referenced type, so we added it to the parent and also updated the
358     // local_to_global_type_id_map's global_id value.
359     AddToMapAndTypeGraph(std::move(added_node), parent_map,
360                          &module_->type_graph_);
361 
362     merge_status = MergeStatus(true, updated_self_type_id);
363     return merge_status;
364   }
365 
366   // Update local_to_global_type_id map's MergeStatus.was_newly_added value for
367   // this key with false since this was node was not newly added.
368   // We never remove anything from the local_to_global_type_id_map, what's
369   // the point ? Since you store the decision of whether the type was newly
370   // added or not. It's global type id is the type-id of the element found
371   // in the parent map which refers to the added_node's modified
372   // referenced_type.
373   merge_status = MergeStatus(false, it->second.GetSelfType());
374   (*local_to_global_type_id_map)[addend_node->GetSelfType()] = merge_status;
375 
376   return merge_status;
377 }
378 
379 
380 // This method creates a new node for the addend node in the graph if MergeType
381 // on the reference returned a MergeStatus with was_newly_added_ = true.
MergeReferencingType(const IRReader & addend,const TypeIR * addend_node,AbiElementMap<MergeStatus> * local_to_global_type_id_map)382 MergeStatus IRReader::MergeReferencingType(
383     const IRReader &addend, const TypeIR *addend_node,
384     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
385   // First add the type 'pro-actively'. We need to do this since we'll need to
386   // fill in 'referenced-type' fields in all this type's descendants and
387   // descendants which are compound types (records), can refer to this type.
388   std::string added_type_id = addend_node->GetSelfType();
389   auto type_id_it = module_->type_graph_.find(added_type_id);
390   if (type_id_it != module_->type_graph_.end()) {
391     added_type_id = AllocateNewTypeId(added_type_id, *addend.module_);
392   }
393 
394   // Add the added record type to the local_to_global_type_id_map.
395   local_to_global_type_id_map->emplace(addend_node->GetSelfType(),
396                                        MergeStatus(true, added_type_id));
397 
398   // Merge the type.
399   switch (addend_node->GetKind()) {
400     case PointerTypeKind:
401       return MergeReferencingTypeInternalAndUpdateParent(
402           addend, static_cast<const PointerTypeIR *>(addend_node),
403           local_to_global_type_id_map, &module_->pointer_types_,
404           added_type_id);
405     case QualifiedTypeKind:
406       return MergeReferencingTypeInternalAndUpdateParent(
407           addend, static_cast<const QualifiedTypeIR *>(addend_node),
408           local_to_global_type_id_map, &module_->qualified_types_,
409           added_type_id);
410     case ArrayTypeKind:
411       return MergeReferencingTypeInternalAndUpdateParent(
412           addend, static_cast<const ArrayTypeIR *>(addend_node),
413           local_to_global_type_id_map, &module_->array_types_,
414           added_type_id);
415     case LvalueReferenceTypeKind:
416       return MergeReferencingTypeInternalAndUpdateParent(
417           addend, static_cast<const LvalueReferenceTypeIR *>(addend_node),
418           local_to_global_type_id_map, &module_->lvalue_reference_types_,
419           added_type_id);
420     case RvalueReferenceTypeKind:
421       return MergeReferencingTypeInternalAndUpdateParent(
422           addend, static_cast<const RvalueReferenceTypeIR *>(addend_node),
423           local_to_global_type_id_map, &module_->rvalue_reference_types_,
424           added_type_id);
425     default:
426       // Only referencing types
427       assert(0);
428   }
429 }
430 
431 
MergeTypeInternal(const TypeIR * addend_node,const IRReader & addend,AbiElementMap<MergeStatus> * local_to_global_type_id_map)432 MergeStatus IRReader::MergeTypeInternal(
433     const TypeIR *addend_node, const IRReader &addend,
434     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
435   switch (addend_node->GetKind()) {
436     case BuiltinTypeKind:
437       return MergeBuiltinType(
438           static_cast<const BuiltinTypeIR *>(addend_node), addend,
439           local_to_global_type_id_map);
440     case RecordTypeKind:
441       return MergeRecordAndDependencies(
442           static_cast<const RecordTypeIR *>(addend_node), addend,
443           local_to_global_type_id_map);
444     case EnumTypeKind:
445       return MergeEnumType(
446           static_cast<const EnumTypeIR *>(addend_node), addend,
447           local_to_global_type_id_map);
448     case FunctionTypeKind:
449       return MergeFunctionType(
450           static_cast<const FunctionTypeIR *>(addend_node), addend,
451           local_to_global_type_id_map);
452     default:
453       return MergeReferencingType(addend, addend_node,
454                                   local_to_global_type_id_map);
455   }
456   assert(0);
457 }
458 
459 
MergeType(const TypeIR * addend_node,const IRReader & addend,AbiElementMap<MergeStatus> * local_to_global_type_id_map)460 MergeStatus IRReader::MergeType(
461     const TypeIR *addend_node, const IRReader &addend,
462     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
463   // Check if the addend type is already in the parent graph. Since we're
464   // going to traverse all the dependencies add whichever ones are not in the
465   // parent graph. This does not add the node itself though.
466   auto type_it = local_to_global_type_id_map->find(addend_node->GetSelfType());
467   if (type_it != local_to_global_type_id_map->end()) {
468     return type_it->second;
469   }
470 
471   MergeStatus merge_status = LookupType(
472       addend_node, addend, local_to_global_type_id_map);
473   if (!merge_status.was_newly_added_) {
474     return merge_status;
475   }
476   merge_status = MergeTypeInternal(
477       addend_node, addend, local_to_global_type_id_map);
478   return merge_status;
479 }
480 
481 
MergeCFunctionLikeDeps(const IRReader & addend,CFunctionLikeIR * cfunction_like_ir,AbiElementMap<MergeStatus> * local_to_global_type_id_map)482 void IRReader::MergeCFunctionLikeDeps(
483     const IRReader &addend, CFunctionLikeIR *cfunction_like_ir,
484     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
485   // Merge the return type.
486   auto ret_type_it =
487       addend.module_->type_graph_.find(cfunction_like_ir->GetReturnType());
488   if (ret_type_it != addend.module_->type_graph_.end()) {
489     // Merge the type if we can find another type in the parent module.
490     MergeStatus ret_merge_status = MergeType(ret_type_it->second, addend,
491                                              local_to_global_type_id_map);
492     cfunction_like_ir->SetReturnType(ret_merge_status.type_id_);
493   }
494 
495   // Merge the argument types.
496   for (auto &param : cfunction_like_ir->GetParameters()) {
497     MergeReferencingTypeInternal(addend, &param, local_to_global_type_id_map);
498   }
499 }
500 
501 
MergeFunctionDeps(FunctionIR * added_node,const IRReader & addend,AbiElementMap<MergeStatus> * local_to_global_type_id_map)502 void IRReader::MergeFunctionDeps(
503     FunctionIR *added_node, const IRReader &addend,
504     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
505   MergeCFunctionLikeDeps(addend, added_node, local_to_global_type_id_map);
506 
507   // Merge the template arguments.
508   for (auto &template_element : added_node->GetTemplateElements()) {
509     MergeReferencingTypeInternal(addend, &template_element,
510                                  local_to_global_type_id_map);
511   }
512 }
513 
514 
515 template <typename T>
IsLinkableMessagePresent(const LinkableMessageIR * lm,const AbiElementMap<T> & message_map)516 static bool IsLinkableMessagePresent(const LinkableMessageIR *lm,
517                                      const AbiElementMap<T> &message_map) {
518   return (message_map.find(lm->GetLinkerSetKey()) != message_map.end());
519 }
520 
521 
MergeFunction(const FunctionIR * addend_node,const IRReader & addend,AbiElementMap<MergeStatus> * local_to_global_type_id_map)522 void IRReader::MergeFunction(
523     const FunctionIR *addend_node, const IRReader &addend,
524     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
525   const std::string &function_linkage_name = addend_node->GetLinkerSetKey();
526   if (IsLinkableMessagePresent(addend_node, module_->functions_)) {
527     // The functions and all of its dependencies have already been added.
528     // No two globally visible functions can have the same symbol name.
529     return;
530   }
531   FunctionIR function_ir = *addend_node;
532   MergeFunctionDeps(&function_ir, addend, local_to_global_type_id_map);
533   // Add it to the parent's function map.
534   module_->functions_.emplace(function_linkage_name, std::move(function_ir));
535 }
536 
537 
AllocateNewTypeId(const std::string & addend_type_id,const ModuleIR & addend_module)538 std::string IRReader::AllocateNewTypeId(const std::string &addend_type_id,
539                                         const ModuleIR &addend_module) {
540   return addend_type_id + "#ODR:" + addend_module.GetCompilationUnitPath();
541 }
542 
543 
MergeGlobalVariable(const GlobalVarIR * addend_node,const IRReader & addend,AbiElementMap<MergeStatus> * local_to_global_type_id_map)544 void IRReader::MergeGlobalVariable(
545     const GlobalVarIR *addend_node, const IRReader &addend,
546     AbiElementMap<MergeStatus> *local_to_global_type_id_map) {
547   const std::string &global_variable_linkage_name =
548       addend_node->GetLinkerSetKey();
549   if (IsLinkableMessagePresent(addend_node, module_->global_variables_)) {
550     // The global variable and all of its dependencies have already been added.
551     return;
552   }
553   GlobalVarIR global_variable_ir = *addend_node;
554   MergeReferencingTypeInternal(addend, &global_variable_ir,
555                                local_to_global_type_id_map);
556   module_->global_variables_.emplace(
557       global_variable_linkage_name, std::move(global_variable_ir));
558 }
559 
560 
MergeGraphs(const IRReader & addend)561 void IRReader::MergeGraphs(const IRReader &addend) {
562   // Iterate through nodes of addend reader and merge them.
563   // Keep a merged types cache since if a type is merged, so will all of its
564   // dependencies which weren't already merged.
565   AbiElementMap<MergeStatus> merged_types_cache;
566 
567   for (auto &&type_ir : addend.module_->type_graph_) {
568     MergeType(type_ir.second, addend, &merged_types_cache);
569   }
570 
571   for (auto &&function_ir : addend.module_->functions_) {
572     MergeFunction(&function_ir.second, addend, &merged_types_cache);
573   }
574 
575   for (auto &&global_var_ir : addend.module_->global_variables_) {
576     MergeGlobalVariable(&global_var_ir.second, addend, &merged_types_cache);
577   }
578 }
579 
580 
581 }  // namespace repr
582 }  // header_checker
583