THRIFT-4918: Avoid dlang name conflicts

Client: dlang

Currently Thrift generates members that are invalid for D because
they are D reserved words. This change fixes the problem by 
appending a '_' to such names.

This closes #1842.
diff --git a/compiler/cpp/src/thrift/generate/t_d_generator.cc b/compiler/cpp/src/thrift/generate/t_d_generator.cc
index 56519e4..b844204 100644
--- a/compiler/cpp/src/thrift/generate/t_d_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_d_generator.cc
@@ -71,6 +71,14 @@
   }
 
 protected:
+
+  // D reserved words are suffixed with an underscore
+  static string suffix_if_reserved(const string& name) {
+	const bool isIn = std::binary_search(std::begin(d_reserved_words), std::end(d_reserved_words), name);
+	string ret = isIn ? name + "_" : name;
+	return ret;
+  }
+
   void init_generator() override {
     // Make output directory
     MKDIR(get_out_dir().c_str());
@@ -132,7 +140,7 @@
       vector<t_const*>::iterator c_iter;
       for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
         this->emit_doc(*c_iter, f_consts);
-        string name = (*c_iter)->get_name();
+        string name = suffix_if_reserved((*c_iter)->get_name());
         t_type* type = (*c_iter)->get_type();
         indent(f_consts) << "immutable(" << render_type_name(type) << ") " << name << ";" << endl;
       }
@@ -148,7 +156,7 @@
           f_consts << endl;
         }
         t_type* type = (*c_iter)->get_type();
-        indent(f_consts) << (*c_iter)->get_name() << " = ";
+        indent(f_consts) << suffix_if_reserved((*c_iter)->get_name()) << " = ";
         if (!is_immutable_type(type)) {
           f_consts << "cast(immutable(" << render_type_name(type) << ")) ";
         }
@@ -169,7 +177,7 @@
     vector<t_enum_value*> constants = tenum->get_constants();
 
     this->emit_doc(tenum, f_types_);
-    string enum_name = tenum->get_name();
+    string enum_name = suffix_if_reserved(tenum->get_name());
     f_types_ << indent() << "enum " << enum_name << " {" << endl;
 
     indent_up();
@@ -177,7 +185,7 @@
     vector<t_enum_value*>::const_iterator c_iter;
     for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
       this->emit_doc(*c_iter, f_types_);
-      indent(f_types_) << (*c_iter)->get_name();
+      indent(f_types_) << suffix_if_reserved((*c_iter)->get_name());
       f_types_ << " = " << (*c_iter)->get_value() << ",";
     }
 
@@ -197,30 +205,30 @@
   }
 
   void generate_service(t_service* tservice) override {
-    string svc_name = tservice->get_name();
+    string svc_name = suffix_if_reserved(tservice->get_name());
 
     // Service implementation file includes
     string f_servicename = package_dir_ + svc_name + ".d";
     ofstream_with_content_based_conditional_update f_service;
     f_service.open(f_servicename.c_str());
-    f_service << autogen_comment() << "module " << render_package(*program_) << svc_name << ";"
+    f_service << autogen_comment() << "module " << suffix_if_reserved(render_package(*program_)) << svc_name << ";"
               << endl << endl;
 
     print_default_imports(f_service);
 
-    f_service << "import " << render_package(*get_program()) << program_name_ << "_types;" << endl;
+    f_service << "import " << suffix_if_reserved(render_package(*get_program())) << program_name_ << "_types;" << endl;
 
     t_service* extends_service = tservice->get_extends();
     if (extends_service != NULL) {
-      f_service << "import " << render_package(*(extends_service->get_program()))
-                << extends_service->get_name() << ";" << endl;
+      f_service << "import " << suffix_if_reserved(render_package(*(extends_service->get_program())))
+                << suffix_if_reserved(extends_service->get_name()) << ";" << endl;
     }
 
     f_service << endl;
 
     string extends = "";
     if (tservice->get_extends() != NULL) {
-      extends = " : " + render_type_name(tservice->get_extends());
+      extends = " : " + suffix_if_reserved(render_type_name(tservice->get_extends()));
     }
 
     this->emit_doc(tservice, f_service);
@@ -274,7 +282,7 @@
         meta << ",";
       }
 
-      meta << endl << indent() << "TMethodMeta(`" << (*fn_iter)->get_name() << "`, " << endl;
+      meta << endl << indent() << "TMethodMeta(`" << suffix_if_reserved((*fn_iter)->get_name()) << "`, " << endl;
       indent_up();
       indent(meta) << "[";
 
@@ -288,7 +296,7 @@
           meta << ", ";
         }
 
-        meta << "TParamMeta(`" << (*p_iter)->get_name() << "`, " << (*p_iter)->get_key();
+        meta << "TParamMeta(`" << suffix_if_reserved((*p_iter)->get_name()) << "`, " << (*p_iter)->get_key();
 
         t_const_value* cv = (*p_iter)->get_value();
         if (cv != NULL) {
@@ -312,8 +320,8 @@
             meta << ", ";
           }
 
