* THRIFT-4655 Parser fails on the word "from"
Client: Compiler (general)
Patch: Jens Geyer

This also fixes an unhandled "normalize" case with enums in netstd that came up during tests for this ticket.

This closes #2715
diff --git a/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc b/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc
index 4ce9c5f..da25338 100644
--- a/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc
@@ -105,6 +105,7 @@
   /* initialization and destruction */
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   /* generation functions */
   void generate_typedef(t_typedef* ttypedef) override;
@@ -4583,4 +4584,9 @@
 }
 
 /* register this generator with the main program */
+std::string t_c_glib_generator::display_name() const {
+  return "C, using GLib";
+}
+
+
 THRIFT_REGISTER_GENERATOR(c_glib, "C, using GLib", "")
diff --git a/compiler/cpp/src/thrift/generate/t_cl_generator.cc b/compiler/cpp/src/thrift/generate/t_cl_generator.cc
index 06b6b65..e0dcc46 100644
--- a/compiler/cpp/src/thrift/generate/t_cl_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_cl_generator.cc
@@ -72,6 +72,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   void generate_typedef     (t_typedef*  ttypedef) override;
   void generate_enum        (t_enum*     tenum) override;
@@ -551,6 +552,11 @@
   return prefix + name;
 }
 
+std::string t_cl_generator::display_name() const {
+  return "Common Lisp";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     cl,
     "Common Lisp",
diff --git a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
index dd444bc..9724fae 100644
--- a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
@@ -104,6 +104,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   void generate_consts(std::vector<t_const*> consts) override;
 
@@ -4751,6 +4752,11 @@
   return program_name;
 }
 
+std::string t_cpp_generator::display_name() const {
+  return "C++";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     cpp,
     "C++",
diff --git a/compiler/cpp/src/thrift/generate/t_d_generator.cc b/compiler/cpp/src/thrift/generate/t_d_generator.cc
index f9e4856..38194c2 100644
--- a/compiler/cpp/src/thrift/generate/t_d_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_d_generator.cc
@@ -69,6 +69,7 @@
 
     out_dir_base_ = "gen-d";
   }
+  std::string display_name() const override;
 
 protected:
 
@@ -371,6 +372,7 @@
   /**
    * Writes a server skeleton for the passed service to out.
    */
