chromeos-dbus-bindings: Extract common code into functions

Moved common code used to parse D-Bus object/interface names
such as "org.chromium.TestInterface" into a class, NameParser.
This allows it to be used to extract the nested namespaces,
produce properly-formed variable names and so on.

Did the same with generating const references for non-integral
types.

BUG=chromium:431737
TEST=FEATURES=test emerge-link chromeos-dbus-bindings

Change-Id: I011639b9c7c355fd0e693b200840811a6e3c33ca
Reviewed-on: https://chromium-review.googlesource.com/232404
Reviewed-by: Vitaly Buka <vitalybuka@chromium.org>
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/chromeos-dbus-bindings/adaptor_generator.cc b/chromeos-dbus-bindings/adaptor_generator.cc
index 8576907..deb26b1 100644
--- a/chromeos-dbus-bindings/adaptor_generator.cc
+++ b/chromeos-dbus-bindings/adaptor_generator.cc
@@ -14,6 +14,7 @@
 #include "chromeos-dbus-bindings/dbus_signature.h"
 #include "chromeos-dbus-bindings/indented_text.h"
 #include "chromeos-dbus-bindings/interface.h"
+#include "chromeos-dbus-bindings/name_parser.h"
 
 using base::StringPrintf;
 using std::string;
@@ -59,17 +60,13 @@
 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";
+  NameParser parser{interface.name};
+  string itf_name = parser.MakeInterfaceName(false);
+  string class_name = parser.MakeAdaptorName(false);
+  string full_itf_name = parser.MakeFullCppName();
 
   text->AddBlankLine();
-  for (const auto& ns : namespaces) {
-    text->AddLine(StringPrintf("namespace %s {", ns.c_str()));
-  }
+  parser.AddOpenNamespaces(text, false);
 
   text->AddBlankLine();
   text->AddLine(StringPrintf("// Interface definition for %s.",
@@ -121,9 +118,7 @@
   text->AddLine("};");
 
   text->AddBlankLine();
-  for (auto it = namespaces.rbegin(); it != namespaces.rend(); ++it) {
-    text->AddLine(StringPrintf("}  // namespace %s", it->c_str()));
-  }
+  parser.AddCloseNamespaces(text, false);
 }
 
 // static
@@ -200,7 +195,7 @@
   if (!interface.properties.empty())
     text->AddBlankLine();
   for (const auto& property : interface.properties) {
-    string variable_name = GetPropertyVariableName(property.name);
+    string variable_name = NameParser{property.name}.MakeVariableName();
     text->AddLine(StringPrintf("itf->AddProperty(\"%s\", &%s_);",
                                property.name.c_str(), variable_name.c_str()));
   }
@@ -264,9 +259,7 @@
     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());
-      }
+      MakeConstReferenceIfNeeded(&param_type);
       string param_name = GetArgName("in", argument.name, ++index);
       method_params.push_back(param_type + ' ' + param_name);
     }
