Merge pull request #2574 from aishasalim/feature/kythe-output-path

kythe: Add --output_path to write extracted facts to a file
diff --git a/verible/verilog/formatting/formatter_test.cc b/verible/verilog/formatting/formatter_test.cc
index 25d200e..dce9f05 100644
--- a/verible/verilog/formatting/formatter_test.cc
+++ b/verible/verilog/formatting/formatter_test.cc
@@ -162,6 +162,12 @@
      "`define  BAR\n",
      "`define FOO\n"
      "`define BAR\n"},
+    {"`define FOO_``BAR 1\n", "`define FOO_``BAR 1\n"},
+    {"`define FOO_```BAR 1\n", "`define FOO_```BAR 1\n"},
+    {"`define FOO ``BAR\n", "`define FOO ``BAR\n"},
+    {"`define A``B``C 2\n", "`define A``B``C 2\n"},
+    {"`define A(x)``y\n", "`define A(x) ``y\n"},
+    {"`define    FOO_``BAR\n", "`define FOO_``BAR\n"},
     {"`ifndef    FOO\n"
      "`endif // FOO\n",
      "`ifndef FOO\n"
@@ -1503,6 +1509,119 @@
      "          int   b\n"   // direction missing
      ");\n"
      "endmodule\n"},
+    {"module t;\n"
+     "    input bit i_bit;\n"
+     "input   byte  i_byte ;\n"
+     "input chandle i_chandle;\n"
+     "input event i_event;\n"
+     "input int i_int;\n"
+     "input integer i_inte;\n"
+     "input longint i_longint;\n"
+     "input real i_real;\n"
+     "input realtime i_realtime;\n"
+     "input shortint i_shortint;\n"
+     "input shortreal i_shortreal;\n"
+     "input string i_string;\n"
+     "input time i_time;\n"
+     "     output bit o_bit;\n"
+     "output    byte   o_byte  ;  \n"
+     "output chandle o_chandle;\n"
+     "output event o_event;\n"
+     "output int o_int;\n"
+     "output integer o_inte;\n"
+     "output longint o_longint;\n"
+     "output real o_real;\n"
+     "output realtime o_realtime;\n"
+     "output shortint o_shortint;\n"
+     "output shortreal o_shortreal;\n"
+     "output string o_string;\n"
+     "output time o_time;\n"
+     "endmodule\n",
+     "module t;\n"
+     "  input bit i_bit;\n"
+     "  input byte i_byte;\n"
+     "  input chandle i_chandle;\n"
+     "  input event i_event;\n"
+     "  input int i_int;\n"
+     "  input integer i_inte;\n"
+     "  input longint i_longint;\n"
+     "  input real i_real;\n"
+     "  input realtime i_realtime;\n"
+     "  input shortint i_shortint;\n"
+     "  input shortreal i_shortreal;\n"
+     "  input string i_string;\n"
+     "  input time i_time;\n"
+     "  output bit o_bit;\n"
+     "  output byte o_byte;\n"
+     "  output chandle o_chandle;\n"
+     "  output event o_event;\n"
+     "  output int o_int;\n"
+     "  output integer o_inte;\n"
+     "  output longint o_longint;\n"
+     "  output real o_real;\n"
+     "  output realtime o_realtime;\n"
+     "  output shortint o_shortint;\n"
+     "  output shortreal o_shortreal;\n"
+     "  output string o_string;\n"
+     "  output time o_time;\n"
+     "endmodule\n"},
+    {"module t (\n"
+     "    input bit i_bit,\n"
+     "input     byte   i_byte  ,\n"
+     "input chandle i_chandle,\n"
+     "input event i_event,\n"
+     "input int i_int,\n"
+     "input integer i_inte,\n"
+     "input longint i_longint,\n"
+     "input real i_real,\n"
+     "input realtime i_realtime,\n"
+     "input shortint i_shortint,\n"
+     "input shortreal i_shortreal,\n"
+     "input string i_string,\n"
+     "input time i_time,\n"
+     "    output bit o_bit,\n"
+     "output     byte   o_byte  ,  \n"
+     "output chandle o_chandle,\n"
+     "output event o_event,\n"
+     "output int o_int,\n"
+     "output integer o_inte,\n"
+     "output longint o_longint,\n"
+     "output real o_real,\n"
+     "output realtime o_realtime,\n"
+     "output shortint o_shortint,\n"
+     "output shortreal o_shortreal,\n"
+     "output string o_string,\n"
+     "output time o_time);\n"
+     "endmodule\n",
+     "module t (\n"
+     "    input  bit       i_bit,\n"
+     "    input  byte      i_byte,\n"
+     "    input  chandle   i_chandle,\n"
+     "    input  event     i_event,\n"
+     "    input  int       i_int,\n"
+     "    input  integer   i_inte,\n"
+     "    input  longint   i_longint,\n"
+     "    input  real      i_real,\n"
+     "    input  realtime  i_realtime,\n"
+     "    input  shortint  i_shortint,\n"
+     "    input  shortreal i_shortreal,\n"
+     "    input  string    i_string,\n"
+     "    input  time      i_time,\n"
+     "    output bit       o_bit,\n"
+     "    output byte      o_byte,\n"
+     "    output chandle   o_chandle,\n"
+     "    output event     o_event,\n"
+     "    output int       o_int,\n"
+     "    output integer   o_inte,\n"
+     "    output longint   o_longint,\n"
+     "    output real      o_real,\n"
+     "    output realtime  o_realtime,\n"
+     "    output shortint  o_shortint,\n"
+     "    output shortreal o_shortreal,\n"
+     "    output string    o_string,\n"
+     "    output time      o_time\n"
+     ");\n"
+     "endmodule\n"},
     {"module m;foo bar(.baz({larry, moe, curly}));endmodule",
      "module m;\n"
      "  foo bar (.baz({larry, moe, curly}));\n"
@@ -3885,6 +4004,22 @@
      "  endtask\n"
      "  // class is about to end\n"
      "endclass\n"},