+
   void print_server_skeleton(ostream& out, t_service* tservice) {
     string svc_name = suffix_if_reserved(tservice->get_name());
 
@@ -432,6 +434,7 @@
   /**
    * Writes the definition of a struct or an exception type to out.
    */
+
   void print_struct_definition(ostream& out, t_struct* tstruct, bool is_exception) {
     const vector<t_field*>& members = tstruct->get_members();
 
@@ -495,6 +498,7 @@
    * Prints the D function signature (including return type) for the given
    * method.
    */
+
   void print_function_signature(ostream& out, t_function* fn) {
     out << render_type_name(fn->get_returntype()) << " " << suffix_if_reserved(fn->get_name()) << "(";
 
@@ -722,6 +726,7 @@
    * Writes the default list of imports (which are written to every generated
    * module) to f.
    */
+
   void print_default_imports(ostream& out) {
     indent(out) << "import thrift.base;" << endl << "import thrift.codegen.base;" << endl
                 << "import thrift.util.hashset;" << endl << endl;
@@ -771,4 +776,9 @@
     "ushort", "version", "void", "wchar", "while", "with"
 };
 
+std::string t_d_generator::display_name() const {
+  return "D";
+}
+
+
 THRIFT_REGISTER_GENERATOR(d, "D", "")
diff --git a/compiler/cpp/src/thrift/generate/t_dart_generator.cc b/compiler/cpp/src/thrift/generate/t_dart_generator.cc
index 61cd981..fda989b 100644
--- a/compiler/cpp/src/thrift/generate/t_dart_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_dart_generator.cc
@@ -123,6 +123,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   void export_class_to_library(string file_name, string class_name);
 
@@ -2508,6 +2509,11 @@
   }
 }
 
+std::string t_dart_generator::display_name() const {
+  return "Dart";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     dart,
     "Dart",
diff --git a/compiler/cpp/src/thrift/generate/t_delphi_generator.cc b/compiler/cpp/src/thrift/generate/t_delphi_generator.cc
index 625179f..8c37c65 100644
--- a/compiler/cpp/src/thrift/generate/t_delphi_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_delphi_generator.cc
@@ -105,6 +105,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   void generate_consts(std::vector<t_const*> consts) override;
 
@@ -1996,7 +1997,7 @@
 #ifdef _WIN32   // TODO: add support for non-windows platforms if needed
   GUID guid;
   if (SUCCEEDED(CoCreateGuid(&guid))) {
-    OLECHAR guid_chars[40];
+    OLECHAR guid_chars[40]{};
     if (StringFromGUID2(guid, &guid_chars[0], sizeof(guid_chars) / sizeof(guid_chars[0])) > 0) {
       std::wstring guid_wstr(guid_chars);
       std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
@@ -4131,9 +4132,14 @@
   return false;
 }
 
+std::string t_delphi_generator::display_name() const {
+  return "Delphi";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     delphi,
-    "delphi",
+    "Delphi",
     "    ansistr_binary:  Use AnsiString for binary datatype (default is TBytes).\n"
     "    register_types:  Enable TypeRegistry, allows for creation of struct, union\n"
     "                     and container instances by interface or TypeInfo()\n"
diff --git a/compiler/cpp/src/thrift/generate/t_erl_generator.cc b/compiler/cpp/src/thrift/generate/t_erl_generator.cc
index 1f4fd50..7293972 100644
--- a/compiler/cpp/src/thrift/generate/t_erl_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_erl_generator.cc
@@ -84,6 +84,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   /**
    * Program-level generation functions
@@ -1280,6 +1281,11 @@
   return make_safe_for_module_name(ttype->get_program()->get_name()) + "_types";
 }
 
+std::string t_erl_generator::display_name() const {
+  return "Erlang";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     erl,
     "Erlang",
diff --git a/compiler/cpp/src/thrift/generate/t_generator.cc b/compiler/cpp/src/thrift/generate/t_generator.cc
index f26690b..970281e 100644
--- a/compiler/cpp/src/thrift/generate/t_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_generator.cc
@@ -76,20 +76,11 @@
   close_generator();
 }
 
-std::set<std::string> t_generator::lang_keywords() const {
-  std::string keywords[] = { "BEGIN", "END", "__CLASS__", "__DIR__", "__FILE__", "__FUNCTION__",
-      "__LINE__", "__METHOD__", "__NAMESPACE__", "abstract", "alias", "and", "args", "as",
-      "assert", "begin", "break", "case", "catch", "class", "clone", "continue", "declare",
-      "def", "default", "del", "delete", "do", "dynamic", "elif", "else", "elseif", "elsif",
-      "end", "enddeclare", "endfor", "endforeach", "endif", "endswitch", "endwhile", "ensure",
-      "except", "exec", "finally", "float", "for", "foreach", "from", "function", "global",
-      "goto", "if", "implements", "import", "in", "inline", "instanceof", "interface", "is",
-      "lambda", "module", "native", "new", "next", "nil", "not", "or", "package", "pass",
-      "public", "print", "private", "protected", "raise", "redo", "rescue", "retry", "register",
-      "return", "self", "sizeof", "static", "super", "switch", "synchronized", "then", "this",
-      "throw", "transient", "try", "undef", "unless", "unsigned", "until", "use", "var",
-      "virtual", "volatile", "when", "while", "with", "xor", "yield" };
-  return std::set<std::string>(keywords, keywords + sizeof(keywords)/sizeof(keywords[0]) );
+std::set<std::string> t_generator::lang_keywords_for_validation() const {
+  // Nothing by default. It makes no sense to restrict the whole world to use non-PHP keywords only. 
+  // Override on a per-generator(!) basis if you cannot live without it, e.g. that particular language has no 
+  // mechanism or way to deal with it properly, so we absolutely need to fail on it as the last possible resort.
+  return {};
 }
 
 void t_generator::validate_input() const {
@@ -143,7 +134,8 @@
 
 void t_generator::validate_id(const string& id) const {
   if (keywords_.find(id) != keywords_.end()) {
-    failure("Cannot use reserved language keyword: \"%s\"", id.c_str());
+    // What the message really means is "we did not get it done yet"
+    failure("Cannot use reserved language keyword \"%s\" with target language %s", id.c_str(), display_name().c_str());
   }
 }
 
diff --git a/compiler/cpp/src/thrift/generate/t_generator.h b/compiler/cpp/src/thrift/generate/t_generator.h
index 21c2798..4d5a295 100644
--- a/compiler/cpp/src/thrift/generate/t_generator.h
+++ b/compiler/cpp/src/thrift/generate/t_generator.h
@@ -43,7 +43,7 @@
 class t_generator {
 public:
   t_generator(t_program* program) {
-    update_keywords();
+    update_keywords_for_validation();
 
     tmp_ = 0;
     indent_ = 0;
@@ -100,18 +100,24 @@
 
   /**
    * Check if all identifiers are valid for the target language
-   * See update_keywords()
+   * See update_keywords_for_validation()
    */
   virtual void validate_input() const;
 
+  /**
+   * Must override. Should be equivalent to the "long name" parameter at THRIFT_REGISTER_GENERATOR.
+   * TODO: essentially duplicates, so we should find a way to get rid of one 
+   */
+  virtual std::string display_name() const = 0;
 protected:
-  virtual std::set<std::string> lang_keywords() const;
+  virtual std::set<std::string> lang_keywords_for_validation() const;
 
   /**
-   * Call this from constructor if you implement lang_keywords()
+   * Call this from constructor if you implement lang_keywords_for_validation()
    */
-  void update_keywords() {
-    keywords_ = lang_keywords();
+
+  void update_keywords_for_validation() {
+    keywords_ = lang_keywords_for_validation();
   }
 
   /**
diff --git a/compiler/cpp/src/thrift/generate/t_go_generator.cc b/compiler/cpp/src/thrift/generate/t_go_generator.cc
index e0ca489..45d047a 100644
--- a/compiler/cpp/src/thrift/generate/t_go_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_go_generator.cc
@@ -4012,6 +4012,11 @@
   */
  }
 
+std::string t_go_generator::display_name() const {
+  return "Go";
+}
+
+
 THRIFT_REGISTER_GENERATOR(go, "Go",
                           "    package_prefix=  Package prefix for generated files.\n" \
                           "    thrift_import=   Override thrift package import path (default:" + DEFAULT_THRIFT_IMPORT + ")\n" \
diff --git a/compiler/cpp/src/thrift/generate/t_go_generator.h b/compiler/cpp/src/thrift/generate/t_go_generator.h
index 5080e1a..a67485c 100644
--- a/compiler/cpp/src/thrift/generate/t_go_generator.h
+++ b/compiler/cpp/src/thrift/generate/t_go_generator.h
@@ -94,6 +94,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   /**
    * Program-level generation functions
diff --git a/compiler/cpp/src/thrift/generate/t_gv_generator.cc b/compiler/cpp/src/thrift/generate/t_gv_generator.cc
index 724a927..f8616ff 100644
--- a/compiler/cpp/src/thrift/generate/t_gv_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_gv_generator.cc
@@ -67,12 +67,15 @@
   /**
    * Init and end of generator
    */
+
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   /**
    * Program-level generation functions
    */
+
   void generate_typedef(t_typedef* ttypedef) override;
   void generate_enum(t_enum* tenum) override;
   void generate_const(t_const* tconst) override;
@@ -83,6 +86,7 @@
   /**
    * Helpers
    */
+
   void print_type(t_type* ttype, string struct_field_ref);
   void print_const_value(t_type* type, t_const_value* tvalue);
 
@@ -336,9 +340,14 @@
     }
   }
 
-  f_out_ << " }" << endl;
+  f_out_ << " }" << endl;	
 }
 
+std::string t_gv_generator::display_name() const {
+  return "Graphviz";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     gv,
     "Graphviz",
diff --git a/compiler/cpp/src/thrift/generate/t_haxe_generator.cc b/compiler/cpp/src/thrift/generate/t_haxe_generator.cc
index 8893742..aa628b7 100644
--- a/compiler/cpp/src/thrift/generate/t_haxe_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_haxe_generator.cc
@@ -75,6 +75,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   void generate_consts(std::vector<t_const*> consts) override;
 
@@ -3017,6 +3018,11 @@
   return package + type->get_name();
 }
 
+std::string t_haxe_generator::display_name() const {
+  return "Haxe";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     haxe,
     "Haxe",
diff --git a/compiler/cpp/src/thrift/generate/t_html_generator.cc b/compiler/cpp/src/thrift/generate/t_html_generator.cc
index f51de48..15a0401 100644
--- a/compiler/cpp/src/thrift/generate/t_html_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_html_generator.cc
@@ -81,6 +81,7 @@
 
     init_allowed__markup();
   }
+  std::string display_name() const override;
 
   void generate_program() override;
   void generate_program_toc();
@@ -1076,6 +1077,11 @@
   }
 }
 