@@ -314,9 +307,7 @@
     for (const auto& argument : signal.arguments) {
       string param_type;
       CHECK(signature.Parse(argument.type, &param_type));
-      if (!IsIntegralType(param_type)) {
-        param_type = StringPrintf("const %s&", param_type.c_str());
-      }
+      MakeConstReferenceIfNeeded(&param_type);
       string param_name = GetArgName("in", argument.name, ++index);
       param_names.push_back(param_name);
       method_params.push_back(param_type + ' ' + param_name);
@@ -395,7 +386,7 @@
     block.AddBlankLine();
     string type;
     CHECK(signature.Parse(property.type, &type));
-    string variable_name = GetPropertyVariableName(property.name);
+    string variable_name = NameParser{property.name}.MakeVariableName();
 
     // Getter method.
     block.AddComments(property.doc_string);
@@ -410,8 +401,7 @@
     block.AddLine("}");
 
     // Setter method.
-    if (!IsIntegralType(type))
-      type = StringPrintf("const %s&", type.c_str());
+    MakeConstReferenceIfNeeded(&type);
     block.AddLine(StringPrintf("void Set%s(%s %s) {",
                                property.name.c_str(),
                                type.c_str(),
@@ -435,7 +425,7 @@
   for (const auto& property : interface.properties) {
     string type;
     CHECK(signature.Parse(property.type, &type));
-    string variable_name = GetPropertyVariableName(property.name);
+    string variable_name = NameParser{property.name}.MakeVariableName();
 
     block.AddLine(
         StringPrintf("chromeos::dbus_utils::ExportedProperty<%s> %s_;",
@@ -447,23 +437,4 @@
   text->AddBlock(block);
 }
 
-// static
-string AdaptorGenerator::GetPropertyVariableName(const string& property_name) {
-  // Convert CamelCase property name to google_style variable name.
-  string result;
-  for (size_t i = 0; i < property_name.length(); i++) {
-    char c = property_name[i];
-    if (c < 'A' || c > 'Z') {
-      result += c;
-      continue;
-    }
-
-    if (i != 0) {
-      result += '_';
-    }
-    result += base::ToLowerASCII(c);
-  }
-  return result;
-}
-
 }  // namespace chromeos_dbus_bindings
diff --git a/chromeos-dbus-bindings/adaptor_generator.h b/chromeos-dbus-bindings/adaptor_generator.h
index 87e1b26..57e2bf5 100644
--- a/chromeos-dbus-bindings/adaptor_generator.h
+++ b/chromeos-dbus-bindings/adaptor_generator.h
@@ -71,9 +71,6 @@
   static void AddPropertyDataMembers(const Interface& interface,
                                      IndentedText *text);
 
-  // Return a variable name based on the given property name.
-  static std::string GetPropertyVariableName(const std::string& property_name);
-
   DISALLOW_COPY_AND_ASSIGN(AdaptorGenerator);
 };
 
diff --git a/chromeos-dbus-bindings/chromeos-dbus-bindings.gyp b/chromeos-dbus-bindings/chromeos-dbus-bindings.gyp
index 5b729d4..79468c1 100644
--- a/chromeos-dbus-bindings/chromeos-dbus-bindings.gyp
+++ b/chromeos-dbus-bindings/chromeos-dbus-bindings.gyp
@@ -29,6 +29,7 @@
         'header_generator.cc',
         'indented_text.cc',
         'method_name_generator.cc',
+        'name_parser.cc',
         'proxy_generator.cc',
         'xml_interface_parser.cc',
       ],
@@ -79,6 +80,7 @@
             'dbus_signature_unittest.cc',
             'indented_text_unittest.cc',
             'method_name_generator_unittest.cc',
+            'name_parser_unittest.cc',
             'proxy_generator_unittest.cc',
             'xml_interface_parser_unittest.cc',
           ],
diff --git a/chromeos-dbus-bindings/header_generator.cc b/chromeos-dbus-bindings/header_generator.cc
index 41d7e1b..d08131d 100644
--- a/chromeos-dbus-bindings/header_generator.cc
+++ b/chromeos-dbus-bindings/header_generator.cc
@@ -8,7 +8,6 @@
 
 #include <base/file_util.h>
 #include <base/files/file_path.h>
-#include <base/strings/string_split.h>
 #include <base/strings/string_util.h>
 #include <base/strings/stringprintf.h>
 #include <chromeos/strings/string_utils.h>
@@ -36,34 +35,15 @@
 }
 
 // static
-bool HeaderGenerator::GetNamespacesAndClassName(
-    const string& interface_name,
-    vector<string>* namespaces,
-    string* class_name) {
-  vector<string> split_namespaces;
-  base::SplitString(interface_name, '.', &split_namespaces);
-  if (split_namespaces.size() < 2) {
-    LOG(ERROR) << "Interface name must have both a domain and object part "
-               << "separated by '.'.  Got " << interface_name << " instead.";
-    return false;
-  }
-  *class_name = split_namespaces.back();
-  split_namespaces.pop_back();
-  namespaces->swap(split_namespaces);
-  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);
+bool HeaderGenerator::IsIntegralType(const string& type) {
+  return type.find("::") == std::string::npos;
 }
 
 // static