+
+    // interface class test cases
+    {"interface class Foo;\nendclass\n",
+     "interface class Foo;\n"
+     "endclass\n"},
+    {"interface   class   Foo  ;  endclass\n",
+     "interface class Foo;\n"
+     "endclass\n"},
+    {"interface class Foo extends Bar , Baz ;\nendclass\n",
+     "interface class Foo extends Bar, Baz;\n"
+     "endclass\n"},
+    {"interface class Foo;\n  pure   virtual   task   foo (  ) ; \nendclass\n",
+     "interface class Foo;\n"
+     "  pure virtual task foo();\n"
+     "endclass\n"},
+
     // class property alignment test cases
     {"class c;\n"
      "int foo  ;\n"
@@ -19245,6 +19380,78 @@
   }
 }
 
+// Regression for https://github.com/chipsalliance/verible/issues/2540:
+// Trailing EOL comment after `end` before `else if` must not change whether
+// the else-if assignment stays on one line across re-format (convergence).
+TEST(FormatterEndToEndTest, EndElseIfWithEOLCommentConverges) {
+  static constexpr FormatterTestCase kTestCases[] = {
+      {// Comment on its own line between end and else if
+       "module m;\n"
+       "  always_comb begin\n"
+       "    case (state)\n"
+       "      STATE_A: begin\n"
+       "        if (cond_aaaa) next_state_value = STATE_B;\n"
+       "        else if (cond_bbbb) begin\n"
+       "          next_state_value = STATE_B;\n"
+       "        end\n"
+       "        // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"
+       "        else if (cond_cccc) next_state_value = STATE_C;\n"
+       "      end\n"
+       "    endcase\n"
+       "  end\n"
+       "endmodule\n",
+       "module m;\n"
+       "  always_comb begin\n"
+       "    case (state)\n"
+       "      STATE_A: begin\n"
+       "        if (cond_aaaa) next_state_value = STATE_B;\n"
+       "        else if (cond_bbbb) begin\n"
+       "          next_state_value = STATE_B;\n"
+       "        end  // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"
+       "        else if (cond_cccc) next_state_value = STATE_C;\n"
+       "      end\n"
+       "    endcase\n"
+       "  end\n"
+       "endmodule\n"},
+      {// Same construct with comment already on the end line
+       "module m;\n"
+       "  always_comb begin\n"
+       "    case (state)\n"
+       "      STATE_A: begin\n"
+       "        if (cond_aaaa) next_state_value = STATE_B;\n"
+       "        else if (cond_bbbb) begin\n"
+       "          next_state_value = STATE_B;\n"
+       "        end  // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"
+       "        else if (cond_cccc) next_state_value = STATE_C;\n"
+       "      end\n"
+       "    endcase\n"
+       "  end\n"
+       "endmodule\n",
+       "module m;\n"
+       "  always_comb begin\n"
+       "    case (state)\n"
+       "      STATE_A: begin\n"
+       "        if (cond_aaaa) next_state_value = STATE_B;\n"
+       "        else if (cond_bbbb) begin\n"
+       "          next_state_value = STATE_B;\n"
+       "        end  // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"
+       "        else if (cond_cccc) next_state_value = STATE_C;\n"
+       "      end\n"
+       "    endcase\n"
+       "  end\n"
+       "endmodule\n"},
+  };
+  FormatStyle style;  // default column_limit (100)
+  for (const auto &test_case : kTestCases) {
+    VLOG(1) << "code-to-format:\n" << test_case.input << "<EOF>";
+    std::ostringstream stream;
+    const auto status =
+        FormatVerilog(test_case.input, "<filename>", style, stream);
+    EXPECT_OK(status) << status.message();
+    EXPECT_EQ(stream.str(), test_case.expected) << "code:\n" << test_case.input;
+  }
+}
+
 // Verify kAlign behavior for body-level param/localparam declarations
 // in module and package bodies.
 TEST(FormatterEndToEndTest, ParamDeclarationAlignmentBasics) {
diff --git a/verible/verilog/formatting/token-annotator.cc b/verible/verilog/formatting/token-annotator.cc
index fcbbdbb..def1349 100644
--- a/verible/verilog/formatting/token-annotator.cc
+++ b/verible/verilog/formatting/token-annotator.cc
@@ -258,6 +258,16 @@
     return {0, "No additional space around empty-string tokens."};
   }
 
