Store the sdump path for each type definition when linking ABI dumps

This commit adds sdump paths to ModuleIR::odr_list_map_. It maps type ID
to list of TypeDefinitions. A TypeDefinition consists of a TypeIR and
the sdump path where the type is defined. The path is used to
distinguish the definitions of the type in different source files.

When header-abi-linker merges modules, the compilation unit paths are
copied to the merged module. Thus, the paths are not lost when the
merged module is merged to another one.

Test: ./test.py
Bug: 147396457
Change-Id: I72a9502b4e81f8ead10c8439af76aea86e3bc3f3
diff --git a/vndk/tools/header-checker/src/diff/abi_diff.cpp b/vndk/tools/header-checker/src/diff/abi_diff.cpp
index 3136e1e..0dd4439 100644
--- a/vndk/tools/header-checker/src/diff/abi_diff.cpp
+++ b/vndk/tools/header-checker/src/diff/abi_diff.cpp
@@ -113,7 +113,7 @@
     if (odr_list.size() != 1) {
       continue;
     }
-    const repr::TypeIR *type = *(odr_list.begin());
+    const repr::TypeIR *type = odr_list.begin()->type_ir_;
     const repr::RecordTypeIR *record_type = nullptr;
     switch (type->GetKind()) {
       case repr::RecordTypeKind:
diff --git a/vndk/tools/header-checker/src/linker/module_merger.cpp b/vndk/tools/header-checker/src/linker/module_merger.cpp
index 85ad5de..54e13af 100644
--- a/vndk/tools/header-checker/src/linker/module_merger.cpp
+++ b/vndk/tools/header-checker/src/linker/module_merger.cpp
@@ -67,7 +67,8 @@
 
   // Compare each user-defined type with the latest input user-defined type.
   // If there is a match, re-use the existing user-defined type.
-  for (auto &contender_ud : it->second) {
+  for (auto &definition : it->second) {
+    const TypeIR *contender_ud = definition.type_ir_;
     DiffStatus result = diff_helper.CompareAndDumpTypeDiff(
         contender_ud->GetSelfType(), ud_type->GetSelfType());
     if (result == DiffStatus::no_diff) {
@@ -81,7 +82,7 @@
 #ifdef DEBUG
   llvm::errs() << "ODR violation detected for: " << ud_type->GetName() << "\n";
 #endif
-  return MergeStatus(true, (*(it->second.begin()))->GetSelfType());
+  return MergeStatus(true, it->second.begin()->type_ir_->GetSelfType());
 }
 
 
@@ -199,10 +200,13 @@
     const T *addend_node, const ModuleIR &addend,
     AbiElementMap<MergeStatus> *local_to_global_type_id_map,
     AbiElementMap<T> *specific_type_map) {
+  const std::string addend_compilation_unit_path =
+      addend.GetCompilationUnitPath(addend_node);
+  assert(addend_compilation_unit_path != "");
   std::string added_type_id = addend_node->GetSelfType();
   auto type_id_it = module_->type_graph_.find(added_type_id);
   if (type_id_it != module_->type_graph_.end()) {
-    added_type_id = AllocateNewTypeId(added_type_id, addend);
+    added_type_id = added_type_id + "#ODR:" + addend_compilation_unit_path;
   }
 
   // Add the ud-type with type-id to the type_graph_, since if there are generic
@@ -217,7 +221,7 @@
   // Add to facilitate ODR checking.
   const std::string &key = GetODRListMapKey(&(it->second));
   MergeStatus type_merge_status = MergeStatus(true, added_type_id);
-  module_->AddToODRListMap(key, &(it->second));
+  module_->AddToODRListMap(key, &(it->second), addend_compilation_unit_path);
   local_to_global_type_id_map->emplace(addend_node->GetSelfType(),
                                        type_merge_status);
   return {type_merge_status, it};
diff --git a/vndk/tools/header-checker/src/repr/ir_representation.cpp b/vndk/tools/header-checker/src/repr/ir_representation.cpp
index 50d1bf9..6f512fd 100644
--- a/vndk/tools/header-checker/src/repr/ir_representation.cpp
+++ b/vndk/tools/header-checker/src/repr/ir_representation.cpp
@@ -109,7 +109,7 @@
   auto it = AddToMapAndTypeGraph(
       std::move(record_type), &record_types_, &type_graph_);
   const std::string &key = GetODRListMapKey(&(it->second));
-  AddToODRListMap(key, &(it->second));
+  AddToODRListMap(key, &(it->second), compilation_unit_path_);
 }
 
 
@@ -120,7 +120,7 @@
   auto it = AddToMapAndTypeGraph(
       std::move(function_type), &function_types_, &type_graph_);
   const std::string &key = GetODRListMapKey(&(it->second));
-  AddToODRListMap(key, &(it->second));
+  AddToODRListMap(key, &(it->second), compilation_unit_path_);
 }
 
 
@@ -131,7 +131,7 @@
   auto it = AddToMapAndTypeGraph(
       std::move(enum_type), &enum_types_, &type_graph_);
   const std::string &key = GetODRListMapKey(&(it->second));
-  AddToODRListMap(key, (&it->second));
+  AddToODRListMap(key, (&it->second), compilation_unit_path_);
 }
 
 