+std::string t_html_generator::display_name() const {
+  return "HTML";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     html,
     "HTML",
diff --git a/compiler/cpp/src/thrift/generate/t_java_generator.cc b/compiler/cpp/src/thrift/generate/t_java_generator.cc
index a6041d7..5c3c76f 100644
--- a/compiler/cpp/src/thrift/generate/t_java_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_java_generator.cc
@@ -145,6 +145,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   void generate_consts(std::vector<t_const*> consts) override;
 
@@ -5777,33 +5778,33 @@
   }
 }
 
+std::string t_java_generator::display_name() const {
+  return "Java";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     java,
     "Java",
     "    beans:           Members will be private, and setter methods will return void.\n"
-    "    private_members: Members will be private, but setter methods will return 'this' like "
-    "usual.\n"
+    "    private_members: Members will be private, but setter methods will return 'this' like usual.\n"
     "    private-members: Same as 'private_members' (deprecated).\n"
     "    nocamel:         Do not use CamelCase field accessors with beans.\n"
     "    fullcamel:       Convert underscored_accessor_or_service_names to camelCase.\n"
     "    android:         Generated structures are Parcelable.\n"
-    "    android_legacy:  Do not use java.io.IOException(throwable) (available for Android 2.3 and "
-    "above).\n"
+    "    android_legacy:  Do not use java.io.IOException(throwable) (available for Android 2.3 and above).\n"
     "    option_type=[thrift|jdk8]:\n"
     "                     thrift: wrap optional fields in thrift Option type.\n"
     "                     jdk8: Wrap optional fields in JDK8+ Option type.\n"
     "                     If the Option type is not specified, 'thrift' is used.\n"
     "    rethrow_unhandled_exceptions:\n"
-    "                     Enable rethrow of unhandled exceptions and let them propagate further."
-    " (Default behavior is to catch and log it.)\n"
+    "                     Enable rethrow of unhandled exceptions and let them propagate further. (Default behavior is to catch and log it.)\n"
     "    java5:           Generate Java 1.5 compliant code (includes android_legacy flag).\n"
     "    future_iface:    Generate CompletableFuture based iface based on async client.\n"
-    "    reuse_objects:   Data objects will not be allocated, but existing instances will be used "
-    "(read and write).\n"
+    "    reuse_objects:   Data objects will not be allocated, but existing instances will be used (read and write).\n"
     "    reuse-objects:   Same as 'reuse_objects' (deprecated).\n"
     "    sorted_containers:\n"
-    "                     Use TreeSet/TreeMap instead of HashSet/HashMap as a implementation of "
-    "set/map.\n"
+    "                     Use TreeSet/TreeMap instead of HashSet/HashMap as a implementation of set/map.\n"
     "    generated_annotations=[undated|suppress]:\n"
     "                     undated: suppress the date at @Generated annotations\n"
     "                     suppress: suppress @Generated annotations entirely\n"
diff --git a/compiler/cpp/src/thrift/generate/t_javame_generator.cc b/compiler/cpp/src/thrift/generate/t_javame_generator.cc
index 4da0869..d8d9056 100644
--- a/compiler/cpp/src/thrift/generate/t_javame_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_javame_generator.cc
@@ -67,6 +67,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   void generate_consts(std::vector<t_const*> consts) override;
 
@@ -3295,4 +3296,9 @@
   indent(out) << "}" << endl << endl;
 }
 
