THRIFT-5179: Fix generated code for struct's named "a" or "b"

Client: cpp
diff --git a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
index c2d88cd..a3ac854 100644
--- a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
@@ -1281,8 +1281,13 @@
 
   if (swap) {
     // Generate a namespace-scope swap() function
-    out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name()
-        << " &b);" << endl << endl;
+    if (tstruct->get_name() == "a" || tstruct->get_name() == "b") {
+      out << indent() << "void swap(" << tstruct->get_name() << " &a1, " << tstruct->get_name()
+          << " &a2);" << endl << endl;
+    } else {
+       out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name()
+           << " &b);" << endl << endl;
+    }
   }
 
   if (is_user_struct) {
@@ -1601,8 +1606,14 @@
  * @param tstruct The struct
  */
 void t_cpp_generator::generate_struct_swap(ostream& out, t_struct* tstruct) {
-  out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name()
-      << " &b) {" << endl;
+  if (tstruct->get_name() == "a" || tstruct->get_name() == "b") {
+    out << indent() << "void swap(" << tstruct->get_name() << " &a1, " << tstruct->get_name()
+        << " &a2) {" << endl; 
+  } else {
+    out << indent() << "void swap(" << tstruct->get_name() << " &a, " << tstruct->get_name()
+        << " &b) {" << endl;
+  }
+
   indent_up();
 
   // Let argument-dependent name lookup find the correct swap() function to
@@ -1617,18 +1628,32 @@
       has_nonrequired_fields = true;
     }
 
-    out << indent() << "swap(a." << tfield->get_name() << ", b." << tfield->get_name() << ");"
-        << endl;
+    if (tstruct->get_name() == "a" || tstruct->get_name() == "b") {
+      out << indent() << "swap(a1." << tfield->get_name() << ", a2." << tfield->get_name() << ");"
+          << endl;
+    } else {
+      out << indent() << "swap(a." << tfield->get_name() << ", b." << tfield->get_name() << ");"
+          << endl;
+    }
   }
 
   if (has_nonrequired_fields) {
-    out << indent() << "swap(a.__isset, b.__isset);" << endl;
+    if (tstruct->get_name() == "a" || tstruct->get_name() == "b") {
+      out << indent() << "swap(a1.__isset, a2.__isset);" << endl; 
+    } else {
+      out << indent() << "swap(a.__isset, b.__isset);" << endl;
+    }
   }
 
   // handle empty structs
   if (fields.size() == 0) {
-    out << indent() << "(void) a;" << endl;
-    out << indent() << "(void) b;" << endl;
+    if (tstruct->get_name() == "a" || tstruct->get_name() == "b") {
+      out << indent() << "(void) a1;" << endl;
+      out << indent() << "(void) a2;" << endl;
+    } else {
+      out << indent() << "(void) a;" << endl;
+      out << indent() << "(void) b;" << endl;
+    }
   }
 
   scope_down(out);
diff --git a/test/Makefile.am b/test/Makefile.am
index 608e488..f1c808e 100755
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -167,6 +167,7 @@
 	ThriftTest.thrift \
 	TypedefTest.thrift \
 	UnsafeTypes.thrift \
+	SpecificNameTest.thrift \
 	known_failures_Linux.json \
 	test.py \
 	tests.json \
diff --git a/test/SpecificNameTest.thrift b/test/SpecificNameTest.thrift
new file mode 100644
index 0000000..165fc31
--- /dev/null
+++ b/test/SpecificNameTest.thrift
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+namespace cpp test.specificname
+
+struct a {
+  1: i32 number,
+  2: string message,
+}
+
+struct b {
+  1: i32 number,
+  2: string message,
+}
+
+service EchoService {
+  void echoA(1: a arg),
+  void echoB(2: b arg),
+}
diff --git a/test/cpp/CMakeLists.txt b/test/cpp/CMakeLists.txt
index 367b6de..9ecc171 100755
--- a/test/cpp/CMakeLists.txt
+++ b/test/cpp/CMakeLists.txt
@@ -56,6 +56,13 @@
 add_library(crossstressgencpp STATIC ${crossstressgencpp_SOURCES})
 LINK_AGAINST_THRIFT_LIBRARY(crossstressgencpp thrift)
 
+set(crossspecificnamegencpp_SOURCES
+    gen-cpp/EchoService.cpp 
+    gen-cpp/SpecificNameTest_types.cpp
+)
+add_library(crossspecificnamegencpp STATIC ${crossspecificnamegencpp_SOURCES})
+LINK_AGAINST_THRIFT_LIBRARY(crossspecificnamegencpp thrift)
+
 add_executable(TestServer src/TestServer.cpp)
 target_link_libraries(TestServer crosstestgencpp ${Boost_LIBRARIES} ${LIBEVENT_LIB})
 LINK_AGAINST_THRIFT_LIBRARY(TestServer thrift)
@@ -86,6 +93,12 @@
     add_test(NAME StressTestNonBlocking COMMAND StressTestNonBlocking)
 endif()
 
+add_executable(SpecificNameTest src/SpecificNameTest.cpp)
+target_link_libraries(SpecificNameTest crossspecificnamegencpp ${Boost_LIBRARIES} ${LIBEVENT_LIB})
+LINK_AGAINST_THRIFT_LIBRARY(SpecificNameTest thrift)
+LINK_AGAINST_THRIFT_LIBRARY(SpecificNameTest thriftnb)
+add_test(NAME SpecificNameTest COMMAND SpecificNameTest)
+
 #
 # Common thrift code generation rules
 #
@@ -97,3 +110,7 @@
 add_custom_command(OUTPUT gen-cpp/Service.cpp
     COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/StressTest.thrift
 )
+
+add_custom_command(OUTPUT gen-cpp/EchoService.cpp gen-cpp/SpecificNameTest_types.cpp
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/SpecificNameTest.thrift
+)
diff --git a/test/cpp/Makefile.am b/test/cpp/Makefile.am
index 4f77c15..d3754f4 100755
--- a/test/cpp/Makefile.am
+++ b/test/cpp/Makefile.am
@@ -103,6 +103,9 @@
 gen-cpp/Service.cpp: $(top_srcdir)/test/StressTest.thrift $(THRIFT)
 	$(THRIFT) --gen cpp $<
 
+gen-cpp/SpecificNameTest_types.cpp gen-cpp/EchoService.cpp: $(top_srcdir)/test/SpecificName.thrift $(THRIFT)
+	$(THRIFT) --gen cpp $<
+
 AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -Igen-cpp -I.
 AM_CXXFLAGS = -Wall -Wextra -pedantic -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
 AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS) $(ZLIB_LIBS)
diff --git a/test/cpp/src/SpecificNameTest.cpp b/test/cpp/src/SpecificNameTest.cpp
new file mode 100644
index 0000000..9c31ac1
--- /dev/null
+++ b/test/cpp/src/SpecificNameTest.cpp
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+int main(int argc, char** argv) {
+  
+  //Empty in main function, 
+  //because we just want to test  
+  //whether the generated source code
+  //(IDL file contains struct named as
+  //'a' or 'b') can be compiled.
+
+  return 0;
+}