@@ -197,6 +197,34 @@
 }
 
 
+std::string ModuleIR::GetCompilationUnitPath(const TypeIR *type_ir) const {
+  std::string key;
+  switch (type_ir->GetKind()) {
+    case RecordTypeKind:
+      key = GetODRListMapKey(static_cast<const RecordTypeIR *>(type_ir));
+      break;
+    case EnumTypeKind:
+      key = GetODRListMapKey(static_cast<const EnumTypeIR *>(type_ir));
+      break;
+    case FunctionTypeKind:
+      key = GetODRListMapKey(static_cast<const FunctionTypeIR *>(type_ir));
+      break;
+    default:
+      return "";
+  }
+  auto it = odr_list_map_.find(key);
+  if (it == odr_list_map_.end()) {
+    return "";
+  }
+  for (const auto &definition : it->second) {
+    if (definition.type_ir_ == type_ir) {
+      return definition.compilation_unit_path_;
+    }
+  }
+  return "";
+}
+
+
 bool ModuleIR::IsLinkableMessageInExportedHeaders(
     const LinkableMessageIR *linkable_message) const {
   if (exported_headers_ == nullptr || exported_headers_->empty()) {
diff --git a/vndk/tools/header-checker/src/repr/ir_representation.h b/vndk/tools/header-checker/src/repr/ir_representation.h
index 12ba97a..f74d3b7 100644
--- a/vndk/tools/header-checker/src/repr/ir_representation.h
+++ b/vndk/tools/header-checker/src/repr/ir_representation.h
@@ -37,9 +37,6 @@
 template <typename T>
 using AbiElementUnorderedMap = std::unordered_map<std::string, T>;
 
-template <typename T>
-using AbiElementList = std::list<T>;
-
 enum TextFormatIR {
   ProtobufTextFormat = 0,
   Json = 1,
@@ -759,6 +756,16 @@
   }
 };
 
+class TypeDefinition {
+ public:
+  TypeDefinition(const TypeIR *type_ir,
+                 const std::string *compilation_unit_path)
+      : type_ir_(type_ir), compilation_unit_path_(*compilation_unit_path) {}
+
+  const TypeIR *type_ir_;
+  const std::string &compilation_unit_path_;
+};
+
 class ModuleIR {
  public:
   ModuleIR(const std::set<std::string> *exported_headers)
@@ -828,7 +835,7 @@
     return type_graph_;
   }
 
-  const AbiElementUnorderedMap<std::list<const TypeIR *>> &
+  const AbiElementUnorderedMap<std::list<TypeDefinition>> &
   GetODRListMap() const {
     return odr_list_map_;
   }
@@ -864,10 +871,19 @@
 
   void AddElfObject(ElfObjectIR &&elf_object);
 
-  void AddToODRListMap(const std::string &key, const TypeIR *value) {
+  // Find the compilation unit path of a RecordTypeIR, FunctionTypeIR, or
+  // EnumTypeIR in odr_list_map_. Return an empty string if the type is not in
+  // the map.
+  std::string GetCompilationUnitPath(const TypeIR *type_ir) const;
+
+  void AddToODRListMap(const std::string &key, const TypeIR *type_ir,
+                       const std::string &compilation_unit_path) {
+    auto compilation_unit_path_it =
+        compilation_unit_paths_.emplace(compilation_unit_path).first;
     auto map_it = odr_list_map_.find(key);
+    TypeDefinition value(type_ir, &*compilation_unit_path_it);
     if (map_it == odr_list_map_.end()) {
-      odr_list_map_.emplace(key, std::list<const TypeIR *>({value}));
+      odr_list_map_.emplace(key, std::list<TypeDefinition>({value}));
       return;
     }
     odr_list_map_[key].emplace_back(value);
@@ -883,7 +899,6 @@
   // File path to the compilation unit (*.sdump)
   std::string compilation_unit_path_;
 
-  AbiElementList<RecordTypeIR> record_types_list_;
   AbiElementMap<FunctionIR> functions_;
   AbiElementMap<GlobalVarIR> global_variables_;
   AbiElementMap<RecordTypeIR> record_types_;
@@ -904,8 +919,13 @@
   AbiElementMap<ElfObjectIR> elf_objects_;
   // type-id -> LinkableMessageIR * map
   AbiElementMap<const TypeIR *> type_graph_;
-  // maps unique_id + source_file -> const TypeIR *
-  AbiElementUnorderedMap<std::list<const TypeIR *>> odr_list_map_;
+  // maps unique_id + source_file -> TypeDefinition
+  AbiElementUnorderedMap<std::list<TypeDefinition>> odr_list_map_;
+
+
+ private:
+  // The compilation unit paths referenced by odr_list_map_;
+  std::set<std::string> compilation_unit_paths_;
   const std::set<std::string> *exported_headers_;
 };
 
diff --git a/vndk/tools/header-checker/tests/reference_dumps/arm64/libmerge_multi_definitions.so.lsdump b/vndk/tools/header-checker/tests/reference_dumps/arm64/libmerge_multi_definitions.so.lsdump
index ff2627d..fa5cfe5 100644
--- a/vndk/tools/header-checker/tests/reference_dumps/arm64/libmerge_multi_definitions.so.lsdump
+++ b/vndk/tools/header-checker/tests/reference_dumps/arm64/libmerge_multi_definitions.so.lsdump
@@ -66,7 +66,7 @@
    "alignment" : 8,
    "linker_set_key" : "_ZTIP6Struct",
    "name" : "Struct *",
-   "referenced_type" : "_ZTI6Struct#ODR:",
+   "referenced_type" : "_ZTI6Struct#ODR:/def2.h.sdump",
    "self_type" : "_ZTIP6Struct#ODR:",
    "size" : 8,
    "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h"
@@ -123,7 +123,7 @@
    "is_const" : true,
    "linker_set_key" : "_ZTIK6Struct",
    "name" : "const Struct",
-   "referenced_type" : "_ZTI6Struct#ODR:",
+   "referenced_type" : "_ZTI6Struct#ODR:/def2.h.sdump",
    "self_type" : "_ZTIK6Struct#ODR:",
    "size" : 8,
    "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h"
@@ -168,8 +168,8 @@
    ],
    "linker_set_key" : "_ZTI6Struct",
    "name" : "Struct",
-   "referenced_type" : "_ZTI6Struct#ODR:",
-   "self_type" : "_ZTI6Struct#ODR:",
+   "referenced_type" : "_ZTI6Struct#ODR:/def2.h.sdump",
+   "self_type" : "_ZTI6Struct#ODR:/def2.h.sdump",
    "size" : 8,
    "source_file" : "/development/vndk/tools/header-checker/tests/integration/merge_multi_definitions/include/def2.h"
   }