+std::string t_javame_generator::display_name() const {
+  return "Java ME";
+}
+
+
 THRIFT_REGISTER_GENERATOR(javame, "Java ME", "")
diff --git a/compiler/cpp/src/thrift/generate/t_js_generator.cc b/compiler/cpp/src/thrift/generate/t_js_generator.cc
index 03a307f..fbd657e 100644
--- a/compiler/cpp/src/thrift/generate/t_js_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_js_generator.cc
@@ -131,6 +131,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   /**
    * Program-level generation functions
@@ -151,6 +152,7 @@
   /**
    * Structs!
    */
+
   void generate_js_struct(t_struct* tstruct, bool is_exception);
   void generate_js_struct_definition(std::ostream& out,
                                      t_struct* tstruct,
@@ -163,6 +165,7 @@
   /**
    * Service-level generation functions
    */
+
   void generate_service_helpers(t_service* tservice);
   void generate_service_interface(t_service* tservice);
   void generate_service_rest(t_service* tservice);
@@ -229,6 +232,7 @@
   /**
    * Helper parser functions
    */
+
   void parse_imports(t_program* program, const std::string& imports_string);
   void parse_thrift_package_output_directory(const std::string& thrift_package_output_directory);
 
@@ -2997,6 +3001,11 @@
   return current_name;
 }
 
+std::string t_js_generator::display_name() const {
+  return "Javascript";
+}
+
+
 THRIFT_REGISTER_GENERATOR(js,
                           "Javascript",
                           "    jquery:          Generate jQuery compatible code.\n"
diff --git a/compiler/cpp/src/thrift/generate/t_json_generator.cc b/compiler/cpp/src/thrift/generate/t_json_generator.cc
index 5a854ce..b94e81c 100644
--- a/compiler/cpp/src/thrift/generate/t_json_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_json_generator.cc
@@ -73,9 +73,9 @@
   /**
   * Init and close methods
   */
-
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   void generate_typedef(t_typedef* ttypedef) override;
   void generate_enum(t_enum* tenum) override;
@@ -803,6 +803,11 @@
   return ttype->get_program()->get_name() + "." + ttype->get_name();
 }
 
+std::string t_json_generator::display_name() const {
+  return "JSON";
+}
+
+
 THRIFT_REGISTER_GENERATOR(json,
                           "JSON",
                           "    merge:           Generate output with included files merged\n")
diff --git a/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc b/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc
index 29cf00a..a017272 100644
--- a/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc
@@ -75,8 +75,10 @@
   /**
    * Init and close methods
    */
+
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   void generate_consts(std::vector<t_const*> consts) override;
 
@@ -2005,4 +2007,9 @@
   }
 }
 
+std::string t_kotlin_generator::display_name() const {
+  return "Kotlin";
+}
+
+
 THRIFT_REGISTER_GENERATOR(kotlin, "Kotlin", "")
diff --git a/compiler/cpp/src/thrift/generate/t_lua_generator.cc b/compiler/cpp/src/thrift/generate/t_lua_generator.cc
index a4b4a37..0dc7743 100644
--- a/compiler/cpp/src/thrift/generate/t_lua_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_lua_generator.cc
@@ -56,12 +56,15 @@
   /**
    * Init and close methods
    */
+
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   /**
    * Program-level generation functions
    */
+
   void generate_typedef(t_typedef* ttypedef) override;
   void generate_enum(t_enum* tenum) override;
   void generate_const(t_const* tconst) override;
@@ -80,6 +83,7 @@
   /**
    * Struct-level generation functions
    */
