Extend hidl-gen to support generate vts file.
b/30762234
TODO: add regression test.
Change-Id: I1c31fd9a85805cd450ea03cc0ccc750a756d1009
diff --git a/generateVts.cpp b/generateVts.cpp
new file mode 100644
index 0000000..5c90529
--- /dev/null
+++ b/generateVts.cpp
@@ -0,0 +1,150 @@
+#include "AST.h"
+
+#include "Annotation.h"
+#include "Coordinator.h"
+#include "Formatter.h"
+#include "Interface.h"
+#include "Method.h"
+#include "Scope.h"
+
+#include <android-base/logging.h>
+#include <string>
+#include <vector>
+
+namespace android {
+
+// Remove the double quotas in a string.
+static std::string removeQuotes(const std::string in) {
+ std::string out{in};
+ return out.substr(1, out.size() - 2);
+}
+
+status_t AST::emitVtsTypeDeclarations(
+ Formatter &out,
+ Vector<Type*> types) const {
+ for (const auto& type : types) {
+ out << "attribute: {\n";
+ out.indent();
+ status_t status = type->emitVtsTypeDeclarations(out);
+ if (status != OK) {
+ return status;
+ }
+ out.unindent();
+ out << "}\n\n";
+ }
+ return OK;
+}
+
+status_t AST::generateVts(const std::string &outputPath) const {
+ std::string path = outputPath;
+ path.append(mCoordinator->convertPackageRootToPath(mPackage));
+ path.append(mCoordinator->getPackagePath(mPackage, true /* relative */));
+
+ std::string ifaceName;
+ std::string baseName;
+
+ bool isInterface = true;
+ if (!AST::isInterface(&ifaceName)) {
+ baseName = "types";
+ isInterface = false;
+ } else {
+ baseName = ifaceName.substr(1); // cut off the leading 'I'.
+ }
+
+ path.append(baseName);
+ path.append(".vts");
+
+ CHECK(Coordinator::MakeParentHierarchy(path));
+ FILE *file = fopen(path.c_str(), "w");
+
+ if (file == NULL) {
+ return -errno;
+ }
+
+ Formatter out(file);
+
+ out << "component_class: HAL_HIDL\n";
+
+ // Get the component_type for interface from annotation.
+ if (isInterface) {
+ const Interface *iface = mRootScope->getInterface();
+ Annotation *annotation = iface->annotations().valueFor("hal_type");
+ if (annotation != NULL) {
+ std::vector<std::string> * values = annotation->params().valueFor(
+ "type");
+ if (values != NULL) {
+ out << "component_type: "
+ << removeQuotes(values->at(0))
+ << "\n";
+ }
+ }
+ }
+
+ out << "component_type_version: " << mPackage.version().substr(1) << "\n";
+ out << "component_name: \""
+ << (isInterface ? ifaceName : "types")
+ << "\"\n\n";
+
+ out << "package: \"" << mPackage.package() << "\"\n\n";
+
+ for (const auto &item : mImportedNames) {
+ out << "import: \"" << item.string() << "\"\n";
+ }
+
+ out << "\n";
+
+ if (isInterface) {
+ const Interface *iface = mRootScope->getInterface();
+ out << "interface: {\n";
+ out.indent();
+
+ status_t status = emitVtsTypeDeclarations(out, iface->getSubTypes());
+ if (status != OK) {
+ return status;
+ }
+
+ for (const auto &method : iface->methods()) {
+ out << "api: {\n";
+ out.indent();
+ out << "name: \"" << method->name() << "\"\n";
+ for (const auto &result : method->results()) {
+ out << "return_type_hidl: {\n";
+ out.indent();
+ status_t status = result->type().emitVtsArgumentType(out);
+ if (status != OK) {
+ return status;
+ }
+ out.unindent();
+ out << "}\n";
+ }
+ for (const auto &arg : method->args()) {
+ out << "arg: {\n";
+ out.indent();
+ status_t status = arg->type().emitVtsArgumentType(out);
+ if (status != OK) {
+ return status;
+ }
+ out.unindent();
+ out << "}\n";
+ }
+ out.unindent();
+ out << "}\n\n";
+ }
+
+ out.unindent();
+ out << "}\n";
+ } else {
+ status_t status = emitVtsTypeDeclarations(out,
+ mRootScope->getSubTypes());
+ if (status != OK) {
+ return status;
+ }
+ }
+ return OK;
+}
+
+} // namespace android
+
+
+
+