Commit message: THRIFT-3893 Command injection in format_go_output
Client: Go
Patch: Jens Geyer
CVE: CVE-2016-5397
CWE: CWE-77
Vulnerability description: The Apache Thrift Go client library exposed the potential during code generation for command injection due to using an external formatting tool. Affected Apache Thrift 0.9.3 and older, Fixed in Apache Thrift 0.10.0.

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_service(t_service* tservice) {
  string test_suffix("_test");
  string filename = lowercase(service_name_);
  string f_service_name;

  generate_service_interface(tservice);
  generate_service_client(tservice);
  generate_service_server(tservice);
  generate_service_helpers(tservice);
  generate_service_remote(tservice);
  f_types_ << endl;
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_go_docstring(ofstream& out,
                                           t_doc* tdoc,
                                           t_struct* tstruct,
                                           const char* subheader) {
  bool has_doc = false;
  stringstream ss;

  if (tdoc->has_doc()) {
    has_doc = true;
    ss << tdoc->get_doc();
  }

  const vector<t_field*>& fields = tstruct->get_members();

  if (fields.size() > 0) {
    if (has_doc) {
      ss << endl;
    }

    has_doc = true;
    ss << subheader << ":\n";
    vector<t_field*>::const_iterator p_iter;

    for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
      t_field* p = *p_iter;
      ss << " - " << publicize(p->get_name());

      if (p->has_doc()) {
        ss << ": " << p->get_doc();
      } else {
        ss << endl;
      }
    }
  }

  if (has_doc) {
    generate_docstring_comment(out, "", "// ", ss.str(), "");
  }
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_deserialize_field(ofstream& out,
                                                t_field* tfield,
                                                bool declare,
                                                string prefix,
                                                bool inclass,
                                                bool coerceData,
                                                bool inkey,
                                                bool in_container_value,
                                                bool use_true_type) {
  (void)inclass;
  (void)coerceData;
  t_type* orig_type = tfield->get_type();
  t_type* type = get_true_type(orig_type);
  string name(prefix + publicize(tfield->get_name()));

  if (type->is_void()) {
    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + name;
  }

  if (type->is_struct() || type->is_xception()) {
    generate_deserialize_struct(out,
                                (t_struct*)type,
                                is_pointer_field(tfield, in_container_value),
                                declare,
                                name);
  } else if (type->is_container()) {
    generate_deserialize_container(out, orig_type, is_pointer_field(tfield), declare, name);
  } else if (type->is_base_type() || type->is_enum()) {

    if (declare) {
      t_type* actual_type = use_true_type ? tfield->get_type()->get_true_type()
                                          : tfield->get_type();

      string type_name = inkey ? type_to_go_key_type(actual_type) : type_to_go_type(actual_type);

      out << "var " << tfield->get_name() << " " << type_name << endl;
    }

    indent(out) << "if v, err := iprot.";

    if (type->is_base_type()) {
      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();

      switch (tbase) {
      case t_base_type::TYPE_VOID:
        throw "compiler error: cannot serialize void field in a struct: " + name;
        break;

      case t_base_type::TYPE_STRING:
        if (((t_base_type*)type)->is_binary() && !inkey) {
          out << "ReadBinary()";
        } else {
          out << "ReadString()";
        }

        break;

      case t_base_type::TYPE_BOOL:
        out << "ReadBool()";
        break;

      case t_base_type::TYPE_I8:
        out << "ReadByte()";
        break;

      case t_base_type::TYPE_I16:
        out << "ReadI16()";
        break;

      case t_base_type::TYPE_I32:
        out << "ReadI32()";
        break;

      case t_base_type::TYPE_I64:
        out << "ReadI64()";
        break;

      case t_base_type::TYPE_DOUBLE:
        out << "ReadDouble()";
        break;

      default:
        throw "compiler error: no Go name for base type " + t_base_type::t_base_name(tbase);
      }
    } else if (type->is_enum()) {
      out << "ReadI32()";
    }

    out << "; err != nil {" << endl;
    out << indent() << "return thrift.PrependError(\"error reading field " << tfield->get_key()
        << ": \", err)" << endl;

    out << "} else {" << endl;
    string wrap;

    if (type->is_enum() || (orig_type->is_typedef() && !use_true_type)) {
      wrap = publicize(type_name(orig_type));
    } else if (((t_base_type*)type)->get_base() == t_base_type::TYPE_I8) {
      wrap = "int8";
    }

    string maybe_address = (is_pointer_field(tfield) ? "&" : "");
    if (wrap == "") {
      indent(out) << name << " = " << maybe_address << "v" << endl;
    } else {
      indent(out) << "temp := " << wrap << "(v)" << endl;
      indent(out) << name << " = " << maybe_address << "temp" << endl;
    }

    out << "}" << endl;
  } else {
    throw "INVALID TYPE IN generate_deserialize_field '" + type->get_name() + "' for field '"
        + tfield->get_name() + "'";
  }
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_serialize_map_element(ofstream& out,
                                                    t_map* tmap,
                                                    string kiter,
                                                    string viter) {
  t_field kfield(tmap->get_key_type(), "");
  t_field vfield(tmap->get_val_type(), "");
  kfield.set_req(t_field::T_OPT_IN_REQ_OUT);
  vfield.set_req(t_field::T_OPT_IN_REQ_OUT);
  generate_serialize_field(out, &kfield, kiter, true);
  generate_serialize_field(out, &vfield, viter);
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_service_server(t_service* tservice) {
  // Generate the dispatch methods
  vector<t_function*> functions = tservice->get_functions();
  vector<t_function*>::iterator f_iter;
  string extends = "";
  string extends_processor = "";
  string extends_processor_new = "";
  string serviceName(publicize(tservice->get_name()));

  if (tservice->get_extends() != NULL) {
    extends = type_name(tservice->get_extends());
    size_t index = extends.rfind(".");

    if (index != string::npos) {
      extends_processor = extends.substr(0, index + 1) + publicize(extends.substr(index + 1))
                          + "Processor";
      extends_processor_new = extends.substr(0, index + 1) + "New"
                              + publicize(extends.substr(index + 1)) + "Processor";
    } else {
      extends_processor = publicize(extends) + "Processor";
      extends_processor_new = "New" + extends_processor;
    }
  }

  string pServiceName(privatize(tservice->get_name()));
  // Generate the header portion
  string self(tmp("self"));

  if (extends_processor.empty()) {
    f_types_ << indent() << "type " << serviceName << "Processor struct {" << endl;
    f_types_ << indent() << "  processorMap map[string]thrift.TProcessorFunction" << endl;
    f_types_ << indent() << "  handler " << serviceName << endl;
    f_types_ << indent() << "}" << endl << endl;
    f_types_ << indent() << "func (p *" << serviceName
               << "Processor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) {"
               << endl;
    f_types_ << indent() << "  p.processorMap[key] = processor" << endl;
    f_types_ << indent() << "}" << endl << endl;
    f_types_ << indent() << "func (p *" << serviceName
               << "Processor) GetProcessorFunction(key string) "
                  "(processor thrift.TProcessorFunction, ok bool) {" << endl;
    f_types_ << indent() << "  processor, ok = p.processorMap[key]" << endl;
    f_types_ << indent() << "  return processor, ok" << endl;
    f_types_ << indent() << "}" << endl << endl;
    f_types_ << indent() << "func (p *" << serviceName
               << "Processor) ProcessorMap() map[string]thrift.TProcessorFunction {" << endl;
    f_types_ << indent() << "  return p.processorMap" << endl;
    f_types_ << indent() << "}" << endl << endl;
    f_types_ << indent() << "func New" << serviceName << "Processor(handler " << serviceName
               << ") *" << serviceName << "Processor {" << endl << endl;
    f_types_
        << indent() << "  " << self << " := &" << serviceName
        << "Processor{handler:handler, processorMap:make(map[string]thrift.TProcessorFunction)}"
        << endl;

    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
      string escapedFuncName(escape_string((*f_iter)->get_name()));
      f_types_ << indent() << "  " << self << ".processorMap[\"" << escapedFuncName << "\"] = &"
                 << pServiceName << "Processor" << publicize((*f_iter)->get_name())
                 << "{handler:handler}" << endl;
    }

    string x(tmp("x"));
    f_types_ << indent() << "return " << self << endl;
    f_types_ << indent() << "}" << endl << endl;
    f_types_ << indent() << "func (p *" << serviceName
               << "Processor) Process(iprot, oprot thrift.TProtocol) (success bool, err "
                  "thrift.TException) {" << endl;
    f_types_ << indent() << "  name, _, seqId, err := iprot.ReadMessageBegin()" << endl;
    f_types_ << indent() << "  if err != nil { return false, err }" << endl;
    f_types_ << indent() << "  if processor, ok := p.GetProcessorFunction(name); ok {" << endl;
    f_types_ << indent() << "    return processor.Process(seqId, iprot, oprot)" << endl;
    f_types_ << indent() << "  }" << endl;
    f_types_ << indent() << "  iprot.Skip(thrift.STRUCT)" << endl;
    f_types_ << indent() << "  iprot.ReadMessageEnd()" << endl;
    f_types_ << indent() << "  " << x
               << " := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, \"Unknown function "
                  "\" + name)" << endl;
    f_types_ << indent() << "  oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId)" << endl;
    f_types_ << indent() << "  " << x << ".Write(oprot)" << endl;
    f_types_ << indent() << "  oprot.WriteMessageEnd()" << endl;
    f_types_ << indent() << "  oprot.Flush()" << endl;
    f_types_ << indent() << "  return false, " << x << endl;
    f_types_ << indent() << "" << endl;
    f_types_ << indent() << "}" << endl << endl;
  } else {
    f_types_ << indent() << "type " << serviceName << "Processor struct {" << endl;
    f_types_ << indent() << "  *" << extends_processor << endl;
    f_types_ << indent() << "}" << endl << endl;
    f_types_ << indent() << "func New" << serviceName << "Processor(handler " << serviceName
               << ") *" << serviceName << "Processor {" << endl;
    f_types_ << indent() << "  " << self << " := &" << serviceName << "Processor{"
               << extends_processor_new << "(handler)}" << endl;

    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
      string escapedFuncName(escape_string((*f_iter)->get_name()));
      f_types_ << indent() << "  " << self << ".AddToProcessorMap(\"" << escapedFuncName
                 << "\", &" << pServiceName << "Processor" << publicize((*f_iter)->get_name())
                 << "{handler:handler})" << endl;
    }

    f_types_ << indent() << "  return " << self << endl;
    f_types_ << indent() << "}" << endl << endl;
  }

  // Generate the process subfunctions
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
    generate_process_function(tservice, *f_iter);
  }

  f_types_ << endl;
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_serialize_field(ofstream& out,
                                              t_field* tfield,
                                              string prefix,
                                              bool inkey) {
  t_type* type = get_true_type(tfield->get_type());
  string name(prefix + publicize(tfield->get_name()));

  // Do nothing for void types
  if (type->is_void()) {
    throw "compiler error: cannot generate serialize for void type: " + name;
  }

  if (type->is_struct() || type->is_xception()) {
    generate_serialize_struct(out, (t_struct*)type, name);
  } else if (type->is_container()) {
    generate_serialize_container(out, type, is_pointer_field(tfield), name);
  } else if (type->is_base_type() || type->is_enum()) {
    indent(out) << "if err := oprot.";

    if (is_pointer_field(tfield)) {
      name = "*" + name;
    }

    if (type->is_base_type()) {
      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();

      switch (tbase) {
      case t_base_type::TYPE_VOID:
        throw "compiler error: cannot serialize void field in a struct: " + name;
        break;

      case t_base_type::TYPE_STRING:
        if (((t_base_type*)type)->is_binary() && !inkey) {
          out << "WriteBinary(" << name << ")";
        } else {
          out << "WriteString(string(" << name << "))";
        }

        break;

      case t_base_type::TYPE_BOOL:
        out << "WriteBool(bool(" << name << "))";
        break;

      case t_base_type::TYPE_I8:
        out << "WriteByte(int8(" << name << "))";
        break;

      case t_base_type::TYPE_I16:
        out << "WriteI16(int16(" << name << "))";
        break;

      case t_base_type::TYPE_I32:
        out << "WriteI32(int32(" << name << "))";
        break;

      case t_base_type::TYPE_I64:
        out << "WriteI64(int64(" << name << "))";
        break;

      case t_base_type::TYPE_DOUBLE:
        out << "WriteDouble(float64(" << name << "))";
        break;

      default:
        throw "compiler error: no Go name for base type " + t_base_type::t_base_name(tbase);
      }
    } else if (type->is_enum()) {
      out << "WriteI32(int32(" << name << "))";
    }

    out << "; err != nil {" << endl;
    out << indent() << "return thrift.PrependError(fmt.Sprintf(\"%T."
        << escape_string(tfield->get_name()) << " (" << tfield->get_key()
        << ") field write error: \", p), err) }" << endl;
  } else {
    throw "compiler error: Invalid type in generate_serialize_field '" + type->get_name()
        + "' for field '" + name + "'";
  }
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_typedef(t_typedef* ttypedef) {
  generate_go_docstring(f_types_, ttypedef);
  string new_type_name(publicize(ttypedef->get_symbolic()));
  string base_type(type_to_go_type(ttypedef->get_type()));

  if (base_type == new_type_name) {
    return;
  }

  f_types_ << "type " << new_type_name << " " << base_type << endl << endl;
  // Generate a convenience function that converts an instance of a type
  // (which may be a constant) into a pointer to an instance of a type.
  f_types_ << "func " << new_type_name << "Ptr(v " << new_type_name << ") *" << new_type_name
           << " { return &v }" << endl << endl;
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_go_struct(t_struct* tstruct, bool is_exception) {
  generate_go_struct_definition(f_types_, tstruct, is_exception);
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_serialize_set_element(ofstream& out, t_set* tset, string prefix) {
  t_field efield(tset->get_elem_type(), "");
  efield.set_req(t_field::T_OPT_IN_REQ_OUT);
  generate_serialize_field(out, &efield, prefix);
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::render_includes(bool consts) {
  const vector<t_program*>& includes = program_->get_includes();
  string result = "";
  string unused_prot = "";

  string local_namespace = program_->get_namespace("go");
  for (size_t i = 0; i < includes.size(); ++i) {
    if (!local_namespace.empty() && local_namespace == includes[i]->get_namespace("go")) {
      continue;
    }

    string go_module = get_real_go_module(includes[i]);
    size_t found = 0;
    for (size_t j = 0; j < go_module.size(); j++) {
      // Import statement uses slashes ('/') in namespace
      if (go_module[j] == '.') {
        go_module[j] = '/';
        found = j + 1;
      }
    }

    result += "\t\"" + gen_package_prefix_ + go_module + "\"\n";
    unused_prot += "var _ = " + go_module.substr(found) + ".GoUnusedProtection__\n";
  }

  if (includes.size() > 0) {
    result += "\n";
  }

  return go_imports_begin(consts) + result + go_imports_end() + unused_prot;
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_const(t_const* tconst) {
  t_type* type = tconst->get_type();
  string name = publicize(tconst->get_name());
  t_const_value* value = tconst->get_value();

  if (type->is_base_type() || type->is_enum()) {
    indent(f_consts_) << "const " << name << " = " << render_const_value(type, value, name) << endl;
  } else {
    f_const_values_ << indent() << name << " = " << render_const_value(type, value, name) << endl
                    << endl;

    f_consts_ << indent() << "var " << name << " " << type_to_go_type(type) << endl;
  }
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_enum(t_enum* tenum) {
  std::ostringstream to_string_mapping, from_string_mapping;
  std::string tenum_name(publicize(tenum->get_name()));
  generate_go_docstring(f_types_, tenum);
  f_types_ << "type " << tenum_name << " int64" << endl << "const (" << endl;

  to_string_mapping << indent() << "func (p " << tenum_name << ") String() string {" << endl;
  to_string_mapping << indent() << "  switch p {" << endl;

  from_string_mapping << indent() << "func " << tenum_name << "FromString(s string) (" << tenum_name
                      << ", error) {" << endl;
  from_string_mapping << indent() << "  switch s {" << endl;

  vector<t_enum_value*> constants = tenum->get_constants();
  vector<t_enum_value*>::iterator c_iter;
  int value = -1;

  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
    value = (*c_iter)->get_value();

    string iter_std_name(escape_string((*c_iter)->get_name()));
    string iter_name((*c_iter)->get_name());
    f_types_ << indent() << "  " << tenum_name << "_" << iter_name << ' ' << tenum_name << " = "
             << value << endl;
    // Dictionaries to/from string names of enums
    to_string_mapping << indent() << "  case " << tenum_name << "_" << iter_name << ": return \""
                      << iter_std_name << "\"" << endl;

    if (iter_std_name != escape_string(iter_name)) {
      from_string_mapping << indent() << "  case \"" << iter_std_name << "\", \""
                          << escape_string(iter_name) << "\": return " << tenum_name << "_"
                          << iter_name << ", nil " << endl;
    } else {
      from_string_mapping << indent() << "  case \"" << iter_std_name << "\": return " << tenum_name
                          << "_" << iter_name << ", nil " << endl;
    }
  }

  to_string_mapping << indent() << "  }" << endl;
  to_string_mapping << indent() << "  return \"<UNSET>\"" << endl;
  to_string_mapping << indent() << "}" << endl;
  from_string_mapping << indent() << "  }" << endl;
  from_string_mapping << indent() << "  return " << tenum_name << "(0),"
                      << " fmt.Errorf(\"not a valid " << tenum_name << " string\")" << endl;
  from_string_mapping << indent() << "}" << endl;

  f_types_ << ")" << endl << endl << to_string_mapping.str() << endl << from_string_mapping.str()
           << endl << endl;

  // Generate a convenience function that converts an instance of an enum
  // (which may be a constant) into a pointer to an instance of that enum
  // type.
  f_types_ << "func " << tenum_name << "Ptr(v " << tenum_name << ") *" << tenum_name
           << " { return &v }" << endl << endl;

  // Generate MarshalText
  f_types_ << "func (p " << tenum_name << ") MarshalText() ([]byte, error) {" << endl;
  f_types_ << "return []byte(p.String()), nil" << endl;
  f_types_ << "}" << endl << endl;

  // Generate UnmarshalText
  f_types_ << "func (p *" << tenum_name << ") UnmarshalText(text []byte) error {" << endl;
  f_types_ << "q, err := " << tenum_name << "FromString(string(text))" << endl;
  f_types_ << "if (err != nil) {" << endl << "return err" << endl << "}" << endl;
  f_types_ << "*p = q" << endl;
  f_types_ << "return nil" << endl;
  f_types_ << "}" << endl << endl;

  // Generate Scan for sql.Scanner interface
  f_types_ << "func (p *" << tenum_name << ") Scan(value interface{}) error {" <<endl;
  f_types_ << "v, ok := value.(int64)" <<endl;
  f_types_ << "if !ok {" <<endl;
  f_types_ << "return errors.New(\"Scan value is not int64\")" <<endl;
  f_types_ << "}" <<endl;
  f_types_ << "*p = " << tenum_name << "(v)" << endl;
  f_types_ << "return nil" << endl;
  f_types_ << "}" << endl << endl;

  // Generate Value for driver.Valuer interface
  f_types_ << "func (p * " << tenum_name << ") Value() (driver.Value, error) {" <<endl;
  f_types_ << "  if p == nil {" << endl;
  f_types_ << "    return nil, nil" << endl;
  f_types_ << "  }" << endl;
  f_types_ << "return int64(*p), nil" << endl;
  f_types_ << "}" << endl;

}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_deserialize_container(ofstream& out,
                                                    t_type* orig_type,
                                                    bool pointer_field,
                                                    bool declare,
                                                    string prefix) {
  t_type* ttype = get_true_type(orig_type);
  string eq(" = ");

  if (declare) {
    eq = " := ";
  }

  // Declare variables, read header
  if (ttype->is_map()) {
    out << indent() << "_, _, size, err := iprot.ReadMapBegin()" << endl;
    out << indent() << "if err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(\"error reading map begin: \", err)" << endl;
    out << indent() << "}" << endl;
    out << indent() << "tMap := make(" << type_to_go_type(orig_type) << ", size)" << endl;
    out << indent() << prefix << eq << " " << (pointer_field ? "&" : "") << "tMap" << endl;
  } else if (ttype->is_set()) {
    t_set* t = (t_set*)ttype;
    out << indent() << "_, size, err := iprot.ReadSetBegin()" << endl;
    out << indent() << "if err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(\"error reading set begin: \", err)" << endl;
    out << indent() << "}" << endl;
    out << indent() << "tSet := make(map["
        << type_to_go_key_type(t->get_elem_type()->get_true_type()) << "]struct{}, size)" << endl;
    out << indent() << prefix << eq << " " << (pointer_field ? "&" : "") << "tSet" << endl;
  } else if (ttype->is_list()) {
    out << indent() << "_, size, err := iprot.ReadListBegin()" << endl;
    out << indent() << "if err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(\"error reading list begin: \", err)" << endl;
    out << indent() << "}" << endl;
    out << indent() << "tSlice := make(" << type_to_go_type(orig_type) << ", 0, size)" << endl;
    out << indent() << prefix << eq << " " << (pointer_field ? "&" : "") << "tSlice" << endl;
  } else {
    throw "INVALID TYPE IN generate_deserialize_container '" + ttype->get_name() + "' for prefix '"
        + prefix + "'";
  }

  // For loop iterates over elements
  out << indent() << "for i := 0; i < size; i ++ {" << endl;
  indent_up();

  if (pointer_field) {
    prefix = "(*" + prefix + ")";
  }
  if (ttype->is_map()) {
    generate_deserialize_map_element(out, (t_map*)ttype, declare, prefix);
  } else if (ttype->is_set()) {
    generate_deserialize_set_element(out, (t_set*)ttype, declare, prefix);
  } else if (ttype->is_list()) {
    generate_deserialize_list_element(out, (t_list*)ttype, declare, prefix);
  }

  indent_down();
  out << indent() << "}" << endl;

  // Read container end
  if (ttype->is_map()) {
    out << indent() << "if err := iprot.ReadMapEnd(); err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(\"error reading map end: \", err)" << endl;
    out << indent() << "}" << endl;
  } else if (ttype->is_set()) {
    out << indent() << "if err := iprot.ReadSetEnd(); err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(\"error reading set end: \", err)" << endl;
    out << indent() << "}" << endl;
  } else if (ttype->is_list()) {
    out << indent() << "if err := iprot.ReadListEnd(); err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(\"error reading list end: \", err)" << endl;
    out << indent() << "}" << endl;
  }
}

Project: thrift
File: t_go_generator.cc

bool t_go_generator::is_pointer_field(t_field* tfield, bool in_container_value) {
  (void)in_container_value;
  if (tfield->annotations_.count("cpp.ref") != 0) {
    return true;
  }
  t_type* type = tfield->get_type()->get_true_type();
  // Structs in containers are pointers
  if (type->is_struct() || type->is_xception()) {
    return true;
  }
  if (!(tfield->get_req() == t_field::T_OPTIONAL)) {
    return false;
  }

  bool has_default = tfield->get_value();
  if (type->is_base_type()) {
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();

    switch (tbase) {
    case t_base_type::TYPE_VOID:
      throw "";

    case t_base_type::TYPE_STRING:
      if (((t_base_type*)type)->is_binary()) {
        //[]byte are always inline
        return false;
      }
      // strings are pointers if has no default
      return !has_default;

    case t_base_type::TYPE_BOOL:
    case t_base_type::TYPE_I8:
    case t_base_type::TYPE_I16:
    case t_base_type::TYPE_I32:
    case t_base_type::TYPE_I64:
    case t_base_type::TYPE_DOUBLE:
      return !has_default;
    }
  } else if (type->is_enum()) {
    return !has_default;
  } else if (type->is_struct() || type->is_xception()) {
    return true;
  } else if (type->is_map()) {
    return has_default;
  } else if (type->is_set()) {
    return has_default;
  } else if (type->is_list()) {
    return has_default;
  } else if (type->is_typedef()) {
    return has_default;
  }

  throw "INVALID TYPE IN type_to_go_type: " + type->get_name();
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_go_struct_definition(ofstream& out,
                                                   t_struct* tstruct,
                                                   bool is_exception,
                                                   bool is_result,
                                                   bool is_args) {
  const vector<t_field*>& members = tstruct->get_members();
  const vector<t_field*>& sorted_members = tstruct->get_sorted_members();
  vector<t_field*>::const_iterator m_iter;

  std::string tstruct_name(publicize(tstruct->get_name(), is_args || is_result));
  generate_go_docstring(out, tstruct);
  out << indent() << "type " << tstruct_name << " struct {" << endl;
  /*
     Here we generate the structure specification for the fastbinary codec.
     These specifications have the following structure:
     thrift_spec -> tuple of item_spec
     item_spec -> nil | (tag, type_enum, name, spec_args, default)
     tag -> integer
     type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ...
     name -> string_literal
     default -> nil  # Handled by __init__
     spec_args -> nil  # For simple types
                | (type_enum, spec_args)  # Value type for list/set
                | (type_enum, spec_args, type_enum, spec_args)
                  # Key and value for map
                | (class_name, spec_args_ptr) # For struct/exception
     class_name -> identifier  # Basically a pointer to the class
     spec_args_ptr -> expression  # just class_name.spec_args

     TODO(dreiss): Consider making this work for structs with negative tags.
  */
  // TODO(dreiss): Look into generating an empty tuple instead of nil
  // for structures with no members.
  // TODO(dreiss): Test encoding of structs where some inner structs
  // don't have thrift_spec.
  indent_up();

  int num_setable = 0;
  if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) {
    int sorted_keys_pos = 0;

    for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) {
      // Set field to optional if field is union, this is so we can get a
      // pointer to the field.
      if (tstruct->is_union())
        (*m_iter)->set_req(t_field::T_OPTIONAL);
      if (sorted_keys_pos != (*m_iter)->get_key()) {
        int first_unused = std::max(1, sorted_keys_pos++);
        while (sorted_keys_pos != (*m_iter)->get_key()) {
          ++sorted_keys_pos;
        }
        int last_unused = sorted_keys_pos - 1;
        if (first_unused < last_unused) {
          indent(out) << "// unused fields # " << first_unused << " to " << last_unused << endl;
        } else if (first_unused == last_unused) {
          indent(out) << "// unused field # " << first_unused << endl;
        }
      }

      t_type* fieldType = (*m_iter)->get_type();
      string goType = type_to_go_type_with_opt(fieldType, is_pointer_field(*m_iter));
      string gotag = "db:\"" + escape_string((*m_iter)->get_name())  + "\" ";
      if ((*m_iter)->get_req() == t_field::T_OPTIONAL) {
        gotag += "json:\"" + escape_string((*m_iter)->get_name()) + ",omitempty\"";
      } else {
        gotag += "json:\"" + escape_string((*m_iter)->get_name()) + "\"";
      }

      // Check for user override of db and json tags using "go.tag"
      std::map<string, string>::iterator it = (*m_iter)->annotations_.find("go.tag");
      if (it != (*m_iter)->annotations_.end()) {
        gotag = it->second;
      }
      indent(out) << publicize((*m_iter)->get_name()) << " " << goType << " `thrift:\""
                  << escape_string((*m_iter)->get_name()) << "," << sorted_keys_pos;
      if ((*m_iter)->get_req() == t_field::T_REQUIRED) {
        out << ",required";
      }

      out << "\" " << gotag << "`" << endl;
      sorted_keys_pos++;
    }
  } else {
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
      // This fills in default values, as opposed to nulls
      out << indent() << publicize((*m_iter)->get_name()) << " "
          << type_to_go_type((*m_iter)->get_type()) << endl;
    }
  }

  indent_down();
  out << indent() << "}" << endl << endl;
  out << indent() << "func New" << tstruct_name << "() *" << tstruct_name << " {" << endl;
  out << indent() << "  return &";
  generate_go_struct_initializer(out, tstruct, is_result || is_args);
  out << indent() << "}" << endl << endl;
  // Default values for optional fields
  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    string publicized_name;
    t_const_value* def_value;
    get_publicized_name_and_def_value(*m_iter, &publicized_name, &def_value);
    t_type* fieldType = (*m_iter)->get_type();
    string goType = type_to_go_type_with_opt(fieldType, false);
    string def_var_name = tstruct_name + "_" + publicized_name + "_DEFAULT";
    if ((*m_iter)->get_req() == t_field::T_OPTIONAL || is_pointer_field(*m_iter)) {
      out << indent() << "var " << def_var_name << " " << goType;
      if (def_value != NULL) {
        out << " = " << render_const_value(fieldType, def_value, (*m_iter)->get_name());
      }
      out << endl;
    }
    if (is_pointer_field(*m_iter)) {
      string goOptType = type_to_go_type_with_opt(fieldType, true);
      string maybepointer = goOptType != goType ? "*" : "";
      out << indent() << "func (p *" << tstruct_name << ") Get" << publicized_name << "() "
          << goType << " {" << endl;
      out << indent() << "  if !p.IsSet" << publicized_name << "() {" << endl;
      out << indent() << "    return " << def_var_name << endl;
      out << indent() << "  }" << endl;
      out << indent() << "return " << maybepointer << "p." << publicized_name << endl;
      out << indent() << "}" << endl;
      num_setable += 1;
    } else {
      out << endl;
      out << indent() << "func (p *" << tstruct_name << ") Get" << publicized_name << "() "
          << goType << " {" << endl;
      out << indent() << "  return p." << publicized_name << endl;
      out << indent() << "}" << endl;
    }
  }

  if (tstruct->is_union() && num_setable > 0) {
    generate_countsetfields_helper(out, tstruct, tstruct_name, is_result);
  }

  generate_isset_helpers(out, tstruct, tstruct_name, is_result);
  generate_go_struct_reader(out, tstruct, tstruct_name, is_result);
  generate_go_struct_writer(out, tstruct, tstruct_name, is_result, num_setable > 0);

  out << indent() << "func (p *" << tstruct_name << ") String() string {" << endl;
  out << indent() << "  if p == nil {" << endl;
  out << indent() << "    return \"<nil>\"" << endl;
  out << indent() << "  }" << endl;
  out << indent() << "  return fmt.Sprintf(\"" << escape_string(tstruct_name) << "(%+v)\", *p)"
      << endl;
  out << indent() << "}" << endl << endl;

  if (is_exception) {
    out << indent() << "func (p *" << tstruct_name << ") Error() string {" << endl;
    out << indent() << "  return p.String()" << endl;
    out << indent() << "}" << endl << endl;
  }
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::function_signature(t_function* tfunction, string prefix) {
  // TODO(mcslee): Nitpicky, no ',' if argument_list is empty
  return publicize(prefix + tfunction->get_name()) + "(" + argument_list(tfunction->get_arglist())
         + ")";
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::go_imports_begin(bool consts) {
  string extra;
  // If not writing constants, and there are enums, need extra imports.
  if (!consts && get_program()->get_enums().size() > 0) {
    extra =
      "\t\"database/sql/driver\"\n"
      "\t\"errors\"\n";
  }
  return string(
      "import (\n"
      "\t\"bytes\"\n"
      + extra +
      "\t\"fmt\"\n"
      "\t\"" + gen_thrift_import_ + "\"\n");
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::module_name(t_type* ttype) {
  t_program* program = ttype->get_program();

  if (program != NULL && program != program_) {
    if (program->get_namespace("go").empty() || 
        program_->get_namespace("go").empty() || 
        program->get_namespace("go") != program_->get_namespace("go")) {
      string module(get_real_go_module(program));
      // for namespaced includes, only keep part after dot.
      size_t dot = module.rfind('.');
      if (dot != string::npos) {
        module = module.substr(dot + 1);
      }
      return module;
    }
  }

  return "";
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::type_to_go_type_with_opt(t_type* type,
                                                bool optional_field) {
  string maybe_pointer(optional_field ? "*" : "");

  if (type->is_typedef() && ((t_typedef*)type)->is_forward_typedef()) {
    type = ((t_typedef*)type)->get_true_type();
  }

  if (type->is_base_type()) {
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();

    switch (tbase) {
    case t_base_type::TYPE_VOID:
      throw "";

    case t_base_type::TYPE_STRING:
      if (((t_base_type*)type)->is_binary()) {
        return maybe_pointer + "[]byte";
      }

      return maybe_pointer + "string";

    case t_base_type::TYPE_BOOL:
      return maybe_pointer + "bool";

    case t_base_type::TYPE_I8:
      return maybe_pointer + "int8";

    case t_base_type::TYPE_I16:
      return maybe_pointer + "int16";

    case t_base_type::TYPE_I32:
      return maybe_pointer + "int32";

    case t_base_type::TYPE_I64:
      return maybe_pointer + "int64";

    case t_base_type::TYPE_DOUBLE:
      return maybe_pointer + "float64";
    }
  } else if (type->is_enum()) {
    return maybe_pointer + publicize(type_name(type));
  } else if (type->is_struct() || type->is_xception()) {
    return "*" + publicize(type_name(type));
  } else if (type->is_map()) {
    t_map* t = (t_map*)type;
    string keyType = type_to_go_key_type(t->get_key_type());
    string valueType = type_to_go_type(t->get_val_type());
    return maybe_pointer + string("map[") + keyType + "]" + valueType;
  } else if (type->is_set()) {
    t_set* t = (t_set*)type;
    string elemType = type_to_go_key_type(t->get_elem_type());
    return maybe_pointer + string("map[") + elemType + string("]struct{}");
  } else if (type->is_list()) {
    t_list* t = (t_list*)type;
    string elemType = type_to_go_type(t->get_elem_type());
    return maybe_pointer + string("[]") + elemType;
  } else if (type->is_typedef()) {
    return maybe_pointer + publicize(type_name(type));
  }

  throw "INVALID TYPE IN type_to_go_type: " + type->get_name();
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::render_import_protection() {
  return string("var GoUnusedProtection__ int;\n\n");
}

Project: thrift
File: t_go_generator.cc

bool format_go_output(const string& file_path) {

  // formatting via gofmt deactivated due to THRIFT-3893
  // Please look at the ticket and make sure you fully understand all the implications
  // before submitting a patch that enables this feature again. Thank you.
  (void) file_path;
  return false;
  
  /*
  const string command = "gofmt -w " + file_path;

  if (system(command.c_str()) == 0) {
    return true;
  }

  fprintf(stderr, "WARNING - Running '%s' failed.\n", command.c_str());
  return false;
  */
 }

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_go_struct_initializer(ofstream& out,
                                                    t_struct* tstruct,
                                                    bool is_args_or_result) {
  out << publicize(type_name(tstruct), is_args_or_result) << "{";
  const vector<t_field*>& members = tstruct->get_members();
  for (vector<t_field*>::const_iterator m_iter = members.begin(); m_iter != members.end();
       ++m_iter) {
    bool pointer_field = is_pointer_field(*m_iter);
    string publicized_name;
    t_const_value* def_value;
    get_publicized_name_and_def_value(*m_iter, &publicized_name, &def_value);
    if (!pointer_field && def_value != NULL && !omit_initialization(*m_iter)) {
      out << endl << indent() << publicized_name << ": "
          << render_field_initial_value(*m_iter, (*m_iter)->get_name(), pointer_field) << ","
          << endl;
    }
  }

  out << "}" << endl;
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::type_to_go_type(t_type* type) {
  return type_to_go_type_with_opt(type, false);
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::fix_common_initialism(std::string& value, int i) const {
  if (!ignore_initialisms_) {
    size_t wordLen = value.find('_', i);
    if (wordLen != std::string::npos) {
      wordLen -= i;
    }
    std::string word = value.substr(i, wordLen);
    std::transform(word.begin(), word.end(), word.begin(), ::toupper);
    if (commonInitialisms.find(word) != commonInitialisms.end()) {
      value.replace(i, word.length(), word);
    }
  }
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
  // Open function
  string processorName = privatize(tservice->get_name()) + "Processor"
                         + publicize(tfunction->get_name());
  string argsname = publicize(tfunction->get_name() + "_args", true);
  string resultname = publicize(tfunction->get_name() + "_result", true);
  // t_struct* xs = tfunction->get_xceptions();
  // const std::vector<t_field*>& xceptions = xs->get_members();
  vector<t_field*>::const_iterator x_iter;
  f_types_ << indent() << "type " << processorName << " struct {" << endl;
  f_types_ << indent() << "  handler " << publicize(tservice->get_name()) << endl;
  f_types_ << indent() << "}" << endl << endl;
  f_types_ << indent() << "func (p *" << processorName
             << ") Process(seqId int32, iprot, oprot thrift.TProtocol) (success bool, err "
                "thrift.TException) {" << endl;
  indent_up();
  f_types_ << indent() << "args := " << argsname << "{}" << endl;
  f_types_ << indent() << "if err = args." << read_method_name_ <<  "(iprot); err != nil {" << endl;
  f_types_ << indent() << "  iprot.ReadMessageEnd()" << endl;
  if (!tfunction->is_oneway()) {
    f_types_ << indent()
               << "  x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error())"
               << endl;
    f_types_ << indent() << "  oprot.WriteMessageBegin(\"" << escape_string(tfunction->get_name())
               << "\", thrift.EXCEPTION, seqId)" << endl;
    f_types_ << indent() << "  x.Write(oprot)" << endl;
    f_types_ << indent() << "  oprot.WriteMessageEnd()" << endl;
    f_types_ << indent() << "  oprot.Flush()" << endl;
  }
  f_types_ << indent() << "  return false, err" << endl;
  f_types_ << indent() << "}" << endl << endl;
  f_types_ << indent() << "iprot.ReadMessageEnd()" << endl;

  if (!tfunction->is_oneway()) {
    f_types_ << indent() << "result := " << resultname << "{}" << endl;
  }
  bool need_reference = type_need_reference(tfunction->get_returntype());
  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
    f_types_ << "var retval " << type_to_go_type(tfunction->get_returntype()) << endl;
  }

  f_types_ << indent() << "var err2 error" << endl;
  f_types_ << indent() << "if ";

  if (!tfunction->is_oneway()) {
    if (!tfunction->get_returntype()->is_void()) {
      f_types_ << "retval, ";
    }
  }

  // Generate the function call
  t_struct* arg_struct = tfunction->get_arglist();
  const std::vector<t_field*>& fields = arg_struct->get_members();
  vector<t_field*>::const_iterator f_iter;
  f_types_ << "err2 = p.handler." << publicize(tfunction->get_name()) << "(";
  bool first = true;

  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    if (first) {
      first = false;
    } else {
      f_types_ << ", ";
    }

    f_types_ << "args." << publicize((*f_iter)->get_name());
  }

  f_types_ << "); err2 != nil {" << endl;

  t_struct* exceptions = tfunction->get_xceptions();
  const vector<t_field*>& x_fields = exceptions->get_members();
  if (!x_fields.empty()) {
    f_types_ << indent() << "switch v := err2.(type) {" << endl;

    vector<t_field*>::const_iterator xf_iter;

    for (xf_iter = x_fields.begin(); xf_iter != x_fields.end(); ++xf_iter) {
      f_types_ << indent() << "  case " << type_to_go_type(((*xf_iter)->get_type())) << ":"
                 << endl;
      f_types_ << indent() << "result." << publicize((*xf_iter)->get_name()) << " = v" << endl;
    }

    f_types_ << indent() << "  default:" << endl;
  }

  if (!tfunction->is_oneway()) {
    f_types_ << indent() << "  x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "
                              "\"Internal error processing " << escape_string(tfunction->get_name())
               << ": \" + err2.Error())" << endl;
    f_types_ << indent() << "  oprot.WriteMessageBegin(\"" << escape_string(tfunction->get_name())
               << "\", thrift.EXCEPTION, seqId)" << endl;
    f_types_ << indent() << "  x.Write(oprot)" << endl;
    f_types_ << indent() << "  oprot.WriteMessageEnd()" << endl;
    f_types_ << indent() << "  oprot.Flush()" << endl;
  }

  f_types_ << indent() << "  return true, err2" << endl;

  if (!x_fields.empty()) {
    f_types_ << indent() << "}" << endl;
  }

  f_types_ << indent() << "}"; // closes err2 != nil

  if (!tfunction->is_oneway()) {
    if (!tfunction->get_returntype()->is_void()) {
      f_types_ << " else {" << endl; // make sure we set Success retval only on success
      indent_up();
      f_types_ << indent() << "result.Success = ";
      if (need_reference) {
        f_types_ << "&";
      }
      f_types_ << "retval" << endl;
      indent_down();
      f_types_ << "}" << endl;
    } else {
      f_types_ << endl;
    }
    f_types_ << indent() << "if err2 = oprot.WriteMessageBegin(\""
               << escape_string(tfunction->get_name()) << "\", thrift.REPLY, seqId); err2 != nil {"
               << endl;
    f_types_ << indent() << "  err = err2" << endl;
    f_types_ << indent() << "}" << endl;
    f_types_ << indent() << "if err2 = result." << write_method_name_ << "(oprot); err == nil && err2 != nil {" << endl;
    f_types_ << indent() << "  err = err2" << endl;
    f_types_ << indent() << "}" << endl;
    f_types_ << indent() << "if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil {"
               << endl;
    f_types_ << indent() << "  err = err2" << endl;
    f_types_ << indent() << "}" << endl;
    f_types_ << indent() << "if err2 = oprot.Flush(); err == nil && err2 != nil {" << endl;
    f_types_ << indent() << "  err = err2" << endl;
    f_types_ << indent() << "}" << endl;
    f_types_ << indent() << "if err != nil {" << endl;
    f_types_ << indent() << "  return" << endl;
    f_types_ << indent() << "}" << endl;
    f_types_ << indent() << "return true, err" << endl;
  } else {
    f_types_ << endl;
    f_types_ << indent() << "return true, nil" << endl;
  }
  indent_down();
  f_types_ << indent() << "}" << endl << endl;
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_isset_helpers(ofstream& out,
                                            t_struct* tstruct,
                                            const string& tstruct_name,
                                            bool is_result) {
  (void)is_result;
  const vector<t_field*>& fields = tstruct->get_members();
  vector<t_field*>::const_iterator f_iter;
  const string escaped_tstruct_name(escape_string(tstruct->get_name()));

  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    const string field_name(publicize(escape_string((*f_iter)->get_name())));
    if ((*f_iter)->get_req() == t_field::T_OPTIONAL || is_pointer_field(*f_iter)) {
      out << indent() << "func (p *" << tstruct_name << ") IsSet" << field_name << "() bool {"
          << endl;
      indent_up();
      t_type* ttype = (*f_iter)->get_type()->get_true_type();
      bool is_byteslice = ttype->is_base_type() && ((t_base_type*)ttype)->is_binary();
      bool compare_to_nil_only = ttype->is_set() || ttype->is_list() || ttype->is_map()
                                 || (is_byteslice && !(*f_iter)->get_value());
      if (is_pointer_field(*f_iter) || compare_to_nil_only) {
        out << indent() << "return p." << field_name << " != nil" << endl;
      } else {
        string def_var_name = tstruct_name + "_" + field_name + "_DEFAULT";
        if (is_byteslice) {
          out << indent() << "return !bytes.Equal(p." << field_name << ", " << def_var_name << ")"
              << endl;
        } else {
          out << indent() << "return p." << field_name << " != " << def_var_name << endl;
        }
      }
      indent_down();
      out << indent() << "}" << endl << endl;
    }
  }
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_go_struct_reader(ofstream& out,
                                               t_struct* tstruct,
                                               const string& tstruct_name,
                                               bool is_result) {
  (void)is_result;
  const vector<t_field*>& fields = tstruct->get_members();
  vector<t_field*>::const_iterator f_iter;
  string escaped_tstruct_name(escape_string(tstruct->get_name()));
  out << indent() << "func (p *" << tstruct_name << ") " << read_method_name_ << "(iprot thrift.TProtocol) error {"
      << endl;
  indent_up();
  out << indent() << "if _, err := iprot.ReadStructBegin(); err != nil {" << endl;
  out << indent() << "  return thrift.PrependError(fmt.Sprintf(\"%T read error: \", p), err)"
      << endl;
  out << indent() << "}" << endl << endl;

  // Required variables does not have IsSet functions, so we need tmp vars to check them.
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
      const string field_name(publicize(escape_string((*f_iter)->get_name())));
      indent(out) << "var isset" << field_name << " bool = false;" << endl;
    }
  }
  out << endl;

  // Loop over reading in fields
  indent(out) << "for {" << endl;
  indent_up();
  // Read beginning field marker
  out << indent() << "_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()" << endl;
  out << indent() << "if err != nil {" << endl;
  out << indent() << "  return thrift.PrependError(fmt.Sprintf("
                     "\"%T field %d read error: \", p, fieldId), err)" << endl;
  out << indent() << "}" << endl;
  // Check for field STOP marker and break
  out << indent() << "if fieldTypeId == thrift.STOP { break; }" << endl;

  string thriftFieldTypeId;
  // Generate deserialization code for known cases
  int32_t field_id = -1;

  // Switch statement on the field we are reading, false if no fields present
  bool have_switch = !fields.empty();
  if (have_switch) {
    indent(out) << "switch fieldId {" << endl;
  }

  // All the fields we know
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    field_id = (*f_iter)->get_key();

    // if negative id, ensure we generate a valid method name
    string field_method_prefix("ReadField");
    int32_t field_method_suffix = field_id;

    if (field_method_suffix < 0) {
      field_method_prefix += "_";
      field_method_suffix *= -1;
    }

    out << indent() << "case " << field_id << ":" << endl;
    indent_up();
    thriftFieldTypeId = type_to_enum((*f_iter)->get_type());

    if (thriftFieldTypeId == "thrift.BINARY") {
      thriftFieldTypeId = "thrift.STRING";
    }

    out << indent() << "if err := p." << field_method_prefix << field_method_suffix << "(iprot); err != nil {"
        << endl;
    out << indent() << "  return err" << endl;
    out << indent() << "}" << endl;

    // Mark required field as read
    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
      const string field_name(publicize(escape_string((*f_iter)->get_name())));
      out << indent() << "isset" << field_name << " = true" << endl;
    }

    indent_down();
  }

  // Begin switch default case
  if (have_switch) {
    out << indent() << "default:" << endl;
    indent_up();
  }

  // Skip unknown fields in either case
  out << indent() << "if err := iprot.Skip(fieldTypeId); err != nil {" << endl;
  out << indent() << "  return err" << endl;
  out << indent() << "}" << endl;

  // End switch default case
  if (have_switch) {
    indent_down();
    out << indent() << "}" << endl;
  }

  // Read field end marker
  out << indent() << "if err := iprot.ReadFieldEnd(); err != nil {" << endl;
  out << indent() << "  return err" << endl;
  out << indent() << "}" << endl;
  indent_down();
  out << indent() << "}" << endl;
  out << indent() << "if err := iprot.ReadStructEnd(); err != nil {" << endl;
  out << indent() << "  return thrift.PrependError(fmt.Sprintf("
                     "\"%T read struct end error: \", p), err)" << endl;
  out << indent() << "}" << endl;

  // Return error if any required fields are missing.
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
      const string field_name(publicize(escape_string((*f_iter)->get_name())));
      out << indent() << "if !isset" << field_name << "{" << endl;
      out << indent() << "  return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, "
                         "fmt.Errorf(\"Required field " << field_name << " is not set\"));" << endl;
      out << indent() << "}" << endl;
    }
  }

  out << indent() << "return nil" << endl;
  indent_down();
  out << indent() << "}" << endl << endl;

  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    string field_type_name(publicize((*f_iter)->get_type()->get_name()));
    string field_name(publicize((*f_iter)->get_name()));
    string field_method_prefix("ReadField");
    int32_t field_id = (*f_iter)->get_key();
    int32_t field_method_suffix = field_id;

    if (field_method_suffix < 0) {
      field_method_prefix += "_";
      field_method_suffix *= -1;
    }

    out << indent() << "func (p *" << tstruct_name << ")  " << field_method_prefix << field_method_suffix
        << "(iprot thrift.TProtocol) error {" << endl;
    indent_up();
    generate_deserialize_field(out, *f_iter, false, "p.");
    indent_down();
    out << indent() << "  return nil" << endl;
    out << indent() << "}" << endl << endl;
  }
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_go_docstring(ofstream& out, t_doc* tdoc) {
  if (tdoc->has_doc()) {
    generate_docstring_comment(out, "", "//", tdoc->get_doc(), "");
  }
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_deserialize_list_element(ofstream& out,
                                                       t_list* tlist,
                                                       bool declare,
                                                       string prefix) {
  (void)declare;
  string elem = tmp("_elem");
  t_field felem(((t_list*)tlist)->get_elem_type(), elem);
  felem.set_req(t_field::T_OPT_IN_REQ_OUT);
  generate_deserialize_field(out, &felem, true, "", false, false, false, true, true);
  indent(out) << prefix << " = append(" << prefix << ", " << elem << ")" << endl;
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::render_fastbinary_includes() {
  return "";
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_countsetfields_helper(ofstream& out,
                                                    t_struct* tstruct,
                                                    const string& tstruct_name,
                                                    bool is_result) {
  (void)is_result;
  const vector<t_field*>& fields = tstruct->get_members();
  vector<t_field*>::const_iterator f_iter;
  const string escaped_tstruct_name(escape_string(tstruct->get_name()));

  out << indent() << "func (p *" << tstruct_name << ") CountSetFields" << tstruct_name << "() int {"
      << endl;
  indent_up();
  out << indent() << "count := 0" << endl;
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    if ((*f_iter)->get_req() == t_field::T_REQUIRED)
      continue;

    if (!is_pointer_field(*f_iter))
      continue;

    const string field_name(publicize(escape_string((*f_iter)->get_name())));

    out << indent() << "if (p.IsSet" << field_name << "()) {" << endl;
    indent_up();
    out << indent() << "count++" << endl;
    indent_down();
    out << indent() << "}" << endl;
  }

  out << indent() << "return count" << endl << endl;
  indent_down();
  out << indent() << "}" << endl << endl;
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_service_remote(t_service* tservice) {
  vector<t_function*> functions = tservice->get_functions();
  t_service* parent = tservice->get_extends();

  // collect inherited functions
  while (parent != NULL) {
    vector<t_function*> p_functions = parent->get_functions();
    functions.insert(functions.end(), p_functions.begin(), p_functions.end());
    parent = parent->get_extends();
  }

  vector<t_function*>::iterator f_iter;
  string f_remote_name = package_dir_ + "/" + underscore(service_name_) + "-remote/"
                         + underscore(service_name_) + "-remote.go";
  ofstream f_remote;
  f_remote.open(f_remote_name.c_str());
  string service_module = get_real_go_module(program_);
  string::size_type loc;

  while ((loc = service_module.find(".")) != string::npos) {
    service_module.replace(loc, 1, 1, '/');
  }
  if (!gen_package_prefix_.empty()) {
    service_module = gen_package_prefix_ + service_module;
  }

  string unused_protection;

  f_remote << go_autogen_comment();
  f_remote << indent() << "package main" << endl << endl;
  f_remote << indent() << "import (" << endl;
  f_remote << indent() << "        \"flag\"" << endl;
  f_remote << indent() << "        \"fmt\"" << endl;
  f_remote << indent() << "        \"math\"" << endl;
  f_remote << indent() << "        \"net\"" << endl;
  f_remote << indent() << "        \"net/url\"" << endl;
  f_remote << indent() << "        \"os\"" << endl;
  f_remote << indent() << "        \"strconv\"" << endl;
  f_remote << indent() << "        \"strings\"" << endl;
  f_remote << indent() << "        \"" + gen_thrift_import_ + "\"" << endl;
  f_remote << indent() << render_included_programs(unused_protection);
  f_remote << indent() << "        \"" << service_module << "\"" << endl;
  f_remote << indent() << ")" << endl;
  f_remote << indent() << endl;
  f_remote << indent() << unused_protection; // filled in render_included_programs()
  f_remote << indent() << endl;
  f_remote << indent() << "func Usage() {" << endl;
  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Usage of \", os.Args[0], \" "
                          "[-h host:port] [-u url] [-f[ramed]] function [arg1 [arg2...]]:\")"
           << endl;
  f_remote << indent() << "  flag.PrintDefaults()" << endl;
  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"\\nFunctions:\")" << endl;

  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
    f_remote << "  fmt.Fprintln(os.Stderr, \"  " << (*f_iter)->get_returntype()->get_name() << " "
             << (*f_iter)->get_name() << "(";
    t_struct* arg_struct = (*f_iter)->get_arglist();
    const std::vector<t_field*>& args = arg_struct->get_members();
    vector<t_field*>::const_iterator a_iter;
    std::vector<t_field*>::size_type num_args = args.size();
    bool first = true;

    for (std::vector<t_field*>::size_type i = 0; i < num_args; ++i) {
      if (first) {
        first = false;
      } else {
        f_remote << ", ";
      }

      f_remote << args[i]->get_type()->get_name() << " " << args[i]->get_name();
    }

    f_remote << ")\")" << endl;
  }

  f_remote << indent() << "  fmt.Fprintln(os.Stderr)" << endl;
  f_remote << indent() << "  os.Exit(0)" << endl;
  f_remote << indent() << "}" << endl;
  f_remote << indent() << endl;
  f_remote << indent() << "func main() {" << endl;
  indent_up();
  f_remote << indent() << "flag.Usage = Usage" << endl;
  f_remote << indent() << "var host string" << endl;
  f_remote << indent() << "var port int" << endl;
  f_remote << indent() << "var protocol string" << endl;
  f_remote << indent() << "var urlString string" << endl;
  f_remote << indent() << "var framed bool" << endl;
  f_remote << indent() << "var useHttp bool" << endl;
  f_remote << indent() << "var parsedUrl url.URL" << endl;
  f_remote << indent() << "var trans thrift.TTransport" << endl;
  f_remote << indent() << "_ = strconv.Atoi" << endl;
  f_remote << indent() << "_ = math.Abs" << endl;
  f_remote << indent() << "flag.Usage = Usage" << endl;
  f_remote << indent() << "flag.StringVar(&host, \"h\", \"localhost\", \"Specify host and port\")"
           << endl;
  f_remote << indent() << "flag.IntVar(&port, \"p\", 9090, \"Specify port\")" << endl;
  f_remote << indent() << "flag.StringVar(&protocol, \"P\", \"binary\", \""
                          "Specify the protocol (binary, compact, simplejson, json)\")" << endl;
  f_remote << indent() << "flag.StringVar(&urlString, \"u\", \"\", \"Specify the url\")" << endl;
  f_remote << indent() << "flag.BoolVar(&framed, \"framed\", false, \"Use framed transport\")"
           << endl;
  f_remote << indent() << "flag.BoolVar(&useHttp, \"http\", false, \"Use http\")" << endl;
  f_remote << indent() << "flag.Parse()" << endl;
  f_remote << indent() << endl;
  f_remote << indent() << "if len(urlString) > 0 {" << endl;
  f_remote << indent() << "  parsedUrl, err := url.Parse(urlString)" << endl;
  f_remote << indent() << "  if err != nil {" << endl;
  f_remote << indent() << "    fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << endl;
  f_remote << indent() << "    flag.Usage()" << endl;
  f_remote << indent() << "  }" << endl;
  f_remote << indent() << "  host = parsedUrl.Host" << endl;
  f_remote << indent() << "  useHttp = len(parsedUrl.Scheme) <= 0 || parsedUrl.Scheme == \"http\""
           << endl;
  f_remote << indent() << "} else if useHttp {" << endl;
  f_remote << indent() << "  _, err := url.Parse(fmt.Sprint(\"http://\", host, \":\", port))"
           << endl;
  f_remote << indent() << "  if err != nil {" << endl;
  f_remote << indent() << "    fmt.Fprintln(os.Stderr, \"Error parsing URL: \", err)" << endl;
  f_remote << indent() << "    flag.Usage()" << endl;
  f_remote << indent() << "  }" << endl;
  f_remote << indent() << "}" << endl;
  f_remote << indent() << endl;
  f_remote << indent() << "cmd := flag.Arg(0)" << endl;
  f_remote << indent() << "var err error" << endl;
  f_remote << indent() << "if useHttp {" << endl;
  f_remote << indent() << "  trans, err = thrift.NewTHttpClient(parsedUrl.String())" << endl;
  f_remote << indent() << "} else {" << endl;
  f_remote << indent() << "  portStr := fmt.Sprint(port)" << endl;
  f_remote << indent() << "  if strings.Contains(host, \":\") {" << endl;
  f_remote << indent() << "         host, portStr, err = net.SplitHostPort(host)" << endl;
  f_remote << indent() << "         if err != nil {" << endl;
  f_remote << indent() << "                 fmt.Fprintln(os.Stderr, \"error with host:\", err)"
           << endl;
  f_remote << indent() << "                 os.Exit(1)" << endl;
  f_remote << indent() << "         }" << endl;
  f_remote << indent() << "  }" << endl;
  f_remote << indent() << "  trans, err = thrift.NewTSocket(net.JoinHostPort(host, portStr))"
           << endl;
  f_remote << indent() << "  if err != nil {" << endl;
  f_remote << indent() << "    fmt.Fprintln(os.Stderr, \"error resolving address:\", err)" << endl;
  f_remote << indent() << "    os.Exit(1)" << endl;
  f_remote << indent() << "  }" << endl;
  f_remote << indent() << "  if framed {" << endl;
  f_remote << indent() << "    trans = thrift.NewTFramedTransport(trans)" << endl;
  f_remote << indent() << "  }" << endl;
  f_remote << indent() << "}" << endl;
  f_remote << indent() << "if err != nil {" << endl;
  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Error creating transport\", err)" << endl;
  f_remote << indent() << "  os.Exit(1)" << endl;
  f_remote << indent() << "}" << endl;
  f_remote << indent() << "defer trans.Close()" << endl;
  f_remote << indent() << "var protocolFactory thrift.TProtocolFactory" << endl;
  f_remote << indent() << "switch protocol {" << endl;
  f_remote << indent() << "case \"compact\":" << endl;
  f_remote << indent() << "  protocolFactory = thrift.NewTCompactProtocolFactory()" << endl;
  f_remote << indent() << "  break" << endl;
  f_remote << indent() << "case \"simplejson\":" << endl;
  f_remote << indent() << "  protocolFactory = thrift.NewTSimpleJSONProtocolFactory()" << endl;
  f_remote << indent() << "  break" << endl;
  f_remote << indent() << "case \"json\":" << endl;
  f_remote << indent() << "  protocolFactory = thrift.NewTJSONProtocolFactory()" << endl;
  f_remote << indent() << "  break" << endl;
  f_remote << indent() << "case \"binary\", \"\":" << endl;
  f_remote << indent() << "  protocolFactory = thrift.NewTBinaryProtocolFactoryDefault()" << endl;
  f_remote << indent() << "  break" << endl;
  f_remote << indent() << "default:" << endl;
  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Invalid protocol specified: \", protocol)"
           << endl;
  f_remote << indent() << "  Usage()" << endl;
  f_remote << indent() << "  os.Exit(1)" << endl;
  f_remote << indent() << "}" << endl;
  f_remote << indent() << "client := " << package_name_ << ".New" << publicize(service_name_)
           << "ClientFactory(trans, protocolFactory)" << endl;
  f_remote << indent() << "if err := trans.Open(); err != nil {" << endl;
  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Error opening socket to \", "
                          "host, \":\", port, \" \", err)" << endl;
  f_remote << indent() << "  os.Exit(1)" << endl;
  f_remote << indent() << "}" << endl;
  f_remote << indent() << endl;
  f_remote << indent() << "switch cmd {" << endl;

  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
    t_struct* arg_struct = (*f_iter)->get_arglist();
    const std::vector<t_field*>& args = arg_struct->get_members();
    vector<t_field*>::const_iterator a_iter;
    std::vector<t_field*>::size_type num_args = args.size();
    string funcName((*f_iter)->get_name());
    string pubName(publicize(funcName));
    string argumentsName(publicize(funcName + "_args", true));
    f_remote << indent() << "case \"" << escape_string(funcName) << "\":" << endl;
    indent_up();
    f_remote << indent() << "if flag.NArg() - 1 != " << num_args << " {" << endl;
    f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"" << escape_string(pubName) << " requires "
             << num_args << " args\")" << endl;
    f_remote << indent() << "  flag.Usage()" << endl;
    f_remote << indent() << "}" << endl;

    for (std::vector<t_field*>::size_type i = 0; i < num_args; ++i) {
      int flagArg = i + 1;
      t_type* the_type(args[i]->get_type());
      t_type* the_type2(get_true_type(the_type));

      if (the_type2->is_enum()) {
        f_remote << indent() << "tmp" << i << ", err := (strconv.Atoi(flag.Arg(" << flagArg << ")))"
                 << endl;
        f_remote << indent() << "if err != nil {" << endl;
        f_remote << indent() << "  Usage()" << endl;
        f_remote << indent() << " return" << endl;
        f_remote << indent() << "}" << endl;
        f_remote << indent() << "argvalue" << i << " := " << package_name_ << "."
                 << publicize(the_type->get_name()) << "(tmp" << i << ")" << endl;
      } else if (the_type2->is_base_type()) {
        t_base_type::t_base e = ((t_base_type*)the_type2)->get_base();
        string err(tmp("err"));

        switch (e) {
        case t_base_type::TYPE_VOID:
          break;

        case t_base_type::TYPE_STRING:
          if (((t_base_type*)the_type2)->is_binary()) {
            f_remote << indent() << "argvalue" << i << " := []byte(flag.Arg(" << flagArg << "))"
                     << endl;
          } else {
            f_remote << indent() << "argvalue" << i << " := flag.Arg(" << flagArg << ")" << endl;
          }
          break;

        case t_base_type::TYPE_BOOL:
          f_remote << indent() << "argvalue" << i << " := flag.Arg(" << flagArg << ") == \"true\""
                   << endl;
          break;

        case t_base_type::TYPE_I8:
          f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg("
                   << flagArg << ")))" << endl;
          f_remote << indent() << "if " << err << " != nil {" << endl;
          f_remote << indent() << "  Usage()" << endl;
          f_remote << indent() << "  return" << endl;
          f_remote << indent() << "}" << endl;
          f_remote << indent() << "argvalue" << i << " := int8(tmp" << i << ")" << endl;
          break;

        case t_base_type::TYPE_I16:
          f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg("
                   << flagArg << ")))" << endl;
          f_remote << indent() << "if " << err << " != nil {" << endl;
          f_remote << indent() << "  Usage()" << endl;
          f_remote << indent() << "  return" << endl;
          f_remote << indent() << "}" << endl;
          f_remote << indent() << "argvalue" << i << " := int16(tmp" << i << ")" << endl;
          break;

        case t_base_type::TYPE_I32:
          f_remote << indent() << "tmp" << i << ", " << err << " := (strconv.Atoi(flag.Arg("
                   << flagArg << ")))" << endl;
          f_remote << indent() << "if " << err << " != nil {" << endl;
          f_remote << indent() << "  Usage()" << endl;
          f_remote << indent() << "  return" << endl;
          f_remote << indent() << "}" << endl;
          f_remote << indent() << "argvalue" << i << " := int32(tmp" << i << ")" << endl;
          break;

        case t_base_type::TYPE_I64:
          f_remote << indent() << "argvalue" << i << ", " << err
                   << " := (strconv.ParseInt(flag.Arg(" << flagArg << "), 10, 64))" << endl;
          f_remote << indent() << "if " << err << " != nil {" << endl;
          f_remote << indent() << "  Usage()" << endl;
          f_remote << indent() << "  return" << endl;
          f_remote << indent() << "}" << endl;
          break;

        case t_base_type::TYPE_DOUBLE:
          f_remote << indent() << "argvalue" << i << ", " << err
                   << " := (strconv.ParseFloat(flag.Arg(" << flagArg << "), 64))" << endl;
          f_remote << indent() << "if " << err << " != nil {" << endl;
          f_remote << indent() << "  Usage()" << endl;
          f_remote << indent() << "  return" << endl;
          f_remote << indent() << "}" << endl;
          break;

        default:
          throw("Invalid base type in generate_service_remote");
        }

        // f_remote << publicize(args[i]->get_name()) << "(strconv.Atoi(flag.Arg(" << flagArg <<
        // ")))";
      } else if (the_type2->is_struct()) {
        string arg(tmp("arg"));
        string mbTrans(tmp("mbTrans"));
        string err1(tmp("err"));
        string factory(tmp("factory"));
        string jsProt(tmp("jsProt"));
        string err2(tmp("err"));
        std::string tstruct_name(publicize(the_type->get_name()));
        std::string tstruct_module( module_name(the_type));
        if(tstruct_module.empty()) {
          tstruct_module = package_name_;
        }

        f_remote << indent() << arg << " := flag.Arg(" << flagArg << ")" << endl;
        f_remote << indent() << mbTrans << " := thrift.NewTMemoryBufferLen(len(" << arg << "))"
                 << endl;
        f_remote << indent() << "defer " << mbTrans << ".Close()" << endl;
        f_remote << indent() << "_, " << err1 << " := " << mbTrans << ".WriteString(" << arg << ")"
                 << endl;
        f_remote << indent() << "if " << err1 << " != nil {" << endl;
        f_remote << indent() << "  Usage()" << endl;
        f_remote << indent() << "  return" << endl;
        f_remote << indent() << "}" << endl;
        f_remote << indent() << factory << " := thrift.NewTSimpleJSONProtocolFactory()" << endl;
        f_remote << indent() << jsProt << " := " << factory << ".GetProtocol(" << mbTrans << ")"
                 << endl;
        f_remote << indent() << "argvalue" << i << " := " << tstruct_module << ".New" << tstruct_name
                 << "()" << endl;
        f_remote << indent() << err2 << " := argvalue" << i << "." << read_method_name_ <<  "(" << jsProt << ")" << endl;
        f_remote << indent() << "if " << err2 << " != nil {" << endl;
        f_remote << indent() << "  Usage()" << endl;
        f_remote << indent() << "  return" << endl;
        f_remote << indent() << "}" << endl;
      } else if (the_type2->is_container() || the_type2->is_xception()) {
        string arg(tmp("arg"));
        string mbTrans(tmp("mbTrans"));
        string err1(tmp("err"));
        string factory(tmp("factory"));
        string jsProt(tmp("jsProt"));
        string err2(tmp("err"));
        std::string argName(publicize(args[i]->get_name()));
        f_remote << indent() << arg << " := flag.Arg(" << flagArg << ")" << endl;
        f_remote << indent() << mbTrans << " := thrift.NewTMemoryBufferLen(len(" << arg << "))"
                 << endl;
        f_remote << indent() << "defer " << mbTrans << ".Close()" << endl;
        f_remote << indent() << "_, " << err1 << " := " << mbTrans << ".WriteString(" << arg << ")"
                 << endl;
        f_remote << indent() << "if " << err1 << " != nil { " << endl;
        f_remote << indent() << "  Usage()" << endl;
        f_remote << indent() << "  return" << endl;
        f_remote << indent() << "}" << endl;
        f_remote << indent() << factory << " := thrift.NewTSimpleJSONProtocolFactory()" << endl;
        f_remote << indent() << jsProt << " := " << factory << ".GetProtocol(" << mbTrans << ")"
                 << endl;
        f_remote << indent() << "containerStruct" << i << " := " << package_name_ << ".New"
                 << argumentsName << "()" << endl;
        f_remote << indent() << err2 << " := containerStruct" << i << ".ReadField" << (i + 1) << "("
                 << jsProt << ")" << endl;
        f_remote << indent() << "if " << err2 << " != nil {" << endl;
        f_remote << indent() << "  Usage()" << endl;
        f_remote << indent() << "  return" << endl;
        f_remote << indent() << "}" << endl;
        f_remote << indent() << "argvalue" << i << " := containerStruct" << i << "." << argName
                 << endl;
      } else {
        throw("Invalid argument type in generate_service_remote");
      }

      if (the_type->is_typedef()) {
        std::string typedef_module( module_name(the_type));
        if(typedef_module.empty()) {
          typedef_module = package_name_;
        }
        f_remote << indent() << "value" << i << " := " << typedef_module << "."
                 << publicize(the_type->get_name()) << "(argvalue" << i << ")" << endl;
      } else {
        f_remote << indent() << "value" << i << " := argvalue" << i << endl;
      }
    }

    f_remote << indent() << "fmt.Print(client." << pubName << "(";
    bool argFirst = true;

    for (std::vector<t_field*>::size_type i = 0; i < num_args; ++i) {
      if (argFirst) {
        argFirst = false;
      } else {
        f_remote << ", ";
      }

      if (args[i]->get_type()->is_enum()) {
        f_remote << "value" << i;
      } else if (args[i]->get_type()->is_base_type()) {
        t_base_type::t_base e = ((t_base_type*)(args[i]->get_type()))->get_base();

        switch (e) {
        case t_base_type::TYPE_VOID:
          break;

        case t_base_type::TYPE_STRING:
        case t_base_type::TYPE_BOOL:
        case t_base_type::TYPE_I8:
        case t_base_type::TYPE_I16:
        case t_base_type::TYPE_I32:
        case t_base_type::TYPE_I64:
        case t_base_type::TYPE_DOUBLE:
          f_remote << "value" << i;
          break;

        default:
          throw("Invalid base type in generate_service_remote");
        }

        // f_remote << publicize(args[i]->get_name()) << "(strconv.Atoi(flag.Arg(" << flagArg <<
        // ")))";
      } else {
        f_remote << "value" << i;
      }
    }

    f_remote << "))" << endl;
    f_remote << indent() << "fmt.Print(\"\\n\")" << endl;
    f_remote << indent() << "break" << endl;
    indent_down();
  }

  f_remote << indent() << "case \"\":" << endl;
  f_remote << indent() << "  Usage()" << endl;
  f_remote << indent() << "  break" << endl;
  f_remote << indent() << "default:" << endl;
  f_remote << indent() << "  fmt.Fprintln(os.Stderr, \"Invalid function \", cmd)" << endl;
  f_remote << indent() << "}" << endl;
  indent_down();
  f_remote << indent() << "}" << endl;
  // Close service file
  f_remote.close();
  format_go_output(f_remote_name);
#ifndef _MSC_VER
  // Make file executable, love that bitwise OR action
  chmod(f_remote_name.c_str(),
        S_IRUSR | S_IWUSR | S_IXUSR
#ifndef _WIN32
        | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
#endif
        );
#endif
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_deserialize_struct(ofstream& out,
                                                 t_struct* tstruct,
                                                 bool pointer_field,
                                                 bool declare,
                                                 string prefix) {
  string eq(declare ? " := " : " = ");

  out << indent() << prefix << eq << (pointer_field ? "&" : "");
  generate_go_struct_initializer(out, tstruct);
  out << indent() << "if err := " << prefix << "." << read_method_name_ <<  "(iprot); err != nil {" << endl;
  out << indent() << "  return thrift.PrependError(fmt.Sprintf(\"%T error reading struct: \", "
      << prefix << "), err)" << endl;
  out << indent() << "}" << endl;
}

Project: thrift
File: t_go_generator.cc

  t_go_generator(t_program* program,
                 const std::map<std::string, std::string>& parsed_options,
                 const std::string& option_string)
    : t_generator(program) {
    (void)option_string;
    std::map<std::string, std::string>::const_iterator iter;


    gen_thrift_import_ = DEFAULT_THRIFT_IMPORT;
    gen_package_prefix_ = "";
    package_flag = "";
    read_write_private_ = false;
    ignore_initialisms_ = false;
    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
      if( iter->first.compare("package_prefix") == 0) {
        gen_package_prefix_ = (iter->second);
      } else if( iter->first.compare("thrift_import") == 0) {
        gen_thrift_import_ = (iter->second);
      } else if( iter->first.compare("package") == 0) {
        package_flag = (iter->second);
      } else if( iter->first.compare("read_write_private") == 0) {
        read_write_private_ = true;
      } else if( iter->first.compare("ignore_initialisms") == 0) {
        ignore_initialisms_ =  true;
      } else {
        throw "unknown option go:" + iter->first; 
      }
    }

    out_dir_base_ = "gen-go";
  }

Project: thrift
File: t_go_generator.cc

std::string t_go_generator::new_prefix(const std::string& value) const {
  if (value.size() <= 0) {
    return value;
  }

  string::size_type dot_pos = value.rfind('.');
  if (dot_pos != string::npos) {
    return value.substr(0, dot_pos + 1) + "New" + publicize(value.substr(dot_pos + 1));
  }
  return "New" + publicize(value);
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::go_autogen_comment() {
  return
        std::string() +
        "// Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
        "// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n\n";
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::init_generator() {
  // Make output directory
  string module = get_real_go_module(program_);
  string target = module;
  package_dir_ = get_out_dir();

  // This set is taken from https://github.com/golang/lint/blob/master/lint.go#L692
  commonInitialisms.insert("API");
  commonInitialisms.insert("ASCII");
  commonInitialisms.insert("CPU");
  commonInitialisms.insert("CSS");
  commonInitialisms.insert("DNS");
  commonInitialisms.insert("EOF");
  commonInitialisms.insert("GUID");
  commonInitialisms.insert("HTML");
  commonInitialisms.insert("HTTP");
  commonInitialisms.insert("HTTPS");
  commonInitialisms.insert("ID");
  commonInitialisms.insert("IP");
  commonInitialisms.insert("JSON");
  commonInitialisms.insert("LHS");
  commonInitialisms.insert("QPS");
  commonInitialisms.insert("RAM");
  commonInitialisms.insert("RHS");
  commonInitialisms.insert("RPC");
  commonInitialisms.insert("SLA");
  commonInitialisms.insert("SMTP");
  commonInitialisms.insert("SSH");
  commonInitialisms.insert("TCP");
  commonInitialisms.insert("TLS");
  commonInitialisms.insert("TTL");
  commonInitialisms.insert("UDP");
  commonInitialisms.insert("UI");
  commonInitialisms.insert("UID");
  commonInitialisms.insert("UUID");
  commonInitialisms.insert("URI");
  commonInitialisms.insert("URL");
  commonInitialisms.insert("UTF8");
  commonInitialisms.insert("VM");
  commonInitialisms.insert("XML");
  commonInitialisms.insert("XSRF");
  commonInitialisms.insert("XSS");

  // names of read and write methods
  if (read_write_private_) {
    read_method_name_ = "read";
    write_method_name_ = "write";
  } else {
    read_method_name_ = "Read";
    write_method_name_ = "Write";
  }

  while (true) {
    // TODO: Do better error checking here.
    MKDIR(package_dir_.c_str());

    if (module.empty()) {
      break;
    }

    string::size_type pos = module.find('.');

    if (pos == string::npos) {
      package_dir_ += "/";
      package_dir_ += module;
      package_name_ = module;
      module.clear();
    } else {
      package_dir_ += "/";
      package_dir_ += module.substr(0, pos);
      module.erase(0, pos + 1);
    }
  }

  string::size_type loc;

  while ((loc = target.find(".")) != string::npos) {
    target.replace(loc, 1, 1, '/');
  }

  // Make output files
  f_types_name_ = package_dir_ + "/" + program_name_ + ".go";
  f_types_.open(f_types_name_.c_str());

  f_consts_name_ = package_dir_ + "/" + program_name_ + "-consts.go";
  f_consts_.open(f_consts_name_.c_str());

  vector<t_service*> services = program_->get_services();
  vector<t_service*>::iterator sv_iter;

  for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
    string service_dir = package_dir_ + "/" + underscore((*sv_iter)->get_name()) + "-remote";
    MKDIR(service_dir.c_str());
  }

  // Print header
  f_types_ << go_autogen_comment() << go_package() << render_includes(false);

  f_consts_ << go_autogen_comment() << go_package() << render_includes(true);

  f_const_values_ << endl << "func init() {" << endl;

  // Create file for the GoUnusedProtection__ variable
  string f_unused_prot_name_ = package_dir_ + "/" + "GoUnusedProtection__.go";
  ofstream f_unused_prot_;
  f_unused_prot_.open(f_unused_prot_name_.c_str());
  f_unused_prot_ << go_autogen_comment() << go_package() << render_import_protection();
  f_unused_prot_.close();
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_struct(t_struct* tstruct) {
  generate_go_struct(tstruct, false);
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::argument_list(t_struct* tstruct) {
  string result = "";
  const vector<t_field*>& fields = tstruct->get_members();
  vector<t_field*>::const_iterator f_iter;
  bool first = true;

  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    if (first) {
      first = false;
    } else {
      result += ", ";
    }

    result += variable_name_to_go_name((*f_iter)->get_name()) + " "
              + type_to_go_type((*f_iter)->get_type());
  }

  return result;
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::function_signature_if(t_function* tfunction, string prefix, bool addError) {
  // TODO(mcslee): Nitpicky, no ',' if argument_list is empty
  string signature = publicize(prefix + tfunction->get_name()) + "(";
  signature += argument_list(tfunction->get_arglist()) + ") (";
  t_type* ret = tfunction->get_returntype();
  t_struct* exceptions = tfunction->get_xceptions();
  string errs = argument_list(exceptions);

  if (!ret->is_void()) {
    signature += "r " + type_to_go_type(ret);

    if (addError || errs.size() == 0) {
      signature += ", ";
    }
  }

  if (addError) {
    signature += "err error";
  }

  signature += ")";
  return signature;
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_go_struct_writer(ofstream& out,
                                               t_struct* tstruct,
                                               const string& tstruct_name,
                                               bool is_result,
                                               bool uses_countsetfields) {
  (void)is_result;
  string name(tstruct->get_name());
  const vector<t_field*>& fields = tstruct->get_sorted_members();
  vector<t_field*>::const_iterator f_iter;
  indent(out) << "func (p *" << tstruct_name << ") " << write_method_name_ << "(oprot thrift.TProtocol) error {" << endl;
  indent_up();
  if (tstruct->is_union() && uses_countsetfields) {
    std::string tstruct_name(publicize(tstruct->get_name()));
    out << indent() << "if c := p.CountSetFields" << tstruct_name << "(); c != 1 {" << endl
        << indent()
        << "  return fmt.Errorf(\"%T write union: exactly one field must be set (%d set).\", p, c)"
        << endl << indent() << "}" << endl;
  }
  out << indent() << "if err := oprot.WriteStructBegin(\"" << name << "\"); err != nil {" << endl;
  out << indent() << "  return thrift.PrependError(fmt.Sprintf("
                     "\"%T write struct begin error: \", p), err) }" << endl;

  string field_name;
  string escape_field_name;
  // t_const_value* field_default_value;
  t_field::e_req field_required;
  int32_t field_id = -1;

  out << indent() << "if p != nil {" << endl;
  indent_up();

  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    string field_method_prefix("writeField");
    field_name = (*f_iter)->get_name();
    escape_field_name = escape_string(field_name);
    field_id = (*f_iter)->get_key();
    int32_t field_method_suffix = field_id;

    if (field_method_suffix < 0) {
      field_method_prefix += "_";
      field_method_suffix *= -1;
    }

    out << indent() << "if err := p." << field_method_prefix << field_method_suffix
        << "(oprot); err != nil { return err }" << endl;
  }

  indent_down();
  out << indent() << "}" << endl;

  // Write the struct map
  out << indent() << "if err := oprot.WriteFieldStop(); err != nil {" << endl;
  out << indent() << "  return thrift.PrependError(\"write field stop error: \", err) }" << endl;
  out << indent() << "if err := oprot.WriteStructEnd(); err != nil {" << endl;
  out << indent() << "  return thrift.PrependError(\"write struct stop error: \", err) }" << endl;
  out << indent() << "return nil" << endl;
  indent_down();
  out << indent() << "}" << endl << endl;

  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
    string field_method_prefix("writeField");
    field_id = (*f_iter)->get_key();
    field_name = (*f_iter)->get_name();
    escape_field_name = escape_string(field_name);
    // field_default_value = (*f_iter)->get_value();
    field_required = (*f_iter)->get_req();
    int32_t field_method_suffix = field_id;

    if (field_method_suffix < 0) {
      field_method_prefix += "_";
      field_method_suffix *= -1;
    }

    out << indent() << "func (p *" << tstruct_name << ") " << field_method_prefix << field_method_suffix
        << "(oprot thrift.TProtocol) (err error) {" << endl;
    indent_up();

    if (field_required == t_field::T_OPTIONAL) {
      out << indent() << "if p.IsSet" << publicize(field_name) << "() {" << endl;
      indent_up();
    }

    out << indent() << "if err := oprot.WriteFieldBegin(\"" << escape_field_name << "\", "
        << type_to_enum((*f_iter)->get_type()) << ", " << field_id << "); err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(fmt.Sprintf(\"%T write field begin error "
        << field_id << ":" << escape_field_name << ": \", p), err) }" << endl;

    // Write field contents
    generate_serialize_field(out, *f_iter, "p.");

    // Write field closer
    out << indent() << "if err := oprot.WriteFieldEnd(); err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(fmt.Sprintf(\"%T write field end error "
        << field_id << ":" << escape_field_name << ": \", p), err) }" << endl;

    if (field_required == t_field::T_OPTIONAL) {
      indent_down();
      out << indent() << "}" << endl;
    }

    indent_down();
    out << indent() << "  return err" << endl;
    out << indent() << "}" << endl << endl;
  }
}

Project: thrift
File: t_go_generator.cc

static bool type_need_reference(t_type* type) {
  type = type->get_true_type();
  if (type->is_map() || type->is_set() || type->is_list() || type->is_struct()
      || type->is_xception() || (type->is_string() && ((t_base_type*)type)->is_binary())) {
    return false;
  }
  return true;
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::go_package() {
  return string("package ") + package_name_ + "\n\n";
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::close_generator() {
  f_const_values_ << "}" << endl << endl;
  f_consts_ << f_const_values_.str();

  // Close types and constants files
  f_consts_.close();
  f_types_.close();
  format_go_output(f_types_name_);
  format_go_output(f_consts_name_);
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_go_function_helpers(t_function* tfunction) {
  if (!tfunction->is_oneway()) {
    t_struct result(program_, tfunction->get_name() + "_result");
    t_field success(tfunction->get_returntype(), "success", 0);
    success.set_req(t_field::T_OPTIONAL);

    if (!tfunction->get_returntype()->is_void()) {
      result.append(&success);
    }

    t_struct* xs = tfunction->get_xceptions();
    const vector<t_field*>& fields = xs->get_members();
    vector<t_field*>::const_iterator f_iter;

    for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
      t_field* f = *f_iter;
      f->set_req(t_field::T_OPTIONAL);
      result.append(f);
    }

    generate_go_struct_definition(f_types_, &result, false, true);
  }
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_deserialize_set_element(ofstream& out,
                                                      t_set* tset,
                                                      bool declare,
                                                      string prefix) {
  (void)declare;
  string elem = tmp("_elem");
  t_field felem(tset->get_elem_type(), elem);
  felem.set_req(t_field::T_OPT_IN_REQ_OUT);
  generate_deserialize_field(out, &felem, true, "", false, false, false, true, true);
  indent(out) << prefix << "[" << elem << "] = struct{}{}" << endl;
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::declare_argument(t_field* tfield) {
  std::ostringstream result;
  result << publicize(tfield->get_name()) << "=";

  if (tfield->get_value() != NULL) {
    result << "thrift_spec[" << tfield->get_key() << "][4]";
  } else {
    result << "nil";
  }

  return result.str();
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::type_to_go_key_type(t_type* type) {
  t_type* resolved_type = type;

  while (resolved_type->is_typedef()) {
    resolved_type = ((t_typedef*)resolved_type)->get_type()->get_true_type();
  }

  if (resolved_type->is_map() || resolved_type->is_list() || resolved_type->is_set()) {
    throw "Cannot produce a valid type for a Go map key: " + type_to_go_type(type) + " - aborting.";
  }

  if (resolved_type->is_string() && ((t_base_type*)resolved_type)->is_binary())
    return "string";

  return type_to_go_type(type);
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::type_name(t_type* ttype) {
  string module( module_name(ttype));
  if( ! module.empty()) {
    return module + "." + ttype->get_name();
  }

  return ttype->get_name();
}

Project: thrift
File: t_go_generator.cc

std::string t_go_generator::publicize(const std::string& value, bool is_args_or_result) const {
  if (value.size() <= 0) {
    return value;
  }

  std::string value2(value), prefix;

  string::size_type dot_pos = value.rfind('.');
  if (dot_pos != string::npos) {
    prefix = value.substr(0, dot_pos + 1) + prefix;
    value2 = value.substr(dot_pos + 1);
  }

  if (!isupper(value2[0])) {
    value2[0] = toupper(value2[0]);
  }

  value2 = camelcase(value2);

  // final length before further checks, the string may become longer
  size_t len_before = value2.length();

  // IDL identifiers may start with "New" which interferes with the CTOR pattern
  // Adding an extra underscore to all those identifiers solves this
  if ((len_before >= 3) && (value2.substr(0, 3) == "New")) {
    value2 += '_';
  }

  // IDL identifiers may end with "Args"/"Result" which interferes with the implicit service
  // function structs
  // Adding another extra underscore to all those identifiers solves this
  // Suppress this check for the actual helper struct names
  if (!is_args_or_result) {
    bool ends_with_args = (len_before >= 4) && (value2.substr(len_before - 4, 4) == "Args");
    bool ends_with_rslt = (len_before >= 6) && (value2.substr(len_before - 6, 6) == "Result");
    if (ends_with_args || ends_with_rslt) {
      value2 += '_';
    }
  }

  // Avoid naming collisions with other services
  if (is_args_or_result) {
    prefix += publicize(service_name_);
  }

  return prefix + value2;
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::type_to_enum(t_type* type) {
  type = get_true_type(type);

  if (type->is_base_type()) {
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();

    switch (tbase) {
    case t_base_type::TYPE_VOID:
      throw "NO T_VOID CONSTRUCT";

    case t_base_type::TYPE_STRING:
      /* this is wrong, binary is still a string type internally
      if (((t_base_type*)type)->is_binary()) {
          return "thrift.BINARY";
      }
      */
      return "thrift.STRING";

    case t_base_type::TYPE_BOOL:
      return "thrift.BOOL";

    case t_base_type::TYPE_I8:
      return "thrift.BYTE";

    case t_base_type::TYPE_I16:
      return "thrift.I16";

    case t_base_type::TYPE_I32:
      return "thrift.I32";

    case t_base_type::TYPE_I64:
      return "thrift.I64";

    case t_base_type::TYPE_DOUBLE:
      return "thrift.DOUBLE";
    }
  } else if (type->is_enum()) {
    return "thrift.I32";
  } else if (type->is_struct() || type->is_xception()) {
    return "thrift.STRUCT";
  } else if (type->is_map()) {
    return "thrift.MAP";
  } else if (type->is_set()) {
    return "thrift.SET";
  } else if (type->is_list()) {
    return "thrift.LIST";
  }

  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::render_const_value(t_type* type, t_const_value* value, const string& name) {
  type = get_true_type(type);
  std::ostringstream out;

  if (type->is_base_type()) {
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();

    switch (tbase) {
    case t_base_type::TYPE_STRING:
      if (((t_base_type*)type)->is_binary()) {
        out << "[]byte(\"" << get_escaped_string(value) << "\")";
      } else {
        out << '"' << get_escaped_string(value) << '"';
      }

      break;

    case t_base_type::TYPE_BOOL:
      out << (value->get_integer() > 0 ? "true" : "false");
      break;

    case t_base_type::TYPE_I8:
    case t_base_type::TYPE_I16:
    case t_base_type::TYPE_I32:
    case t_base_type::TYPE_I64:
      out << value->get_integer();
      break;

    case t_base_type::TYPE_DOUBLE:
      if (value->get_type() == t_const_value::CV_INTEGER) {
        out << value->get_integer();
      } else {
        out << value->get_double();
      }

      break;

    default:
      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
    }
  } else if (type->is_enum()) {
    indent(out) << value->get_integer();
  } else if (type->is_struct() || type->is_xception()) {
    out << "&" << publicize(type_name(type)) << "{";
    indent_up();
    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
    vector<t_field*>::const_iterator f_iter;
    const map<t_const_value*, t_const_value*>& val = value->get_map();
    map<t_const_value*, t_const_value*>::const_iterator v_iter;

    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
      t_type* field_type = NULL;

      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
          field_type = (*f_iter)->get_type();
        }
      }

      if (field_type == NULL) {
        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
      }

      out << endl << indent() << publicize(v_iter->first->get_string()) << ": "
          << render_const_value(field_type, v_iter->second, name) << "," << endl;
    }

    indent_down();
    out << "}";

  } else if (type->is_map()) {
    t_type* ktype = ((t_map*)type)->get_key_type();
    t_type* vtype = ((t_map*)type)->get_val_type();
    const map<t_const_value*, t_const_value*>& val = value->get_map();
    out << "map[" << type_to_go_type(ktype) << "]" << type_to_go_type(vtype) << "{" << endl;
    indent_up();
    map<t_const_value*, t_const_value*>::const_iterator v_iter;

    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
      out << indent() << render_const_value(ktype, v_iter->first, name) << ": "
          << render_const_value(vtype, v_iter->second, name) << "," << endl;
    }

    indent_down();
    out << indent() << "}";
  } else if (type->is_list()) {
    t_type* etype = ((t_list*)type)->get_elem_type();
    const vector<t_const_value*>& val = value->get_list();
    out << "[]" << type_to_go_type(etype) << "{" << endl;
    indent_up();
    vector<t_const_value*>::const_iterator v_iter;

    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
      out << indent() << render_const_value(etype, *v_iter, name) << ", ";
    }

    indent_down();
    out << indent() << "}";
  } else if (type->is_set()) {
    t_type* etype = ((t_set*)type)->get_elem_type();
    const vector<t_const_value*>& val = value->get_list();
    out << "map[" << type_to_go_key_type(etype) << "]struct{}{" << endl;
    indent_up();
    vector<t_const_value*>::const_iterator v_iter;

    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
      out << indent() << render_const_value(etype, *v_iter, name) << ": struct{}{}," << endl;
    }

    indent_down();
    out << indent() << "}";
  } else {
    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
  }

  return out.str();
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::get_publicized_name_and_def_value(t_field* tfield,
                                                       string* OUT_pub_name,
                                                       t_const_value** OUT_def_value) const {
  const string base_field_name = tfield->get_name();
  const string escaped_field_name = escape_string(base_field_name);
  *OUT_pub_name = publicize(escaped_field_name);
  *OUT_def_value = tfield->get_value();
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_serialize_list_element(ofstream& out, t_list* tlist, string prefix) {
  t_field efield(tlist->get_elem_type(), "");
  efield.set_req(t_field::T_OPT_IN_REQ_OUT);
  generate_serialize_field(out, &efield, prefix);
}

Project: thrift
File: t_go_generator.cc

bool t_go_generator::omit_initialization(t_field* tfield) {
  t_const_value* value = tfield->get_value();
  if (!value) {
    return true;
  }
  t_type* type = tfield->get_type()->get_true_type();
  if (type->is_base_type()) {
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();

    switch (tbase) {
    case t_base_type::TYPE_VOID:
      throw "";

    case t_base_type::TYPE_STRING:
      if (((t_base_type*)type)->is_binary()) {
        //[]byte are always inline
        return false;
      }
      // strings are pointers if has no default
      return value->get_string().empty();

    case t_base_type::TYPE_BOOL:
    case t_base_type::TYPE_I8:
    case t_base_type::TYPE_I16:
    case t_base_type::TYPE_I32:
    case t_base_type::TYPE_I64:
      return value->get_integer() == 0;
    case t_base_type::TYPE_DOUBLE:
      if (value->get_type() == t_const_value::CV_INTEGER) {
        return value->get_integer() == 0;
      } else {
        return value->get_double() == 0.;
      }
    }
  }
  return false;
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_xception(t_struct* txception) {
  generate_go_struct(txception, true);
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_service_helpers(t_service* tservice) {
  vector<t_function*> functions = tservice->get_functions();
  vector<t_function*>::iterator f_iter;
  f_types_ << "// HELPER FUNCTIONS AND STRUCTURES" << endl << endl;

  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
    t_struct* ts = (*f_iter)->get_arglist();
    generate_go_struct_definition(f_types_, ts, false, false, true);
    generate_go_function_helpers(*f_iter);
  }
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) {
  (void)tstruct;
  out << indent() << "if err := " << prefix << "." << write_method_name_ << "(oprot); err != nil {" << endl;
  out << indent() << "  return thrift.PrependError(fmt.Sprintf(\"%T error writing struct: \", "
      << prefix << "), err)" << endl;
  out << indent() << "}" << endl;
}

Project: thrift
File: t_go_generator.cc

std::string t_go_generator::camelcase(const std::string& value) const {
  std::string value2(value);
  std::setlocale(LC_ALL, "C"); // set locale to classic

  // Fix common initialism in first word
  fix_common_initialism(value2, 0);

  // as long as we are changing things, let's change _ followed by lowercase to
  // capital and fix common initialisms
  for (std::string::size_type i = 1; i < value2.size() - 1; ++i) {
    if (value2[i] == '_') {
      if (islower(value2[i + 1])) {
        value2.replace(i, 2, 1, toupper(value2[i + 1]));
      }
      fix_common_initialism(value2, i);
    }
  }

  return value2;
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::render_included_programs(string& unused_protection) {
  const vector<t_program*>& includes = program_->get_includes();
  string result = "";

  unused_protection = "";

  string local_namespace = program_->get_namespace("go");
  for (size_t i = 0; i < includes.size(); ++i) {
    if (!local_namespace.empty() && local_namespace == includes[i]->get_namespace("go")) {
      continue;
    }

    string go_module = get_real_go_module(includes[i]);
    size_t found = 0;
    for (size_t j = 0; j < go_module.size(); j++) {
      // Import statement uses slashes ('/') in namespace
      if (go_module[j] == '.') {
        go_module[j] = '/';
        found = j + 1;
      }
    }

    result += "\t\"" + gen_package_prefix_ + go_module + "\"\n";
    unused_protection += "var _ = " + go_module.substr(found) + ".GoUnusedProtection__\n";
  }

  return result;
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_service_interface(t_service* tservice) {
  string extends = "";
  string extends_if = "";
  string serviceName(publicize(tservice->get_name()));
  string interfaceName = serviceName;

  if (tservice->get_extends() != NULL) {
    extends = type_name(tservice->get_extends());
    size_t index = extends.rfind(".");

    if (index != string::npos) {
      extends_if = "\n" + indent() + "  " + extends.substr(0, index + 1)
                   + publicize(extends.substr(index + 1)) + "\n";
    } else {
      extends_if = "\n" + indent() + publicize(extends) + "\n";
    }
  }

  f_types_ << indent() << "type " << interfaceName << " interface {" << extends_if;
  indent_up();
  generate_go_docstring(f_types_, tservice);
  vector<t_function*> functions = tservice->get_functions();

  if (!functions.empty()) {
    f_types_ << endl;
    vector<t_function*>::iterator f_iter;

    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
      generate_go_docstring(f_types_, (*f_iter));
      f_types_ << indent() << function_signature_if(*f_iter, "", true) << endl;
    }
  }

  indent_down();
  f_types_ << indent() << "}" << endl << endl;
}

Project: thrift
File: t_go_generator.cc

std::string t_go_generator::privatize(const std::string& value) const {
  if (value.size() <= 0) {
    return value;
  }

  std::string value2(value);

  if (!islower(value2[0])) {
    value2[0] = tolower(value2[0]);
  }

  value2 = camelcase(value2);

  return value2;
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_service_client(t_service* tservice) {
  string extends = "";
  string extends_field = "";
  string extends_client = "";
  string extends_client_new = "";
  string serviceName(publicize(tservice->get_name()));

  if (tservice->get_extends() != NULL) {
    extends = type_name(tservice->get_extends());
    size_t index = extends.rfind(".");

    if (index != string::npos) {
      extends_client = extends.substr(0, index + 1) + publicize(extends.substr(index + 1))
                       + "Client";
      extends_client_new = extends.substr(0, index + 1) + "New"
                           + publicize(extends.substr(index + 1)) + "Client";
    } else {
      extends_client = publicize(extends) + "Client";
      extends_client_new = "New" + extends_client;
    }
  }

  extends_field = extends_client.substr(extends_client.find(".") + 1);

  generate_go_docstring(f_types_, tservice);
  f_types_ << indent() << "type " << serviceName << "Client struct {" << endl;
  indent_up();

  if (!extends_client.empty()) {
    f_types_ << indent() << "*" << extends_client << endl;
  } else {
    f_types_ << indent() << "Transport thrift.TTransport" << endl;
    f_types_ << indent() << "ProtocolFactory thrift.TProtocolFactory" << endl;
    f_types_ << indent() << "InputProtocol thrift.TProtocol" << endl;
    f_types_ << indent() << "OutputProtocol thrift.TProtocol" << endl;
    f_types_ << indent() << "SeqId int32" << endl;
    /*f_types_ << indent() << "reqs map[int32]Deferred" << endl*/;
  }

  indent_down();
  f_types_ << indent() << "}" << endl << endl;
  // Constructor function
  f_types_ << indent() << "func New" << serviceName
             << "ClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *" << serviceName
             << "Client {" << endl;
  indent_up();
  f_types_ << indent() << "return &" << serviceName << "Client";

  if (!extends.empty()) {
    f_types_ << "{" << extends_field << ": " << extends_client_new << "Factory(t, f)}";
  } else {
    indent_up();
    f_types_ << "{Transport: t," << endl;
    f_types_ << indent() << "ProtocolFactory: f," << endl;
    f_types_ << indent() << "InputProtocol: f.GetProtocol(t)," << endl;
    f_types_ << indent() << "OutputProtocol: f.GetProtocol(t)," << endl;
    f_types_ << indent() << "SeqId: 0," << endl;
    /*f_types_ << indent() << "Reqs: make(map[int32]Deferred)" << endl*/;
    indent_down();
    f_types_ << indent() << "}" << endl;
  }

  indent_down();
  f_types_ << indent() << "}" << endl << endl;
  // Constructor function
  f_types_
      << indent() << "func New" << serviceName
      << "ClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *"
      << serviceName << "Client {" << endl;
  indent_up();
  f_types_ << indent() << "return &" << serviceName << "Client";

  if (!extends.empty()) {
    f_types_ << "{" << extends_field << ": " << extends_client_new << "Protocol(t, iprot, oprot)}"
               << endl;
  } else {
    indent_up();
    f_types_ << "{Transport: t," << endl;
    f_types_ << indent() << "ProtocolFactory: nil," << endl;
    f_types_ << indent() << "InputProtocol: iprot," << endl;
    f_types_ << indent() << "OutputProtocol: oprot," << endl;
    f_types_ << indent() << "SeqId: 0," << endl;
    /*f_types_ << indent() << "Reqs: make(map[int32]interface{})" << endl*/;
    indent_down();
    f_types_ << indent() << "}" << endl;
  }

  indent_down();
  f_types_ << indent() << "}" << endl << endl;
  // Generate client method implementations
  vector<t_function*> functions = tservice->get_functions();
  vector<t_function*>::const_iterator f_iter;

  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
    t_struct* arg_struct = (*f_iter)->get_arglist();
    const vector<t_field*>& fields = arg_struct->get_members();
    vector<t_field*>::const_iterator fld_iter;
    string funname = publicize((*f_iter)->get_name());
    // Open function
    generate_go_docstring(f_types_, (*f_iter));
    f_types_ << indent() << "func (p *" << serviceName << "Client) "
               << function_signature_if(*f_iter, "", true) << " {" << endl;
    indent_up();
    /*
    f_types_ <<
      indent() << "p.SeqId += 1" << endl;
    if (!(*f_iter)->is_oneway()) {
      f_types_ <<
        indent() << "d := defer.Deferred()" << endl <<
        indent() << "p.Reqs[p.SeqId] = d" << endl;
    }
    */
    f_types_ << indent() << "if err = p.send" << funname << "(";
    bool first = true;

    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
      if (first) {
        first = false;
      } else {
        f_types_ << ", ";
      }

      f_types_ << variable_name_to_go_name((*fld_iter)->get_name());
    }

    f_types_ << "); err != nil { return }" << endl;

    if (!(*f_iter)->is_oneway()) {
      f_types_ << indent() << "return p.recv" << funname << "()" << endl;
    } else {
      f_types_ << indent() << "return" << endl;
    }

    indent_down();
    f_types_ << indent() << "}" << endl << endl;
    f_types_ << indent() << "func (p *" << serviceName << "Client) send"
               << function_signature(*f_iter) << "(err error) {" << endl;
    indent_up();
    std::string argsname = publicize((*f_iter)->get_name() + "_args", true);
    // Serialize the request header
    f_types_ << indent() << "oprot := p.OutputProtocol" << endl;
    f_types_ << indent() << "if oprot == nil {" << endl;
    f_types_ << indent() << "  oprot = p.ProtocolFactory.GetProtocol(p.Transport)" << endl;
    f_types_ << indent() << "  p.OutputProtocol = oprot" << endl;
    f_types_ << indent() << "}" << endl;
    f_types_ << indent() << "p.SeqId++" << endl;
    f_types_ << indent() << "if err = oprot.WriteMessageBegin(\"" << (*f_iter)->get_name()
               << "\", " << ((*f_iter)->is_oneway() ? "thrift.ONEWAY" : "thrift.CALL")
               << ", p.SeqId); err != nil {" << endl;
    indent_up();
    f_types_ << indent() << "  return" << endl;
    indent_down();
    f_types_ << indent() << "}" << endl;
    f_types_ << indent() << "args := " << argsname << "{" << endl;

    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
      f_types_ << indent() << publicize((*fld_iter)->get_name()) << " : "
                 << variable_name_to_go_name((*fld_iter)->get_name()) << "," << endl;
    }
    f_types_ << indent() << "}" << endl;

    // Write to the stream
    f_types_ << indent() << "if err = args." << write_method_name_ << "(oprot); err != nil {" << endl;
    indent_up();
    f_types_ << indent() << "  return" << endl;
    indent_down();
    f_types_ << indent() << "}" << endl;
    f_types_ << indent() << "if err = oprot.WriteMessageEnd(); err != nil {" << endl;
    indent_up();
    f_types_ << indent() << "  return" << endl;
    indent_down();
    f_types_ << indent() << "}" << endl;
    f_types_ << indent() << "return oprot.Flush()" << endl;
    indent_down();
    f_types_ << indent() << "}" << endl << endl;

    if (!(*f_iter)->is_oneway()) {
      std::string resultname = publicize((*f_iter)->get_name() + "_result", true);
      // Open function
      f_types_ << endl << indent() << "func (p *" << serviceName << "Client) recv"
                 << publicize((*f_iter)->get_name()) << "() (";

      if (!(*f_iter)->get_returntype()->is_void()) {
        f_types_ << "value " << type_to_go_type((*f_iter)->get_returntype()) << ", ";
      }

      f_types_ << "err error) {" << endl;
      indent_up();
      // TODO(mcslee): Validate message reply here, seq ids etc.
      string error(tmp("error"));
      string error2(tmp("error"));
      f_types_ << indent() << "iprot := p.InputProtocol" << endl;
      f_types_ << indent() << "if iprot == nil {" << endl;
      f_types_ << indent() << "  iprot = p.ProtocolFactory.GetProtocol(p.Transport)" << endl;
      f_types_ << indent() << "  p.InputProtocol = iprot" << endl;
      f_types_ << indent() << "}" << endl;
      f_types_ << indent() << "method, mTypeId, seqId, err := iprot.ReadMessageBegin()" << endl;
      f_types_ << indent() << "if err != nil {" << endl;
      f_types_ << indent() << "  return" << endl;
      f_types_ << indent() << "}" << endl;
      f_types_ << indent() << "if method != \"" << (*f_iter)->get_name() << "\" {" << endl;
      f_types_ << indent() << "  err = thrift.NewTApplicationException("
                 << "thrift.WRONG_METHOD_NAME, \"" << (*f_iter)->get_name()
                 << " failed: wrong method name\")" << endl;
      f_types_ << indent() << "  return" << endl;
      f_types_ << indent() << "}" << endl;
      f_types_ << indent() << "if p.SeqId != seqId {" << endl;
      f_types_ << indent() << "  err = thrift.NewTApplicationException("
                 << "thrift.BAD_SEQUENCE_ID, \"" << (*f_iter)->get_name()
                 << " failed: out of sequence response\")" << endl;
      f_types_ << indent() << "  return" << endl;
      f_types_ << indent() << "}" << endl;
      f_types_ << indent() << "if mTypeId == thrift.EXCEPTION {" << endl;
      f_types_ << indent() << "  " << error
                 << " := thrift.NewTApplicationException(thrift.UNKNOWN_APPLICATION_EXCEPTION, "
                    "\"Unknown Exception\")" << endl;
      f_types_ << indent() << "  var " << error2 << " error" << endl;
      f_types_ << indent() << "  " << error2 << ", err = " << error << ".Read(iprot)" << endl;
      f_types_ << indent() << "  if err != nil {" << endl;
      f_types_ << indent() << "    return" << endl;
      f_types_ << indent() << "  }" << endl;
      f_types_ << indent() << "  if err = iprot.ReadMessageEnd(); err != nil {" << endl;
      f_types_ << indent() << "    return" << endl;
      f_types_ << indent() << "  }" << endl;
      f_types_ << indent() << "  err = " << error2 << endl;
      f_types_ << indent() << "  return" << endl;
      f_types_ << indent() << "}" << endl;
      f_types_ << indent() << "if mTypeId != thrift.REPLY {" << endl;
      f_types_ << indent() << "  err = thrift.NewTApplicationException("
                 << "thrift.INVALID_MESSAGE_TYPE_EXCEPTION, \"" << (*f_iter)->get_name()
                 << " failed: invalid message type\")" << endl;
      f_types_ << indent() << "  return" << endl;
      f_types_ << indent() << "}" << endl;
      f_types_ << indent() << "result := " << resultname << "{}" << endl;
      f_types_ << indent() << "if err = result." << read_method_name_ << "(iprot); err != nil {" << endl;
      f_types_ << indent() << "  return" << endl;
      f_types_ << indent() << "}" << endl;
      f_types_ << indent() << "if err = iprot.ReadMessageEnd(); err != nil {" << endl;
      f_types_ << indent() << "  return" << endl;
      f_types_ << indent() << "}" << endl;

      t_struct* xs = (*f_iter)->get_xceptions();
      const std::vector<t_field*>& xceptions = xs->get_members();
      vector<t_field*>::const_iterator x_iter;

      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
        const std::string pubname = publicize((*x_iter)->get_name());

        f_types_ << indent() << "if result." << pubname << " != nil {" << endl;
        f_types_ << indent() << "  err = result." << pubname << endl;
        f_types_ << indent() << "  return " << endl;
        f_types_ << indent() << "}";

        if ((x_iter + 1) != xceptions.end()) {
          f_types_ << " else ";
        } else {
          f_types_ << endl;
        }
      }

      // Careful, only return _result if not a void function
      if (!(*f_iter)->get_returntype()->is_void()) {
        f_types_ << indent() << "value = result.GetSuccess()" << endl;
      }

      f_types_ << indent() << "return" << endl;
      // Close function
      indent_down();
      f_types_ << indent() << "}" << endl << endl;
    }
  }

  // indent_down();
  f_types_ << endl;
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_go_docstring(ofstream& out, t_struct* tstruct) {
  generate_go_docstring(out, tstruct, tstruct, "Attributes");
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_go_docstring(ofstream& out, t_function* tfunction) {
  generate_go_docstring(out, tfunction, tfunction->get_arglist(), "Parameters");
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::type_to_spec_args(t_type* ttype) {
  while (ttype->is_typedef()) {
    ttype = ((t_typedef*)ttype)->get_type();
  }

  if (ttype->is_base_type() || ttype->is_enum()) {
    return "nil";
  } else if (ttype->is_struct() || ttype->is_xception()) {
    return "(" + type_name(ttype) + ", " + type_name(ttype) + ".thrift_spec)";
  } else if (ttype->is_map()) {
    return "(" + type_to_enum(((t_map*)ttype)->get_key_type()) + ","
           + type_to_spec_args(((t_map*)ttype)->get_key_type()) + ","
           + type_to_enum(((t_map*)ttype)->get_val_type()) + ","
           + type_to_spec_args(((t_map*)ttype)->get_val_type()) + ")";
  } else if (ttype->is_set()) {
    return "(" + type_to_enum(((t_set*)ttype)->get_elem_type()) + ","
           + type_to_spec_args(((t_set*)ttype)->get_elem_type()) + ")";
  } else if (ttype->is_list()) {
    return "(" + type_to_enum(((t_list*)ttype)->get_elem_type()) + ","
           + type_to_spec_args(((t_list*)ttype)->get_elem_type()) + ")";
  }

  throw "INVALID TYPE IN type_to_spec_args: " + ttype->get_name();
}

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_deserialize_map_element(ofstream& out,
                                                      t_map* tmap,
                                                      bool declare,
                                                      string prefix) {
  (void)declare;
  string key = tmp("_key");
  string val = tmp("_val");
  t_field fkey(tmap->get_key_type(), key);
  t_field fval(tmap->get_val_type(), val);
  fkey.set_req(t_field::T_OPT_IN_REQ_OUT);
  fval.set_req(t_field::T_OPT_IN_REQ_OUT);
  generate_deserialize_field(out, &fkey, true, "", false, false, true);
  generate_deserialize_field(out, &fval, true, "", false, false, false, true);
  indent(out) << prefix << "[" << key << "] = " << val << endl;
}

Project: thrift
File: t_go_generator.cc

std::string t_go_generator::variable_name_to_go_name(const std::string& value) {
  if (value.size() <= 0) {
    return value;
  }

  std::string value2(value);
  std::transform(value2.begin(), value2.end(), value2.begin(), ::tolower);

  switch (value[0]) {
  case 'b':
  case 'B':
    if (value2 != "break") {
      return value;
    }

    break;

  case 'c':
  case 'C':
    if (value2 != "case" && value2 != "chan" && value2 != "const" && value2 != "continue") {
      return value;
    }

    break;

  case 'd':
  case 'D':
    if (value2 != "default" && value2 != "defer") {
      return value;
    }

    break;

  case 'e':
  case 'E':
    if (value2 != "else" && value2 != "error") {
      return value;
    }

    break;

  case 'f':
  case 'F':
    if (value2 != "fallthrough" && value2 != "for" && value2 != "func") {
      return value;
    }

    break;

  case 'g':
  case 'G':
    if (value2 != "go" && value2 != "goto") {
      return value;
    }

    break;

  case 'i':
  case 'I':
    if (value2 != "if" && value2 != "import" && value2 != "interface") {
      return value;
    }

    break;

  case 'm':
  case 'M':
    if (value2 != "map") {
      return value;
    }

    break;

  case 'p':
  case 'P':
    if (value2 != "package") {
      return value;
    }

    break;

  case 'r':
  case 'R':
    if (value2 != "range" && value2 != "return") {
      return value;
    }

    break;

  case 's':
  case 'S':
    if (value2 != "select" && value2 != "struct" && value2 != "switch") {
      return value;
    }

    break;

  case 't':
  case 'T':
    if (value2 != "type") {
      return value;
    }

    break;

  case 'v':
  case 'V':
    if (value2 != "var") {
      return value;
    }

    break;

  default:
    return value;
  }

  return value2 + "_a1";
}

Project: thrift
File: t_go_generator.cc

  static std::string get_real_go_module(const t_program* program) {

    if (!package_flag.empty()) {
      return package_flag;
    }
    std::string real_module = program->get_namespace("go");
    if (!real_module.empty()) {
      return real_module;
    }

    return lowercase(program->get_name());
  }

Project: thrift
File: t_go_generator.cc

void t_go_generator::generate_serialize_container(ofstream& out,
                                                  t_type* ttype,
                                                  bool pointer_field,
                                                  string prefix) {
  if (pointer_field) {
    prefix = "*" + prefix;
  }
  if (ttype->is_map()) {
    out << indent() << "if err := oprot.WriteMapBegin("
        << type_to_enum(((t_map*)ttype)->get_key_type()) << ", "
        << type_to_enum(((t_map*)ttype)->get_val_type()) << ", "
        << "len(" << prefix << ")); err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(\"error writing map begin: \", err)" << endl;
    out << indent() << "}" << endl;
  } else if (ttype->is_set()) {
    out << indent() << "if err := oprot.WriteSetBegin("
        << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", "
        << "len(" << prefix << ")); err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(\"error writing set begin: \", err)" << endl;
    out << indent() << "}" << endl;
  } else if (ttype->is_list()) {
    out << indent() << "if err := oprot.WriteListBegin("
        << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", "
        << "len(" << prefix << ")); err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(\"error writing list begin: \", err)" << endl;
    out << indent() << "}" << endl;
  } else {
    throw "compiler error: Invalid type in generate_serialize_container '" + ttype->get_name()
        + "' for prefix '" + prefix + "'";
  }

  if (ttype->is_map()) {
    t_map* tmap = (t_map*)ttype;
    out << indent() << "for k, v := range " << prefix << " {" << endl;
    indent_up();
    generate_serialize_map_element(out, tmap, "k", "v");
    indent_down();
    indent(out) << "}" << endl;
  } else if (ttype->is_set()) {
    t_set* tset = (t_set*)ttype;
    out << indent() << "for v, _ := range " << prefix << " {" << endl;
    indent_up();
    generate_serialize_set_element(out, tset, "v");
    indent_down();
    indent(out) << "}" << endl;
  } else if (ttype->is_list()) {
    t_list* tlist = (t_list*)ttype;
    out << indent() << "for _, v := range " << prefix << " {" << endl;

    indent_up();
    generate_serialize_list_element(out, tlist, "v");
    indent_down();
    indent(out) << "}" << endl;
  }

  if (ttype->is_map()) {
    out << indent() << "if err := oprot.WriteMapEnd(); err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(\"error writing map end: \", err)" << endl;
    out << indent() << "}" << endl;
  } else if (ttype->is_set()) {
    out << indent() << "if err := oprot.WriteSetEnd(); err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(\"error writing set end: \", err)" << endl;
    out << indent() << "}" << endl;
  } else if (ttype->is_list()) {
    out << indent() << "if err := oprot.WriteListEnd(); err != nil {" << endl;
    out << indent() << "  return thrift.PrependError(\"error writing list end: \", err)" << endl;
    out << indent() << "}" << endl;
  }
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::go_imports_end() {
  return string(
      ")\n\n"
      "// (needed to ensure safety because of naive import list construction.)\n"
      "var _ = thrift.ZERO\n"
      "var _ = fmt.Printf\n"
      "var _ = bytes.Equal\n\n");
}

Project: thrift
File: t_go_generator.cc

string t_go_generator::render_field_initial_value(t_field* tfield,
                                                  const string& name,
                                                  bool optional_field) {
  t_type* type = get_true_type(tfield->get_type());

  if (optional_field) {
    // The caller will make a second pass for optional fields,
    // assigning the result of render_const_value to "*field_name". It
    // is maddening that Go syntax does not allow for a type-agnostic
    // way to initialize a pointer to a const value, but so it goes.
    // The alternative would be to write type specific functions that
    // convert from const values to pointer types, but given the lack
    // of overloading it would be messy.
    return "new(" + type_to_go_type(tfield->get_type()) + ")";
  } else {
    return render_const_value(type, tfield->get_value(), name);
  }
}