summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chromeos-dbus-bindings/adaptor_generator.cc464
-rw-r--r--chromeos-dbus-bindings/adaptor_generator.h32
-rw-r--r--chromeos-dbus-bindings/adaptor_generator_unittest.cc217
-rw-r--r--chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc20
-rw-r--r--chromeos-dbus-bindings/header_generator.cc16
-rw-r--r--chromeos-dbus-bindings/header_generator.h14
-rw-r--r--chromeos-dbus-bindings/interface.h8
-rw-r--r--chromeos-dbus-bindings/method_name_generator.cc34
-rw-r--r--chromeos-dbus-bindings/method_name_generator.h7
-rw-r--r--chromeos-dbus-bindings/method_name_generator_unittest.cc17
-rw-r--r--chromeos-dbus-bindings/proxy_generator.cc176
-rw-r--r--chromeos-dbus-bindings/proxy_generator.h8
-rw-r--r--chromeos-dbus-bindings/proxy_generator_unittest.cc79
-rw-r--r--chromeos-dbus-bindings/xml_interface_parser.cc114
-rw-r--r--chromeos-dbus-bindings/xml_interface_parser.h20
-rw-r--r--chromeos-dbus-bindings/xml_interface_parser_unittest.cc47
16 files changed, 795 insertions, 478 deletions
diff --git a/chromeos-dbus-bindings/adaptor_generator.cc b/chromeos-dbus-bindings/adaptor_generator.cc
index 990976a..5f71816 100644
--- a/chromeos-dbus-bindings/adaptor_generator.cc
+++ b/chromeos-dbus-bindings/adaptor_generator.cc
@@ -9,6 +9,7 @@
#include <base/logging.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
+#include <chromeos/strings/string_utils.h>
#include "chromeos-dbus-bindings/dbus_signature.h"
#include "chromeos-dbus-bindings/indented_text.h"
@@ -21,15 +22,20 @@ using std::vector;
namespace chromeos_dbus_bindings {
// static
-bool AdaptorGenerator::GenerateAdaptor(
- const Interface& interface,
+bool AdaptorGenerator::GenerateAdaptors(
+ const std::vector<Interface>& interfaces,
const base::FilePath& output_file) {
IndentedText text;
- text.AddLine(StringPrintf("// Automatic generation of interface for %s",
- interface.name.c_str()));
- string header_guard = GenerateHeaderGuard(output_file, interface.name);
+ CHECK(!interfaces.empty()) << "At least one interface must be provided";
+
+ text.AddLine("// Automatic generation of D-Bus interfaces:");
+ for (const auto& interface : interfaces) {
+ text.AddLine(StringPrintf("// - %s", interface.name.c_str()));
+ }
+ string header_guard = GenerateHeaderGuard(output_file, "");
text.AddLine(StringPrintf("#ifndef %s", header_guard.c_str()));
text.AddLine(StringPrintf("#define %s", header_guard.c_str()));
+ text.AddLine("#include <memory>");
text.AddLine("#include <string>");
text.AddLine("#include <vector>");
text.AddBlankLine();
@@ -39,209 +45,282 @@ bool AdaptorGenerator::GenerateAdaptor(
text.AddLine("#include <chromeos/dbus/dbus_object.h>");
text.AddLine("#include <chromeos/dbus/exported_object_manager.h>");
text.AddLine("#include <chromeos/variant_dictionary.h>");
- text.AddBlankLine();
-
- vector<string> namespaces;
- string class_name;
- CHECK(GetNamespacesAndClassName(interface.name, &namespaces, &class_name));
- for (const auto& space : namespaces) {
- text.AddLine(StringPrintf("namespace %s {", space.c_str()));
- }
- text.AddBlankLine();
- string adaptor_name = StringPrintf("%sAdaptor", class_name.c_str());
- text.AddLine(StringPrintf("class %s {", adaptor_name.c_str()));
- text.AddLineWithOffset("public:", kScopeOffset);
+ for (const auto& interface : interfaces)
+ GenerateInterfaceAdaptor(interface, &text);
- text.PushOffset(kBlockOffset);
- AddMethodInterface(interface, &text);
- AddConstructor(interface, adaptor_name, &text);
- AddSendSignalMethods(interface, &text);
- text.AddLine(StringPrintf("virtual ~%s() = default;", adaptor_name.c_str()));
- text.AddLine("virtual void OnRegisterComplete(bool success) {}");
+ text.AddLine(StringPrintf("#endif // %s", header_guard.c_str()));
- text.AddBlankLine();
- AddPropertyMethods(interface, &text);
- text.PopOffset();
-
- text.AddLineWithOffset("protected:", kScopeOffset);
- text.PushOffset(kBlockOffset);
- text.AddLine("chromeos::dbus_utils::DBusInterface* dbus_interface() {");
- text.PushOffset(kBlockOffset);
- text.AddLine("return dbus_interface_;");
- text.PopOffset();
- text.AddLine("}");
- text.PopOffset();
+ return WriteTextToFile(output_file, text);
+}
- text.AddBlankLine();
- text.AddLineWithOffset("private:", kScopeOffset);
-
- text.PushOffset(kBlockOffset);
- text.AddLine("// Exported properties");
- AddPropertyDataMembers(interface, &text);
- text.AddLine("MethodInterface* interface_; // Owned by caller.");
- text.AddLine("chromeos::dbus_utils::DBusObject dbus_object_;");
- AddSignalDataMembers(interface, &text);
- text.AddLine("// Owned by |dbus_object_|.");
- text.AddLine("chromeos::dbus_utils::DBusInterface* dbus_interface_;");
- text.AddLine(StringPrintf(
- "DISALLOW_COPY_AND_ASSIGN(%s);", adaptor_name.c_str()));
- text.PopOffset();
-
- text.AddLine("};");
- text.AddBlankLine();
+// static
+void AdaptorGenerator::GenerateInterfaceAdaptor(
+ const Interface& interface,
+ IndentedText *text) {
+ vector<string> namespaces;
+ string itf_name;
+ CHECK(GetNamespacesAndClassName(interface.name, &namespaces, &itf_name));
+ string class_name = itf_name + "Adaptor";
+ string full_itf_name = GetFullClassName(namespaces, itf_name);
+ itf_name += "Interface";
+
+ text->AddBlankLine();
+ for (const auto& ns : namespaces) {
+ text->AddLine(StringPrintf("namespace %s {", ns.c_str()));
+ }
+ text->AddBlankLine();
+ text->AddLine(StringPrintf("// Interface definition for %s.",
+ full_itf_name.c_str()));
+ text->AddLine(StringPrintf("class %s {", itf_name.c_str()));
+ text->AddLineWithOffset("public:", kScopeOffset);
+ text->PushOffset(kBlockOffset);
+ text->AddLine(StringPrintf("virtual ~%s() = default;", itf_name.c_str()));
+ AddInterfaceMethods(interface, text);
+ text->PopOffset();
+ text->AddLine("};");
+
+ text->AddBlankLine();
+ text->AddLine(StringPrintf("// Interface adaptor for %s.",
+ full_itf_name.c_str()));
+ text->AddLine(StringPrintf("class %s {", class_name.c_str()));
+ text->AddLineWithOffset("public:", kScopeOffset);
+ text->PushOffset(kBlockOffset);
+ AddConstructor(class_name, itf_name, text);
+ AddRegisterWithDBusObject(itf_name, interface, text);
+ AddSendSignalMethods(interface, text);
+ AddPropertyMethodImplementation(interface, text);
+ text->PopOffset();
+
+ text->AddBlankLine();
+ text->AddLineWithOffset("private:", kScopeOffset);
+ text->PushOffset(kBlockOffset);
+ AddSignalDataMembers(interface, text);
+ AddPropertyDataMembers(interface, text);
+
+ text->AddBlankLine();
+ text->AddLine(StringPrintf(
+ "%s* interface_; // Owned by container of this adapter.",
+ itf_name.c_str()));
+
+ text->AddBlankLine();
+ text->AddLine(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);",
+ class_name.c_str()));
+ text->PopOffset();
+ text->AddLine("};");
+
+ text->AddBlankLine();
for (auto it = namespaces.rbegin(); it != namespaces.rend(); ++it) {
- text.AddLine(StringPrintf("} // namespace %s", it->c_str()));
+ text->AddLine(StringPrintf("} // namespace %s", it->c_str()));
}
- text.AddLine(StringPrintf("#endif // %s", header_guard.c_str()));
-
- return WriteTextToFile(output_file, text);
}
// static
-void AdaptorGenerator::AddConstructor(const Interface& interface,
- const string& class_name,
+void AdaptorGenerator::AddConstructor(const string& class_name,
+ const string& itf_name,
IndentedText *text) {
- IndentedText block;
- block.AddLine(StringPrintf("%s(", class_name.c_str()));
- block.PushOffset(kLineContinuationOffset);
- block.AddLine("chromeos::dbus_utils::ExportedObjectManager* object_manager,");
- block.AddLine("const scoped_refptr<dbus::Bus>& bus,");
- block.AddLine("const std::string& object_path,");
- block.AddLine("MethodInterface* interface) // Owned by caller.");
- block.AddLine(": interface_(interface),");
- block.PushOffset(kBlockOffset);
- block.AddLine("dbus_object_(");
- block.PushOffset(kLineContinuationOffset);
- block.AddLine("object_manager,");
- block.AddLine("bus,");
- block.AddLine("dbus::ObjectPath(object_path)),");
- block.PopOffset();
-
- // Signal constructors.
- for (const auto& signal : interface.signals) {
- block.AddLine(StringPrintf("signal_%s_(", signal.name.c_str()));
- block.PushOffset(kLineContinuationOffset);
- block.AddLine("&dbus_object_,");
- block.AddLine(StringPrintf("\"%s\",", interface.name.c_str()));
- block.AddLine(StringPrintf("\"%s\"),", signal.name.c_str()));
- block.PopOffset();
- }
+ text->AddLine(StringPrintf("%s(%s* interface) : interface_(interface) {}",
+ class_name.c_str(), itf_name.c_str()));
+}
+
+// static
+void AdaptorGenerator::AddRegisterWithDBusObject(
+ const std::string& itf_name,
+ const Interface& interface,
+ IndentedText *text) {
+ text->AddBlankLine();
+ text->AddLine(
+ "void RegisterWithDBusObject(chromeos::dbus_utils::DBusObject* object) {");
+ text->PushOffset(kBlockOffset);
+ text->AddLine("chromeos::dbus_utils::DBusInterface* itf =");
+ text->AddLineWithOffset(
+ StringPrintf("object->AddOrGetInterface(\"%s\");",
+ interface.name.c_str()), kLineContinuationOffset);
+ RegisterInterface(itf_name, interface, text);
+ text->PopOffset();
+ text->AddLine("}");
+}
- block.AddLine("dbus_interface_(");
- block.PushOffset(kLineContinuationOffset);
- block.AddLine(StringPrintf(
- "dbus_object_.AddOrGetInterface(\"%s\")) {", interface.name.c_str()));
- block.PopOffset();
- block.PopOffset();
- block.PopOffset();
- block.PushOffset(kBlockOffset);
+// static
+void AdaptorGenerator::RegisterInterface(const string& itf_name,
+ const Interface& interface,
+ IndentedText *text) {
+ if (!interface.methods.empty())
+ text->AddBlankLine();
for (const auto& method : interface.methods) {
- if (method.output_arguments.size() > 1) {
- // TODO(pstew): Accept multiple output arguments. crbug.com/419271
- continue;
+ string add_handler_name;
+ switch (method.kind) {
+ case Interface::Method::Kind::kSimple:
+ add_handler_name = "AddSimpleMethodHandler";
+ break;
+ case Interface::Method::Kind::kNormal:
+ add_handler_name = "AddSimpleMethodHandlerWithError";
+ break;
+ case Interface::Method::Kind::kAsync:
+ add_handler_name = "AddMethodHandler";
+ break;
+ case Interface::Method::Kind::kRaw:
+ add_handler_name = "AddRawMethodHandler";
+ break;
}
- block.AddLine("dbus_interface_->AddMethodHandler(");
- block.PushOffset(kLineContinuationOffset);
- block.AddLine(StringPrintf("\"%s\",", method.name.c_str()));
- block.AddLine("base::Unretained(interface_),");
- block.AddLine(StringPrintf("&MethodInterface::%s);", method.name.c_str()));
- block.PopOffset();
+
+ text->AddLine(StringPrintf("itf->%s(", add_handler_name.c_str()));
+ text->PushOffset(kLineContinuationOffset);
+ text->AddLine(StringPrintf("\"%s\",", method.name.c_str()));
+ text->AddLine("base::Unretained(interface_),");
+ text->AddLine(StringPrintf("&%s::%s);", itf_name.c_str(),
+ method.name.c_str()));
+ text->PopOffset();
+ }
+
+ // Register signals.
+ if (!interface.signals.empty())
+ text->AddBlankLine();
+ for (const auto& signal : interface.signals) {
+ string signal_var_name = StringPrintf("signal_%s_", signal.name.c_str());
+ string signal_type_name = StringPrintf("Signal%sType", signal.name.c_str());
+ text->AddLine(StringPrintf("%s = itf->RegisterSignalOfType<%s>(\"%s\");",
+ signal_var_name.c_str(),
+ signal_type_name.c_str(),
+ signal.name.c_str()));
}
+
// Register exported properties.
+ if (!interface.properties.empty())
+ text->AddBlankLine();
for (const auto& property : interface.properties) {
string variable_name = GetPropertyVariableName(property.name);
- block.AddLine("dbus_interface_->AddProperty(");
- block.PushOffset(kLineContinuationOffset);
- block.AddLine(StringPrintf("\"%s\",", property.name.c_str()));
- block.AddLine(StringPrintf("&%s_);", variable_name.c_str()));
- block.PopOffset();
+ text->AddLine(StringPrintf("itf->AddProperty(\"%s\", &%s_);",
+ property.name.c_str(), variable_name.c_str()));
}
- block.AddLine("dbus_object_.RegisterAsync(base::Bind(");
- block.AddLineWithOffset(
- StringPrintf("&%s::OnRegisterComplete, base::Unretained(this)));",
- class_name.c_str()),
- kLineContinuationOffset);
- block.PopOffset();
- block.AddLine("}");
- text->AddBlock(block);
}
// static
-void AdaptorGenerator::AddMethodInterface(const Interface& interface,
- IndentedText *text) {
+void AdaptorGenerator::AddInterfaceMethods(const Interface& interface,
+ IndentedText *text) {
IndentedText block;
- block.AddLine("class MethodInterface {");
- block.AddLineWithOffset("public:", kScopeOffset);
DbusSignature signature;
- block.PushOffset(kBlockOffset);
+ if (!interface.methods.empty())
+ block.AddBlankLine();
+
for (const auto& method : interface.methods) {
- string return_type("void");
- if (!method.output_arguments.empty()) {
- if (method.output_arguments.size() > 1) {
- // TODO(pstew): Accept multiple output arguments. crbug.com://419271
- LOG(WARNING) << "Method " << method.name << " has "
- << method.output_arguments.size()
- << " output arguments which is unsupported.";
- continue;
- }
- CHECK(signature.Parse(method.output_arguments[0].type, &return_type));
+ string const_method;
+ if (method.is_const)
+ const_method = " const";
+
+ string return_type = "void";
+ vector<string> method_params;
+ auto input_arguments_copy = method.input_arguments;
+ auto output_arguments_copy = method.output_arguments;
+ switch (method.kind) {
+ case Interface::Method::Kind::kSimple:
+ if (output_arguments_copy.size() == 1) {
+ CHECK(signature.Parse(output_arguments_copy[0].type, &return_type));
+ output_arguments_copy.clear();
+ }
+ break;
+ case Interface::Method::Kind::kNormal:
+ method_params.push_back("chromeos::ErrorPtr* error");
+ return_type = "bool";
+ break;
+ case Interface::Method::Kind::kAsync:
+ method_params.push_back(
+ "scoped_ptr<chromeos::dbus_utils::DBusMethodResponse> response");
+ // Async methods don't return values directly.
+ output_arguments_copy.clear();
+ break;
+ case Interface::Method::Kind::kRaw:
+ method_params.push_back("dbus::MethodCall* method_call");
+ method_params.push_back("chromeos::dbus_utils::ResponseSender sender");
+ // Raw methods don't take static parameters or return values directly.
+ input_arguments_copy.clear();
+ output_arguments_copy.clear();
+ break;
}
- block.AddLine(StringPrintf("virtual %s %s(",
- return_type.c_str(), method.name.c_str()));
- block.PushOffset(kLineContinuationOffset);
- string last_argument = "chromeos::ErrorPtr* /* error */";
- for (const auto& argument : method.input_arguments) {
- block.AddLine(last_argument + ",");
- CHECK(signature.Parse(argument.type, &last_argument));
- if (!IsIntegralType(last_argument)) {
- last_argument = StringPrintf("const %s&", last_argument.c_str());
- }
- if (!argument.name.empty()) {
- last_argument.append(StringPrintf(" /* %s */", argument.name.c_str()));
+ string method_start = StringPrintf("virtual %s %s(",
+ return_type.c_str(),
+ method.name.c_str());
+ string method_end = StringPrintf(")%s = 0;", const_method.c_str());
+ int index = 0;
+ for (const auto& argument : input_arguments_copy) {
+ string param_type;
+ CHECK(signature.Parse(argument.type, &param_type));
+ if (!IsIntegralType(param_type)) {
+ param_type = StringPrintf("const %s&", param_type.c_str());
}
+ string param_name = GetArgName("in", argument.name, ++index);
+ method_params.push_back(param_type + ' ' + param_name);
+ }
+
+ for (const auto& argument : output_arguments_copy) {
+ string param_type;
+ CHECK(signature.Parse(argument.type, &param_type));
+ string param_name = GetArgName("out", argument.name, ++index);
+ method_params.push_back(param_type + "* " + param_name);
}
- block.AddLine(last_argument + ") = 0;");
- block.PopOffset();
- }
- block.PopOffset();
- block.AddLine("};");
+ if (method_params.empty()) {
+ block.AddLine(method_start + method_end);
+ } else {
+ block.AddLine(method_start);
+ block.PushOffset(kLineContinuationOffset);
+ for (size_t i = 0; i < method_params.size() - 1; i++)
+ block.AddLine(method_params[i] + ',');
+ block.AddLine(method_params.back() + method_end);
+ block.PopOffset();
+ }
+ }
text->AddBlock(block);
}
// static
-void AdaptorGenerator::AddSendSignalMethods(const Interface& interface,
- IndentedText *text) {
+void AdaptorGenerator::AddSendSignalMethods(
+ const Interface& interface,
+ IndentedText *text) {
IndentedText block;
DbusSignature signature;
+ if (!interface.signals.empty())
+ block.AddBlankLine();
+
for (const auto& signal : interface.signals) {
- block.AddLine(StringPrintf("void Send%sSignal(", signal.name.c_str()));
- block.PushOffset(kLineContinuationOffset);
- string last_argument;
- int unnamed_args = 0;
- string call_arguments; // The arguments to pass to the Send() call.
+ string method_start = StringPrintf("void Send%sSignal(",
+ signal.name.c_str());
+ string method_end = ") {";
+
+ int index = 0;
+ vector<string> method_params;
+ vector<string> param_names;
for (const auto& argument : signal.arguments) {
- if (!last_argument.empty())
- block.AddLine(last_argument + ",");
- CHECK(signature.Parse(argument.type, &last_argument));
- if (!IsIntegralType(last_argument))
- last_argument = StringPrintf("const %s&", last_argument.c_str());
- string argument_name = argument.name;
- if (argument.name.empty())
- argument_name = StringPrintf("_arg_%d", ++unnamed_args);
- last_argument.append(" " + argument_name);
- if (!call_arguments.empty())
- call_arguments.append(", ");
- call_arguments.append(argument_name);
+ string param_type;
+ CHECK(signature.Parse(argument.type, &param_type));
+ if (!IsIntegralType(param_type)) {
+ param_type = StringPrintf("const %s&", param_type.c_str());
+ }
+ string param_name = GetArgName("in", argument.name, ++index);
+ param_names.push_back(param_name);
+ method_params.push_back(param_type + ' ' + param_name);
}
- block.AddLine(last_argument + ") {");
- block.PopOffset();
+
+ if (method_params.empty()) {
+ block.AddLine(method_start + method_end);
+ } else {
+ block.AddLine(method_start);
+ block.PushOffset(kLineContinuationOffset);
+ for (size_t i = 0; i < method_params.size() - 1; i++)
+ block.AddLine(method_params[i] + ',');
+ block.AddLine(method_params.back() + method_end);
+ block.PopOffset();
+ }
+
+ string args = chromeos::string_utils::Join(", ", param_names);
block.PushOffset(kBlockOffset);
- block.AddLine(StringPrintf(
- "signal_%s_.Send(%s);", signal.name.c_str(), call_arguments.c_str()));
+ block.AddLine(StringPrintf("auto signal = signal_%s_.lock();",
+ signal.name.c_str()));
+ block.AddLine("if (signal)");
+ block.AddLineWithOffset(StringPrintf("signal->Send(%s);", args.c_str()),
+ kBlockOffset);
block.PopOffset();
block.AddLine("}");
}
@@ -255,30 +334,46 @@ void AdaptorGenerator::AddSignalDataMembers(const Interface& interface,
DbusSignature signature;
for (const auto& signal : interface.signals) {
- block.AddLine("chromeos::dbus_utils::DBusSignal<");
- block.PushOffset(kLineContinuationOffset);
- string last_argument;
+ string signal_type_name = StringPrintf("Signal%sType", signal.name.c_str());
+ string signal_type_alias_begin =
+ StringPrintf("using %s = chromeos::dbus_utils::DBusSignal<",
+ signal_type_name.c_str());
+ string signal_type_alias_end = ">;";
+ vector<string> params;
for (const auto& argument : signal.arguments) {
- if (!last_argument.empty())
- block.AddLine(last_argument + ",");
- CHECK(signature.Parse(argument.type, &last_argument));
+ string param;
+ CHECK(signature.Parse(argument.type, &param));
if (!argument.name.empty())
- last_argument.append(StringPrintf(" /* %s */", argument.name.c_str()));
+ base::StringAppendF(&param, " /*%s*/", argument.name.c_str());
+ params.push_back(param);
}
- block.AddLine(StringPrintf(
- "%s> signal_%s_;", last_argument.c_str(), signal.name.c_str()));
- block.PopOffset();
+ if (params.empty()) {
+ block.AddLine(signal_type_alias_begin + signal_type_alias_end);
+ } else {
+ block.AddLine(signal_type_alias_begin);
+ block.PushOffset(kLineContinuationOffset);
+ for (size_t i = 0; i < params.size() - 1; i++)
+ block.AddLine(params[i] + ',');
+ block.AddLine(params.back() + signal_type_alias_end);
+ block.PopOffset();
+ }
+ block.AddLine(
+ StringPrintf("std::weak_ptr<%s> signal_%s_;",
+ signal_type_name.c_str(), signal.name.c_str()));
+ block.AddBlankLine();
}
text->AddBlock(block);
}
// static
-void AdaptorGenerator::AddPropertyMethods(const Interface& interface,
- IndentedText *text) {
+void AdaptorGenerator::AddPropertyMethodImplementation(
+ const Interface& interface,
+ IndentedText *text) {
IndentedText block;
DbusSignature signature;
for (const auto& property : interface.properties) {
+ block.AddBlankLine();
string type;
CHECK(signature.Parse(property.type, &type));
string variable_name = GetPropertyVariableName(property.name);
@@ -295,19 +390,18 @@ void AdaptorGenerator::AddPropertyMethods(const Interface& interface,
block.AddLine("}");
// Setter method.
- block.AddLine(StringPrintf("void Set%s(", property.name.c_str()));
- block.PushOffset(kLineContinuationOffset);
- block.AddLine(StringPrintf("const %s& %s) {",
+ if (!IsIntegralType(type))
+ type = StringPrintf("const %s&", type.c_str());
+ block.AddLine(StringPrintf("void Set%s(%s %s) {",
+ property.name.c_str(),
type.c_str(),
variable_name.c_str()));
- block.PopOffset();
block.PushOffset(kBlockOffset);
block.AddLine(StringPrintf("%s_.SetValue(%s);",
variable_name.c_str(),
variable_name.c_str()));
block.PopOffset();
block.AddLine("}");
- block.AddBlankLine();
}
text->AddBlock(block);
}
diff --git a/chromeos-dbus-bindings/adaptor_generator.h b/chromeos-dbus-bindings/adaptor_generator.h
index 84adec7..87e1b26 100644
--- a/chromeos-dbus-bindings/adaptor_generator.h
+++ b/chromeos-dbus-bindings/adaptor_generator.h
@@ -26,20 +26,34 @@ struct Interface;
class AdaptorGenerator : public HeaderGenerator {
public:
- static bool GenerateAdaptor(const Interface& interface,
- const base::FilePath& output_file);
+ static bool GenerateAdaptors(const std::vector<Interface>& interfaces,
+ const base::FilePath& output_file);
private:
friend class AdaptorGeneratorTest;
+ // Generates one interface adaptor.
+ static void GenerateInterfaceAdaptor(const Interface& interface,
+ IndentedText *text);
+
+ // Generates the method prototypes for an interface declaration.
+ static void AddInterfaceMethods(const Interface& interface,
+ IndentedText *text);
+
// Generates the constructor for the adaptor.
- static void AddConstructor(const Interface& interface,
- const std::string& class_name,
+ static void AddConstructor(const std::string& class_name,
+ const std::string& itf_name,
IndentedText *text);
- // Generates the method interface class.
- static void AddMethodInterface(const Interface& interface,
- IndentedText *text);
+ // Generates RegisterWithDBusObject() method.
+ static void AddRegisterWithDBusObject(const std::string& itf_name,
+ const Interface& interface,
+ IndentedText *text);
+
+ // Generates the code to register the interface with a D-Bus object.
+ static void RegisterInterface(const std::string& itf_name,
+ const Interface& interface,
+ IndentedText *text);
// Generates adaptor methods to send the signals.
static void AddSendSignalMethods(const Interface& interface,
@@ -50,8 +64,8 @@ class AdaptorGenerator : public HeaderGenerator {
IndentedText *text);
// Generates adaptor accessor methods for the properties.
- static void AddPropertyMethods(const Interface& interface,
- IndentedText *text);
+ static void AddPropertyMethodImplementation(const Interface& interface,
+ IndentedText *text);
// Generate ExportProperty data members for the properties.
static void AddPropertyDataMembers(const Interface& interface,
diff --git a/chromeos-dbus-bindings/adaptor_generator_unittest.cc b/chromeos-dbus-bindings/adaptor_generator_unittest.cc
index 41aeeb2..2646c26 100644
--- a/chromeos-dbus-bindings/adaptor_generator_unittest.cc
+++ b/chromeos-dbus-bindings/adaptor_generator_unittest.cc
@@ -33,6 +33,7 @@ const char kMethod1Argument1[] = "i";
const char kMethod1Return[] = "x";
const char kMethod2Name[] = "Kei";
const char kMethod3Name[] = "Kiyoko";
+const char kMethod3ReturnName0[] = "akira";
const char kMethod3Return0[] = "x";
const char kMethod3Return1[] = "s";
const char kSignal0Name[] = "Update";
@@ -40,12 +41,16 @@ const char kSignal1Name[] = "Mapping";
const char kSignal1Argument0[] = "s";
const char kSignal1ArgumentName0[] = "key";
const char kSignal1Argument1[] = "ao";
-const char kProperty0Name[] = "InterfaceName";
+const char kProperty0Name[] = "CharacterName";
const char kProperty0Type[] = "s";
const char kProperty0Access[] = "read";
-const char kInterfaceName[] = "org.chromium.TestInterface";
+const char kInterfaceName[] = "org.chromium.Test";
+const char kInterfaceName2[] = "org.chromium.Test2";
+const char kMethod0Name2[] = "Kaneda2";
+const char kMethod1Name2[] = "Tetsuo2";
const char kExpectedContent[] = R"literal_string(
+#include <memory>
#include <string>
#include <vector>
@@ -59,97 +64,139 @@ const char kExpectedContent[] = R"literal_string(
namespace org {
namespace chromium {
-class TestInterfaceAdaptor {
+// Interface definition for org::chromium::Test.
+class TestInterface {
public:
- class MethodInterface {
- public:
- virtual std::string Kaneda(
- chromeos::ErrorPtr* /* error */,
- const std::string& /* iwata */,
- const std::vector<dbus::ObjectPath>& /* clarke */) = 0;
- virtual int64_t Tetsuo(
- chromeos::ErrorPtr* /* error */,
- int32_t) = 0;
- virtual void Kei(
- chromeos::ErrorPtr* /* error */) = 0;
- };
- TestInterfaceAdaptor(
- chromeos::dbus_utils::ExportedObjectManager* object_manager,
- const scoped_refptr<dbus::Bus>& bus,
- const std::string& object_path,
- MethodInterface* interface) // Owned by caller.
- : interface_(interface),
- dbus_object_(
- object_manager,
- bus,
- dbus::ObjectPath(object_path)),
- signal_Update_(
- &dbus_object_,
- "org.chromium.TestInterface",
- "Update"),
- signal_Mapping_(
- &dbus_object_,
- "org.chromium.TestInterface",
- "Mapping"),
- dbus_interface_(
- dbus_object_.AddOrGetInterface("org.chromium.TestInterface")) {
- dbus_interface_->AddMethodHandler(
+ virtual ~TestInterface() = default;
+
+ virtual bool Kaneda(
+ chromeos::ErrorPtr* error,
+ const std::string& in_iwata,
+ const std::vector<dbus::ObjectPath>& in_clarke,
+ std::string* out_3) = 0;
+ virtual bool Tetsuo(
+ chromeos::ErrorPtr* error,
+ int32_t in_1,
+ int64_t* out_2) = 0;
+ virtual bool Kei(
+ chromeos::ErrorPtr* error) = 0;
+ virtual bool Kiyoko(
+ chromeos::ErrorPtr* error,
+ int64_t* out_akira,
+ std::string* out_2) = 0;
+};
+
+// Interface adaptor for org::chromium::Test.
+class TestAdaptor {
+ public:
+ TestAdaptor(TestInterface* interface) : interface_(interface) {}
+
+ void RegisterWithDBusObject(chromeos::dbus_utils::DBusObject* object) {
+ chromeos::dbus_utils::DBusInterface* itf =
+ object->AddOrGetInterface("org.chromium.Test");
+
+ itf->AddSimpleMethodHandlerWithError(
"Kaneda",
base::Unretained(interface_),
- &MethodInterface::Kaneda);
- dbus_interface_->AddMethodHandler(
+ &TestInterface::Kaneda);
+ itf->AddSimpleMethodHandlerWithError(
"Tetsuo",
base::Unretained(interface_),
- &MethodInterface::Tetsuo);
- dbus_interface_->AddMethodHandler(
+ &TestInterface::Tetsuo);
+ itf->AddSimpleMethodHandlerWithError(
"Kei",
base::Unretained(interface_),
- &MethodInterface::Kei);
- dbus_interface_->AddProperty(
- "InterfaceName",
- &interface_name_);
- dbus_object_.RegisterAsync(base::Bind(
- &TestInterfaceAdaptor::OnRegisterComplete, base::Unretained(this)));
+ &TestInterface::Kei);
+ itf->AddSimpleMethodHandlerWithError(
+ "Kiyoko",
+ base::Unretained(interface_),
+ &TestInterface::Kiyoko);
+
+ signal_Update_ = itf->RegisterSignalOfType<SignalUpdateType>("Update");
+ signal_Mapping_ = itf->RegisterSignalOfType<SignalMappingType>("Mapping");
+
+ itf->AddProperty("CharacterName", &character_name_);
}
- void SendUpdateSignal(
- ) {
- signal_Update_.Send();
+
+ void SendUpdateSignal() {
+ auto signal = signal_Update_.lock();
+ if (signal)
+ signal->Send();
}
void SendMappingSignal(
- const std::string& key,
- const std::vector<dbus::ObjectPath>& _arg_1) {
- signal_Mapping_.Send(key, _arg_1);
+ const std::string& in_key,
+ const std::vector<dbus::ObjectPath>& in_2) {
+ auto signal = signal_Mapping_.lock();
+ if (signal)
+ signal->Send(in_key, in_2);
}
- virtual ~TestInterfaceAdaptor() = default;
- virtual void OnRegisterComplete(bool success) {}
- std::string GetInterfaceName() const {
- return interface_name_.GetValue().Get<std::string>();
+ std::string GetCharacterName() const {
+ return character_name_.GetValue().Get<std::string>();
}
- void SetInterfaceName(
- const std::string& interface_name) {
- interface_name_.SetValue(interface_name);
+ void SetCharacterName(const std::string& character_name) {
+ character_name_.SetValue(character_name);
}
- protected:
- chromeos::dbus_utils::DBusInterface* dbus_interface() {
- return dbus_interface_;
+ private:
+ using SignalUpdateType = chromeos::dbus_utils::DBusSignal<>;
+ std::weak_ptr<SignalUpdateType> signal_Update_;
+
+ using SignalMappingType = chromeos::dbus_utils::DBusSignal<
+ std::string /*key*/,
+ std::vector<dbus::ObjectPath>>;
+ std::weak_ptr<SignalMappingType> signal_Mapping_;
+
+ chromeos::dbus_utils::ExportedProperty<std::string>
+ character_name_;
+
+ TestInterface* interface_; // Owned by container of this adapter.
+
+ DISALLOW_COPY_AND_ASSIGN(TestAdaptor);
+};
+
+} // namespace chromium
+} // namespace org
+
+namespace org {
+namespace chromium {
+
+// Interface definition for org::chromium::Test2.
+class Test2Interface {
+ public:
+ virtual ~Test2Interface() = default;
+
+ virtual std::string Kaneda2(
+ const std::string& in_iwata) const = 0;
+ virtual void Tetsuo2(
+ scoped_ptr<chromeos::dbus_utils::DBusMethodResponse> response,
+ int32_t in_1) = 0;
+};
+
+// Interface adaptor for org::chromium::Test2.
+class Test2Adaptor {
+ public:
+ Test2Adaptor(Test2Interface* interface) : interface_(interface) {}
+
+ void RegisterWithDBusObject(chromeos::dbus_utils::DBusObject* object) {
+ chromeos::dbus_utils::DBusInterface* itf =
+ object->AddOrGetInterface("org.chromium.Test2");
+
+ itf->AddSimpleMethodHandler(
+ "Kaneda2",
+ base::Unretained(interface_),
+ &Test2Interface::Kaneda2);
+ itf->AddMethodHandler(
+ "Tetsuo2",
+ base::Unretained(interface_),
+ &Test2Interface::Tetsuo2);
}
private:
- // Exported properties
- chromeos::dbus_utils::ExportedProperty<std::string>
- interface_name_;
- MethodInterface* interface_; // Owned by caller.
- chromeos::dbus_utils::DBusObject dbus_object_;
- chromeos::dbus_utils::DBusSignal<
- > signal_Update_;
- chromeos::dbus_utils::DBusSignal<
- std::string /* key */,
- std::vector<dbus::ObjectPath>> signal_Mapping_;
- // Owned by |dbus_object_|.
- chromeos::dbus_utils::DBusInterface* dbus_interface_;
- DISALLOW_COPY_AND_ASSIGN(TestInterfaceAdaptor);
+
+ Test2Interface* interface_; // Owned by container of this adapter.
+
+ DISALLOW_COPY_AND_ASSIGN(Test2Adaptor);
};
} // namespace chromium
@@ -194,7 +241,7 @@ TEST_F(AdaptorGeneratorTest, GenerateAdaptors) {
kMethod3Name,
vector<Interface::Argument>{},
vector<Interface::Argument>{
- {"", kMethod3Return0},
+ {kMethod3ReturnName0, kMethod3Return0},
{"", kMethod3Return1}});
// Signals generate helper methods to send them.
interface.signals.emplace_back(
@@ -210,8 +257,24 @@ TEST_F(AdaptorGeneratorTest, GenerateAdaptors) {
kProperty0Type,
kProperty0Access);
+ Interface interface2;
+ interface2.name = kInterfaceName2;
+ interface2.methods.emplace_back(
+ kMethod0Name2,
+ vector<Interface::Argument>{
+ {kMethod0ArgumentName0, kMethod0Argument0}},
+ vector<Interface::Argument>{{"", kMethod0Return}});
+ interface2.methods.back().is_const = true;
+ interface2.methods.back().kind = Interface::Method::Kind::kSimple;
+ interface2.methods.emplace_back(
+ kMethod1Name2,
+ vector<Interface::Argument>{{"", kMethod1Argument1}},
+ vector<Interface::Argument>{});
+ interface2.methods.back().kind = Interface::Method::Kind::kAsync;
+
base::FilePath output_path = temp_dir_.path().Append("output.h");
- EXPECT_TRUE(AdaptorGenerator::GenerateAdaptor(interface, output_path));
+ EXPECT_TRUE(AdaptorGenerator::GenerateAdaptors({interface, interface2},
+ output_path));
string contents;
EXPECT_TRUE(base::ReadFileToString(output_path, &contents));
// The header guards contain the (temporary) filename, so we search for
diff --git a/chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc b/chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc
index 5bf35e1..c53168c 100644
--- a/chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc
+++ b/chromeos-dbus-bindings/generate_chromeos_dbus_bindings.cc
@@ -14,6 +14,10 @@
#include "chromeos-dbus-bindings/proxy_generator.h"
#include "chromeos-dbus-bindings/xml_interface_parser.h"
+using chromeos_dbus_bindings::AdaptorGenerator;
+using chromeos_dbus_bindings::MethodNameGenerator;
+using chromeos_dbus_bindings::ProxyGenerator;
+
namespace switches {
static const char kHelp[] = "help";
@@ -65,20 +69,19 @@ int main(int argc, char** argv) {
std::string method_name_file =
cl->GetSwitchValueASCII(switches::kMethodNames);
VLOG(1) << "Outputting method names to " << method_name_file;
- if (!chromeos_dbus_bindings::MethodNameGenerator::GenerateMethodNames(
- parser.interface(),
+ if (!MethodNameGenerator::GenerateMethodNames(
+ parser.interfaces(),
base::FilePath(method_name_file))) {
LOG(ERROR) << "Failed to output method names.";
return 1;
- }
+ }
}
if (cl->HasSwitch(switches::kAdaptor)) {
std::string adaptor_file = cl->GetSwitchValueASCII(switches::kAdaptor);
VLOG(1) << "Outputting adaptor to " << adaptor_file;
- if (!chromeos_dbus_bindings::AdaptorGenerator::GenerateAdaptor(
- parser.interface(),
- base::FilePath(adaptor_file))) {
+ if (!AdaptorGenerator::GenerateAdaptors(parser.interfaces(),
+ base::FilePath(adaptor_file))) {
LOG(ERROR) << "Failed to output adaptor.";
return 1;
}
@@ -87,9 +90,8 @@ int main(int argc, char** argv) {
if (cl->HasSwitch(switches::kProxy)) {
std::string proxy_file = cl->GetSwitchValueASCII(switches::kProxy);
LOG(INFO) << "Outputting proxy to " << proxy_file;
- if (!chromeos_dbus_bindings::ProxyGenerator::GenerateProxy(
- parser.interface(),
- base::FilePath(proxy_file))) {
+ if (!ProxyGenerator::GenerateProxy(parser.interfaces(),
+ base::FilePath(proxy_file))) {
LOG(ERROR) << "Failed to output proxy.";
return 1;
}
diff --git a/chromeos-dbus-bindings/header_generator.cc b/chromeos-dbus-bindings/header_generator.cc
index c339c13..da4bc74 100644
--- a/chromeos-dbus-bindings/header_generator.cc
+++ b/chromeos-dbus-bindings/header_generator.cc
@@ -11,6 +11,7 @@
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
+#include <chromeos/strings/string_utils.h>
#include "chromeos-dbus-bindings/indented_text.h"
@@ -53,6 +54,14 @@ bool HeaderGenerator::GetNamespacesAndClassName(
return true;
}
+std::string HeaderGenerator::GetFullClassName(
+ const std::vector<std::string>& namespaces,
+ const std::string& class_name) {
+ std::vector<std::string> parts = namespaces;
+ parts.push_back(class_name);
+ return chromeos::string_utils::Join("::", parts);
+}
+
// static
bool HeaderGenerator::IsIntegralType(const string& type) {
return type.find("::") == std::string::npos;
@@ -71,4 +80,11 @@ bool HeaderGenerator::WriteTextToFile(
return true;
}
+string HeaderGenerator::GetArgName(const char* prefix,
+ const string& arg_name,
+ int arg_index) {
+ string name = arg_name.empty() ? std::to_string(arg_index) : arg_name;
+ return base::StringPrintf("%s_%s", prefix, name.c_str());
+}
+
} // namespace chromeos_dbus_bindings
diff --git a/chromeos-dbus-bindings/header_generator.h b/chromeos-dbus-bindings/header_generator.h
index 7be8d5b..b4f521d 100644
--- a/chromeos-dbus-bindings/header_generator.h
+++ b/chromeos-dbus-bindings/header_generator.h
@@ -27,11 +27,16 @@ class HeaderGenerator {
static std::string GenerateHeaderGuard(const base::FilePath& output_file,
const std::string& interface_name);
- // Returns a vector of nesting namepsaces.
+ // Returns a vector of nesting namespaces.
static bool GetNamespacesAndClassName(const std::string& interface_name,
std::vector<std::string>* namespaces,
std::string* class_name);
+ // Returns a fully-qualified class name like "ns1::ns2::class_name".
+ static std::string GetFullClassName(
+ const std::vector<std::string>& namespaces,
+ const std::string& class_name);
+
// Used to decide whether the argument should be a const reference.
static bool IsIntegralType(const std::string& type);
@@ -39,6 +44,13 @@ class HeaderGenerator {
static bool WriteTextToFile(const base::FilePath& output_file,
const IndentedText& text);
+ // Generate a name of a method/signal argument based on the name provided in
+ // the XML file. If |arg_name| is empty, it generates a name using
+ // the |arg_index| counter.
+ static std::string GetArgName(const char* prefix,
+ const std::string& arg_name,
+ int arg_index);
+
static const int kScopeOffset = 1;
static const int kBlockOffset = 2;
static const int kLineContinuationOffset = 4;
diff --git a/chromeos-dbus-bindings/interface.h b/chromeos-dbus-bindings/interface.h
index 627dce4..214511b 100644
--- a/chromeos-dbus-bindings/interface.h
+++ b/chromeos-dbus-bindings/interface.h
@@ -18,6 +18,12 @@ struct Interface {
std::string type;
};
struct Method {
+ enum class Kind {
+ kSimple,
+ kNormal,
+ kAsync,
+ kRaw
+ };
Method(const std::string& name_in,
const std::vector<Argument>& input_arguments_in,
const std::vector<Argument>& output_arguments_in)
@@ -32,6 +38,8 @@ struct Interface {
std::string name;
std::vector<Argument> input_arguments;
std::vector<Argument> output_arguments;
+ Kind kind{Kind::kNormal};
+ bool is_const{false};
};
struct Signal {
Signal(const std::string& name_in,
diff --git a/chromeos-dbus-bindings/method_name_generator.cc b/chromeos-dbus-bindings/method_name_generator.cc
index 4b4154e..d35f058 100644
--- a/chromeos-dbus-bindings/method_name_generator.cc
+++ b/chromeos-dbus-bindings/method_name_generator.cc
@@ -4,16 +4,14 @@
#include "chromeos-dbus-bindings/method_name_generator.h"
-#include <string>
-
-#include <base/file_util.h>
#include <base/files/file_path.h>
-#include <base/logging.h>
#include <base/strings/stringprintf.h>
+#include "chromeos-dbus-bindings/indented_text.h"
#include "chromeos-dbus-bindings/interface.h"
using std::string;
+using std::vector;
namespace chromeos_dbus_bindings {
@@ -25,23 +23,23 @@ string MethodNameGenerator::GenerateMethodNameConstant(
// static
bool MethodNameGenerator::GenerateMethodNames(
- const Interface& interface,
+ const vector<Interface>& interfaces,
const base::FilePath& output_file) {
string contents;
- for (const auto& method : interface.methods) {
- contents.append(
- base::StringPrintf("const char %s[] = \"%s\";\n",
- GenerateMethodNameConstant(method.name).c_str(),
- method.name.c_str()));
- }
-
- int expected_write_return = contents.size();
- if (base::WriteFile(output_file, contents.c_str(), contents.size()) !=
- expected_write_return) {
- LOG(ERROR) << "Failed to write file " << output_file.value();
- return false;
+ IndentedText text;
+ for (const auto& interface : interfaces) {
+ text.AddBlankLine();
+ text.AddLine(base::StringPrintf("namespace %s {", interface.name.c_str()));
+ for (const auto& method : interface.methods) {
+ text.AddLine(
+ base::StringPrintf("const char %s[] = \"%s\";",
+ GenerateMethodNameConstant(method.name).c_str(),
+ method.name.c_str()));
+ }
+ text.AddLine(base::StringPrintf("} // namespace %s",
+ interface.name.c_str()));
}
- return true;
+ return HeaderGenerator::WriteTextToFile(output_file, text);
}
} // namespace chromeos_dbus_bindings
diff --git a/chromeos-dbus-bindings/method_name_generator.h b/chromeos-dbus-bindings/method_name_generator.h
index 59ca890..24a3dc1 100644
--- a/chromeos-dbus-bindings/method_name_generator.h
+++ b/chromeos-dbus-bindings/method_name_generator.h
@@ -6,9 +6,12 @@
#define CHROMEOS_DBUS_BINDINGS_METHOD_NAME_GENERATOR_H_
#include <string>
+#include <vector>
#include <base/macros.h>
+#include "chromeos-dbus-bindings/header_generator.h"
+
namespace base {
class FilePath;
@@ -19,9 +22,9 @@ namespace chromeos_dbus_bindings {
struct Interface;
-class MethodNameGenerator {
+class MethodNameGenerator : public HeaderGenerator {
public:
- static bool GenerateMethodNames(const Interface &interface,
+ static bool GenerateMethodNames(const std::vector<Interface>& interfaces,
const base::FilePath& output_file);
static std::string GenerateMethodNameConstant(const std::string& method_name);
diff --git a/chromeos-dbus-bindings/method_name_generator_unittest.cc b/chromeos-dbus-bindings/method_name_generator_unittest.cc
index dc461d6..d237350 100644
--- a/chromeos-dbus-bindings/method_name_generator_unittest.cc
+++ b/chromeos-dbus-bindings/method_name_generator_unittest.cc
@@ -5,6 +5,7 @@
#include "chromeos-dbus-bindings/method_name_generator.h"
#include <string>
+#include <vector>
#include <base/file_util.h>
#include <base/files/file_path.h>
@@ -23,10 +24,14 @@ namespace {
const char kMethodName0[] = "Zircon";
const char kMethodName1[] = "Encrusted";
const char kMethodName2[] = "Tweezers";
-const char kExpectedOutput[] =
- "const char kZirconMethod[] = \"Zircon\";\n"
- "const char kEncrustedMethod[] = \"Encrusted\";\n"
- "const char kTweezersMethod[] = \"Tweezers\";\n";
+const char kExpectedOutput[] = R"(
+namespace MyInterface {
+const char kZirconMethod[] = "Zircon";
+const char kEncrustedMethod[] = "Encrusted";
+const char kTweezersMethod[] = "Tweezers";
+} // namespace MyInterface
+)";
+
} // namespace
class MethodNameGeneratorTest : public Test {
@@ -49,11 +54,13 @@ class MethodNameGeneratorTest : public Test {
TEST_F(MethodNameGeneratorTest, GnerateMethodNames) {
Interface interface;
+ interface.name = "MyInterface";
interface.methods.emplace_back(kMethodName0);
interface.methods.emplace_back(kMethodName1);
interface.methods.emplace_back(kMethodName2);
base::FilePath output_path = temp_dir_.path().Append("output.h");
- EXPECT_TRUE(MethodNameGenerator::GenerateMethodNames(interface, output_path));
+ EXPECT_TRUE(MethodNameGenerator::GenerateMethodNames({interface},
+ output_path));
string contents;
EXPECT_TRUE(base::ReadFileToString(output_path, &contents));
EXPECT_STREQ(kExpectedOutput, contents.c_str());
diff --git a/chromeos-dbus-bindings/proxy_generator.cc b/chromeos-dbus-bindings/proxy_generator.cc
index 34b44c0..67cba22 100644
--- a/chromeos-dbus-bindings/proxy_generator.cc
+++ b/chromeos-dbus-bindings/proxy_generator.cc
@@ -6,6 +6,7 @@
#include <base/logging.h>
#include <base/strings/stringprintf.h>
+#include <chromeos/strings/string_utils.h>
#include "chromeos-dbus-bindings/dbus_signature.h"
#include "chromeos-dbus-bindings/indented_text.h"
@@ -18,12 +19,22 @@ namespace chromeos_dbus_bindings {
// static
bool ProxyGenerator::GenerateProxy(
- const Interface& interface,
+ const std::vector<Interface>& interfaces,
const base::FilePath& output_file) {
IndentedText text;
- text.AddLine(StringPrintf("// Automatic generation of interface for %s",
- interface.name.c_str()));
- string header_guard = GenerateHeaderGuard(output_file, interface.name);
+ CHECK(!interfaces.empty()) << "At least one interface must be provided";
+ vector<string> namespaces;
+ string proxy_name;
+ CHECK(GetNamespacesAndClassName(interfaces.front().name,
+ &namespaces,
+ &proxy_name));
+ proxy_name += "Proxy";
+
+ text.AddLine("// Automatic generation of D-Bus interfaces:");
+ for (const auto& interface : interfaces) {
+ text.AddLine(StringPrintf("// - %s", interface.name.c_str()));
+ }
+ string header_guard = GenerateHeaderGuard(output_file, proxy_name);
text.AddLine(StringPrintf("#ifndef %s", header_guard.c_str()));
text.AddLine(StringPrintf("#define %s", header_guard.c_str()));
text.AddLine("#include <string>");
@@ -44,24 +55,22 @@ bool ProxyGenerator::GenerateProxy(
text.AddLine("#include <dbus/object_proxy.h>");
text.AddBlankLine();
- vector<string> namespaces;
- string class_name;
- CHECK(GetNamespacesAndClassName(interface.name, &namespaces, &class_name));
for (const auto& space : namespaces) {
text.AddLine(StringPrintf("namespace %s {", space.c_str()));
}
text.AddBlankLine();
- string proxy_name = StringPrintf("%sProxy", class_name.c_str());
text.AddLine(StringPrintf("class %s {", proxy_name.c_str()));
text.AddLineWithOffset("public:", kScopeOffset);
text.PushOffset(kBlockOffset);
- AddMethodInterface(interface, &text);
- AddConstructor(interface, proxy_name, &text);
+ AddSignalReceiver(interfaces, &text);
+ AddConstructor(interfaces, proxy_name, &text);
AddDestructor(proxy_name, &text);
AddSignalConnectedCallback(&text);
- for (const auto& method : interface.methods) {
- AddMethodProxy(method, interface.name, &text);
+ for (const auto& interface : interfaces) {
+ for (const auto& method : interface.methods) {
+ AddMethodProxy(method, interface.name, &text);
+ }
}
text.PopOffset();
@@ -91,9 +100,9 @@ bool ProxyGenerator::GenerateProxy(
}
// static
-void ProxyGenerator::AddConstructor(const Interface& interface,
- const string& class_name,
- IndentedText* text) {
+void ProxyGenerator::AddConstructor(const vector<Interface>& interfaces,
+ const string& class_name,
+ IndentedText* text) {
IndentedText block;
block.AddLine(StringPrintf("%s(", class_name.c_str()));
block.PushOffset(kLineContinuationOffset);
@@ -112,26 +121,28 @@ void ProxyGenerator::AddConstructor(const Interface& interface,
block.PopOffset();
block.PopOffset();
block.PushOffset(kBlockOffset);
- for (const auto& signal : interface.signals) {
- block.AddLine("chromeos::dbus_utils::ConnectToSignal(");
- block.PushOffset(kLineContinuationOffset);
- block.AddLine("dbus_object_proxy_,");
- block.AddLine(StringPrintf("\"%s\",", interface.name.c_str()));
- block.AddLine(StringPrintf("\"%s\",", signal.name.c_str()));
- block.AddLine("base::Bind(");
- block.PushOffset(kLineContinuationOffset);
- block.AddLine(StringPrintf(
+ for (const auto& interface : interfaces) {
+ for (const auto& signal : interface.signals) {
+ block.AddLine("chromeos::dbus_utils::ConnectToSignal(");
+ block.PushOffset(kLineContinuationOffset);
+ block.AddLine("dbus_object_proxy_,");
+ block.AddLine(StringPrintf("\"%s\",", interface.name.c_str()));
+ block.AddLine(StringPrintf("\"%s\",", signal.name.c_str()));
+ block.AddLine("base::Bind(");
+ block.PushOffset(kLineContinuationOffset);
+ block.AddLine(StringPrintf(
"&SignalReceiver::%s,",
GetHandlerNameForSignal(signal.name).c_str()));
- block.AddLine("base::Unretained(signal_receiver)),");
- block.PopOffset();
- block.AddLine("base::Bind(");
- block.PushOffset(kLineContinuationOffset);
- block.AddLine(StringPrintf(
+ block.AddLine("base::Unretained(signal_receiver)),");
+ block.PopOffset();
+ block.AddLine("base::Bind(");
+ block.PushOffset(kLineContinuationOffset);
+ block.AddLine(StringPrintf(
"&%s::OnDBusSignalConnected,", class_name.c_str()));
- block.AddLine("base::Unretained(this)));");
- block.PopOffset();
- block.PopOffset();
+ block.AddLine("base::Unretained(this)));");
+ block.PopOffset();
+ block.PopOffset();
+ }
}
block.PopOffset();
block.AddLine("}");
@@ -179,35 +190,44 @@ void ProxyGenerator::AddSignalConnectedCallback(IndentedText* text) {
}
// static
-void ProxyGenerator::AddMethodInterface(const Interface& interface,
- IndentedText* text) {
+void ProxyGenerator::AddSignalReceiver(const vector<Interface>& interfaces,
+ IndentedText* text) {
IndentedText block;
block.AddLine("class SignalReceiver {");
block.AddLineWithOffset("public:", kScopeOffset);
block.PushOffset(kBlockOffset);
DbusSignature signature;
- for (const auto& signal : interface.signals) {
- if (signal.arguments.empty()) {
- block.AddLine(StringPrintf("virtual void %s() {}",
- GetHandlerNameForSignal(signal.name).c_str()));
- continue;
- }
- block.AddLine(StringPrintf("virtual void %s(",
- GetHandlerNameForSignal(signal.name).c_str()));
- block.PushOffset(kLineContinuationOffset);
- string last_argument;
- vector<string> argument_types;
- for (const auto& argument : signal.arguments) {
- if (!last_argument.empty()) {
- block.AddLine(StringPrintf("%s,", last_argument.c_str()));
+ for (const auto& interface : interfaces) {
+ for (const auto& signal : interface.signals) {
+ string signal_begin = StringPrintf(
+ "virtual void %s(",
+ GetHandlerNameForSignal(signal.name).c_str());
+ string signal_end = ") {}";
+
+ if (signal.arguments.empty()) {
+ block.AddLine(signal_begin + signal_end);
+ continue;
}
- CHECK(signature.Parse(argument.type, &last_argument));
- if (!IsIntegralType(last_argument)) {
- last_argument = StringPrintf("const %s&", last_argument.c_str());
+ block.AddLine(signal_begin);
+ block.PushOffset(kLineContinuationOffset);
+ string last_argument;
+ vector<string> argument_types;
+ for (const auto& argument : signal.arguments) {
+ if (!last_argument.empty()) {
+ block.AddLine(StringPrintf("%s,", last_argument.c_str()));
+ }
+ CHECK(signature.Parse(argument.type, &last_argument));
+ if (!IsIntegralType(last_argument)) {
+ last_argument = StringPrintf("const %s&", last_argument.c_str());
+ }
+ if (!argument.name.empty()) {
+ last_argument += ' ';
+ last_argument += argument.name;
+ }
}
+ block.AddLine(last_argument + signal_end);
+ block.PopOffset();
}
- block.AddLine(StringPrintf("%s) {}", last_argument.c_str()));
- block.PopOffset();
}
block.PopOffset();
block.AddLine("};");
@@ -220,21 +240,8 @@ void ProxyGenerator::AddMethodProxy(const Interface::Method& method,
const string& interface_name,
IndentedText* text) {
IndentedText block;
- string return_type("void");
- bool is_void_method = true;
DbusSignature signature;
- if (!method.output_arguments.empty()) {
- if (method.output_arguments.size() > 1) {
- LOG(WARNING) << "Method " << method.name << " has "
- << method.output_arguments.size()
- << " output arguments which is unsupported.";
- return;
- }
- CHECK(signature.Parse(method.output_arguments[0].type, &return_type));
- is_void_method = false;
- }
- block.AddLine(StringPrintf("virtual %s %s(",
- return_type.c_str(), method.name.c_str()));
+ block.AddLine(StringPrintf("virtual bool %s(", method.name.c_str()));
block.PushOffset(kLineContinuationOffset);
vector<string> argument_names;
int argument_number = 0;
@@ -244,15 +251,20 @@ void ProxyGenerator::AddMethodProxy(const Interface::Method& method,
if (!IsIntegralType(argument_type)) {
argument_type = StringPrintf("const %s&", argument_type.c_str());
}
- ++argument_number;
- string argument_prefix(argument.name.empty() ?
- StringPrintf("argument%d", argument_number) :
- argument.name);
- string argument_name(StringPrintf("%s_in", argument_prefix.c_str()));
+ string argument_name = GetArgName("in", argument.name, ++argument_number);
argument_names.push_back(argument_name);
block.AddLine(StringPrintf(
"%s %s,", argument_type.c_str(), argument_name.c_str()));
}
+ vector<string> out_param_names{"response.get()", "error"};
+ for (const auto& argument : method.output_arguments) {
+ string argument_type;
+ CHECK(signature.Parse(argument.type, &argument_type));
+ string argument_name = GetArgName("out", argument.name, ++argument_number);
+ out_param_names.push_back(argument_name);
+ block.AddLine(StringPrintf(
+ "%s* %s,", argument_type.c_str(), argument_name.c_str()));
+ }
block.AddLine("chromeos::ErrorPtr* error) {");
block.PopOffset();
block.PushOffset(kBlockOffset);
@@ -270,21 +282,11 @@ void ProxyGenerator::AddMethodProxy(const Interface::Method& method,
block.AddLine(StringPrintf("%s);", last_argument.c_str()));
block.PopOffset();
- if (!is_void_method) {
- block.AddLine(StringPrintf("%s result{};", return_type.c_str()));
- }
- block.AddLine("if (!response) {");
- block.AddLineWithOffset(StringPrintf(
- "return%s;", is_void_method ? "" : " result"), kBlockOffset);
- block.AddLine("}");
- block.AddLine("chromeos::dbus_utils::ExtractMethodCallResults(");
- block.AddLineWithOffset(StringPrintf("response.get(), error%s);",
- is_void_method ? "" : ", &result"),
- kLineContinuationOffset);
- if (!is_void_method) {
- block.AddLine("return result;");
- }
-
+ block.AddLine("return response && "
+ "chromeos::dbus_utils::ExtractMethodCallResults(");
+ block.PushOffset(kLineContinuationOffset);
+ block.AddLine(chromeos::string_utils::Join(", ", out_param_names) + ");");
+ block.PopOffset();
block.PopOffset();
block.AddLine("}");
diff --git a/chromeos-dbus-bindings/proxy_generator.h b/chromeos-dbus-bindings/proxy_generator.h
index 66dd8ba..b8f7e7b 100644
--- a/chromeos-dbus-bindings/proxy_generator.h
+++ b/chromeos-dbus-bindings/proxy_generator.h
@@ -27,14 +27,14 @@ struct Interface;
class ProxyGenerator : public HeaderGenerator {
public:
- static bool GenerateProxy(const Interface& interface,
+ static bool GenerateProxy(const std::vector<Interface>& interfaces,
const base::FilePath& output_file);
private:
friend class ProxyGeneratorTest;
// Generates the constructor and destructor for the proxy.
- static void AddConstructor(const Interface& interface,
+ static void AddConstructor(const std::vector<Interface>& interfaces,
const std::string& class_name,
IndentedText* text);
static void AddDestructor(const std::string& class_name,
@@ -44,8 +44,8 @@ class ProxyGenerator : public HeaderGenerator {
static void AddSignalConnectedCallback(IndentedText *text);
// Generates the method signatures for signal receivers.
- static void AddMethodInterface(const Interface& interface,
- IndentedText* text);
+ static void AddSignalReceiver(const std::vector<Interface>& interfaces,
+ IndentedText* text);
// Generates a native C++ method which calls a D-Bus method on the proxy.
static void AddMethodProxy(const Interface::Method& interface,
diff --git a/chromeos-dbus-bindings/proxy_generator_unittest.cc b/chromeos-dbus-bindings/proxy_generator_unittest.cc
index 1149de9..7bb1ab9 100644
--- a/chromeos-dbus-bindings/proxy_generator_unittest.cc
+++ b/chromeos-dbus-bindings/proxy_generator_unittest.cc
@@ -23,6 +23,7 @@ namespace chromeos_dbus_bindings {
namespace {
const char kInterfaceName[] = "org.chromium.TestInterface";
+const char kInterfaceName2[] = "org.chromium.TestInterface2";
const char kMethod1Name[] = "Elements";
const char kMethod1Return[] = "s";
const char kMethod1Argument1[] = "s";
@@ -34,6 +35,11 @@ const char kMethod2Return[] = "x";
const char kMethod3Name[] = "NiceWeatherForDucks";
const char kMethod3Argument1[] = "b";
const char kMethod4Name[] = "ExperimentNumberSix";
+const char kMethod5Name[] = "GetPersonInfo";
+const char kMethod5Argument1[] = "s";
+const char kMethod5ArgumentName1[] = "name";
+const char kMethod5Argument2[] = "i";
+const char kMethod5ArgumentName2[] = "age";
const char kSignal1Name[] = "Closer";
const char kSignal2Name[] = "TheCurseOfKaZar";
const char kSignal2Argument1[] = "as";
@@ -114,68 +120,66 @@ class TestInterfaceProxy {
<< object_path_.value();
}
}
- virtual std::string Elements(
- const std::string& space_walk_in,
- const std::vector<dbus::ObjectPath>& ramblin_man_in,
+ virtual bool Elements(
+ const std::string& in_space_walk,
+ const std::vector<dbus::ObjectPath>& in_ramblin_man,
+ std::string* out_3,
chromeos::ErrorPtr* error) {
auto response = chromeos::dbus_utils::CallMethodAndBlock(
dbus_object_proxy_,
"org.chromium.TestInterface",
"Elements",
error,
- space_walk_in,
- ramblin_man_in);
- std::string result{};
- if (!response) {
- return result;
- }
- chromeos::dbus_utils::ExtractMethodCallResults(
- response.get(), error, &result);
- return result;
+ in_space_walk,
+ in_ramblin_man);
+ return response && chromeos::dbus_utils::ExtractMethodCallResults(
+ response.get(), error, out_3);
}
- virtual int64_t ReturnToPatagonia(
+ virtual bool ReturnToPatagonia(
+ int64_t* out_1,
chromeos::ErrorPtr* error) {
auto response = chromeos::dbus_utils::CallMethodAndBlock(
dbus_object_proxy_,
"org.chromium.TestInterface",
"ReturnToPatagonia",
error);
- int64_t result{};
- if (!response) {
- return result;
- }
- chromeos::dbus_utils::ExtractMethodCallResults(
- response.get(), error, &result);
- return result;
+ return response && chromeos::dbus_utils::ExtractMethodCallResults(
+ response.get(), error, out_1);
}
- virtual void NiceWeatherForDucks(
- bool argument1_in,
+ virtual bool NiceWeatherForDucks(
+ bool in_1,
chromeos::ErrorPtr* error) {
auto response = chromeos::dbus_utils::CallMethodAndBlock(
dbus_object_proxy_,
"org.chromium.TestInterface",
"NiceWeatherForDucks",
error,
- argument1_in);
- if (!response) {
- return;
- }
- chromeos::dbus_utils::ExtractMethodCallResults(
+ in_1);
+ return response && chromeos::dbus_utils::ExtractMethodCallResults(
response.get(), error);
}
- virtual void ExperimentNumberSix(
+ virtual bool ExperimentNumberSix(
chromeos::ErrorPtr* error) {
auto response = chromeos::dbus_utils::CallMethodAndBlock(
dbus_object_proxy_,
"org.chromium.TestInterface",
"ExperimentNumberSix",
error);
- if (!response) {
- return;
- }
- chromeos::dbus_utils::ExtractMethodCallResults(
+ return response && chromeos::dbus_utils::ExtractMethodCallResults(
response.get(), error);
}
+ virtual bool GetPersonInfo(
+ std::string* out_name,
+ int32_t* out_age,
+ chromeos::ErrorPtr* error) {
+ auto response = chromeos::dbus_utils::CallMethodAndBlock(
+ dbus_object_proxy_,
+ "org.chromium.TestInterface2",
+ "GetPersonInfo",
+ error);
+ return response && chromeos::dbus_utils::ExtractMethodCallResults(
+ response.get(), error, out_name, out_age);
+ }
private:
scoped_refptr<dbus::Bus> bus_;
@@ -234,8 +238,17 @@ TEST_F(ProxyGeneratorTest, GenerateAdaptors) {
vector<Interface::Argument>{
{"", kSignal2Argument1},
{"", kSignal2Argument2}});
+ Interface interface2;
+ interface2.name = kInterfaceName2;
+ interface2.methods.emplace_back(
+ kMethod5Name,
+ vector<Interface::Argument>{},
+ vector<Interface::Argument>{
+ {kMethod5ArgumentName1, kMethod5Argument1},
+ {kMethod5ArgumentName2, kMethod5Argument2}});
+ vector<Interface> interfaces{interface, interface2};
base::FilePath output_path = temp_dir_.path().Append("output.h");
- EXPECT_TRUE(ProxyGenerator::GenerateProxy(interface, output_path));
+ EXPECT_TRUE(ProxyGenerator::GenerateProxy(interfaces, output_path));
string contents;
EXPECT_TRUE(base::ReadFileToString(output_path, &contents));
// The header guards contain the (temporary) filename, so we search for
diff --git a/chromeos-dbus-bindings/xml_interface_parser.cc b/chromeos-dbus-bindings/xml_interface_parser.cc
index 7189ec4..3baef84 100644
--- a/chromeos-dbus-bindings/xml_interface_parser.cc
+++ b/chromeos-dbus-bindings/xml_interface_parser.cc
@@ -23,13 +23,27 @@ const char XmlInterfaceParser::kMethodTag[] = "method";
const char XmlInterfaceParser::kNodeTag[] = "node";
const char XmlInterfaceParser::kSignalTag[] = "signal";
const char XmlInterfaceParser::kPropertyTag[] = "property";
+const char XmlInterfaceParser::kAnnotationTag[] = "annotation";
const char XmlInterfaceParser::kNameAttribute[] = "name";
const char XmlInterfaceParser::kTypeAttribute[] = "type";
+const char XmlInterfaceParser::kValueAttribute[] = "value";
const char XmlInterfaceParser::kDirectionAttribute[] = "direction";
const char XmlInterfaceParser::kAccessAttribute[] = "access";
const char XmlInterfaceParser::kArgumentDirectionIn[] = "in";
const char XmlInterfaceParser::kArgumentDirectionOut[] = "out";
+const char XmlInterfaceParser::kTrue[] = "true";
+const char XmlInterfaceParser::kFalse[] = "false";
+
+const char XmlInterfaceParser::kMethodConst[] =
+ "org.chromium.DBus.Method.Const";
+
+const char XmlInterfaceParser::kMethodKind[] = "org.chromium.DBus.Method.Kind";
+const char XmlInterfaceParser::kMethodKindSimple[] = "simple";
+const char XmlInterfaceParser::kMethodKindNormal[] = "normal";
+const char XmlInterfaceParser::kMethodKindAsync[] = "async";
+const char XmlInterfaceParser::kMethodKindRaw[] = "raw";
+
bool XmlInterfaceParser::ParseXmlInterfaceFile(
const base::FilePath& interface_file) {
string contents;
@@ -62,36 +76,84 @@ bool XmlInterfaceParser::ParseXmlInterfaceFile(
void XmlInterfaceParser::OnOpenElement(
const string& element_name, const XmlAttributeMap& attributes) {
+ string prev_element;
+ if (!element_path_.empty())
+ prev_element = element_path_.back();
element_path_.push_back(element_name);
- if (element_path_ == vector<string> { kNodeTag, kInterfaceTag }) {
+ if (element_name == kNodeTag) {
+ CHECK(prev_element.empty())
+ << "Unexpected tag " << element_name << " inside " << prev_element;
+ } else if (element_name == kInterfaceTag) {
+ CHECK_EQ(kNodeTag, prev_element)
+ << "Unexpected tag " << element_name << " inside " << prev_element;
string interface_name = GetValidatedElementName(attributes, kInterfaceTag);
- CHECK(interface_.name.empty())
- << "Found a second interface named " << interface_name << ". "
- << "Interface " << interface_.name << " has already been parsed.";
- interface_.name = interface_name;
- } else if (element_path_ == vector<string> {
- kNodeTag, kInterfaceTag, kMethodTag }) {
- interface_.methods.push_back(
+ interfaces_.emplace_back(interface_name,
+ std::vector<Interface::Method>{},
+ std::vector<Interface::Signal>{},
+ std::vector<Interface::Property>{});
+ } else if (element_name == kMethodTag) {
+ CHECK_EQ(kInterfaceTag, prev_element)
+ << "Unexpected tag " << element_name << " inside " << prev_element;
+ interfaces_.back().methods.push_back(
Interface::Method(GetValidatedElementName(attributes, kMethodTag)));
- } else if (element_path_ == vector<string> {
- kNodeTag, kInterfaceTag, kMethodTag, kArgumentTag }) {
- AddMethodArgument(attributes);
- } else if (element_path_ == vector<string> {
- kNodeTag, kInterfaceTag, kSignalTag }) {
- interface_.signals.push_back(
+ } else if (element_name == kSignalTag) {
+ CHECK_EQ(kInterfaceTag, prev_element)
+ << "Unexpected tag " << element_name << " inside " << prev_element;
+ interfaces_.back().signals.push_back(
Interface::Signal(GetValidatedElementName(attributes, kSignalTag)));
- } else if (element_path_ == vector<string> {
- kNodeTag, kInterfaceTag, kSignalTag, kArgumentTag }) {
- AddSignalArgument(attributes);
- } else if (element_path_ == vector<string> {
- kNodeTag, kInterfaceTag, kPropertyTag }) {
- interface_.properties.push_back(ParseProperty(attributes));
+ } else if (element_name == kPropertyTag) {
+ CHECK_EQ(kInterfaceTag, prev_element)
+ << "Unexpected tag " << element_name << " inside " << prev_element;
+ interfaces_.back().properties.push_back(ParseProperty(attributes));
+ } else if (element_name == kArgumentTag) {
+ if (prev_element == kMethodTag) {
+ AddMethodArgument(attributes);
+ } else if (prev_element == kSignalTag) {
+ AddSignalArgument(attributes);
+ } else {
+ LOG(FATAL) << "Unexpected tag " << element_name
+ << " inside " << prev_element;
+ }
+ } else if (element_name == kAnnotationTag) {
+ string element_path = prev_element + " " + element_name;
+ string name = GetValidatedElementAttribute(attributes, element_path,
+ kNameAttribute);
+ // Value is optional. Default to empty string if omitted.
+ string value;
+ GetElementAttribute(attributes, element_path, kValueAttribute, &value);
+ if (prev_element == kInterfaceTag) {
+ // Parse interface annotations...
+ } else if (prev_element == kMethodTag) {
+ // Parse method annotations...
+ Interface::Method& method = interfaces_.back().methods.back();
+ if (name == kMethodConst) {
+ CHECK(value == kTrue || value == kFalse);
+ method.is_const = (value == kTrue);
+ } else if (name == kMethodKind) {
+ if (value == kMethodKindSimple) {
+ method.kind = Interface::Method::Kind::kSimple;
+ } else if (value == kMethodKindNormal) {
+ method.kind = Interface::Method::Kind::kNormal;
+ } else if (value == kMethodKindAsync) {
+ method.kind = Interface::Method::Kind::kAsync;
+ } else if (value == kMethodKindRaw) {
+ method.kind = Interface::Method::Kind::kRaw;
+ } else {
+ LOG(FATAL) << "Invalid method kind: " << value;
+ }
+ }
+ } else if (prev_element == kSignalTag) {
+ // Parse signal annotations...
+ } else if (prev_element == kPropertyTag) {
+ // Parse property annotations...
+ } else {
+ LOG(FATAL) << "Unexpected tag " << element_name
+ << " inside " << prev_element;
+ }
}
}
void XmlInterfaceParser::AddMethodArgument(const XmlAttributeMap& attributes) {
- CHECK(!interface_.methods.empty())
- << " we have a method argument but the interface has no methods";
string argument_direction;
bool is_direction_paramter_present = GetElementAttribute(
attributes,
@@ -101,9 +163,9 @@ void XmlInterfaceParser::AddMethodArgument(const XmlAttributeMap& attributes) {
vector<Interface::Argument>* argument_list = nullptr;
if (!is_direction_paramter_present ||
argument_direction == kArgumentDirectionIn) {
- argument_list = &interface_.methods.back().input_arguments;
+ argument_list = &interfaces_.back().methods.back().input_arguments;
} else if (argument_direction == kArgumentDirectionOut) {
- argument_list = &interface_.methods.back().output_arguments;
+ argument_list = &interfaces_.back().methods.back().output_arguments;
} else {
LOG(FATAL) << "Unknown method argument direction " << argument_direction;
}
@@ -111,9 +173,7 @@ void XmlInterfaceParser::AddMethodArgument(const XmlAttributeMap& attributes) {
}
void XmlInterfaceParser::AddSignalArgument(const XmlAttributeMap& attributes) {
- CHECK(interface_.signals.size())
- << " we have a signal argument but the interface has no signals";
- interface_.signals.back().arguments.push_back(
+ interfaces_.back().signals.back().arguments.push_back(
ParseArgument(attributes, kSignalTag));
}
diff --git a/chromeos-dbus-bindings/xml_interface_parser.h b/chromeos-dbus-bindings/xml_interface_parser.h
index f890806..059f1d6 100644
--- a/chromeos-dbus-bindings/xml_interface_parser.h
+++ b/chromeos-dbus-bindings/xml_interface_parser.h
@@ -31,7 +31,7 @@ class XmlInterfaceParser {
virtual ~XmlInterfaceParser() = default;
virtual bool ParseXmlInterfaceFile(const base::FilePath& interface_file);
- const Interface& interface() const { return interface_; }
+ const std::vector<Interface>& interfaces() const { return interfaces_; }
private:
friend class XmlInterfaceParserTest;
@@ -43,17 +43,31 @@ class XmlInterfaceParser {
static const char kNodeTag[];
static const char kSignalTag[];
static const char kPropertyTag[];
+ static const char kAnnotationTag[];
// XML attribute names.
static const char kNameAttribute[];
static const char kTypeAttribute[];
static const char kDirectionAttribute[];
static const char kAccessAttribute[];
+ static const char kValueAttribute[];
// XML argument directions.
static const char kArgumentDirectionIn[];
static const char kArgumentDirectionOut[];
+ // XML annotations.
+ static const char kTrue[];
+ static const char kFalse[];
+
+ static const char kMethodConst[];
+
+ static const char kMethodKind[];
+ static const char kMethodKindSimple[];
+ static const char kMethodKindNormal[];
+ static const char kMethodKindAsync[];
+ static const char kMethodKindRaw[];
+
// Element callbacks on |this| called by HandleElementStart() and
// HandleElementEnd(), respectively.
void OnOpenElement(const std::string& element_name,
@@ -78,7 +92,7 @@ class XmlInterfaceParser {
const std::string& element_type,
const std::string& element_key);
- // Calls GetValidatedElementAttribute() for for the "name" property.
+ // Calls GetValidatedElementAttribute() for the "name" property.
static std::string GetValidatedElementName(
const XmlAttributeMap& attributes,
const std::string& element_type);
@@ -97,7 +111,7 @@ class XmlInterfaceParser {
static void HandleElementEnd(void* user_data, const XML_Char* element);
// The output of the parse.
- Interface interface_;
+ std::vector<Interface> interfaces_;
// Tracks where in the element traversal our parse has taken us.
std::vector<std::string> element_path_;
diff --git a/chromeos-dbus-bindings/xml_interface_parser_unittest.cc b/chromeos-dbus-bindings/xml_interface_parser_unittest.cc
index 9c61253..7f861e3 100644
--- a/chromeos-dbus-bindings/xml_interface_parser_unittest.cc
+++ b/chromeos-dbus-bindings/xml_interface_parser_unittest.cc
@@ -12,6 +12,7 @@
#include "chromeos-dbus-bindings/interface.h"
using std::string;
+using std::vector;
using testing::Test;
namespace chromeos_dbus_bindings {
@@ -20,22 +21,25 @@ namespace {
const char kBadInterfaceFileContents0[] = "This has no resemblance to XML";
const char kBadInterfaceFileContents1[] = "<node>";
-const char kGoodInterfaceFileContents[] =
- "<node>\n"
- " <interface name=\"fi.w1.wpa_supplicant1.Interface\">\n"
- " <method name=\"Scan\">\n"
- " <arg name=\"args\" type=\"a{sv}\" direction=\"in\"/>\n"
- " </method>\n"
- " <method name=\"GetBlob\">\n"
- " <arg name=\"name\" type=\"s\"/>\n"
- " <arg name=\"data\" type=\"ay\" direction=\"out\"/>\n"
- " </method>\n"
- " <property name=\"Capabilities\" type=\"a{sv}\" access=\"read\"/>\n"
- " <signal name=\"BSSRemoved\">\n"
- " <arg name=\"BSS\" type=\"o\"/>\n"
- " </signal>\n"
- " </interface>\n"
- "</node>\n";
+const char kGoodInterfaceFileContents[] = R"literal_string(
+<node>
+ <interface name="fi.w1.wpa_supplicant1.Interface">
+ <method name="Scan">
+ <arg name="args" type="a{sv}" direction="in"/>
+ <annotation name="org.chromium.DBus.Method.Kind" value="async"/>
+ </method>
+ <method name="GetBlob">
+ <arg name="name" type="s"/>
+ <arg name="data" type="ay" direction="out"/>
+ <annotation name="org.chromium.DBus.Method.Const" value="true"/>
+ </method>
+ <property name="Capabilities" type="a{sv}" access="read"/>
+ <signal name="BSSRemoved">
+ <arg name="BSS" type="o"/>
+ </signal>
+ </interface>
+</node>
+)literal_string";
const char kInterfaceName[] = "fi.w1.wpa_supplicant1.Interface";
const char kScanMethod[] = "Scan";
const char kArgsArgument[] = "args";
@@ -77,13 +81,18 @@ TEST_F(XmlInterfaceParserTest, BadInputFile) {
TEST_F(XmlInterfaceParserTest, GoodInputFile) {
EXPECT_TRUE(ParseXmlContents(kGoodInterfaceFileContents));
- const Interface& interface = parser_.interface();
+ const vector<Interface>& interfaces = parser_.interfaces();
+ ASSERT_EQ(1, interfaces.size());
+ const Interface& interface = interfaces.back();
+
EXPECT_EQ(kInterfaceName, interface.name);
ASSERT_EQ(2, interface.methods.size());
ASSERT_EQ(1, interface.signals.size());
// <method name="Scan">
EXPECT_EQ(kScanMethod, interface.methods[0].name);
+ EXPECT_EQ(Interface::Method::Kind::kAsync, interface.methods[0].kind);
+ EXPECT_FALSE(interface.methods[0].is_const);
ASSERT_EQ(1, interface.methods[0].input_arguments.size());
// <arg name="args" type="a{sv}" direction="in"/>
@@ -94,10 +103,12 @@ TEST_F(XmlInterfaceParserTest, GoodInputFile) {
// <method name="GetBlob">
EXPECT_EQ(kGetBlobMethod, interface.methods[1].name);
+ EXPECT_EQ(Interface::Method::Kind::kNormal, interface.methods[1].kind);
+ EXPECT_TRUE(interface.methods[1].is_const);
EXPECT_EQ(1, interface.methods[1].input_arguments.size());
EXPECT_EQ(1, interface.methods[1].output_arguments.size());
- // <arg name="name" type="s"/> (direciton="in" is implicit)
+ // <arg name="name" type="s"/> (direction="in" is implicit)
EXPECT_EQ(kNameArgument, interface.methods[1].input_arguments[0].name);
EXPECT_EQ(kStringType, interface.methods[1].input_arguments[0].type);