+
   void generate_lua_struct_definition(std::ostream& out,
                                       t_struct* tstruct,
                                       bool is_xception = false);
@@ -89,6 +93,7 @@
   /**
    * Service-level generation functions
    */
+
   void generate_service_client(std::ostream& out, t_service* tservice);
   void generate_service_interface(std::ostream& out, t_service* tservice);
   void generate_service_processor(std::ostream& out, t_service* tservice);
@@ -99,6 +104,7 @@
   /**
    * Deserialization (Read)
    */
+
   void generate_deserialize_field(std::ostream& out,
                                   t_field* tfield,
                                   bool local,
@@ -125,6 +131,7 @@
   /**
    * Serialization (Write)
    */
+
   void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
 
   void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
@@ -1164,6 +1171,11 @@
   throw "INVALID TYPE IN type_to_enum: " + type->get_name();
 }
 
+std::string t_lua_generator::display_name() const {
+  return "Lua";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     lua,
     "Lua",
diff --git a/compiler/cpp/src/thrift/generate/t_markdown_generator.cc b/compiler/cpp/src/thrift/generate/t_markdown_generator.cc
index 0f6aa22..76fe98b 100644
--- a/compiler/cpp/src/thrift/generate/t_markdown_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_markdown_generator.cc
@@ -84,6 +84,8 @@
     init_allowed__markup();
   }
 
+  std::string display_name() const override;
+
   void generate_program() override;
   void generate_program_toc();
   void generate_program_toc_row(t_program* tprog);
@@ -1103,6 +1105,11 @@
   }
 }
 
+std::string t_markdown_generator::display_name() const {
+  return "Markdown";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     markdown,
     "Markdown",
diff --git a/compiler/cpp/src/thrift/generate/t_netstd_generator.cc b/compiler/cpp/src/thrift/generate/t_netstd_generator.cc
index 4cf3db5..b9c7fa8 100644
--- a/compiler/cpp/src/thrift/generate/t_netstd_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_netstd_generator.cc
@@ -427,7 +427,7 @@
     {
         generate_netstd_doc(out, *c_iter);
         int value = (*c_iter)->get_value();
-        out << indent() << (*c_iter)->get_name() << " = " << value << "," << endl;
+        out << indent() << normalize_name((*c_iter)->get_name()) << " = " << value << "," << endl;
     }
 
     scope_down(out);
@@ -3874,6 +3874,11 @@
     return "global::" + package + type->get_name();
 }
 
+std::string t_netstd_generator::display_name() const {
+  return "C#";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     netstd,
     "C#",
diff --git a/compiler/cpp/src/thrift/generate/t_netstd_generator.h b/compiler/cpp/src/thrift/generate/t_netstd_generator.h
index 982cd26..b9456c8 100644
--- a/compiler/cpp/src/thrift/generate/t_netstd_generator.h
+++ b/compiler/cpp/src/thrift/generate/t_netstd_generator.h
@@ -71,6 +71,7 @@
   // overrides
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
   void generate_consts(vector<t_const*> consts) override;
   void generate_consts(ostream& out, vector<t_const*> consts);
   void generate_typedef(t_typedef* ttypedef) override;
diff --git a/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc b/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc
index 747adcb..5f9b80c 100644
--- a/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc
@@ -64,10 +64,12 @@
   ~t_ocaml_generator() override;
 
   void init_generator() override;
+  std::string display_name() const override;
 
   /**
    * Program-level generation functions
    */
+
   void generate_program() override;
   void generate_typedef(t_typedef* ttypedef) override;
   void generate_enum(t_enum* tenum) override;
@@ -1769,4 +1771,9 @@
   throw "INVALID TYPE IN type_to_enum: " + type->get_name();
 }
 
+std::string t_ocaml_generator::display_name() const {
+  return "OCaml";
+}
+
+
 THRIFT_REGISTER_GENERATOR(ocaml, "OCaml", "")
