THRIFT-681. The HTML generator does not handle JavaDoc style comments very well

Patch: Kevin Burnett

git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1333222 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_html_generator.cc b/compiler/cpp/src/generate/t_html_generator.cc
index 77cb972..6372ab4 100644
--- a/compiler/cpp/src/generate/t_html_generator.cc
+++ b/compiler/cpp/src/generate/t_html_generator.cc
@@ -27,6 +27,7 @@
 #include <sys/stat.h>
 #include <sstream>
 #include "t_generator.h"
+#include "t_html_generator.h"
 #include "platform.h"
 using namespace std;
 
@@ -77,6 +78,7 @@
   void print_doc        (t_doc* tdoc);
   int  print_type       (t_type* ttype);
   void print_const_value(t_const_value* tvalue);
+  void print_fn_args_doc(t_function* tfunction);
 
   std::ofstream f_out_;
 };
@@ -85,8 +87,8 @@
  * Emits the Table of Contents links at the top of the module's page
  */
 void t_html_generator::generate_program_toc() {
-  f_out_ << "<table><tr><th>Module</th><th>Services</th>"
-   << "<th>Data types</th><th>Constants</th></tr>" << endl;
+  f_out_ << "<table class=\"table-bordered table-striped table-condensed\"><thead><th>Module</th><th>Services</th>"
+   << "<th>Data types</th><th>Constants</th></thead>" << endl;
   generate_program_toc_row(program_);
   f_out_ << "</table>" << endl;
 }
@@ -186,15 +188,15 @@
        dt_iter != data_types.end(); dt_iter++) {
     f_out_ << dt_iter->second << "<br/>" << endl;
   }
-  f_out_ << "</td>" << endl << "<td><code>";
+  f_out_ << "</td>" << endl << "<td>";
   if (!tprog->get_consts().empty()) {
     map<string,string> const_html;
     vector<t_const*> consts = tprog->get_consts();
     vector<t_const*>::iterator con_iter;
     for (con_iter = consts.begin(); con_iter != consts.end(); ++con_iter) {
       string name = (*con_iter)->get_name();
-      string html ="<a href=\"" + fname + "#Const_" + name +
-        "\">" + name + "</a>";
+      string html ="<code><a href=\"" + fname + "#Const_" + name +
+        "\">" + name + "</a></code>";
       const_html.insert(pair<string,string>(name, html));
     }
     for (map<string,string>::iterator con_iter = const_html.begin();
@@ -219,10 +221,11 @@
   f_out_ << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl;
   f_out_ << "<head>" << endl;
   f_out_ << "<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" />" << endl;
-  f_out_ << "<link href=\"style.css\" rel=\"stylesheet\" type=\"text/css\"/>"
-   << endl;
+  f_out_ << "<link href=\"style.css\" rel=\"stylesheet\" type=\"text/css\"/>" << endl;
   f_out_ << "<title>Thrift module: " << program_->get_name()
-   << "</title></head><body>" << endl << "<h1>Thrift module: "
+   << "</title></head><body>" << endl
+   << "<div class=\"container-fluid\">" << endl
+   << "<h1>Thrift module: "
    << program_->get_name() << "</h1>" << endl;
 
   print_doc(program_);
@@ -232,8 +235,8 @@
   if (!program_->get_consts().empty()) {
     f_out_ << "<hr/><h2 id=\"Constants\">Constants</h2>" << endl;
     vector<t_const*> consts = program_->get_consts();
-    f_out_ << "<table>";
-    f_out_ << "<tr><th>Constant</th><th>Type</th><th>Value</th></tr>" << endl;
+    f_out_ << "<table class=\"table-bordered table-striped table-condensed\">";
+    f_out_ << "<thead><th>Constant</th><th>Type</th><th>Value</th></thead>" << endl;
     generate_consts(consts);
     f_out_ << "</table>";
   }
@@ -283,7 +286,7 @@
     }
   }
 
-  f_out_ << "</body></html>" << endl;
+  f_out_ << "</div></body></html>" << endl;
   f_out_.close();
 
   generate_index();