+  // A macro definition body that begins with the token-concatenation
+  // operator "``" is part of macro name; preserve spacing if present.
+  // If a closing ')', that ends the definition name.
+  if (left.TokenEnum() == verilog_tokentype::PP_Identifier &&
+      right.TokenEnum() == verilog_tokentype::PP_define_body &&
+      right.Text().substr(0, 2) == "``" &&
+      right.OriginalLeadingSpaces().empty()) {
+    return {0, "Preserve spacing in concatenated name"};
+  }
+
   // Remove any extra spaces between numeric literals' width, base and digits.
   // "16'h123, 'h123" instead of "16 'h123", "16'h 123, 'h 123"
   if (IsInsideNumericLiteral(left, right)) {
diff --git a/verible/verilog/formatting/tree-unwrapper.cc b/verible/verilog/formatting/tree-unwrapper.cc
index 28f6391..a6601ac 100644
--- a/verible/verilog/formatting/tree-unwrapper.cc
+++ b/verible/verilog/formatting/tree-unwrapper.cc
@@ -803,6 +803,7 @@
     case NodeEnum::kTypeDeclaration:
     case NodeEnum::kNetTypeDeclaration:
     case NodeEnum::kForwardDeclaration:
+    case NodeEnum::kInterfaceClassMethod:
     case NodeEnum::kConstraintDeclaration:
     case NodeEnum::kConstraintExpression:
     case NodeEnum::kCovergroupDeclaration:
@@ -881,6 +882,7 @@
     case NodeEnum::kTaskDeclaration:
     case NodeEnum::kClassDeclaration:
     case NodeEnum::kClassHeader:
+    case NodeEnum::kInterfaceClassDeclaration:
     case NodeEnum::kBegin:
     case NodeEnum::kEnd:
     // case NodeEnum::kFork:  // TODO(fangism): introduce this node enum
@@ -1201,7 +1203,6 @@
     // For the following constructs, always expand the view to subpartitions.
     // Add a level of indentation.
     case NodeEnum::kPackageImportList:
-    case NodeEnum::kInterfaceClassDeclaration:
     case NodeEnum::kCasePatternItemList:
     case NodeEnum::kConstraintBlockItemList:
     case NodeEnum::kConstraintExpressionList:
@@ -1311,6 +1312,7 @@
     case NodeEnum::kCaseInsideItemList:
     case NodeEnum::kGenerateCaseItemList:
     case NodeEnum::kClassItems:
+    case NodeEnum::kInterfaceClassItemList:
     case NodeEnum::kModuleItemList:
     case NodeEnum::kGenerateItemList:
     // Aligns parameter, net/variable, and assignment declarations in packages.
@@ -1817,6 +1819,14 @@
   }
 }
 