-bool HeaderGenerator::IsIntegralType(const string& type) {
-  return type.find("::") == std::string::npos;
+void HeaderGenerator::MakeConstReferenceIfNeeded(std::string* type) {
+  if (!IsIntegralType(*type)) {
+    *type = base::StringPrintf("const %s&", type->c_str());
+  }
 }
 
 // static
diff --git a/chromeos-dbus-bindings/header_generator.h b/chromeos-dbus-bindings/header_generator.h
index 938e93b..55b1265 100644
--- a/chromeos-dbus-bindings/header_generator.h
+++ b/chromeos-dbus-bindings/header_generator.h
@@ -30,19 +30,12 @@
   // Create a unique header guard string to protect multiple includes of header.
   static std::string GenerateHeaderGuard(const base::FilePath& output_file);
 
-  // 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);
 
+  // If |type| is a non-integral type, converts it into a const reference.
+  static void MakeConstReferenceIfNeeded(std::string* type);
+
   // Writes indented text to a file.
   static bool WriteTextToFile(const base::FilePath& output_file,
                               const IndentedText& text);
diff --git a/chromeos-dbus-bindings/method_name_generator.cc b/chromeos-dbus-bindings/method_name_generator.cc
index d35f058..5332660 100644
--- a/chromeos-dbus-bindings/method_name_generator.cc
+++ b/chromeos-dbus-bindings/method_name_generator.cc
@@ -9,6 +9,7 @@
 
 #include "chromeos-dbus-bindings/indented_text.h"
 #include "chromeos-dbus-bindings/interface.h"
+#include "chromeos-dbus-bindings/name_parser.h"
 
 using std::string;
 using std::vector;
@@ -29,15 +30,15 @@
   IndentedText text;
   for (const auto& interface : interfaces) {
     text.AddBlankLine();
-    text.AddLine(base::StringPrintf("namespace %s {", interface.name.c_str()));
+    NameParser parser{interface.name};
+    parser.AddOpenNamespaces(&text, true);
     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()));
+    parser.AddCloseNamespaces(&text, true);
   }
   return HeaderGenerator::WriteTextToFile(output_file, text);
 }