@@ -300,37 +303,29 @@
   f_out_ << "<link href=\"style.css\" rel=\"stylesheet\" type=\"text/css\"/>"
    << endl;
   f_out_ << "<title>All Thrift declarations</title></head><body>"
+   << endl << "<div class=\"container-fluid\">"
    << endl << "<h1>All Thrift declarations</h1>" << endl;
-  f_out_ << "<table><tr><th>Module</th><th>Services</th><th>Data types</th>"
-   << "<th>Constants</th></tr>" << endl;
+  f_out_ << "<table class=\"table-bordered table-striped table-condensed\"><thead><th>Module</th><th>Services</th><th>Data types</th>"
+   << "<th>Constants</th></thead>" << endl;
   vector<t_program*> programs;
   generate_program_toc_rows(program_, programs);
   f_out_ << "</table>" << endl;
-  f_out_ << "</body></html>" << endl;
+  f_out_ << "</div></body></html>" << endl;
   f_out_.close();
 }
 
 void t_html_generator::generate_css() {
   string css_fname = get_out_dir() + "style.css";
   f_out_.open(css_fname.c_str());
+  f_out_ << BOOTSTRAP_CSS() << endl;
   f_out_ << "/* Auto-generated CSS for generated Thrift docs */" << endl;
-  f_out_ <<
-    "body { font-family: Tahoma, sans-serif; }" << endl;
-  f_out_ <<
-    "pre { background-color: #dddddd; padding: 6px; }" << endl;
-  f_out_ <<
-    "h3,h4 { padding-top: 0px; margin-top: 0px; }" << endl;
-  f_out_ <<
-    "div.definition { border: 1px solid gray; margin: 10px; padding: 10px; }" << endl;
-  f_out_ <<
-    "div.extends { margin: -0.5em 0 1em 5em }" << endl;
-  f_out_ <<
-    "table { border: 1px solid grey; border-collapse: collapse; }" << endl;
-  f_out_ <<
-    "td { border: 1px solid grey; padding: 1px 6px; vertical-align: top; }" << endl;
-  f_out_ <<
-    "th { border: 1px solid black; background-color: #bbbbbb;" << endl <<
-    "     text-align: left; padding: 1px 6px; }" << endl;
+  f_out_ << "h3, h4 { margin-bottom: 6px; }" << endl;
+  f_out_ << "div.definition { border: 1px solid #CCC; margin-bottom: 10px; padding: 10px; }" << endl;
+  f_out_ << "div.extends { margin: -0.5em 0 1em 5em }" << endl;
+  f_out_ << "td { vertical-align: top; }" << endl;
+  f_out_ << "table { empty-cells: show; }" << endl;
+  f_out_ << "code { line-height: 20px; }" << endl;
+  f_out_ << ".table-bordered th, .table-bordered td { border-bottom: 1px solid #DDDDDD; }" << endl;
   f_out_.close();
 }
 