diff --git a/compiler/cpp/src/thrift/generate/t_perl_generator.cc b/compiler/cpp/src/thrift/generate/t_perl_generator.cc
index 72de698..d133b24 100644
--- a/compiler/cpp/src/thrift/generate/t_perl_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_perl_generator.cc
@@ -68,6 +68,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   /**
    * Program-level generation functions
@@ -1684,4 +1685,9 @@
   throw "INVALID TYPE IN type_to_enum: " + type->get_name();
 }
 
+std::string t_perl_generator::display_name() const {
+  return "Perl";
+}
+
+
 THRIFT_REGISTER_GENERATOR(perl, "Perl", "")
diff --git a/compiler/cpp/src/thrift/generate/t_php_generator.cc b/compiler/cpp/src/thrift/generate/t_php_generator.cc
index c6e60c8..5e02b9b 100644
--- a/compiler/cpp/src/thrift/generate/t_php_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_php_generator.cc
@@ -99,6 +99,7 @@
       throw "oop and inlined are mutually exclusive.";
     }
 
+    update_keywords_for_validation();
     out_dir_base_ = (binary_inline_ ? "gen-phpi" : "gen-php");
     escape_['$'] = "\\$";
   }
@@ -115,6 +116,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   /**
    * Program-level generation functions
@@ -128,6 +130,7 @@
   void generate_service(t_service* tservice) override;
 
   std::string render_const_value(t_type* type, t_const_value* value);
+  std::set<std::string> lang_keywords_for_validation() const override;
 
   /**
    * Structs!
@@ -418,6 +421,22 @@
   bool getters_setters_;
 };
 
+std::set<std::string> t_php_generator::lang_keywords_for_validation() const {
+  std::string keywords[] = { "BEGIN", "END", "__CLASS__", "__DIR__", "__FILE__", "__FUNCTION__",
+      "__LINE__", "__METHOD__", "__NAMESPACE__", "abstract", "alias", "and", "args", "as",
+      "assert", "begin", "break", "case", "catch", "class", "clone", "continue", "declare",
+      "def", "default", "del", "delete", "do", "dynamic", "elif", "else", "elseif", "elsif",
+      "end", "enddeclare", "endfor", "endforeach", "endif", "endswitch", "endwhile", "ensure",
+      "except", "exec", "finally", "float", "for", "foreach", "from", "function", "global",
+      "goto", "if", "implements", "import", "in", "inline", "instanceof", "interface", "is",
+      "lambda", "module", "native", "new", "next", "nil", "not", "or", "package", "pass",
+      "public", "print", "private", "protected", "raise", "redo", "rescue", "retry", "register",
+      "return", "self", "sizeof", "static", "super", "switch", "synchronized", "then", "this",
+      "throw", "transient", "try", "undef", "unless", "unsigned", "until", "use", "var",
+      "virtual", "volatile", "when", "while", "with", "xor", "yield" };
+  return std::set<std::string>(keywords, keywords + sizeof(keywords)/sizeof(keywords[0]) );
+}
+
 bool t_php_generator::is_valid_namespace(const std::string& sub_namespace) {
   return sub_namespace == "path";
 }
@@ -2871,6 +2890,11 @@
   throw "INVALID TYPE IN type_to_enum: " + type->get_name();
 }
 
+std::string t_php_generator::display_name() const {
+  return "PHP";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     php,
     "PHP",
diff --git a/compiler/cpp/src/thrift/generate/t_py_generator.cc b/compiler/cpp/src/thrift/generate/t_py_generator.cc
index 8ab8b98..857cb77 100644
--- a/compiler/cpp/src/thrift/generate/t_py_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_py_generator.cc
@@ -52,7 +52,7 @@
                  const std::map<std::string, std::string>& parsed_options,
                  const std::string& option_string)
     : t_generator (program) {
-    update_keywords();
+    update_keywords_for_validation();
 
     std::map<std::string, std::string>::const_iterator iter;
 
@@ -157,6 +157,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   /**
    * Program-level generation functions
@@ -357,7 +358,7 @@
   std::string module_;
 
 protected:
-  std::set<std::string> lang_keywords() const override {
+  std::set<std::string> lang_keywords_for_validation() const override {
     std::string keywords[] = { "False", "None", "True", "and", "as", "assert", "break", "class",
           "continue", "def", "del", "elif", "else", "except", "exec", "finally", "for", "from",
           "global", "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass", "print",
@@ -2821,6 +2822,11 @@
   throw "INVALID TYPE IN type_to_spec_args: " + ttype->get_name();
 }
 
+std::string t_py_generator::display_name() const {
+  return "Python";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     py,
     "Python",
diff --git a/compiler/cpp/src/thrift/generate/t_rb_generator.cc b/compiler/cpp/src/thrift/generate/t_rb_generator.cc
index 2ec5787..90dbfe5 100644
--- a/compiler/cpp/src/thrift/generate/t_rb_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_rb_generator.cc
@@ -104,6 +104,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   /**
    * Program-level generation functions
@@ -1283,6 +1284,11 @@
   out.indent() << "end" << endl << endl;
 }
 
+std::string t_rb_generator::display_name() const {
+  return "Ruby";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     rb,
     "Ruby",
diff --git a/compiler/cpp/src/thrift/generate/t_rs_generator.cc b/compiler/cpp/src/thrift/generate/t_rs_generator.cc
index 5946e1d..f454d9b 100644
--- a/compiler/cpp/src/thrift/generate/t_rs_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_rs_generator.cc
@@ -76,6 +76,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   /**
    * Program-level generation functions
@@ -3366,6 +3367,11 @@
   }
 }
 
+std::string t_rs_generator::display_name() const {
+  return "Rust";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
   rs,
   "Rust",
diff --git a/compiler/cpp/src/thrift/generate/t_st_generator.cc b/compiler/cpp/src/thrift/generate/t_st_generator.cc
index 5edb852..b141186 100644
--- a/compiler/cpp/src/thrift/generate/t_st_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_st_generator.cc
@@ -73,6 +73,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   /**
    * Program-level generation functions
@@ -1055,4 +1056,9 @@
   throw "INVALID TYPE IN type_to_enum: " + type->get_name();
 }
 
+std::string t_st_generator::display_name() const {
+  return "Smalltalk";
+}
+
+
 THRIFT_REGISTER_GENERATOR(st, "Smalltalk", "")
diff --git a/compiler/cpp/src/thrift/generate/t_swift_generator.cc b/compiler/cpp/src/thrift/generate/t_swift_generator.cc
index 78fb1d8..fab1413 100644
--- a/compiler/cpp/src/thrift/generate/t_swift_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_swift_generator.cc
@@ -50,7 +50,7 @@
                     const map<string, string>& parsed_options,
                     const string& option_string)
     : t_oop_generator(program) {
-    update_keywords();
+    update_keywords_for_validation();
     
     (void)option_string;
     map<string, string>::const_iterator iter;
@@ -98,6 +98,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   void generate_consts(vector<t_const*> consts) override;
 
@@ -291,7 +292,7 @@
   bool promise_kit_;
 
 protected:
-  std::set<std::string> lang_keywords() const override {
+  std::set<std::string> lang_keywords_for_validation() const override {
       return {};
   }
 };
@@ -3201,6 +3202,11 @@
 }
 
 
+std::string t_swift_generator::display_name() const {
+  return "Swift 3.0";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
     swift,
     "Swift 3.0",
diff --git a/compiler/cpp/src/thrift/generate/t_xml_generator.cc b/compiler/cpp/src/thrift/generate/t_xml_generator.cc
index 220d50c..68675cf 100644
--- a/compiler/cpp/src/thrift/generate/t_xml_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_xml_generator.cc
@@ -83,6 +83,8 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
+
   void generate_program() override;
 
   void iterate_program(t_program* program);
@@ -692,6 +694,11 @@
   return "(unknown)";
 }
 
+std::string t_xml_generator::display_name() const {
+  return "XML";
+}
+
+
 THRIFT_REGISTER_GENERATOR(
   xml,
   "XML",
diff --git a/compiler/cpp/src/thrift/generate/t_xsd_generator.cc b/compiler/cpp/src/thrift/generate/t_xsd_generator.cc
index 15ede75..1f58f3a 100644
--- a/compiler/cpp/src/thrift/generate/t_xsd_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_xsd_generator.cc
@@ -67,6 +67,7 @@
 
   void init_generator() override;
   void close_generator() override;
+  std::string display_name() const override;
 
   /**
    * Program-level generation functions
@@ -360,4 +361,9 @@
   }
 }
 
+std::string t_xsd_generator::display_name() const {
+  return "XSD";
+}
+
+
 THRIFT_REGISTER_GENERATOR(xsd, "XSD", "")
diff --git a/compiler/cpp/test/CMakeLists.txt b/compiler/cpp/test/CMakeLists.txt
index b80f060..6cf309b 100644
--- a/compiler/cpp/test/CMakeLists.txt
+++ b/compiler/cpp/test/CMakeLists.txt
@@ -18,8 +18,8 @@
 #
 
 file(GLOB KEYWORD_SAMPLES "${CMAKE_CURRENT_SOURCE_DIR}/keyword-samples/*.thrift")
-set(KEYWORD_LANGS ${thrift_compiler_LANGS})
-LIST(REMOVE_ITEM KEYWORD_LANGS swift) # in Swift you can escape reserved words
+set(KEYWORD_LANGS php)  # the whole ticket THRIFT-4655 is only about PHP so leave other languages alone
+LIST(REMOVE_ITEM KEYWORD_LANGS swift) # in Swift you can escape reserved words (and in other languages as well)
 foreach(LANG ${KEYWORD_LANGS})
     foreach(SAMPLE ${KEYWORD_SAMPLES})
         get_filename_component(FILENAME ${SAMPLE} NAME_WE)
diff --git a/compiler/cpp/test/keyword-samples/const1_return.thrift b/compiler/cpp/test/keyword-samples/const1_return.thrift
index f75f980..5a120c2 100644
--- a/compiler/cpp/test/keyword-samples/const1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/const1_return.thrift
@@ -17,4 +17,7 @@
  * under the License.
  */
 
