libvintf: use toFQNameString

Centralize the hard-coded "@" "::" "/".

Test: builds
Test: libvintf_test
Test: vintf_object_test
Change-Id: I1942441865585b11801e7d9b38c0c57b5c5ebe17
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index 7bdc3a9..deb1fa1 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -16,13 +16,12 @@
 
 #include "CompatibilityMatrix.h"
 
+#include <iostream>
 #include <utility>
 
 #include "parse_string.h"
-#include "utils.h"
-
-#include <iostream>
 #include "parse_xml.h"
+#include "utils.h"
 
 namespace android {
 namespace vintf {
@@ -129,7 +128,7 @@
 
             if (!existingHal->optional && !existingHal->containsInstances(halToAdd)) {
                 if (error != nullptr) {
-                    *error = "HAL " + name + "@" + to_string(vr.minVer()) + " is a required " +
+                    *error = "HAL " + toFQNameString(name, vr.minVer()) + " is a required " +
                              "HAL, but fully qualified instance names don't match (at FCM "
                              "Version " +
                              std::to_string(level()) + " and " + std::to_string(other->level()) +
diff --git a/HalManifest.cpp b/HalManifest.cpp
index 540edee..6f05cab 100644
--- a/HalManifest.cpp
+++ b/HalManifest.cpp
@@ -125,7 +125,7 @@
     std::set<std::string> names{};
     for (const auto &hal : getHals()) {
         for (const auto &version : hal.versions) {
-            names.insert(hal.name + "@" + to_string(version));
+            names.insert(toFQNameString(hal.name, version));
         }
     }
     return names;
@@ -149,21 +149,22 @@
         }
         auto it = hal->interfaces.find(interfaceName);
         if (it == hal->interfaces.end()) {
-            LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot find interface '"
-                      << interfaceName << "' in " << package << "@" << to_string(v);
+            LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType)
+                       << "): Cannot find interface '" << interfaceName << "' in "
+                       << toFQNameString(package, v);
             continue;
         }
         const auto &instances = it->second.instances;
         if (instances.find(instanceName) == instances.end()) {
-            LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot find instance '"
-                      << instanceName << "' in "
-                      << package << "@" << to_string(v) << "::" << interfaceName;
+            LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType)
+                       << "): Cannot find instance '" << instanceName << "' in "
+                       << toFQNameString(package, v, interfaceName);
             continue;
         }
         return hal->transportArch.transport;
     }
     LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot get transport for "
-                 << package << "@" << v << "::" << interfaceName << "/" << instanceName;
+               << toFQNameString(package, v, interfaceName, instanceName);
     return Transport::EMPTY;
 
 }
@@ -270,7 +271,7 @@
         for (const auto& ifacePair : pair.second) {
             const auto& interface = ifacePair.first;
             for (const auto& instance : ifacePair.second) {
-                lines.push_back("@" + to_string(version) + "::" + interface + "/" + instance);
+                lines.push_back(toFQNameString(version, interface, instance));
             }
         }
     }
diff --git a/VintfObject.cpp b/VintfObject.cpp
index e89ca56..c66011b 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -597,7 +597,7 @@
             targetMatrix.getHalWithMajorVersion(package, version.majorVer);
         if (targetMatrixHal == nullptr || targetMatrixRange == nullptr) {
             if (error) {
-                *error = package + "@" + to_string(servedVersion) +
+                *error = toFQNameString(package, servedVersion) +
                          "is deprecated in compatibility matrix at FCM Version " +
                          to_string(targetMatrix.level()) + "; it should not be served.";
             }
@@ -607,9 +607,9 @@
         const auto& targetMatrixInstances = targetMatrixHal->getInstances(interface);
         if (targetMatrixInstances.find(instance) == targetMatrixInstances.end()) {
             if (error) {
-                *error += package + "@" + to_string(servedVersion) + "::" + interface + "/" +
-                          instance + " is deprecated at FCM version " +
-                          to_string(targetMatrix.level()) + "; it should be not be served.\n";
+                *error += toFQNameString(package, servedVersion, interface, instance) +
+                          " is deprecated at FCM version " + to_string(targetMatrix.level()) +
+                          "; it should be not be served.\n";
             }
             return true;
         }
@@ -621,7 +621,7 @@
 
         if (!targetVersionServed) {
             if (error) {
-                *error += package + "@" + to_string(servedVersion) + " is deprecated; " +
+                *error += toFQNameString(package, servedVersion) + " is deprecated; " +
                           "require at least " + to_string(targetMatrixRange->minVer()) + "\n";
             }
             return true;
diff --git a/include/vintf/parse_string.h b/include/vintf/parse_string.h
index 7ae45f8..8820639 100644
--- a/include/vintf/parse_string.h
+++ b/include/vintf/parse_string.h
@@ -105,6 +105,20 @@
 
 std::vector<std::string> expandInstances(const MatrixHal& req);
 
+std::string toFQNameString(const std::string& package, const Version& version,
+                           const std::string& intf = "", const std::string& instance = "");
+
+std::string toFQNameString(const Version& version, const std::string& intf,
+                           const std::string& instance);
+
+// android.hardware.foo@1.0-1::IFoo/default.
+// Note that the format is extended to support a range of versions.
+std::string toFQNameString(const std::string& package, const VersionRange& range,
+                           const std::string& interface, const std::string& instance);
+
+std::string toFQNameString(const VersionRange& range, const std::string& interface,
+                           const std::string& instance);
+
 } // namespace vintf
 } // namespace android
 
