1// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chromeos-dbus-bindings/proxy_generator.h"
6
7#include <utility>
8
9#include <base/files/file_path.h>
10#include <base/format_macros.h>
11#include <base/logging.h>
12#include <base/strings/stringprintf.h>
13#include <brillo/strings/string_utils.h>
14
15#include "chromeos-dbus-bindings/dbus_signature.h"
16#include "chromeos-dbus-bindings/indented_text.h"
17#include "chromeos-dbus-bindings/name_parser.h"
18
19using base::StringPrintf;
20using std::pair;
21using std::string;
22using std::vector;
23
24namespace chromeos_dbus_bindings {
25
26namespace {
27// Helper struct to encapsulate information about method call parameter during
28// code generation.
29struct ParamDef {
30  ParamDef(const string& param_type, const string& param_name, bool param_ref)
31      : type(param_type), name(param_name), is_const_ref(param_ref) {}
32
33  string type;
34  string name;
35  bool is_const_ref;
36};
37
38string GetParamString(const ParamDef& param_def) {
39  return StringPrintf(param_def.is_const_ref ? "const %s& %s" : "%s* %s",
40                      param_def.type.c_str(), param_def.name.c_str());
41}
42}  // anonymous namespace
43
44// static
45bool ProxyGenerator::GenerateProxies(
46    const ServiceConfig& config,
47    const std::vector<Interface>& interfaces,
48    const base::FilePath& output_file) {
49  IndentedText text;
50
51  text.AddLine("// Automatic generation of D-Bus interfaces:");
52  for (const auto& interface : interfaces) {
53    text.AddLine(StringPrintf("//  - %s", interface.name.c_str()));
54  }
55  string header_guard = GenerateHeaderGuard(output_file);
56  text.AddLine(StringPrintf("#ifndef %s", header_guard.c_str()));
57  text.AddLine(StringPrintf("#define %s", header_guard.c_str()));
58  text.AddLine("#include <memory>");
59  text.AddLine("#include <string>");
60  text.AddLine("#include <vector>");
61  text.AddBlankLine();
62  text.AddLine("#include <base/bind.h>");
63  text.AddLine("#include <base/callback.h>");
64  text.AddLine("#include <base/logging.h>");
65  text.AddLine("#include <base/macros.h>");
66  text.AddLine("#include <base/memory/ref_counted.h>");
67  text.AddLine("#include <brillo/any.h>");
68  text.AddLine("#include <brillo/dbus/dbus_method_invoker.h>");
69  text.AddLine("#include <brillo/dbus/dbus_property.h>");
70  text.AddLine("#include <brillo/dbus/dbus_signal_handler.h>");
71  text.AddLine("#include <brillo/errors/error.h>");
72  text.AddLine("#include <brillo/variant_dictionary.h>");
73  text.AddLine("#include <dbus/bus.h>");
74  text.AddLine("#include <dbus/message.h>");
75  text.AddLine("#include <dbus/object_manager.h>");
76  text.AddLine("#include <dbus/object_path.h>");
77  text.AddLine("#include <dbus/object_proxy.h>");
78  text.AddBlankLine();
79
80  if (!config.object_manager.name.empty()) {
81    // Add forward-declaration for Object Manager proxy class.
82    NameParser parser{config.object_manager.name};
83    parser.AddOpenNamespaces(&text, false);
84    text.AddLine(StringPrintf("class %s;",
85                              parser.MakeProxyName(false).c_str()));
86    parser.AddCloseNamespaces(&text, false);
87    text.AddBlankLine();
88  }
89
90  for (const auto& interface : interfaces) {
91    GenerateInterfaceProxyInterface(config, interface, &text);
92    GenerateInterfaceProxy(config, interface, &text);
93  }
94
95  ObjectManager::GenerateProxy(config, interfaces, &text);
96
97  text.AddLine(StringPrintf("#endif  // %s", header_guard.c_str()));
98  return WriteTextToFile(output_file, text);
99}
100
101// static
102bool ProxyGenerator::GenerateMocks(const ServiceConfig& config,
103                                   const std::vector<Interface>& interfaces,
104                                   const base::FilePath& mock_file,
105                                   const base::FilePath& proxy_file,
106                                   bool use_literal_proxy_file) {
107  IndentedText text;
108
109  text.AddLine("// Automatic generation of D-Bus interface mock proxies for:");
110  for (const auto& interface : interfaces) {
111    text.AddLine(StringPrintf("//  - %s", interface.name.c_str()));
112  }
113  string header_guard = GenerateHeaderGuard(mock_file);
114  text.AddLine(StringPrintf("#ifndef %s", header_guard.c_str()));
115  text.AddLine(StringPrintf("#define %s", header_guard.c_str()));
116  text.AddLine("#include <string>");
117  text.AddLine("#include <vector>");
118  text.AddBlankLine();
119  text.AddLine("#include <base/callback_forward.h>");
120  text.AddLine("#include <base/logging.h>");
121  text.AddLine("#include <base/macros.h>");
122  text.AddLine("#include <brillo/any.h>");
123  text.AddLine("#include <brillo/errors/error.h>");
124  text.AddLine("#include <brillo/variant_dictionary.h>");
125  text.AddLine("#include <gmock/gmock.h>");
126  text.AddBlankLine();
127
128  if (!proxy_file.empty()) {
129    // If we have a proxy header file, it would have the proxy interfaces we
130    // need to base our mocks on, so we need to include that header file.
131    base::FilePath relative_path;
132    if (use_literal_proxy_file) {
133      relative_path = proxy_file;
134    } else {
135      // Generate a relative path from |mock_file| to |proxy_file|.
136
137      // First, get the path components for both source and destination paths.
138      std::vector<base::FilePath::StringType> src_components;
139      mock_file.DirName().GetComponents(&src_components);
140      std::vector<base::FilePath::StringType> dest_components;
141      proxy_file.DirName().GetComponents(&dest_components);
142
143      // Find the common root.
144
145      // I wish we had C++14 and its 4-parameter version of std::mismatch()...
146      auto src_end = src_components.end();
147      if (src_components.size() > dest_components.size())
148        src_end = src_components.begin() + dest_components.size();
149
150      auto mismatch_pair = std::mismatch(src_components.begin(), src_end,
151                                         dest_components.begin());
152
153      // For each remaining components in the |src_components|, generate the
154      // parent directory references ("..").
155      size_t src_count = std::distance(mismatch_pair.first,
156                                       src_components.end());
157      std::vector<base::FilePath::StringType> components{
158          src_count, base::FilePath::kParentDirectory};
159      // Append the remaining components from |dest_components|.
160      components.insert(components.end(),
161                        mismatch_pair.second, dest_components.end());
162      // Finally, add the base name of the target file name.
163      components.push_back(proxy_file.BaseName().value());
164      // Now reconstruct the relative path.
165      relative_path = base::FilePath{base::FilePath::kCurrentDirectory};
166      for (const auto& component : components)
167        relative_path = relative_path.Append(component);
168    }
169    text.AddLine(StringPrintf("#include \"%s\"",
170                              relative_path.value().c_str()));
171    text.AddBlankLine();
172  }
173
174  for (const auto& interface : interfaces) {
175    // If we have no proxy file, we need the abstract interfaces generated here.
176    if (proxy_file.empty())
177      GenerateInterfaceProxyInterface(config, interface, &text);
178    GenerateInterfaceMock(config, interface, &text);
179  }
180
181  text.AddLine(StringPrintf("#endif  // %s", header_guard.c_str()));
182  return WriteTextToFile(mock_file, text);
183}
184
185// static
186void ProxyGenerator::GenerateInterfaceProxyInterface(
187    const ServiceConfig& config,
188    const Interface& interface,
189    IndentedText* text) {
190  NameParser parser{interface.name};
191  string proxy_name = parser.MakeProxyName(false);
192  string base_interface_name = proxy_name + "Interface";
193
194  parser.AddOpenNamespaces(text, false);
195  text->AddBlankLine();
196
197  text->AddLine(StringPrintf("// Abstract interface proxy for %s.",
198                             parser.MakeFullCppName().c_str()));
199  text->AddComments(interface.doc_string);
200  text->AddLine(StringPrintf("class %s {", base_interface_name.c_str()));
201  text->AddLineWithOffset("public:", kScopeOffset);
202  text->PushOffset(kBlockOffset);
203  text->AddLine(
204      StringPrintf("virtual ~%s() = default;", base_interface_name.c_str()));
205
206  for (const auto& method : interface.methods) {
207    AddMethodProxy(method, interface.name, true, text);
208    AddAsyncMethodProxy(method, interface.name, true, text);
209  }
210  for (const auto& signal : interface.signals) {
211    AddSignalHandlerRegistration(signal, interface.name, true, text);
212  }
213  AddProperties(config, interface, true, text);
214  text->AddBlankLine();
215  text->AddLine("virtual const dbus::ObjectPath& GetObjectPath() const = 0;");
216  if (!config.object_manager.name.empty() && !interface.properties.empty())
217    AddPropertyPublicMethods(proxy_name, true, text);
218
219  text->PopOffset();
220  text->AddLine("};");
221  text->AddBlankLine();
222
223  parser.AddCloseNamespaces(text, false);
224  text->AddBlankLine();
225}
226
227// static
228void ProxyGenerator::GenerateInterfaceProxy(const ServiceConfig& config,
229                                            const Interface& interface,
230                                            IndentedText* text) {
231  NameParser parser{interface.name};
232  string proxy_name = parser.MakeProxyName(false);
233  string base_interface_name = proxy_name + "Interface";
234
235  parser.AddOpenNamespaces(text, false);
236  text->AddBlankLine();
237
238  text->AddLine(StringPrintf("// Interface proxy for %s.",
239                             parser.MakeFullCppName().c_str()));
240  text->AddComments(interface.doc_string);
241  text->AddLine(StringPrintf("class %s final : public %s {",
242                             proxy_name.c_str(), base_interface_name.c_str()));
243  text->AddLineWithOffset("public:", kScopeOffset);
244  text->PushOffset(kBlockOffset);
245  AddPropertySet(config, interface, text);
246  AddConstructor(config, interface, proxy_name, text);
247  AddDestructor(proxy_name, text);
248  for (const auto& signal : interface.signals) {
249    AddSignalHandlerRegistration(signal, interface.name, false, text);
250  }
251  AddReleaseObjectProxy(text);
252  AddGetObjectPath(text);
253  AddGetObjectProxy(text);
254  if (!config.object_manager.name.empty() && !interface.properties.empty())
255    AddPropertyPublicMethods(proxy_name, false, text);
256  for (const auto& method : interface.methods) {
257    AddMethodProxy(method, interface.name, false, text);
258    AddAsyncMethodProxy(method, interface.name, false, text);
259  }
260  AddProperties(config, interface, false, text);
261
262  text->PopOffset();
263  text->AddBlankLine();
264  text->AddLineWithOffset("private:", kScopeOffset);
265
266  text->PushOffset(kBlockOffset);
267  if (!config.object_manager.name.empty() && !interface.properties.empty())
268    AddOnPropertyChanged(text);
269  text->AddLine("scoped_refptr<dbus::Bus> bus_;");
270  if (config.service_name.empty()) {
271    text->AddLine("std::string service_name_;");
272  } else {
273    text->AddLine(StringPrintf("const std::string service_name_{\"%s\"};",
274                               config.service_name.c_str()));
275  }
276  if (interface.path.empty()) {
277    text->AddLine("dbus::ObjectPath object_path_;");
278  } else {
279    text->AddLine(StringPrintf("const dbus::ObjectPath object_path_{\"%s\"};",
280                               interface.path.c_str()));
281  }
282  if (!config.object_manager.name.empty() && !interface.properties.empty()) {
283    text->AddLine("PropertySet* property_set_;");
284    text->AddLine(
285        StringPrintf("base::Callback<void(%sInterface*, const std::string&)> "
286                     "on_property_changed_;",
287                     proxy_name.c_str()));
288  }
289  text->AddLine("dbus::ObjectProxy* dbus_object_proxy_;");
290  text->AddBlankLine();
291
292  if (!config.object_manager.name.empty() && !interface.properties.empty()) {
293    text->AddLine(StringPrintf(
294        "friend class %s;",
295        NameParser{config.object_manager.name}.MakeProxyName(true).c_str()));
296  }
297  text->AddLine(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);",
298                             proxy_name.c_str()));
299  text->PopOffset();
300  text->AddLine("};");
301
302  text->AddBlankLine();
303
304  parser.AddCloseNamespaces(text, false);
305
306  text->AddBlankLine();
307}
308
309// static
310void ProxyGenerator::GenerateInterfaceMock(const ServiceConfig& config,
311                                           const Interface& interface,
312                                           IndentedText* text) {
313  NameParser parser{interface.name};
314  string proxy_name = parser.MakeProxyName(false);
315  string base_interface_name = proxy_name + "Interface";
316  string mock_name = proxy_name + "Mock";
317
318  parser.AddOpenNamespaces(text, false);
319  text->AddBlankLine();
320
321  text->AddLine(StringPrintf("// Mock object for %s.",
322                             base_interface_name.c_str()));
323  text->AddLine(StringPrintf("class %s : public %s {",
324                             mock_name.c_str(), base_interface_name.c_str()));
325  text->AddLineWithOffset("public:", kScopeOffset);
326  text->PushOffset(kBlockOffset);
327  text->AddLine(StringPrintf("%s() = default;", mock_name.c_str()));
328  text->AddBlankLine();
329
330  for (const auto& method : interface.methods) {
331    AddMethodMock(method, interface.name, text);
332    AddAsyncMethodMock(method, interface.name, text);
333  }
334  for (const auto& signal : interface.signals) {
335    AddSignalHandlerRegistrationMock(signal, text);
336  }
337
338  DbusSignature signature;
339  for (const auto& prop : interface.properties) {
340    string type;
341    CHECK(signature.Parse(prop.type, &type));
342    MakeConstReferenceIfNeeded(&type);
343    string name = NameParser{prop.name}.MakeVariableName();
344    text->AddLine(StringPrintf("MOCK_CONST_METHOD0(%s, %s());",
345                               name.c_str(), type.c_str()));
346    if (prop.access == "readwrite") {
347      text->AddLine(StringPrintf("MOCK_METHOD2(set_%s, void(%s, "
348                                 "const base::Callback<bool>&));",
349                                 name.c_str(), type.c_str()));
350    }
351  }
352  text->AddLine(
353      "MOCK_CONST_METHOD0(GetObjectPath, const dbus::ObjectPath&());");
354  if (!config.object_manager.name.empty() && !interface.properties.empty()) {
355    text->AddLineAndPushOffsetTo(
356        "MOCK_METHOD1(SetPropertyChangedCallback,", 1, '(');
357    text->AddLine(StringPrintf(
358        "void(const base::Callback<void(%sInterface*, const std::string&)>&));",
359        proxy_name.c_str()));
360    text->PopOffset();
361  }
362
363  text->PopOffset();
364  text->AddBlankLine();
365  text->AddLineWithOffset("private:", kScopeOffset);
366  text->AddLineWithOffset(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);",
367                                       mock_name.c_str()),
368                          kBlockOffset);
369  text->AddLine("};");
370
371  parser.AddCloseNamespaces(text, false);
372  text->AddBlankLine();
373}
374
375// static
376void ProxyGenerator::AddConstructor(const ServiceConfig& config,
377                                    const Interface& interface,
378                                    const string& class_name,
379                                    IndentedText* text) {
380  IndentedText block;
381  vector<ParamDef> args{{"scoped_refptr<dbus::Bus>", "bus", true}};
382  if (config.service_name.empty())
383    args.emplace_back("std::string", "service_name", true);
384  if (interface.path.empty())
385    args.emplace_back("dbus::ObjectPath", "object_path", true);
386  if (!config.object_manager.name.empty() && !interface.properties.empty())
387    args.emplace_back("PropertySet", "property_set", false);
388
389  if (args.size() == 1) {
390    block.AddLine(StringPrintf("%s(%s) :", class_name.c_str(),
391                               GetParamString(args.front()).c_str()));
392  } else {
393    block.AddLine(StringPrintf("%s(", class_name.c_str()));
394    block.PushOffset(kLineContinuationOffset);
395    for (size_t i = 0; i < args.size() - 1; i++) {
396      block.AddLine(StringPrintf("%s,", GetParamString(args[i]).c_str()));
397    }
398    block.AddLine(StringPrintf("%s) :", GetParamString(args.back()).c_str()));
399  }
400  block.PushOffset(kLineContinuationOffset);
401  for (const auto& arg : args) {
402    block.AddLine(StringPrintf("%s_{%s},", arg.name.c_str(),
403                               arg.name.c_str()));
404  }
405  block.AddLine("dbus_object_proxy_{");
406  block.AddLineWithOffset(
407      "bus_->GetObjectProxy(service_name_, object_path_)} {",
408      kLineContinuationOffset);
409  block.PopOffset();
410  if (args.size() > 1)
411    block.PopOffset();
412  block.AddLine("}");
413  block.AddBlankLine();
414  text->AddBlock(block);
415}
416
417// static
418void ProxyGenerator::AddDestructor(const string& class_name,
419                                   IndentedText* text) {
420  IndentedText block;
421  block.AddLine(StringPrintf("~%s() override {", class_name.c_str()));
422  block.AddLine("}");
423  text->AddBlock(block);
424}
425
426// static
427void ProxyGenerator::AddReleaseObjectProxy(IndentedText* text) {
428  text->AddBlankLine();
429  text->AddLine("void ReleaseObjectProxy(const base::Closure& callback) {");
430  text->AddLineWithOffset(
431      "bus_->RemoveObjectProxy(service_name_, object_path_, callback);",
432      kBlockOffset);
433  text->AddLine("}");
434}
435
436// static
437void ProxyGenerator::AddGetObjectPath(IndentedText* text) {
438  text->AddBlankLine();
439  text->AddLine("const dbus::ObjectPath& GetObjectPath() const override {");
440  text->AddLineWithOffset("return object_path_;", kBlockOffset);
441  text->AddLine("}");
442}
443
444// static
445void ProxyGenerator::AddGetObjectProxy(IndentedText* text) {
446  text->AddBlankLine();
447  text->AddLine("dbus::ObjectProxy* GetObjectProxy() const { "
448                "return dbus_object_proxy_; }");
449}
450
451// static
452void ProxyGenerator::AddPropertyPublicMethods(const string& class_name,
453                                              bool declaration_only,
454                                              IndentedText* text) {
455  text->AddBlankLine();
456  text->AddLine(StringPrintf("%svoid SetPropertyChangedCallback(",
457                             declaration_only ? "virtual " : ""));
458  text->AddLineWithOffset(
459      StringPrintf("const base::Callback<void(%sInterface*, "
460                   "const std::string&)>& callback) %s",
461                   class_name.c_str(),
462                   declaration_only ? "= 0;" : "override {"),
463      kLineContinuationOffset);
464  if (!declaration_only) {
465    text->AddLineWithOffset("on_property_changed_ = callback;", kBlockOffset);
466    text->AddLine("}");
467    text->AddBlankLine();
468
469    text->AddLine(
470        "const PropertySet* GetProperties() const { return property_set_; }");
471    text->AddLine("PropertySet* GetProperties() { return property_set_; }");
472  }
473}
474
475// static
476void ProxyGenerator::AddOnPropertyChanged(IndentedText* text) {
477  text->AddLine("void OnPropertyChanged(const std::string& property_name) {");
478  text->PushOffset(kBlockOffset);
479  text->AddLine("if (!on_property_changed_.is_null())");
480  text->PushOffset(kBlockOffset);
481  text->AddLine("on_property_changed_.Run(this, property_name);");
482  text->PopOffset();
483  text->PopOffset();
484  text->AddLine("}");
485  text->AddBlankLine();
486}
487
488void ProxyGenerator::AddSignalHandlerRegistration(
489      const Interface::Signal& signal,
490      const string& interface_name,
491      bool declaration_only,
492      IndentedText* text) {
493  IndentedText block;
494  block.AddBlankLine();
495  block.AddLine(StringPrintf("%svoid Register%sSignalHandler(",
496                             declaration_only ? "virtual " : "",
497                             signal.name.c_str()));
498  block.PushOffset(kLineContinuationOffset);
499  AddSignalCallbackArg(signal, false, &block);
500  block.AddLine(StringPrintf(
501      "dbus::ObjectProxy::OnConnectedCallback on_connected_callback)%s",
502      declaration_only ? " = 0;" : " override {"));
503  if (!declaration_only) {
504    block.PopOffset();  // Method signature arguments
505    block.PushOffset(kBlockOffset);
506    block.AddLine("brillo::dbus_utils::ConnectToSignal(");
507    block.PushOffset(kLineContinuationOffset);
508    block.AddLine("dbus_object_proxy_,");
509    block.AddLine(StringPrintf("\"%s\",", interface_name.c_str()));
510    block.AddLine(StringPrintf("\"%s\",", signal.name.c_str()));
511    block.AddLine("signal_callback,");
512    block.AddLine("on_connected_callback);");
513    block.PopOffset();  // Function call line continuation
514    block.PopOffset();  // Method body
515    block.AddLine("}");
516  }
517  text->AddBlock(block);
518}
519
520// static
521void ProxyGenerator::AddPropertySet(const ServiceConfig& config,
522                                    const Interface& interface,
523                                    IndentedText* text) {
524  // Must have ObjectManager in order for property system to work correctly.
525  if (config.object_manager.name.empty())
526    return;
527
528  IndentedText block;
529  block.AddLine("class PropertySet : public dbus::PropertySet {");
530  block.AddLineWithOffset("public:", kScopeOffset);
531  block.PushOffset(kBlockOffset);
532  block.AddLineAndPushOffsetTo("PropertySet(dbus::ObjectProxy* object_proxy,",
533                               1, '(');
534  block.AddLine("const PropertyChangedCallback& callback)");
535  block.PopOffset();
536  block.PushOffset(kLineContinuationOffset);
537  block.AddLineAndPushOffsetTo(": dbus::PropertySet{object_proxy,", 1, '{');
538  block.AddLine(StringPrintf("\"%s\",", interface.name.c_str()));
539  block.AddLine("callback} {");
540  block.PopOffset();
541  block.PopOffset();
542  block.PushOffset(kBlockOffset);
543  for (const auto& prop : interface.properties) {
544    block.AddLine(
545        StringPrintf("RegisterProperty(%sName(), &%s);",
546                     prop.name.c_str(),
547                     NameParser{prop.name}.MakeVariableName().c_str()));
548  }
549  block.PopOffset();
550  block.AddLine("}");
551  block.AddBlankLine();
552
553  DbusSignature signature;
554  for (const auto& prop : interface.properties) {
555    string type;
556    CHECK(signature.Parse(prop.type, &type));
557    block.AddLine(
558        StringPrintf("brillo::dbus_utils::Property<%s> %s;",
559                     type.c_str(),
560                     NameParser{prop.name}.MakeVariableName().c_str()));
561  }
562  block.AddBlankLine();
563
564  block.PopOffset();
565  block.AddLineWithOffset("private:", kScopeOffset);
566  block.AddLineWithOffset("DISALLOW_COPY_AND_ASSIGN(PropertySet);",
567                          kBlockOffset);
568  block.AddLine("};");
569  block.AddBlankLine();
570
571  text->AddBlock(block);
572}
573
574// static
575void ProxyGenerator::AddProperties(const ServiceConfig& config,
576                                   const Interface& interface,
577                                   bool declaration_only,
578                                   IndentedText* text) {
579  // Must have ObjectManager in order for property system to work correctly.
580  if (config.object_manager.name.empty())
581    return;
582
583  if (declaration_only && !interface.properties.empty())
584    text->AddBlankLine();
585
586  DbusSignature signature;
587  for (const auto& prop : interface.properties) {
588    if (declaration_only) {
589      text->AddLine(
590          StringPrintf("static const char* %sName() { return \"%s\"; }",
591                       prop.name.c_str(),
592                       prop.name.c_str()));
593    }
594    string type;
595    CHECK(signature.Parse(prop.type, &type));
596    MakeConstReferenceIfNeeded(&type);
597    string name = NameParser{prop.name}.MakeVariableName();
598    if (!declaration_only)
599      text->AddBlankLine();
600    text->AddLine(
601        StringPrintf("%s%s %s() const%s",
602                     declaration_only ? "virtual " : "",
603                     type.c_str(),
604                     name.c_str(),
605                     declaration_only ? " = 0;" : " override {"));
606    if (!declaration_only) {
607      text->AddLineWithOffset(
608          StringPrintf("return property_set_->%s.value();", name.c_str()),
609          kBlockOffset);
610      text->AddLine("}");
611    }
612    if (prop.access == "readwrite") {
613      if (!declaration_only)
614        text->AddBlankLine();
615      text->AddLineAndPushOffsetTo(
616          StringPrintf("%svoid set_%s(%s value,",
617                       declaration_only ? "virtual " : "",
618                       name.c_str(),
619                       type.c_str()),
620          1, '(');
621      text->AddLine(
622          StringPrintf("const base::Callback<void(bool)>& callback)%s",
623                       declaration_only ? " = 0;" : " override {"));
624      text->PopOffset();
625      if (!declaration_only) {
626        text->AddLineWithOffset(
627            StringPrintf("property_set_->%s.Set(value, callback);", name.c_str()),
628            kBlockOffset);
629        text->AddLine("}");
630      }
631    }
632  }
633}
634
635// static
636void ProxyGenerator::AddMethodProxy(const Interface::Method& method,
637                                    const string& interface_name,
638                                    bool declaration_only,
639                                    IndentedText* text) {
640  IndentedText block;
641  DbusSignature signature;
642  block.AddBlankLine();
643  block.AddComments(method.doc_string);
644  block.AddLine(StringPrintf("%sbool %s(",
645                             declaration_only ? "virtual " : "",
646                             method.name.c_str()));
647  block.PushOffset(kLineContinuationOffset);
648  vector<string> argument_names;
649  int argument_number = 0;
650  for (const auto& argument : method.input_arguments) {
651    string argument_type;
652    CHECK(signature.Parse(argument.type, &argument_type));
653    MakeConstReferenceIfNeeded(&argument_type);
654    string argument_name = GetArgName("in", argument.name, ++argument_number);
655    argument_names.push_back(argument_name);
656    block.AddLine(StringPrintf(
657        "%s %s,", argument_type.c_str(), argument_name.c_str()));
658  }
659  vector<string> out_param_names{"response.get()", "error"};
660  for (const auto& argument : method.output_arguments) {
661    string argument_type;
662    CHECK(signature.Parse(argument.type, &argument_type));
663    string argument_name = GetArgName("out", argument.name, ++argument_number);
664    out_param_names.push_back(argument_name);
665    block.AddLine(StringPrintf(
666        "%s* %s,", argument_type.c_str(), argument_name.c_str()));
667  }
668  block.AddLine("brillo::ErrorPtr* error,");
669  block.AddLine(
670      StringPrintf("int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)%s",
671                   declaration_only ? " = 0;" : " override {"));
672  block.PopOffset();
673  if (!declaration_only) {
674    block.PushOffset(kBlockOffset);
675
676    block.AddLine(
677        "auto response = brillo::dbus_utils::CallMethodAndBlockWithTimeout(");
678    block.PushOffset(kLineContinuationOffset);
679    block.AddLine("timeout_ms,");
680    block.AddLine("dbus_object_proxy_,");
681    block.AddLine(StringPrintf("\"%s\",", interface_name.c_str()));
682    block.AddLine(StringPrintf("\"%s\",", method.name.c_str()));
683    string last_argument = "error";
684    for (const auto& argument_name : argument_names) {
685      block.AddLine(StringPrintf("%s,", last_argument.c_str()));
686      last_argument = argument_name;
687    }
688    block.AddLine(StringPrintf("%s);", last_argument.c_str()));
689    block.PopOffset();
690
691    block.AddLine("return response && "
692                  "brillo::dbus_utils::ExtractMethodCallResults(");
693    block.PushOffset(kLineContinuationOffset);
694    block.AddLine(brillo::string_utils::Join(", ", out_param_names) + ");");
695    block.PopOffset();
696    block.PopOffset();
697    block.AddLine("}");
698  }
699  text->AddBlock(block);
700}
701
702// static
703void ProxyGenerator::AddAsyncMethodProxy(const Interface::Method& method,
704                                         const string& interface_name,
705                                         bool declaration_only,
706                                         IndentedText* text) {
707  IndentedText block;
708  DbusSignature signature;
709  block.AddBlankLine();
710  block.AddComments(method.doc_string);
711  block.AddLine(StringPrintf("%svoid %sAsync(",
712                             declaration_only ? "virtual " : "",
713                             method.name.c_str()));
714  block.PushOffset(kLineContinuationOffset);
715  vector<string> argument_names;
716  int argument_number = 0;
717  for (const auto& argument : method.input_arguments) {
718    string argument_type;
719    CHECK(signature.Parse(argument.type, &argument_type));
720    MakeConstReferenceIfNeeded(&argument_type);
721    string argument_name = GetArgName("in", argument.name, ++argument_number);
722    argument_names.push_back(argument_name);
723    block.AddLine(StringPrintf(
724        "%s %s,", argument_type.c_str(), argument_name.c_str()));
725  }
726  vector<string> out_params;
727  for (const auto& argument : method.output_arguments) {
728    string argument_type;
729    CHECK(signature.Parse(argument.type, &argument_type));
730    MakeConstReferenceIfNeeded(&argument_type);
731    if (!argument.name.empty())
732      base::StringAppendF(&argument_type, " /*%s*/", argument.name.c_str());
733    out_params.push_back(argument_type);
734  }
735  block.AddLine(StringPrintf(
736      "const base::Callback<void(%s)>& success_callback,",
737      brillo::string_utils::Join(", ", out_params).c_str()));
738  block.AddLine(
739      "const base::Callback<void(brillo::Error*)>& error_callback,");
740  block.AddLine(
741      StringPrintf("int timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)%s",
742                   declaration_only ? " = 0;" : " override {"));
743  block.PopOffset();
744  if (!declaration_only) {
745    block.PushOffset(kBlockOffset);
746
747    block.AddLine("brillo::dbus_utils::CallMethodWithTimeout(");
748    block.PushOffset(kLineContinuationOffset);
749    block.AddLine("timeout_ms,");
750    block.AddLine("dbus_object_proxy_,");
751    block.AddLine(StringPrintf("\"%s\",", interface_name.c_str()));
752    block.AddLine(StringPrintf("\"%s\",", method.name.c_str()));
753    block.AddLine("success_callback,");
754    string last_argument = "error_callback";
755    for (const auto& argument_name : argument_names) {
756      block.AddLine(StringPrintf("%s,", last_argument.c_str()));
757      last_argument = argument_name;
758    }
759    block.AddLine(StringPrintf("%s);", last_argument.c_str()));
760    block.PopOffset();
761
762    block.PopOffset();
763    block.AddLine("}");
764  }
765  text->AddBlock(block);
766}
767
768// static
769void ProxyGenerator::AddMethodMock(const Interface::Method& method,
770                                   const string& /* interface_name */,
771                                   IndentedText* text) {
772  DbusSignature signature;
773  vector<string> arguments;
774  for (const auto& argument : method.input_arguments) {
775    string argument_type;
776    CHECK(signature.Parse(argument.type, &argument_type));
777    MakeConstReferenceIfNeeded(&argument_type);
778    if (!argument.name.empty())
779      base::StringAppendF(&argument_type, " /*in_%s*/", argument.name.c_str());
780    arguments.push_back(argument_type);
781  }
782  for (const auto& argument : method.output_arguments) {
783    string argument_type;
784    CHECK(signature.Parse(argument.type, &argument_type));
785    argument_type += '*';
786    if (!argument.name.empty())
787      base::StringAppendF(&argument_type, " /*out_%s*/", argument.name.c_str());
788    arguments.push_back(argument_type);
789  }
790  arguments.push_back("brillo::ErrorPtr* /*error*/");
791  arguments.push_back("int /*timeout_ms*/");
792  AddMockMethodDeclaration(method.name, "bool", arguments, text);
793}
794
795// static
796void ProxyGenerator::AddAsyncMethodMock(const Interface::Method& method,
797                                        const string& /* interface_name */,
798                                        IndentedText* text) {
799  DbusSignature signature;
800  vector<string> arguments;
801  for (const auto& argument : method.input_arguments) {
802    string argument_type;
803    CHECK(signature.Parse(argument.type, &argument_type));
804    MakeConstReferenceIfNeeded(&argument_type);
805    if (!argument.name.empty())
806      base::StringAppendF(&argument_type, " /*in_%s*/", argument.name.c_str());
807    arguments.push_back(argument_type);
808  }
809  vector<string> out_params;
810  for (const auto& argument : method.output_arguments) {
811    string argument_type;
812    CHECK(signature.Parse(argument.type, &argument_type));
813    MakeConstReferenceIfNeeded(&argument_type);
814    if (!argument.name.empty())
815      base::StringAppendF(&argument_type, " /*%s*/", argument.name.c_str());
816    out_params.push_back(argument_type);
817  }
818  arguments.push_back(StringPrintf(
819      "const base::Callback<void(%s)>& /*success_callback*/",
820      brillo::string_utils::Join(", ", out_params).c_str()));
821  arguments.push_back(
822      "const base::Callback<void(brillo::Error*)>& /*error_callback*/");
823  arguments.push_back("int /*timeout_ms*/");
824  AddMockMethodDeclaration(method.name + "Async", "void", arguments, text);
825}
826
827void ProxyGenerator::AddMockMethodDeclaration(const string& method_name,
828                                              const string& return_type,
829                                              const vector<string>& arguments,
830                                              IndentedText* text) {
831  IndentedText block;
832  // GMOCK doesn't go all the way up to 11, so we need to handle methods with
833  // 11 arguments or more in a different way.
834  if (arguments.size() >= 11) {
835    block.AddLineAndPushOffsetTo(
836        StringPrintf("%s %s(%s,",
837                     return_type.c_str(),
838                     method_name.c_str(),
839                     arguments.front().c_str()),
840        1, '(');
841    for (size_t i = 1; i < arguments.size() - 1; i++)
842      block.AddLine(StringPrintf("%s,", arguments[i].c_str()));
843    block.AddLine(StringPrintf("%s) override {", arguments.back().c_str()));
844    block.PopOffset();
845    block.PushOffset(kBlockOffset);
846    block.AddLine(StringPrintf(
847        "LOG(WARNING) << \"%s(): gmock can't handle methods with %" PRIuS
848        " arguments. You can override this method in a subclass if you need"
849        " to.\";",
850        method_name.c_str(), arguments.size()));
851    if (return_type == "void") {
852      // No return added here.
853    } else if (return_type == "bool") {
854      block.AddLine("return false;");
855    } else {
856      LOG(FATAL) << "The return type is not supported.";
857    }
858    block.PopOffset();
859    block.AddLine("}");
860  } else {
861    block.AddLineAndPushOffsetTo(
862        StringPrintf("MOCK_METHOD%zu(%s,",
863                     arguments.size(), method_name.c_str()),
864        1, '(');
865    block.AddLineAndPushOffsetTo(
866        StringPrintf("%s(%s,", return_type.c_str(), arguments.front().c_str()),
867        1, '(');
868    for (size_t i = 1; i < arguments.size() - 1; i++)
869      block.AddLine(StringPrintf("%s,", arguments[i].c_str()));
870    block.AddLine(StringPrintf("%s));", arguments.back().c_str()));
871    block.PopOffset();
872    block.PopOffset();
873  }
874  text->AddBlock(block);
875}
876
877// static
878void ProxyGenerator::AddSignalHandlerRegistrationMock(
879    const Interface::Signal& signal,
880    IndentedText* text) {
881  IndentedText callback_arg_text;
882  AddSignalCallbackArg(signal, true, &callback_arg_text);
883  vector<string> arg_lines = callback_arg_text.GetLines();
884
885  IndentedText block;
886  block.AddLineAndPushOffsetTo(
887      StringPrintf("MOCK_METHOD2(Register%sSignalHandler,",
888                   signal.name.c_str()),
889      1, '(');
890  for (size_t i = 0; i < arg_lines.size(); ++i) {
891    if (i == 0)
892      block.AddLineAndPushOffsetTo("void(" + arg_lines[i], 1, '(');
893    else
894      block.AddLine(arg_lines[i]);
895  }
896  block.AddLine(
897      "dbus::ObjectProxy::OnConnectedCallback /*on_connected_callback*/));");
898  text->AddBlock(block);
899}
900
901// static
902void ProxyGenerator::AddSignalCallbackArg(const Interface::Signal& signal,
903                                          bool comment_arg_name,
904                                          IndentedText* block) {
905  DbusSignature signature;
906  string signal_callback = StringPrintf("%ssignal_callback%s",
907                                        comment_arg_name ? "/*" : "",
908                                        comment_arg_name ? "*/" : "");
909  if (signal.arguments.empty()) {
910    block->AddLine(StringPrintf("const base::Closure& %s,",
911                                signal_callback.c_str()));
912  } else {
913    string last_argument;
914    string prefix{"const base::Callback<void("};
915    for (const auto argument : signal.arguments) {
916      if (!last_argument.empty()) {
917        if (!prefix.empty()) {
918          block->AddLineAndPushOffsetTo(
919              StringPrintf("%s%s,", prefix.c_str(), last_argument.c_str()),
920              1, '(');
921          prefix.clear();
922        } else {
923          block->AddLine(StringPrintf("%s,", last_argument.c_str()));
924        }
925      }
926      CHECK(signature.Parse(argument.type, &last_argument));
927      MakeConstReferenceIfNeeded(&last_argument);
928    }
929    block->AddLine(StringPrintf("%s%s)>& %s,",
930                                prefix.c_str(),
931                                last_argument.c_str(),
932                                signal_callback.c_str()));
933    if (prefix.empty()) {
934      block->PopOffset();
935    }
936  }
937}
938
939// static
940void ProxyGenerator::ObjectManager::GenerateProxy(
941    const ServiceConfig& config,
942    const std::vector<Interface>& interfaces,
943    IndentedText* text) {
944  if (config.object_manager.name.empty())
945    return;
946
947  NameParser object_manager{config.object_manager.name};
948  object_manager.AddOpenNamespaces(text, false);
949  text->AddBlankLine();
950
951  string class_name = object_manager.type_name + "Proxy";
952  text->AddLine(StringPrintf("class %s : "
953                             "public dbus::ObjectManager::Interface {",
954                             class_name.c_str()));
955  text->AddLineWithOffset("public:", kScopeOffset);
956  text->PushOffset(kBlockOffset);
957
958  AddConstructor(config, class_name, interfaces, text);
959  AddDestructor(class_name, interfaces, text);
960  AddGetObjectManagerProxy(text);
961  for (const auto& itf : interfaces) {
962    AddInterfaceAccessors(itf, text);
963  }
964  text->PopOffset();
965
966  text->AddLineWithOffset("private:", kScopeOffset);
967  text->PushOffset(kBlockOffset);
968  AddOnPropertyChanged(interfaces, text);
969  AddObjectAdded(config, interfaces, text);
970  AddObjectRemoved(interfaces, text);
971  AddCreateProperties(interfaces, class_name, text);
972  AddDataMembers(config, interfaces, class_name, text);
973
974  text->AddLine(StringPrintf("DISALLOW_COPY_AND_ASSIGN(%s);",
975                              class_name.c_str()));
976  text->PopOffset();
977  text->AddLine("};");
978  text->AddBlankLine();
979  object_manager.AddCloseNamespaces(text, false);
980  text->AddBlankLine();
981}
982
983void ProxyGenerator::ObjectManager::AddConstructor(
984    const ServiceConfig& config,
985    const std::string& class_name,
986    const std::vector<Interface>& interfaces,
987    IndentedText* text) {
988  if (config.service_name.empty()) {
989    text->AddLineAndPushOffsetTo(
990        StringPrintf("%s(const scoped_refptr<dbus::Bus>& bus,",
991                     class_name.c_str()),
992        1, '(');
993    text->AddLine("const std::string& service_name)");
994    text->PopOffset();
995  } else {
996    text->AddLine(StringPrintf("%s(const scoped_refptr<dbus::Bus>& bus)",
997                               class_name.c_str()));
998  }
999  text->PushOffset(kLineContinuationOffset);
1000  text->AddLine(": bus_{bus},");
1001  text->PushOffset(kBlockOffset);
1002  if (config.service_name.empty()) {
1003    text->AddLine("service_name_{service_name},");
1004  }
1005  text->AddLine("dbus_object_manager_{bus->GetObjectManager(");
1006  text->PushOffset(kLineContinuationOffset);
1007  if (config.service_name.empty()) {
1008    text->AddLine("service_name,");
1009  } else {
1010    text->AddLine(StringPrintf("\"%s\",", config.service_name.c_str()));
1011  }
1012  text->AddLine(StringPrintf("dbus::ObjectPath{\"%s\"})} {",
1013                             config.object_manager.object_path.c_str()));
1014  text->PopOffset();
1015  text->PopOffset();
1016  text->PopOffset();
1017  text->PushOffset(kBlockOffset);
1018  for (const auto& itf : interfaces) {
1019    text->AddLine(
1020        StringPrintf("dbus_object_manager_->RegisterInterface(\"%s\", this);",
1021                     itf.name.c_str()));
1022  }
1023  text->PopOffset();
1024  text->AddLine("}");
1025  text->AddBlankLine();
1026}
1027
1028void ProxyGenerator::ObjectManager::AddDestructor(
1029    const std::string& class_name,
1030    const std::vector<Interface>& interfaces,
1031    IndentedText* text) {
1032  text->AddLine(StringPrintf("~%s() override {", class_name.c_str()));
1033  text->PushOffset(kBlockOffset);
1034  for (const auto& itf : interfaces) {
1035    text->AddLine(
1036        StringPrintf("dbus_object_manager_->UnregisterInterface(\"%s\");",
1037                     itf.name.c_str()));
1038  }
1039  text->PopOffset();
1040  text->AddLine("}");
1041  text->AddBlankLine();
1042}
1043
1044void ProxyGenerator::ObjectManager::AddGetObjectManagerProxy(
1045    IndentedText* text) {
1046  text->AddLine("dbus::ObjectManager* GetObjectManagerProxy() const {");
1047  text->AddLineWithOffset("return dbus_object_manager_;", kBlockOffset);
1048  text->AddLine("}");
1049  text->AddBlankLine();
1050}
1051
1052void ProxyGenerator::ObjectManager::AddInterfaceAccessors(
1053    const Interface& interface,
1054    IndentedText* text) {
1055  NameParser itf_name{interface.name};
1056  string map_name = itf_name.MakeVariableName() + "_instances_";
1057
1058  // GetProxy().
1059  if (interface.path.empty()) {
1060    // We have no fixed path, so there could be multiple instances of this itf.
1061    text->AddLine(StringPrintf("%sInterface* Get%s(",
1062                                itf_name.MakeProxyName(true).c_str(),
1063                                itf_name.MakeProxyName(false).c_str()));
1064    text->PushOffset(kLineContinuationOffset);
1065    text->AddLine("const dbus::ObjectPath& object_path) {");
1066    text->PopOffset();
1067    text->PushOffset(kBlockOffset);
1068    text->AddLine(StringPrintf("auto p = %s.find(object_path);",
1069                                map_name.c_str()));
1070    text->AddLine(StringPrintf("if (p != %s.end())", map_name.c_str()));
1071    text->PushOffset(kBlockOffset);
1072    text->AddLine("return p->second.get();");
1073    text->PopOffset();
1074    text->AddLine("return nullptr;");
1075    text->PopOffset();
1076    text->AddLine("}");
1077  } else {
1078    // We have a fixed path, so the object could be considered a "singleton".
1079    // Skip the object_path parameter and return the first available instance.
1080    text->AddLine(StringPrintf("%sInterface* Get%s() {",
1081                                itf_name.MakeProxyName(true).c_str(),
1082                                itf_name.MakeProxyName(false).c_str()));
1083    text->PushOffset(kBlockOffset);
1084    text->AddLine(StringPrintf("if (%s.empty())", map_name.c_str()));
1085    text->AddLineWithOffset("return nullptr;", kBlockOffset);
1086    text->AddLine(StringPrintf("return %s.begin()->second.get();",
1087                               map_name.c_str()));
1088    text->PopOffset();
1089    text->AddLine("}");
1090  }
1091
1092  // GetInstances().
1093  text->AddLine(
1094      StringPrintf("std::vector<%sInterface*> Get%sInstances() const {",
1095                   itf_name.MakeProxyName(true).c_str(),
1096                   itf_name.type_name.c_str()));
1097  text->PushOffset(kBlockOffset);
1098  text->AddLine(StringPrintf("std::vector<%sInterface*> values;",
1099                             itf_name.MakeProxyName(true).c_str()));
1100  text->AddLine(StringPrintf("values.reserve(%s.size());", map_name.c_str()));
1101  text->AddLine(StringPrintf("for (const auto& pair : %s)", map_name.c_str()));
1102  text->AddLineWithOffset("values.push_back(pair.second.get());", kBlockOffset);
1103  text->AddLine("return values;");
1104  text->PopOffset();
1105  text->AddLine("}");
1106
1107  // SetAddedCallback().
1108  text->AddLine(StringPrintf("void Set%sAddedCallback(",
1109                              itf_name.type_name.c_str()));
1110  text->PushOffset(kLineContinuationOffset);
1111  text->AddLine(
1112      StringPrintf("const base::Callback<void(%sInterface*)>& callback) {",
1113                   itf_name.MakeProxyName(true).c_str()));
1114  text->PopOffset();
1115  text->PushOffset(kBlockOffset);
1116  text->AddLine(StringPrintf("on_%s_added_ = callback;",
1117                             itf_name.MakeVariableName().c_str()));
1118  text->PopOffset();
1119  text->AddLine("}");
1120
1121  // SetRemovedCallback().
1122  text->AddLine(StringPrintf("void Set%sRemovedCallback(",
1123                             itf_name.type_name.c_str()));
1124  text->PushOffset(kLineContinuationOffset);
1125  text->AddLine("const base::Callback<void(const dbus::ObjectPath&)>& "
1126                "callback) {");
1127  text->PopOffset();
1128  text->PushOffset(kBlockOffset);
1129  text->AddLine(StringPrintf("on_%s_removed_ = callback;",
1130                              itf_name.MakeVariableName().c_str()));
1131  text->PopOffset();
1132  text->AddLine("}");
1133
1134  text->AddBlankLine();
1135}
1136
1137void ProxyGenerator::ObjectManager::AddOnPropertyChanged(
1138    const std::vector<Interface>& interfaces,
1139    IndentedText* text) {
1140  // If there are no interfaces with properties, comment out parameter
1141  // names for OnPropertyChanged() to prevent compiler warnings on unused
1142  // function parameters.
1143  auto has_props = [](const Interface& itf) { return !itf.properties.empty(); };
1144  auto itf_with_props = std::find_if(interfaces.begin(), interfaces.end(),
1145                                     has_props);
1146  if (itf_with_props == interfaces.end()) {
1147    text->AddLineAndPushOffsetTo("void OnPropertyChanged("
1148                                 "const dbus::ObjectPath& /* object_path */,",
1149                                 1, '(');
1150    text->AddLine("const std::string& /* interface_name */,");
1151    text->AddLine("const std::string& /* property_name */) {}");
1152    text->PopOffset();
1153    text->AddBlankLine();
1154    return;
1155  }
1156  text->AddLineAndPushOffsetTo("void OnPropertyChanged("
1157                               "const dbus::ObjectPath& object_path,",
1158                               1, '(');
1159  text->AddLine("const std::string& interface_name,");
1160  text->AddLine("const std::string& property_name) {");
1161  text->PopOffset();
1162  text->PushOffset(kBlockOffset);
1163  for (const auto& itf : interfaces) {
1164    if (itf.properties.empty())
1165      continue;
1166
1167    NameParser itf_name{itf.name};
1168    text->AddLine(StringPrintf("if (interface_name == \"%s\") {",
1169                               itf.name.c_str()));
1170    text->PushOffset(kBlockOffset);
1171    string map_name = itf_name.MakeVariableName() + "_instances_";
1172    text->AddLine(StringPrintf("auto p = %s.find(object_path);",
1173                               map_name.c_str()));
1174    text->AddLine(StringPrintf("if (p == %s.end())", map_name.c_str()));
1175    text->PushOffset(kBlockOffset);
1176    text->AddLine("return;");
1177    text->PopOffset();
1178    text->AddLine("p->second->OnPropertyChanged(property_name);");
1179    text->AddLine("return;");
1180    text->PopOffset();
1181    text->AddLine("}");
1182  }
1183  text->PopOffset();
1184  text->AddLine("}");
1185  text->AddBlankLine();
1186}
1187
1188void ProxyGenerator::ObjectManager::AddObjectAdded(
1189    const ServiceConfig& config,
1190    const std::vector<Interface>& interfaces,
1191    IndentedText* text) {
1192  text->AddLine("void ObjectAdded(");
1193  text->PushOffset(kLineContinuationOffset);
1194  text->AddLine("const dbus::ObjectPath& object_path,");
1195  text->AddLine("const std::string& interface_name) override {");
1196  text->PopOffset();
1197  text->PushOffset(kBlockOffset);
1198  for (const auto& itf : interfaces) {
1199    NameParser itf_name{itf.name};
1200    string var_name = itf_name.MakeVariableName();
1201    text->AddLine(StringPrintf("if (interface_name == \"%s\") {",
1202                               itf.name.c_str()));
1203    text->PushOffset(kBlockOffset);
1204    if (!itf.properties.empty()) {
1205      text->AddLine("auto property_set =");
1206      text->PushOffset(kLineContinuationOffset);
1207      text->AddLine(StringPrintf("static_cast<%s::PropertySet*>(",
1208                                 itf_name.MakeProxyName(true).c_str()));
1209      text->PushOffset(kLineContinuationOffset);
1210      text->AddLine("dbus_object_manager_->GetProperties(object_path, "
1211                    "interface_name));");
1212      text->PopOffset();
1213      text->PopOffset();
1214    }
1215    text->AddLine(StringPrintf("std::unique_ptr<%s> %s_proxy{",
1216                               itf_name.MakeProxyName(true).c_str(),
1217                               var_name.c_str()));
1218    text->PushOffset(kBlockOffset);
1219    string new_instance = StringPrintf("new %s{bus_",
1220                                       itf_name.MakeProxyName(true).c_str());
1221    if (config.service_name.empty()) {
1222      new_instance += ", service_name_";
1223    }
1224    if (itf.path.empty())
1225      new_instance += ", object_path";
1226    if (!itf.properties.empty())
1227      new_instance += ", property_set";
1228    new_instance += "}";
1229    text->AddLine(new_instance);
1230    text->PopOffset();
1231    text->AddLine("};");
1232    text->AddLine(StringPrintf("auto p = %s_instances_.emplace(object_path, "
1233                               "std::move(%s_proxy));",
1234                               var_name.c_str(), var_name.c_str()));
1235    text->AddLine(StringPrintf("if (!on_%s_added_.is_null())",
1236                               var_name.c_str()));
1237    text->PushOffset(kBlockOffset);
1238    text->AddLine(StringPrintf("on_%s_added_.Run(p.first->second.get());",
1239                               var_name.c_str()));
1240    text->PopOffset();
1241    text->AddLine("return;");
1242    text->PopOffset();
1243    text->AddLine("}");
1244  }
1245  text->PopOffset();
1246  text->AddLine("}");
1247  text->AddBlankLine();
1248}
1249
1250void ProxyGenerator::ObjectManager::AddObjectRemoved(
1251    const std::vector<Interface>& interfaces,
1252    IndentedText* text) {
1253  text->AddLine("void ObjectRemoved(");
1254  text->PushOffset(kLineContinuationOffset);
1255  text->AddLine("const dbus::ObjectPath& object_path,");
1256  text->AddLine("const std::string& interface_name) override {");
1257  text->PopOffset();
1258  text->PushOffset(kBlockOffset);
1259  for (const auto& itf : interfaces) {
1260    NameParser itf_name{itf.name};
1261    string var_name = itf_name.MakeVariableName();
1262    text->AddLine(StringPrintf("if (interface_name == \"%s\") {",
1263                               itf.name.c_str()));
1264    text->PushOffset(kBlockOffset);
1265    text->AddLine(StringPrintf("auto p = %s_instances_.find(object_path);",
1266                               var_name.c_str()));
1267    text->AddLine(StringPrintf("if (p != %s_instances_.end()) {",
1268                               var_name.c_str()));
1269    text->PushOffset(kBlockOffset);
1270    text->AddLine(StringPrintf("if (!on_%s_removed_.is_null())",
1271                               var_name.c_str()));
1272    text->PushOffset(kBlockOffset);
1273    text->AddLine(StringPrintf("on_%s_removed_.Run(object_path);",
1274                               var_name.c_str()));
1275    text->PopOffset();
1276    text->AddLine(StringPrintf("%s_instances_.erase(p);",
1277                               var_name.c_str()));
1278    text->PopOffset();
1279    text->AddLine("}");
1280    text->AddLine("return;");
1281    text->PopOffset();
1282    text->AddLine("}");
1283  }
1284  text->PopOffset();
1285  text->AddLine("}");
1286  text->AddBlankLine();
1287}
1288
1289void ProxyGenerator::ObjectManager::AddCreateProperties(
1290    const std::vector<Interface>& interfaces,
1291    const std::string& class_name,
1292    IndentedText* text) {
1293  text->AddLine("dbus::PropertySet* CreateProperties(");
1294  text->PushOffset(kLineContinuationOffset);
1295  text->AddLine("dbus::ObjectProxy* object_proxy,");
1296  text->AddLine("const dbus::ObjectPath& object_path,");
1297  text->AddLine("const std::string& interface_name) override {");
1298  text->PopOffset();
1299  text->PushOffset(kBlockOffset);
1300  for (const auto& itf : interfaces) {
1301    NameParser itf_name{itf.name};
1302    text->AddLine(StringPrintf("if (interface_name == \"%s\") {",
1303                               itf.name.c_str()));
1304    text->PushOffset(kBlockOffset);
1305    text->AddLine(StringPrintf("return new %s::PropertySet{",
1306                               itf_name.MakeProxyName(true).c_str()));
1307    text->PushOffset(kLineContinuationOffset);
1308    text->AddLine("object_proxy,");
1309    text->AddLineAndPushOffsetTo(
1310        StringPrintf("base::Bind(&%s::OnPropertyChanged,",
1311                     class_name.c_str()),
1312        1, '(');
1313    text->AddLine("weak_ptr_factory_.GetWeakPtr(),");
1314    text->AddLine("object_path,");
1315    text->AddLine("interface_name)");
1316    text->PopOffset();
1317    text->PopOffset();
1318    text->AddLine("};");
1319    text->PopOffset();
1320    text->AddLine("}");
1321  }
1322  text->AddLineAndPushOffsetTo("LOG(FATAL) << \"Creating properties for "
1323                               "unsupported interface \"", 1, ' ');
1324  text->AddLine("<< interface_name;");
1325  text->PopOffset();
1326  text->AddLine("return nullptr;");
1327  text->PopOffset();
1328  text->AddLine("}");
1329  text->AddBlankLine();
1330}
1331
1332void ProxyGenerator::ObjectManager::AddDataMembers(
1333    const ServiceConfig& config,
1334    const std::vector<Interface>& interfaces,
1335    const std::string& class_name,
1336    IndentedText* text) {
1337  text->AddLine("scoped_refptr<dbus::Bus> bus_;");
1338  if (config.service_name.empty()) {
1339    text->AddLine("std::string service_name_;");
1340  }
1341  text->AddLine("dbus::ObjectManager* dbus_object_manager_;");
1342  for (const auto& itf : interfaces) {
1343    NameParser itf_name{itf.name};
1344    string var_name = itf_name.MakeVariableName();
1345    text->AddLineAndPushOffsetTo("std::map<dbus::ObjectPath,", 1, '<');
1346    text->AddLine(StringPrintf("std::unique_ptr<%s>> %s_instances_;",
1347                               itf_name.MakeProxyName(true).c_str(),
1348                               var_name.c_str()));
1349    text->PopOffset();
1350    text->AddLine(
1351        StringPrintf("base::Callback<void(%sInterface*)> on_%s_added_;",
1352                     itf_name.MakeProxyName(true).c_str(),
1353                     var_name.c_str()));
1354    text->AddLine(StringPrintf("base::Callback<void(const dbus::ObjectPath&)> "
1355                               "on_%s_removed_;",
1356                               var_name.c_str()));
1357  }
1358  text->AddLine(
1359      StringPrintf("base::WeakPtrFactory<%s> weak_ptr_factory_{this};",
1360                   class_name.c_str()));
1361  text->AddBlankLine();
1362}
1363
1364// static
1365string ProxyGenerator::GetHandlerNameForSignal(const string& signal) {
1366  return StringPrintf("On%sSignal", signal.c_str());
1367}
1368
1369}  // namespace chromeos_dbus_bindings
1370