+// True if any token in this leaf partition is an EOL comment.
+static bool PartitionContainsEOLComment(const TokenPartitionTree &partition) {
+  for (const auto &token : partition.Value().TokensRange()) {
+    if (token.TokenEnum() == verilog_tokentype::TK_EOL_COMMENT) return true;
+  }
+  return false;
+}
+
 static void PushEndIntoElsePartition(TokenPartitionTree *partition_ptr) {
   // Then combine 'end' with the following 'else' ...
   // Do not flatten, so that if- and else- clauses can make formatting
@@ -1824,6 +1834,15 @@
   auto &partition = *partition_ptr;
   auto &if_clause_partition = partition.Children().front();
   auto *end_partition = &RightmostDescendant(if_clause_partition);
+  // When 'end' carries a trailing EOL comment, 'else' must start on the next
+  // line (see token annotator: comment before else => MustWrap). Merging
+  // end+comment into the else-if header makes fit-else-expand treat the
+  // header as wider than the eventual formatted line, which wraps the
+  // else-if body on re-format and fails convergence (GitHub issue 2540).
+  if (PartitionContainsEOLComment(*end_partition)) {
+    VLOG(4) << "end has EOL comment, skip merge into else";
+    return;
+  }
   auto *end_parent = verible::MergeLeafIntoNextLeaf(end_partition);
   // if moving leaf results in any singleton partitions, hoist.
   if (end_parent != nullptr) {
diff --git a/verible/verilog/parser/verilog-parser_test.cc b/verible/verilog/parser/verilog-parser_test.cc
index 0600bb7..754498b 100644
--- a/verible/verilog/parser/verilog-parser_test.cc
+++ b/verible/verilog/parser/verilog-parser_test.cc
@@ -1390,6 +1390,62 @@
     "input logic [N:0] a;\n"
     "output logic co;\n"
     "endmodule",
+    "module t;\n"
+    "input bit i_bit;\n"
+    "input byte i_byte;\n"
+    "input chandle i_chandle;\n"
+    "input event i_event;\n"
+    "input int i_int;\n"
+    "input integer i_inte;\n"
+    "input longint i_longint;\n"
+    "input real i_real;\n"
+    "input realtime i_realtime;\n"
+    "input shortint i_shortint;\n"
+    "input shortreal i_shortreal;\n"
+    "input string i_string;\n"
+    "input time i_time;\n"
+    "output bit o_bit;\n"
+    "output byte o_byte;\n"
+    "output chandle o_chandle;\n"
+    "output event o_event;\n"
+    "output int o_int;\n"
+    "output integer o_inte;\n"
+    "output longint o_longint;\n"
+    "output real o_real;\n"
+    "output realtime o_realtime;\n"
+    "output shortint o_shortint;\n"
+    "output shortreal o_shortreal;\n"
+    "output string o_string;\n"
+    "output time o_time;\n"
+    "endmodule\n",
+    "module t (\n"
+    "input bit i_bit,\n"
+    "input byte i_byte,\n"
+    "input chandle i_chandle,\n"
+    "input event i_event,\n"
+    "input int i_int,\n"
+    "input integer i_inte,\n"
+    "input longint i_longint,\n"
+    "input real i_real,\n"
+    "input realtime i_realtime,\n"
+    "input shortint i_shortint,\n"
+    "input shortreal i_shortreal,\n"
+    "input string i_string,\n"
+    "input time i_time,\n"
+    "output bit o_bit,\n"
+    "output byte o_byte,\n"
+    "output chandle o_chandle,\n"
+    "output event o_event,\n"
+    "output int o_int,\n"
+    "output integer o_inte,\n"
+    "output longint o_longint,\n"
+    "output real o_real,\n"
+    "output realtime o_realtime,\n"
+    "output shortint o_shortint,\n"
+    "output shortreal o_shortreal,\n"
+    "output string o_string,\n"
+    "output time o_time);\n"
+    "endmodule\n",
     "module zoom (a, co);\n"
     "input bus_type a;\n"
     "output bus_type [3:0] co;\n"
diff --git a/verible/verilog/parser/verilog.y b/verible/verilog/parser/verilog.y
index ef746fd..f1c24a8 100644
--- a/verible/verilog/parser/verilog.y
+++ b/verible/verilog/parser/verilog.y
@@ -5633,6 +5633,37 @@
     { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1,
                           MakeDataType($3, ForwardChildren($2), MakePackedDimensionsNode($4)),
                           $5, $6); }
+  | port_direction TK_bit signed_unsigned_opt decl_dimensions_opt
+    list_of_identifiers_unpacked_dimensions ';'
+    { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1,
+                          MakeDataType(MakeTaggedNode(N::kDataTypePrimitive, $2, $3),
+                                       MakePackedDimensionsNode($4)),
+                          $5, $6); }
+  | port_direction integer_atom_type signed_unsigned_opt
+    list_of_identifiers_unpacked_dimensions ';'
+    { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1,
+                          MakeDataType(MakeTaggedNode(N::kDataTypePrimitive, $2, $3)),
+                          $4, $5); }
+  | port_direction non_integer_type
+    list_of_identifiers_unpacked_dimensions ';'
+    { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1,
+                          MakeDataType(MakeTaggedNode(N::kDataTypePrimitive, $2)),
+                          $3, $4); }
+  | port_direction TK_string
+    list_of_identifiers_unpacked_dimensions ';'
+    { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1,
+                          MakeDataType(MakeTaggedNode(N::kDataTypePrimitive, $2)),
+                          $3, $4); }
+  | port_direction TK_event
+    list_of_identifiers_unpacked_dimensions ';'
+    { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1,
+                          MakeDataType(MakeTaggedNode(N::kDataTypePrimitive, $2)),
+                          $3, $4); }
+  | port_direction TK_chandle
+    list_of_identifiers_unpacked_dimensions ';'
+    { $$ = MakeTaggedNode(N::kModulePortDeclaration, $1,
+                          MakeDataType(MakeTaggedNode(N::kDataTypePrimitive, $2)),
+                          $3, $4); }
   ;
 
 parameter_override