-          meta << "TExceptionMeta(`" << (*ex_iter)->get_name() << "`, " << (*ex_iter)->get_key()
-               << ", `" << (*ex_iter)->get_type()->get_name() << "`)";
+          meta << "TExceptionMeta(`" << suffix_if_reserved((*ex_iter)->get_name()) << "`, "
+               << (*ex_iter)->get_key() << ", `" << (*ex_iter)->get_type()->get_name() << "`)";
         }
 
         meta << "]";
@@ -364,7 +372,7 @@
    * Writes a server skeleton for the passed service to out.
    */
   void print_server_skeleton(ostream& out, t_service* tservice) {
-    string svc_name = tservice->get_name();
+    string svc_name = suffix_if_reserved(tservice->get_name());
 
     out << "/*" << endl
         << " * This auto-generated skeleton file illustrates how to build a server. If you" << endl
@@ -393,7 +401,7 @@
       indent_up();
 
       out << indent() << "// Your implementation goes here." << endl << indent() << "writeln(\""
-          << (*f_iter)->get_name() << " called\");" << endl;
+          << suffix_if_reserved((*f_iter)->get_name()) << " called\");" << endl;
 
 	  t_type* rt = (*f_iter)->get_returntype();
 	  if (!rt->is_void()) {
@@ -428,16 +436,16 @@
     const vector<t_field*>& members = tstruct->get_members();
 
     if (is_exception) {
-      indent(out) << "class " << tstruct->get_name() << " : TException {" << endl;
+      indent(out) << "class " << suffix_if_reserved(tstruct->get_name()) << " : TException {" << endl;
     } else {
-      indent(out) << "struct " << tstruct->get_name() << " {" << endl;
+      indent(out) << "struct " << suffix_if_reserved(tstruct->get_name()) << " {" << endl;
     }
     indent_up();
 
     // Declare all fields.
     vector<t_field*>::const_iterator m_iter;
     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-      indent(out) << render_type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name() << ";"
+      indent(out) << render_type_name((*m_iter)->get_type()) << " " << suffix_if_reserved((*m_iter)->get_name()) << ";"
                   << endl;
     }
 
@@ -462,7 +470,7 @@
         }
         out << endl;
 
-        indent(out) << "TFieldMeta(`" << (*m_iter)->get_name() << "`, " << (*m_iter)->get_key();
+        indent(out) << "TFieldMeta(`" << suffix_if_reserved((*m_iter)->get_name()) << "`, " << (*m_iter)->get_key();
 
         t_const_value* cv = (*m_iter)->get_value();
         t_field::e_req req = (*m_iter)->get_req();
@@ -488,7 +496,7 @@
    * method.
    */
   void print_function_signature(ostream& out, t_function* fn) {
-    out << render_type_name(fn->get_returntype()) << " " << fn->get_name() << "(";
+    out << render_type_name(fn->get_returntype()) << " " << suffix_if_reserved(fn->get_name()) << "(";
 
     const vector<t_field*>& fields = fn->get_arglist()->get_members();
     vector<t_field*>::const_iterator f_iter;
@@ -499,7 +507,7 @@
       } else {
         out << ", ";
       }
-      out << render_type_name((*f_iter)->get_type(), true) << " " << (*f_iter)->get_name();
+      out << render_type_name((*f_iter)->get_type(), true) << " " << suffix_if_reserved((*f_iter)->get_name());
     }
 
     out << ")";
@@ -737,6 +745,30 @@
   ofstream_with_content_based_conditional_update f_header_;
 
   string package_dir_;
+
+  protected:
+   static vector<string> d_reserved_words;
+
+};
+
+vector<string> t_d_generator::d_reserved_words = {
+    // The keywords are extracted from https://dlang.org/spec/lex.html
+    // and sorted for use with std::binary_search
+    "__FILE_FULL_PATH__", "__FILE__", "__FUNCTION__", "__LINE__", "__MODULE__",
+    "__PRETTY_FUNCTION__", "__gshared", "__parameters", "__traits", "__vector",
+    "abstract", "alias", "align", "asm", "assert", "auto", "body", "bool",
+    "break", "byte", "case", "cast", "catch", "cdouble", "cent", "cfloat",
+    "char", "class", "const", "continue", "creal", "dchar", "debug", "default",
+    "delegate", "delete", "deprecated", "do", "double", "else", "enum",
+    "export", "extern", "false", "final", "finally", "float", "for", "foreach",
+    "foreach_reverse", "function", "goto", "idouble", "if", "ifloat", "immutable",
+    "import", "in", "inout", "int", "interface", "invariant", "ireal", "is",
+    "lazy", "long", "macro ", "mixin", "module", "new", "nothrow", "null", "out",
+    "override", "package", "pragma", "private", "protected", "public", "pure",
+    "real", "ref", "return", "scope", "shared", "short", "static", "struct",
+    "super", "switch", "synchronized", "template", "this", "throw", "true", "try",
+    "typeid", "typeof", "ubyte", "ucent", "uint", "ulong", "union", "unittest",
+    "ushort", "version", "void", "wchar", "while", "with"
 };
 
 THRIFT_REGISTER_GENERATOR(d, "D", "")