@@ -462,6 +457,59 @@
 }
 
 /**
+ * Prints out documentation for arguments/exceptions of a function, if any documentation has been supplied.
+ */
+void t_html_generator::print_fn_args_doc(t_function* tfunction) {
+  bool has_docs = false;
+  vector<t_field*> args = tfunction->get_arglist()->get_members();
+  vector<t_field*>::iterator arg_iter = args.begin();
+  if (arg_iter != args.end()) {
+    for ( ; arg_iter != args.end(); arg_iter++) {
+      if ((*arg_iter)->has_doc() && !(*arg_iter)->get_doc().empty())
+        has_docs = true;
+    }
+    if (has_docs) {
+      arg_iter = args.begin();
+      f_out_ << "<br/><h4 id=\"Parameters_" << service_name_ << "_" << tfunction->get_name()
+        << "\">Parameters</h4>" << endl;
+      f_out_ << "<table class=\"table-bordered table-striped table-condensed\">";
+      f_out_ << "<thead><th>Name</th><th>Description</th></thead>";
+      for ( ; arg_iter != args.end(); arg_iter++) {
+        f_out_ << "<tr><td>" << (*arg_iter)->get_name();
+        f_out_ << "</td><td>";
+        f_out_ << (*arg_iter)->get_doc();
+        f_out_ << "</td></tr>" << endl;
+      }
+      f_out_ << "</table>";
+    }
+  }
+
+  has_docs = false;
+  vector<t_field*> excepts = tfunction->get_xceptions()->get_members();
+  vector<t_field*>::iterator ex_iter = excepts.begin();
+  if (ex_iter != excepts.end()) {
+    for ( ; ex_iter != excepts.end(); ex_iter++) {
+      if ((*ex_iter)->has_doc() && !(*ex_iter)->get_doc().empty())
+        has_docs = true;
+    }
+    if (has_docs) {
+      ex_iter = excepts.begin();
+      f_out_ << "<br/><h4 id=\"Exceptions_" << service_name_ << "_" << tfunction->get_name()
+        << "\">Exceptions</h4>" << endl;
+      f_out_ << "<table class=\"table-bordered table-striped table-condensed\">";
+      f_out_ << "<thead><th>Type</th><th>Description</th></thead>";
+      for ( ; ex_iter != excepts.end(); ex_iter++) {
+        f_out_ << "<tr><td>" << (*ex_iter)->get_type()->get_name();
+        f_out_ << "</td><td>";
+        f_out_ << (*ex_iter)->get_doc();
+        f_out_ << "</td></tr>" << endl;
+      }
+      f_out_ << "</table>";
+    }
+  }
+}
+
+/**
  * Generates a typedef.
  *
  * @param ttypedef The type definition
@@ -491,7 +539,7 @@
   print_doc(tenum);
   vector<t_enum_value*> values = tenum->get_constants();
   vector<t_enum_value*>::iterator val_iter;
-  f_out_ << "<br/><table>" << endl;
+  f_out_ << "<br/><table class=\"table-bordered table-striped table-condensed\">" << endl;
   for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) {
     f_out_ << "<tr><td><code>";
     f_out_ << (*val_iter)->get_name();
@@ -508,9 +556,9 @@
 void t_html_generator::generate_const(t_const* tconst) {
   string name = tconst->get_name();
   f_out_ << "<tr id=\"Const_" << name << "\"><td><code>" << name
-   << "</code></td><td><code>";
+   << "</code></td><td>";
   print_type(tconst->get_type());
-  f_out_ << "</code></td><td><code>";
+  f_out_ << "</td><td><code>";
   print_const_value(tconst->get_value());
   f_out_ << "</code></td></tr>";
   if (tconst->has_doc()) {
@@ -537,8 +585,8 @@
   f_out_ << name << "</h3>" << endl;
   vector<t_field*> members = tstruct->get_members();
   vector<t_field*>::iterator mem_iter = members.begin();
-  f_out_ << "<table>";
-  f_out_ << "<tr><th>Key</th><th>Field</th><th>Type</th><th>Description</th><th>Requiredness</th><th>Default value</th></tr>"
+  f_out_ << "<table class=\"table-bordered table-striped table-condensed\">";
+  f_out_ << "<thead><th>Key</th><th>Field</th><th>Type</th><th>Description</th><th>Requiredness</th><th>Default value</th></thead>"
     << endl;
   for ( ; mem_iter != members.end(); mem_iter++) {
     f_out_ << "<tr><td>" << (*mem_iter)->get_key() << "</td><td>";
@@ -606,21 +654,19 @@
     offset += fn_name.size() + 2;
     vector<t_field*> args = (*fn_iter)->get_arglist()->get_members();
     vector<t_field*>::iterator arg_iter = args.begin();
-    if (arg_iter != args.end()) {
-      for ( ; arg_iter != args.end(); arg_iter++) {
-        if (!first) {
-          f_out_ << "," << endl;
-          for (int i = 0; i < offset; ++i) {
-            f_out_ << " ";
-          }
+    for ( ; arg_iter != args.end(); arg_iter++) {
+      if (!first) {
+        f_out_ << "," << endl;
+        for (int i = 0; i < offset; ++i) {
+          f_out_ << " ";
         }
-        first = false;
-        print_type((*arg_iter)->get_type());
-        f_out_ << " " << (*arg_iter)->get_name();
-        if ((*arg_iter)->get_value() != NULL) {
-          f_out_ << " = ";
-          print_const_value((*arg_iter)->get_value());
-        }
+      }
+      first = false;
+      print_type((*arg_iter)->get_type());
+      f_out_ << " " << (*arg_iter)->get_name();
+      if ((*arg_iter)->get_value() != NULL) {
+        f_out_ << " = ";
+        print_const_value((*arg_iter)->get_value());
       }
     }
     f_out_ << ")" << endl;
@@ -640,6 +686,7 @@
     }
     f_out_ << "</pre>";
     print_doc(*fn_iter);
+    print_fn_args_doc(*fn_iter);
     f_out_ << "</div>";
   }
 }
diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc
index 945d6ef..ca061f7 100755
--- a/compiler/cpp/src/generate/t_java_generator.cc
+++ b/compiler/cpp/src/generate/t_java_generator.cc
@@ -154,9 +154,9 @@
   void generate_union_hashcode(ofstream& out, t_struct* tstruct);
 
   void generate_scheme_map(ofstream& out, t_struct* tstruct);
-  void generate_standard_writer(ofstream& out, t_struct* tstruct);
+  void generate_standard_writer(ofstream& out, t_struct* tstruct, bool is_result);
   void generate_standard_reader(ofstream& out, t_struct* tstruct);
-  void generate_java_struct_standard_scheme(ofstream& out, t_struct* tstruct);
+  void generate_java_struct_standard_scheme(ofstream& out, t_struct* tstruct, bool is_result);
 
   void generate_java_struct_tuple_scheme(ofstream& out, t_struct* tstruct);
   void generate_java_struct_tuple_reader(ofstream& out, t_struct* tstruct);
@@ -1451,7 +1451,7 @@
   generate_java_struct_write_object(out, tstruct);
   generate_java_struct_read_object(out, tstruct);
 
-  generate_java_struct_standard_scheme(out, tstruct);
+  generate_java_struct_standard_scheme(out, tstruct, is_result);
   generate_java_struct_tuple_scheme(out, tstruct);
 
   scope_down(out);
@@ -4005,7 +4005,7 @@
   out << indent() << "}" << endl;	
 }
 
-void t_java_generator::generate_standard_writer(ofstream& out, t_struct* tstruct) {
+void t_java_generator::generate_standard_writer(ofstream& out, t_struct* tstruct, bool is_result) {
   indent_up();
   out <<
     indent() << "public void write(org.apache.thrift.protocol.TProtocol oprot, " << 
@@ -4026,7 +4026,7 @@
       indent() << "if (struct." << (*f_iter)->get_name() << " != null) {" << endl;
       indent_up();
     }
-    bool optional = (*f_iter)->get_req() == t_field::T_OPTIONAL;
+    bool optional = ((*f_iter)->get_req() == t_field::T_OPTIONAL) || (is_result && !null_allowed);
     if (optional) {
       indent(out) << "if (" << "struct." << generate_isset_check((*f_iter)) << ") {" << endl;
       indent_up();
@@ -4059,7 +4059,7 @@
   indent_down();
 }
 
-void t_java_generator::generate_java_struct_standard_scheme(ofstream& out, t_struct* tstruct){
+void t_java_generator::generate_java_struct_standard_scheme(ofstream& out, t_struct* tstruct, bool is_result){
   indent(out) << "private static class " << tstruct->get_name() << "StandardSchemeFactory implements SchemeFactory {" << endl;
   indent_up();
   indent(out) << "public " << tstruct->get_name() << "StandardScheme getScheme() {" << endl;
@@ -4075,7 +4075,7 @@
   generate_standard_reader(out, tstruct);
   indent_down();
   out << endl;
-  generate_standard_writer(out, tstruct);
+  generate_standard_writer(out, tstruct, is_result);
 
   out <<
   indent() << "}" << endl <<