diff --git a/main.cpp b/main.cpp
index 111b797..c4119c9 100644
--- a/main.cpp
+++ b/main.cpp
@@ -151,15 +151,6 @@
     }
 }
 
-// android.hardware.foo@1.0-1::IFoo/default.
-// Note that the format is extended to support a range of versions.
-std::string fqInstanceName(const std::string& package, const VersionRange& range,
-                           const std::string& interface, const std::string& instance) {
-    std::stringstream ss;
-    ss << package << "@" << range << "::" << interface << "/" << instance;
-    return ss.str();
-}
-
 struct TableRow {
     // Whether the HAL version is in device manifest, framework manifest, device compatibility
     // matrix, framework compatibility matrix, respectively.
@@ -199,7 +190,7 @@
     if (manifest == nullptr) return;
     manifest->forEachInstance([&](const auto& package, const auto& version, const auto& interface,
                                   const auto& instance, bool* /* stop */) {
-        std::string key = fqInstanceName(package, VersionRange{version.majorVer, version.minorVer},
+        std::string key = toFQNameString(package, VersionRange{version.majorVer, version.minorVer},
                                          interface, instance);
         mutate(&(*table)[key]);
     });
@@ -211,7 +202,7 @@
                                 const auto& instance, bool optional, bool* /* stop */) {
         bool missed = false;
         for (auto minorVer = range.minMinor; minorVer <= range.maxMinor; ++minorVer) {
-            std::string key = fqInstanceName(package, VersionRange{range.majorVer, minorVer},
+            std::string key = toFQNameString(package, VersionRange{range.majorVer, minorVer},
                                              interface, instance);
             auto it = table->find(key);
             if (it == table->end()) {
@@ -222,7 +213,7 @@
             }
         }
         if (missed) {
-            std::string key = fqInstanceName(package, range, interface, instance);
+            std::string key = toFQNameString(package, range, interface, instance);
             mutate(&(*table)[key]);
         }
     });
diff --git a/parse_string.cpp b/parse_string.cpp
index beca23b..2aa3c1b 100644
--- a/parse_string.cpp
+++ b/parse_string.cpp
@@ -401,7 +401,7 @@
     for (const auto& interface : iterateValues(req.interfaces)) {
         for (const auto& instance : interface.instances) {
             if (!first) s += " AND ";
-            s += "@" + to_string(vr) + "::" + interface.name + "/" + instance;
+            s += toFQNameString(vr, interface.name, instance);
             first = false;
         }
     }
@@ -470,5 +470,40 @@
     return oss.str();
 }
 
+std::string toFQNameString(const std::string& package, const std::string& version,
+                           const std::string& interface, const std::string& instance) {
+    std::stringstream ss;
+    ss << package << "@" << version;
+    if (!interface.empty()) {
+        ss << "::" << interface;
+        if (!instance.empty()) {
+            ss << "/" << instance;
+        }
+    }
+    return ss.str();
+}
+
+std::string toFQNameString(const std::string& package, const Version& version,
+                           const std::string& interface, const std::string& instance) {
+    return toFQNameString(package, to_string(version), interface, instance);
+}
+
+std::string toFQNameString(const Version& version, const std::string& interface,
+                           const std::string& instance) {
+    return toFQNameString("", version, interface, instance);
+}
+
+// android.hardware.foo@1.0-1::IFoo/default.
+// Note that the format is extended to support a range of versions.
+std::string toFQNameString(const std::string& package, const VersionRange& range,
+                           const std::string& interface, const std::string& instance) {
+    return toFQNameString(package, to_string(range), interface, instance);
+}
+
+std::string toFQNameString(const VersionRange& range, const std::string& interface,
+                           const std::string& instance) {
+    return toFQNameString("", range, interface, instance);
+}
+
 } // namespace vintf
 } // namespace android