Align case-generate items.

issues #413

PiperOrigin-RevId: 331619540
diff --git a/verilog/formatting/align.cc b/verilog/formatting/align.cc
index 6652089..9715514 100644
--- a/verilog/formatting/align.cc
+++ b/verilog/formatting/align.cc
@@ -715,14 +715,16 @@
 
 // This class marks up token-subranges in case items for alignment.
 // e.g. "value1, value2: x = f(y);"
+// This is suitable for a variety of case-like items: statements, generate
+// items.
 class CaseItemColumnSchemaScanner : public ColumnSchemaScanner {
  public:
   CaseItemColumnSchemaScanner() = default;
 
   bool ParentContextIsCaseItem() const {
-    return Context().DirectParentIsOneOf({NodeEnum::kCaseItem,
-                                          NodeEnum::kCaseInsideItem,
-                                          NodeEnum::kDefaultItem});
+    return Context().DirectParentIsOneOf(
+        {NodeEnum::kCaseItem, NodeEnum::kCaseInsideItem,
+         NodeEnum::kGenerateCaseItem, NodeEnum::kDefaultItem});
   }
 
   void Visit(const SyntaxTreeNode& node) override {
@@ -739,6 +741,7 @@
       switch (tag) {
         case NodeEnum::kCaseItem:
         case NodeEnum::kCaseInsideItem:
+        case NodeEnum::kGenerateCaseItem:
         case NodeEnum::kDefaultItem: {
           // Start a new column right away.
           ReserveNewColumn(node, FlushLeft);
@@ -886,12 +889,16 @@
         [](const FormatStyle& vstyle) {
           return vstyle.class_member_variable_alignment;
         }}},
+      // various case-like constructs:
       {NodeEnum::kCaseItemList,
        {kCaseItemAligner,
         [](const FormatStyle& vstyle) { return vstyle.case_items_alignment; }}},
       {NodeEnum::kCaseInsideItemList,
        {kCaseItemAligner,
         [](const FormatStyle& vstyle) { return vstyle.case_items_alignment; }}},
+      {NodeEnum::kGenerateCaseItemList,
+       {kCaseItemAligner,
+        [](const FormatStyle& vstyle) { return vstyle.case_items_alignment; }}},
   };
   const auto handler_iter = kAlignHandlers->find(NodeEnum(node->Tag().tag));
   if (handler_iter == kAlignHandlers->end()) return;
diff --git a/verilog/formatting/formatter_test.cc b/verilog/formatting/formatter_test.cc
index f5f7c3e..5fa3a9f 100644
--- a/verilog/formatting/formatter_test.cc
+++ b/verilog/formatting/formatter_test.cc
@@ -3810,6 +3810,16 @@
      "    d: ee f;\n"
      "  endcase\n"
      "endmodule\n"},
+    {// conditional generate (case), with comments
+     "module mc; case(s)\n//comment a\na:bb  c;\n//comment b\n endcase "
+     "endmodule",
+     "module mc;\n"
+     "  case (s)\n"
+     "    //comment a\n"  // indented to case-item level
+     "    a: bb c;\n"
+     "    //comment b\n"  // indented to case-item level
+     "  endcase\n"
+     "endmodule\n"},
 
     {// "default:", not "default :"
      "function f; case (x) default: x=y; endcase endfunction\n",
@@ -7317,6 +7327,43 @@
        "    [4 : 999999]: yy = zz;\n"
        "  endcase\n"
        "endfunction\n"},