+
+namespace * keyword_test_007
+
 const bool return = 0
diff --git a/compiler/cpp/test/keyword-samples/enum1_return.thrift b/compiler/cpp/test/keyword-samples/enum1_return.thrift
index b3755e0..1dcf594 100644
--- a/compiler/cpp/test/keyword-samples/enum1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/enum1_return.thrift
@@ -17,5 +17,8 @@
  * under the License.
  */
 
+
+namespace * keyword_test_008
+
 enum return {
 }
diff --git a/compiler/cpp/test/keyword-samples/enum2_return.thrift b/compiler/cpp/test/keyword-samples/enum2_return.thrift
index 1c26cc8..e357313 100644
--- a/compiler/cpp/test/keyword-samples/enum2_return.thrift
+++ b/compiler/cpp/test/keyword-samples/enum2_return.thrift
@@ -17,6 +17,9 @@
  * under the License.
  */
 
+
+namespace * keyword_test_009
+
 enum enum_name {
   return
 }
diff --git a/compiler/cpp/test/keyword-samples/exception1_return.thrift b/compiler/cpp/test/keyword-samples/exception1_return.thrift
index d89d9e8..eb31a47 100644
--- a/compiler/cpp/test/keyword-samples/exception1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/exception1_return.thrift
@@ -17,4 +17,6 @@
  * under the License.
  */
 