diff --git a/chromeos-dbus-bindings/name_parser.cc b/chromeos-dbus-bindings/name_parser.cc
new file mode 100644
index 0000000..33584d9
--- /dev/null
+++ b/chromeos-dbus-bindings/name_parser.cc
@@ -0,0 +1,95 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/name_parser.h"
+
+#include <string>
+
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+#include <chromeos/strings/string_utils.h>
+
+#include "chromeos-dbus-bindings/indented_text.h"
+
+namespace chromeos_dbus_bindings {
+
+namespace {
+
+void AddOpenNamespace(IndentedText *text, const std::string& name) {
+  text->AddLine(base::StringPrintf("namespace %s {", name.c_str()));
+}
+
+void AddCloseNamespace(IndentedText *text, const std::string& name) {
+  text->AddLine(base::StringPrintf("}  // namespace %s", name.c_str()));
+}
+
+}  // anonymous namespace
+
+NameParser::NameParser(const std::string& name)
+    : namespaces{chromeos::string_utils::Split(name, '.')} {
+  CHECK(!namespaces.empty()) << "Empty name specified";
+  type_name = namespaces.back();
+  namespaces.pop_back();
+}
+
+std::string NameParser::MakeFullyQualified(const std::string& name) const {
+  std::vector<std::string> parts = namespaces;
+  parts.push_back(name);
+  return chromeos::string_utils::Join("::", parts);
+}
+
+std::string NameParser::MakeFullCppName() const {
+  return MakeFullyQualified(type_name);
+}
+
+std::string NameParser::MakeVariableName() const {
+  // Convert CamelCase name to google_style variable name.
+  std::string result;
+  for (char c : type_name) {
+    if (isupper(c)) {
+      if (!result.empty())
+        result += '_';
+      c = base::ToLowerASCII(c);
+    }
+    result.push_back(c);
+  }
+  return result;
+}
+
+std::string NameParser::MakeInterfaceName(bool fully_qualified) const {
+  std::string interface_name = type_name + "Interface";
+  return fully_qualified ? MakeFullyQualified(interface_name) : interface_name;
+}
+
+std::string NameParser::MakeProxyName(bool fully_qualified) const {
+  std::string proxy_name = type_name + "Proxy";
+  return fully_qualified ? MakeFullyQualified(proxy_name) : proxy_name;
+}
+
+std::string NameParser::MakeAdaptorName(bool fully_qualified) const {
+  std::string adaptor_name = type_name + "Adaptor";
+  return fully_qualified ? MakeFullyQualified(adaptor_name) : adaptor_name;
+}
+
+void NameParser::AddOpenNamespaces(IndentedText *text,
+                                   bool add_main_type) const {
+  for (const auto& ns : namespaces) {
+    AddOpenNamespace(text, ns);
+  }
+
+  if (add_main_type)
+    AddOpenNamespace(text, type_name);
+}
+
+void NameParser::AddCloseNamespaces(IndentedText *text,
+                                    bool add_main_type) const {
+  if (add_main_type)
+    AddCloseNamespace(text, type_name);
+
+  for (auto it = namespaces.rbegin(); it != namespaces.rend(); ++it) {
+    AddCloseNamespace(text, *it);
+  }
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/chromeos-dbus-bindings/name_parser.h b/chromeos-dbus-bindings/name_parser.h
new file mode 100644
index 0000000..0282819
--- /dev/null
+++ b/chromeos-dbus-bindings/name_parser.h
@@ -0,0 +1,63 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_DBUS_BINDINGS_NAME_PARSER_H_
+#define CHROMEOS_DBUS_BINDINGS_NAME_PARSER_H_
+
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+namespace chromeos_dbus_bindings {
+
+struct Interface;
+class  IndentedText;
+
+// A helper class that allows to decompose D-Bus name strings such as
+// "org.chromium.TestInterface" into components and be able to construct the
+// corresponding C++ identifiers, namespaces, variable names, etc.
+class NameParser {
+ public:
+  explicit NameParser(const std::string& name);
+
+  // Returns fully-qualified C++ type name for the current D-Bus name
+  // for example "org::chromium::TestInterface".
+  std::string MakeFullCppName() const;
+
+  // Returns a variable name suitable for object of this type.
+  // For example "test_interface".
+  std::string MakeVariableName() const;
+
+  // Returns a name of an interface for the given type, optionally qualifying
+  // it with the C++ namespaces.
+  std::string MakeInterfaceName(bool fully_qualified) const;
+
+  // Returns a name of a proxy class for the given type, optionally qualifying
+  // it with the C++ namespaces.
+  std::string MakeProxyName(bool fully_qualified) const;
+
+  // Returns a name of an adaptor class for the given type, optionally
+  // qualifying it with the C++ namespaces.
+  std::string MakeAdaptorName(bool fully_qualified) const;
+
+  // Adds opening "namespace ... {" statements to |text|.
+  // If |add_main_type| is true, adds the main type name as a namespace as well.
+  void AddOpenNamespaces(IndentedText *text, bool add_main_type) const;
+
+  // Adds closing "}  // namespace ..." statements to |text|.
+  // If |add_main_type| is true, adds the main type name as a namespace as well.
+  void AddCloseNamespaces(IndentedText *text, bool add_main_type) const;
+
+  std::string type_name;  // e.g. "TestInterface".
+  std::vector<std::string> namespaces;  // e.g. {"org", "chromium"}.
+
+ private:
+  // Helper function to prepend the C++ namespaces to the |name|.
+  std::string MakeFullyQualified(const std::string& name) const;
+};
+
+}  // namespace chromeos_dbus_bindings
+
+#endif  // CHROMEOS_DBUS_BINDINGS_NAME_PARSER_H_
diff --git a/chromeos-dbus-bindings/name_parser_unittest.cc b/chromeos-dbus-bindings/name_parser_unittest.cc
new file mode 100644
index 0000000..62de4fe
--- /dev/null
+++ b/chromeos-dbus-bindings/name_parser_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos-dbus-bindings/name_parser.h"
+
+#include <map>
+#include <string>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "chromeos-dbus-bindings/indented_text.h"
+
+namespace chromeos_dbus_bindings {
+
+TEST(NameParser, Parsing_Empty) {
+  EXPECT_DEATH(NameParser{""}, "Empty name specified");
+}
+
+TEST(NameParser, Parsing_NoNamespaces) {
+  NameParser parser{"foo"};
+  EXPECT_EQ("foo", parser.type_name);
+  EXPECT_TRUE(parser.namespaces.empty());
+}
+
+TEST(NameParser, Parsing_FullyQualified) {
+  NameParser parser{"foo.bar.FooBar"};
+  EXPECT_EQ("FooBar", parser.type_name);
+  EXPECT_THAT(parser.namespaces, testing::ElementsAre("foo", "bar"));
+}
+
+TEST(NameParser, MakeFullCppName) {
+  NameParser parser{"foo.bar.FooBar"};
+  EXPECT_EQ("foo::bar::FooBar", parser.MakeFullCppName());
+}
+
+TEST(NameParser, MakeVariableName) {
+  NameParser parser{"foo.bar.FooBar"};
+  EXPECT_EQ("foo_bar", parser.MakeVariableName());
+}
+
+TEST(NameParser, MakeVariableName_NoCapitals) {
+  NameParser parser{"foo"};
+  EXPECT_EQ("foo", parser.MakeVariableName());
+}
+
+TEST(NameParser, MakeVariableName_NoInitialCapital) {
+  NameParser parser{"fooBarBaz"};
+  EXPECT_EQ("foo_bar_baz", parser.MakeVariableName());
+}
+
+TEST(NameParser, MakeInterfaceName) {
+  NameParser parser{"foo.bar.FooBar"};
+  EXPECT_EQ("FooBarInterface", parser.MakeInterfaceName(false));
+  EXPECT_EQ("foo::bar::FooBarInterface", parser.MakeInterfaceName(true));
+}
+
+TEST(NameParser, MakeProxyName) {
+  NameParser parser{"foo.bar.FooBar"};
+  EXPECT_EQ("FooBarProxy", parser.MakeProxyName(false));
+  EXPECT_EQ("foo::bar::FooBarProxy", parser.MakeProxyName(true));
+}
+
+TEST(NameParser, MakeAdaptorName) {
+  NameParser parser{"foo.bar.FooBar"};
+  EXPECT_EQ("FooBarAdaptor", parser.MakeAdaptorName(false));
+  EXPECT_EQ("foo::bar::FooBarAdaptor", parser.MakeAdaptorName(true));
+}
+
+TEST(NameParser, AddOpenNamespaces) {
+  std::string expected =
+    "namespace foo {\n"
+    "namespace bar {\n";
+  NameParser parser{"foo.bar.FooBar"};
+  IndentedText text;
+  parser.AddOpenNamespaces(&text, false);
+  EXPECT_EQ(expected, text.GetContents());
+}
+
+TEST(NameParser, AddOpenNamespaces_WithMainType) {
+  std::string expected =
+    "namespace foo {\n"
+    "namespace bar {\n"
+    "namespace FooBar {\n";
+  NameParser parser{"foo.bar.FooBar"};
+  IndentedText text;
+  parser.AddOpenNamespaces(&text, true);
+  EXPECT_EQ(expected, text.GetContents());
+}
+
+TEST(NameParser, AddCloseNamespaces) {
+  std::string expected =
+    "}  // namespace bar\n"
+    "}  // namespace foo\n";
+  NameParser parser{"foo.bar.FooBar"};
+  IndentedText text;
+  parser.AddCloseNamespaces(&text, false);
+  EXPECT_EQ(expected, text.GetContents());
+}
+
+TEST(NameParser, AddCloseNamespaces_WithMainType) {
+  std::string expected =
+    "}  // namespace FooBar\n"
+    "}  // namespace bar\n"
+    "}  // namespace foo\n";
+  NameParser parser{"foo.bar.FooBar"};
+  IndentedText text;
+  parser.AddCloseNamespaces(&text, true);
+  EXPECT_EQ(expected, text.GetContents());
+}
+
+}  // namespace chromeos_dbus_bindings
diff --git a/chromeos-dbus-bindings/proxy_generator.cc b/chromeos-dbus-bindings/proxy_generator.cc
index 01f2a75..1c09f33 100644
--- a/chromeos-dbus-bindings/proxy_generator.cc
+++ b/chromeos-dbus-bindings/proxy_generator.cc
@@ -12,6 +12,7 @@
 
 #include "chromeos-dbus-bindings/dbus_signature.h"
 #include "chromeos-dbus-bindings/indented_text.h"
+#include "chromeos-dbus-bindings/name_parser.h"
 
 using base::StringPrintf;
 using std::pair;
@@ -72,20 +73,14 @@
 void ProxyGenerator::GenerateInterfaceProxy(const ServiceConfig& config,
                                             const Interface& interface,
                                             IndentedText* text) {
-  vector<string> namespaces;
-  string itf_name;
-  CHECK(GetNamespacesAndClassName(interface.name,
-                                  &namespaces,
-                                  &itf_name));
-  string proxy_name = itf_name + "Proxy";
+  NameParser parser{interface.name};
+  string proxy_name = parser.MakeProxyName(false);
 
-  for (const auto& space : namespaces) {
-    text->AddLine(StringPrintf("namespace %s {", space.c_str()));
-  }
+  parser.AddOpenNamespaces(text, false);
   text->AddBlankLine();
 
   text->AddLine(StringPrintf("// Interface proxy for %s.",
-                             GetFullClassName(namespaces, itf_name).c_str()));
+                             parser.MakeFullCppName().c_str()));
   text->AddComments(interface.doc_string);
   text->AddLine(StringPrintf("class %s final {", proxy_name.c_str()));
   text->AddLineWithOffset("public:", kScopeOffset);
@@ -127,9 +122,7 @@
 
   text->AddBlankLine();
 
-  for (auto it = namespaces.rbegin(); it != namespaces.rend(); ++it) {
-    text->AddLine(StringPrintf("}  // namespace %s", it->c_str()));
-  }
+  parser.AddCloseNamespaces(text, false);
 
   text->AddBlankLine();
 }
@@ -294,9 +287,7 @@
           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());
-      }
+      MakeConstReferenceIfNeeded(&last_argument);
       if (!argument.name.empty()) {
         last_argument += ' ';
         last_argument += argument.name;
@@ -326,9 +317,7 @@
   for (const auto& argument : method.input_arguments) {
     string argument_type;
     CHECK(signature.Parse(argument.type, &argument_type));
-    if (!IsIntegralType(argument_type)) {
-      argument_type = StringPrintf("const %s&", argument_type.c_str());
-    }
+    MakeConstReferenceIfNeeded(&argument_type);
     string argument_name = GetArgName("in", argument.name, ++argument_number);
     argument_names.push_back(argument_name);
     block.AddLine(StringPrintf(