+      {// case-generate: align would add few spaces, so align
+       "module mc ; case (x)kZ  : gg h(); kXYY :j kk();"
+       "endcase endmodule\n",
+       "module mc;\n"
+       "  case (x)\n"
+       "    kZ:   gg h ();\n"  // align
+       "    kXYY: j kk ();\n"
+       "  endcase\n"
+       "endmodule\n"},
+      {// case-generate + comment: align would add few spaces, so align
+       "module mc ; case (x)kZ  : gg h(); \n//c1\n kXYY :j kk();"
+       "endcase endmodule\n",
+       "module mc;\n"
+       "  case (x)\n"
+       "    kZ:   gg h ();\n"  // align
+       "    //c1\n"
+       "    kXYY: j kk ();\n"
+       "  endcase\n"
+       "endmodule\n"},
+      {// case-generate: align would add too many space, so flush-left
+       "module mc ; case (x)kZ  : gg h(); kXYYYY :j kk();"
+       "endcase endmodule\n",
+       "module mc;\n"
+       "  case (x)\n"
+       "    kZ: gg h ();\n"  // flush-left
+       "    kXYYYY: j kk ();\n"
+       "  endcase\n"
+       "endmodule\n"},
+      {// case-generate: inject spaces to induce alignment
+       "module mc ; case (x)kZ  : gg h(); kXYYYY :     j kk();"
+       "endcase endmodule\n",
+       "module mc;\n"
+       "  case (x)\n"
+       "    kZ:     gg h ();\n"  // align
+       "    kXYYYY: j kk ();\n"
+       "  endcase\n"
+       "endmodule\n"},
   };
   // Use a fixed style.
   FormatStyle style;
diff --git a/verilog/formatting/tree_unwrapper.cc b/verilog/formatting/tree_unwrapper.cc
index 575521e..6232ff9 100644
--- a/verilog/formatting/tree_unwrapper.cc
+++ b/verilog/formatting/tree_unwrapper.cc
@@ -530,6 +530,7 @@
     case NodeEnum::kBlockItemStatementList:
     case NodeEnum::kCaseItemList:
     case NodeEnum::kCaseInsideItemList:
+    case NodeEnum::kGenerateCaseItemList:
     case NodeEnum::kConstraintExpressionList:
     case NodeEnum::kConstraintBlockItemList:
       LookAheadBeyondCurrentNode();
@@ -947,7 +948,6 @@
     case NodeEnum::kInterfaceClassDeclaration:
     case NodeEnum::kGenerateItemList:
     case NodeEnum::kCasePatternItemList:
-    case NodeEnum::kGenerateCaseItemList:
     case NodeEnum::kStructUnionMemberList:
     case NodeEnum::kEnumNameList:
     case NodeEnum::kConstraintBlockItemList:
@@ -1006,6 +1006,7 @@
 
     case NodeEnum::kCaseItemList:
     case NodeEnum::kCaseInsideItemList:
+    case NodeEnum::kGenerateCaseItemList:
     case NodeEnum::kClassItems:
     case NodeEnum::kModuleItemList: {
       const int indent = suppress_indentation ? 0 : style_.indentation_spaces;
diff --git a/verilog/formatting/tree_unwrapper_test.cc b/verilog/formatting/tree_unwrapper_test.cc
index 9f33cc2..778258a 100644
--- a/verilog/formatting/tree_unwrapper_test.cc
+++ b/verilog/formatting/tree_unwrapper_test.cc
@@ -1950,6 +1950,28 @@
     },
 
     {
+        "module with case generate statements, and comments",
+        "module multi_cases;\n"
+        "case (foo)//c1\n"
+        "//c2\n"
+        "  A: a aa;//c3\n"
+        "//c4\n"
+        "endcase\n"
+        "endmodule",
+        ModuleDeclaration(
+            0, L(0, {"module", "multi_cases", ";"}),
+            FlowControl(1, L(1, {"case", "(", "foo", ")", "//c1"}),
+                        N(2,                      //
+                          L(2, {"//c2"}),         //
+                          N(2, L(2, {"A", ":"}),  //
+                            L(2, {"a", "aa", ";", "//c3"})),
+                          L(2, {"//c4"})  //
+                          ),
+                        L(1, {"endcase"})),
+            L(0, {"endmodule"})),
+    },
+
+    {
         "module with case generate block statements",
         "module case_block;\n"
         "case (foo)\n"