+namespace * keyword_test_010
+
 exception return {}
diff --git a/compiler/cpp/test/keyword-samples/exception2_return.thrift b/compiler/cpp/test/keyword-samples/exception2_return.thrift
index e1289ed..6193fc0 100644
--- a/compiler/cpp/test/keyword-samples/exception2_return.thrift
+++ b/compiler/cpp/test/keyword-samples/exception2_return.thrift
@@ -17,6 +17,8 @@
  * under the License.
  */
 
+namespace * keyword_test_011
+
 exception exception_name {
   1: required i8 return
 }
diff --git a/compiler/cpp/test/keyword-samples/service1_return.thrift b/compiler/cpp/test/keyword-samples/service1_return.thrift
index c52abb6..da36b1c 100644
--- a/compiler/cpp/test/keyword-samples/service1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/service1_return.thrift
@@ -17,4 +17,6 @@
  * under the License.
  */
 
+namespace * keyword_test_012
+
 service return {}
diff --git a/compiler/cpp/test/keyword-samples/service2_return.thrift b/compiler/cpp/test/keyword-samples/service2_return.thrift
index 0c77a26..3150754 100644
--- a/compiler/cpp/test/keyword-samples/service2_return.thrift
+++ b/compiler/cpp/test/keyword-samples/service2_return.thrift
@@ -17,6 +17,8 @@
  * under the License.
  */
 
+namespace * keyword_test_013
+
 service service_name {
   bool function_name(1: i32 return)
 }
diff --git a/compiler/cpp/test/keyword-samples/service3_return.thrift b/compiler/cpp/test/keyword-samples/service3_return.thrift
index fe084d2..f6909ab 100644
--- a/compiler/cpp/test/keyword-samples/service3_return.thrift
+++ b/compiler/cpp/test/keyword-samples/service3_return.thrift
@@ -17,6 +17,8 @@
  * under the License.
  */
 
+namespace * keyword_test_014
+
 service service_name {
   void return()
 }
diff --git a/compiler/cpp/test/keyword-samples/service4_return.thrift b/compiler/cpp/test/keyword-samples/service4_return.thrift
index 53993f1..72da51c 100644
--- a/compiler/cpp/test/keyword-samples/service4_return.thrift
+++ b/compiler/cpp/test/keyword-samples/service4_return.thrift
@@ -17,6 +17,8 @@
  * under the License.
  */
 
+namespace * keyword_test_001
+
 exception exception_name {}
 
 service service_name {
diff --git a/compiler/cpp/test/keyword-samples/struct1_return.thrift b/compiler/cpp/test/keyword-samples/struct1_return.thrift
index 9664010..0029029 100644
--- a/compiler/cpp/test/keyword-samples/struct1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/struct1_return.thrift
@@ -17,4 +17,6 @@
  * under the License.
  */
 
+namespace * keyword_test_002
+
 struct return {}
diff --git a/compiler/cpp/test/keyword-samples/struct2_return.thrift b/compiler/cpp/test/keyword-samples/struct2_return.thrift
index db123e5..d34d0a7 100644
--- a/compiler/cpp/test/keyword-samples/struct2_return.thrift
+++ b/compiler/cpp/test/keyword-samples/struct2_return.thrift
@@ -17,6 +17,8 @@
  * under the License.
  */
 
+namespace * keyword_test_003
+
 struct struct_name {
   1: required bool return = 1
 }
diff --git a/compiler/cpp/test/keyword-samples/typedef1_return.thrift b/compiler/cpp/test/keyword-samples/typedef1_return.thrift
index 142d51f..be97586 100644
--- a/compiler/cpp/test/keyword-samples/typedef1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/typedef1_return.thrift
@@ -16,4 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
+namespace * keyword_test_004
+
 typedef bool return
diff --git a/compiler/cpp/test/keyword-samples/union1_return.thrift b/compiler/cpp/test/keyword-samples/union1_return.thrift
index af7a8e7..43cd167 100644
--- a/compiler/cpp/test/keyword-samples/union1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/union1_return.thrift
@@ -17,4 +17,7 @@
  * under the License.
  */
 
+
+namespace * keyword_test_005
+
 union return {}
diff --git a/compiler/cpp/test/keyword-samples/union2_return.thrift b/compiler/cpp/test/keyword-samples/union2_return.thrift
index 3361a1a..5ff7955 100644
--- a/compiler/cpp/test/keyword-samples/union2_return.thrift
+++ b/compiler/cpp/test/keyword-samples/union2_return.thrift
@@ -17,6 +17,10 @@
  * under the License.
  */
 
+
+
+namespace * keyword_test_006
+
 union union_name {
   1: optional bool return=1
 }