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