Merge pull request #1575 from antmicro/msrs/fix-kdpiexportitem

Add a size check before merging leaves in kDPIImportItem/kDPIExportItem
diff --git a/WORKSPACE b/WORKSPACE
index 8cea500..dcbc98d 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -126,10 +126,10 @@
 # A version slightly beyond 21.5 as it fixes a warning
 http_archive(
     name = "com_google_protobuf",
-    sha256 = "efcd93bb1a228d08b4b0fcda00e710592fdf17ce6d0f5c8a239c2db0ba268a3f",
-    strip_prefix = "protobuf-4efbcc44605731dc31507b94f0b81d2bd5ec169b",
+    sha256 = "6a31b662deaeb0ac35e6287bda2f3369b19836e6c9f8828d4da444346f420298",
+    strip_prefix = "protobuf-21.12",
     urls = [
-        "https://github.com/protocolbuffers/protobuf/archive/4efbcc44605731dc31507b94f0b81d2bd5ec169b.zip",
+        "https://github.com/protocolbuffers/protobuf/archive/refs/tags/v21.12.zip",
     ],
 )
 
diff --git a/verilog/CST/port.cc b/verilog/CST/port.cc
index a968523..eed3ea9 100644
--- a/verilog/CST/port.cc
+++ b/verilog/CST/port.cc
@@ -32,7 +32,7 @@
 using verible::Symbol;
 using verible::SyntaxTreeLeaf;
 
-std::vector<verible::TreeSearchMatch> FindAllModulePortDeclarations(
+std::vector<verible::TreeSearchMatch> FindAllPortDeclarations(
     const Symbol& root) {
   return SearchSyntaxTree(root, NodekPortDeclaration());
 }
@@ -52,16 +52,14 @@
   return SearchSyntaxTree(root, NodekPortItem());
 }
 
-const SyntaxTreeLeaf* GetIdentifierFromModulePortDeclaration(
-    const Symbol& symbol) {
+const SyntaxTreeLeaf* GetIdentifierFromPortDeclaration(const Symbol& symbol) {
   const auto* identifier_symbol =
       verible::GetSubtreeAsSymbol(symbol, NodeEnum::kPortDeclaration, 3);
   if (!identifier_symbol) return nullptr;
   return AutoUnwrapIdentifier(*identifier_symbol);
 }
 
-const SyntaxTreeLeaf* GetDirectionFromModulePortDeclaration(
-    const Symbol& symbol) {
+const SyntaxTreeLeaf* GetDirectionFromPortDeclaration(const Symbol& symbol) {
   if (const auto* dir_symbol =
           GetSubtreeAsSymbol(symbol, NodeEnum::kPortDeclaration, 0)) {
     return &SymbolCastToLeaf(*dir_symbol);
@@ -69,6 +67,35 @@
   return nullptr;
 }
 
+std::vector<verible::TreeSearchMatch> FindAllModulePortDeclarations(
+    const verible::Symbol& root) {
+  return SearchSyntaxTree(root, NodekModulePortDeclaration());
+}
+
+const verible::SyntaxTreeLeaf* GetIdentifierFromModulePortDeclaration(
+    const verible::Symbol& symbol) {
+  auto& node = SymbolCastToNode(symbol);
+  if (!MatchNodeEnumOrNull(node, NodeEnum::kModulePortDeclaration))
+    return nullptr;
+  auto id_unpacked_dims = FindAllIdentifierUnpackedDimensions(symbol);
+  if (id_unpacked_dims.empty()) return nullptr;
+  if (id_unpacked_dims.size() > 1) {
+    LOG(ERROR) << "Expected one identifier node in port declaration, but got "
+               << id_unpacked_dims.size();
+  }
+  return GetSymbolIdentifierFromIdentifierUnpackedDimensions(
+      *id_unpacked_dims.front().match);
+}
+
+const verible::SyntaxTreeLeaf* GetDirectionFromModulePortDeclaration(
+    const verible::Symbol& symbol) {
+  if (const auto* dir_symbol =
+          GetSubtreeAsSymbol(symbol, NodeEnum::kModulePortDeclaration, 0)) {
+    return &SymbolCastToLeaf(*dir_symbol);
+  }
+  return nullptr;
+}
+
 const verible::SyntaxTreeLeaf* GetIdentifierFromPortReference(
     const verible::Symbol& port_reference) {
   const auto* identifier_symbol =
diff --git a/verilog/CST/port.h b/verilog/CST/port.h
index ef1e3be..7ff13af 100644
--- a/verilog/CST/port.h
+++ b/verilog/CST/port.h
@@ -29,8 +29,8 @@
 
 namespace verilog {
 
-// Find all individual module port declarations.
-std::vector<verible::TreeSearchMatch> FindAllModulePortDeclarations(
+// Find all individual port declarations.
+std::vector<verible::TreeSearchMatch> FindAllPortDeclarations(
     const verible::Symbol&);
 
 // Find all nodes tagged with kPort.
@@ -41,12 +41,24 @@
 std::vector<verible::TreeSearchMatch> FindAllActualNamedPort(
     const verible::Symbol&);
 
-// Extract the name of the module port identifier from a port declaration.
-const verible::SyntaxTreeLeaf* GetIdentifierFromModulePortDeclaration(
+// Extract the name of the port identifier from a port declaration.
+const verible::SyntaxTreeLeaf* GetIdentifierFromPortDeclaration(
     const verible::Symbol&);
 
 // Extract the direction from a port declaration.
 // Can return nullptr if the direction is not explicitly specified.
+const verible::SyntaxTreeLeaf* GetDirectionFromPortDeclaration(
+    const verible::Symbol&);
+
+// Find all individual module port declarations.
+std::vector<verible::TreeSearchMatch> FindAllModulePortDeclarations(
+    const verible::Symbol&);
+
+// Extract the name of the module port identifier from a port declaration.
+const verible::SyntaxTreeLeaf* GetIdentifierFromModulePortDeclaration(
+    const verible::Symbol&);
+
+// Extract the direction from a module port declaration.
 const verible::SyntaxTreeLeaf* GetDirectionFromModulePortDeclaration(
     const verible::Symbol&);
 
diff --git a/verilog/CST/port_test.cc b/verilog/CST/port_test.cc
index 9cb7ab6..b4c9617 100644
--- a/verilog/CST/port_test.cc
+++ b/verilog/CST/port_test.cc
@@ -55,6 +55,135 @@
 using verible::TreeSearchMatch;
 
 // Tests that no ports are found from an empty source.
+TEST(FindAllPortDeclarationsTest, EmptySource) {
+  VerilogAnalyzer analyzer("", "");
+  ASSERT_OK(analyzer.Analyze());
+  const auto& root = analyzer.Data().SyntaxTree();
+  const auto port_declarations =
+      FindAllPortDeclarations(*ABSL_DIE_IF_NULL(root));
+  EXPECT_TRUE(port_declarations.empty());
+}
+
+// Tests that no ports are found in port-less module.
+TEST(FindAllPortDeclarationsTest, NonPort) {
+  VerilogAnalyzer analyzer("module foo; endmodule", "");
+  ASSERT_OK(analyzer.Analyze());
+  const auto& root = analyzer.Data().SyntaxTree();
+  const auto port_declarations =
+      FindAllPortDeclarations(*ABSL_DIE_IF_NULL(root));
+  EXPECT_TRUE(port_declarations.empty());
+}
+
+// Tests that a package-item net declaration is not a port.
+TEST(FindAllPortDeclarationsTest, OneWire) {
+  VerilogAnalyzer analyzer("wire w;", "");
+  ASSERT_OK(analyzer.Analyze());
+  const auto& root = analyzer.Data().SyntaxTree();
+  const auto port_declarations =
+      FindAllPortDeclarations(*ABSL_DIE_IF_NULL(root));
+  EXPECT_TRUE(port_declarations.empty());
+}
+
+// Tests that a local wire inside a module is not a port.
+TEST(FindAllPortDeclarationsTest, OneWireInModule) {
+  VerilogAnalyzer analyzer("module m; wire w; endmodule", "");
+  ASSERT_OK(analyzer.Analyze());
+  const auto& root = analyzer.Data().SyntaxTree();
+  const auto port_declarations =
+      FindAllPortDeclarations(*ABSL_DIE_IF_NULL(root));
+  EXPECT_TRUE(port_declarations.empty());
+}
+
+// Tests that a port wire inside a module is found.
+TEST(FindAllPortDeclarationsTest, OnePortInModule) {
+  const char* kTestCases[] = {
+      "logic l",
+      "wire w",
+      "input w",
+      "input [1:0] w",
+      "input w [0:1]",
+      "input w [6]",
+      "input [7:0] w [6]",
+      "input wire w",
+      "reg r",
+      "output r",
+      "output reg r",
+      "output reg [1:0] r",
+      "output reg r [0:3]",
+      "output reg [1:0] r [0:3]",
+  };
+  for (auto test : kTestCases) {
+    VerilogAnalyzer analyzer(absl::StrCat("module m(", test, "); endmodule"),
+                             "");
+    ASSERT_OK(analyzer.Analyze());
+    const auto& root = analyzer.Data().SyntaxTree();
+    const auto port_declarations =
+        FindAllPortDeclarations(*ABSL_DIE_IF_NULL(root));
+    EXPECT_EQ(port_declarations.size(), 1);
+    const auto& decl = port_declarations.front();
+    EXPECT_TRUE(decl.context.IsInside(NodeEnum::kModuleDeclaration));
+  }
+}
+
+TEST(GetIdentifierFromPortDeclarationTest, VariousPorts) {
+  constexpr int kTag = 1;  // don't care
+  const SyntaxTreeSearchTestCase kTestCases[] = {
+      {"module foo(input ", {kTag, "bar"}, "); endmodule"},
+      {"module foo(input logic ", {kTag, "b_a_r"}, "); endmodule"},
+      {"module foo(input wire ", {kTag, "hello_world"}, " = 1); endmodule"},
+      {"module foo(wire ", {kTag, "hello_world1"}, " = 1); endmodule"},
+      {"module foo(input logic [3:0] ", {kTag, "bar2"}, "); endmodule"},
+      {"module foo(input logic ", {kTag, "b_a_r"}, " [3:0]); endmodule"},
+      {"module foo(input logic ", {kTag, "bar"}, " [4]); endmodule"},
+      // multiple ports
+      {"module foo(input ",
+       {kTag, "bar"},
+       ", output ",
+       {kTag, "bar2"},
+       "); endmodule"},
+      {"module foo(input logic ",
+       {kTag, "bar"},
+       ", input wire ",
+       {kTag, "bar2"},
+       "); endmodule"},
+      {"module foo(input logic ",
+       {kTag, "bar"},
+       ", output ",
+       {kTag, "bar2"},
+       "); endmodule"},
+      {"module foo(wire ",
+       {kTag, "bar"},
+       ", wire ",
+       {kTag, "bar2"},
+       " = 1); endmodule"},
+      {"module foo(input logic [3:0] ",
+       {kTag, "bar"},
+       ", input logic ",
+       {kTag, "bar2"},
+       " [4]); endmodule"},
+      {"module foo(input logic ",
+       {kTag, "bar"},
+       " [3:0], input logic [3:0] ",
+       {kTag, "bar2"},
+       "); endmodule"},
+  };
+  for (const auto& test : kTestCases) {
+    TestVerilogSyntaxRangeMatches(
+        __FUNCTION__, test, [](const TextStructureView& text_structure) {
+          const auto& root = text_structure.SyntaxTree();
+          const auto port_declarations = FindAllPortDeclarations(*root);
+          std::vector<TreeSearchMatch> ids;
+          for (const auto& port : port_declarations) {
+            const auto* identifier_leaf =
+                GetIdentifierFromPortDeclaration(*port.match);
+            ids.push_back(TreeSearchMatch{identifier_leaf, /* no context */});
+          }
+          return ids;
+        });
+  }
+}
+
+// Tests that no ports are found from an empty source.
 TEST(FindAllModulePortDeclarationsTest, EmptySource) {
   VerilogAnalyzer analyzer("", "");
   ASSERT_OK(analyzer.Analyze());
@@ -97,23 +226,12 @@
 // Tests that a port wire inside a module is found.
 TEST(FindAllModulePortDeclarationsTest, OnePortInModule) {
   const char* kTestCases[] = {
-      "logic l",
-      "wire w",
-      "input w",
-      "input [1:0] w",
-      "input w [0:1]",
-      "input w [6]",
-      "input [7:0] w [6]",
-      "input wire w",
-      "reg r",
-      "output r",
-      "output reg r",
-      "output reg [1:0] r",
-      "output reg r [0:3]",
-      "output reg [1:0] r [0:3]",
+      "input p",     "input [1:0] p",     "input p [0:1]",
+      "input p [6]", "input [7:0] p [6]", "input wire p",
+      "output p",    "output reg p",      "output reg [1:0] p",
   };
   for (auto test : kTestCases) {
-    VerilogAnalyzer analyzer(absl::StrCat("module m(", test, "); endmodule"),
+    VerilogAnalyzer analyzer(absl::StrCat("module m(p); ", test, "; endmodule"),
                              "");
     ASSERT_OK(analyzer.Analyze());
     const auto& root = analyzer.Data().SyntaxTree();
@@ -128,44 +246,37 @@
 TEST(GetIdentifierFromModulePortDeclarationTest, VariousPorts) {
   constexpr int kTag = 1;  // don't care
   const SyntaxTreeSearchTestCase kTestCases[] = {
-      {"module foo(input ", {kTag, "bar"}, "); endmodule"},
-      {"module foo(input logic ", {kTag, "b_a_r"}, "); endmodule"},
-      {"module foo(input wire ", {kTag, "hello_world"}, " = 1); endmodule"},
-      {"module foo(wire ", {kTag, "hello_world1"}, " = 1); endmodule"},
-      {"module foo(input logic [3:0] ", {kTag, "bar2"}, "); endmodule"},
-      {"module foo(input logic ", {kTag, "b_a_r"}, " [3:0]); endmodule"},
-      {"module foo(input logic ", {kTag, "bar"}, " [4]); endmodule"},
+      {"module foo(bar); input ", {kTag, "bar"}, "; endmodule"},
+      {"module foo(b_a_r); input logic ", {kTag, "b_a_r"}, "; endmodule"},
+      {"module foo(bar2); input logic [3:0] ", {kTag, "bar2"}, "; endmodule"},
+      {"module foo(b_a_r); input logic ", {kTag, "b_a_r"}, " [3:0]; endmodule"},
+      {"module foo(bar); input logic ", {kTag, "bar"}, " [4]; endmodule"},
       // multiple ports
-      {"module foo(input ",
+      {"module foo(bar, bar2); input ",
        {kTag, "bar"},
-       ", output ",
+       "; output ",
        {kTag, "bar2"},
-       "); endmodule"},
-      {"module foo(input logic ",
+       "; endmodule"},
+      {"module foo(bar, bar2); input logic ",
        {kTag, "bar"},
-       ", input wire ",
+       "; input wire ",
        {kTag, "bar2"},
-       "); endmodule"},
-      {"module foo(input logic ",
+       "; endmodule"},
+      {"module foo(bar, bar2); input logic ",
        {kTag, "bar"},
-       ", output ",
+       "; output ",
        {kTag, "bar2"},
-       "); endmodule"},
-      {"module foo(wire ",
+       "; endmodule"},
+      {"module foo(bar, bar2); input logic [3:0] ",
        {kTag, "bar"},
-       ", wire ",
+       "; input logic ",
        {kTag, "bar2"},
-       " = 1); endmodule"},
-      {"module foo(input logic [3:0] ",
+       " [4]; endmodule"},
+      {"module foo(bar, bar2); input logic ",
        {kTag, "bar"},
-       ", input logic ",
+       " [3:0]; input logic [3:0] ",
        {kTag, "bar2"},
-       " [4]); endmodule"},
-      {"module foo(input logic ",
-       {kTag, "bar"},
-       " [3:0], input logic [3:0] ",
-       {kTag, "bar2"},
-       "); endmodule"},
+       "; endmodule"},
   };
   for (const auto& test : kTestCases) {
     TestVerilogSyntaxRangeMatches(
@@ -422,13 +533,12 @@
     TestVerilogSyntaxRangeMatches(
         __FUNCTION__, test, [](const TextStructureView& text_structure) {
           const auto& root = text_structure.SyntaxTree();
-          const auto& ports =
-              FindAllModulePortDeclarations(*ABSL_DIE_IF_NULL(root));
+          const auto& ports = FindAllPortDeclarations(*ABSL_DIE_IF_NULL(root));
 
           std::vector<TreeSearchMatch> directions;
           for (const auto& port : ports) {
             const auto* direction =
-                GetDirectionFromModulePortDeclaration(*port.match);
+                GetDirectionFromPortDeclaration(*port.match);
             directions.emplace_back(
                 TreeSearchMatch{(const verible::Symbol*)direction, {}});
           }
diff --git a/verilog/analysis/checkers/port_name_suffix_rule.cc b/verilog/analysis/checkers/port_name_suffix_rule.cc
index 242c6e1..eb946e0 100644
--- a/verilog/analysis/checkers/port_name_suffix_rule.cc
+++ b/verilog/analysis/checkers/port_name_suffix_rule.cc
@@ -103,9 +103,8 @@
   constexpr absl::string_view implicit_direction = "input";
   verible::matcher::BoundSymbolManager manager;
   if (PortMatcher().Matches(symbol, &manager)) {
-    const auto* identifier_leaf =
-        GetIdentifierFromModulePortDeclaration(symbol);
-    const auto* direction_leaf = GetDirectionFromModulePortDeclaration(symbol);
+    const auto* identifier_leaf = GetIdentifierFromPortDeclaration(symbol);
+    const auto* direction_leaf = GetDirectionFromPortDeclaration(symbol);
     const auto token = identifier_leaf->get();
     const auto direction =
         direction_leaf ? direction_leaf->get().text() : implicit_direction;
diff --git a/verilog/analysis/checkers/signal_name_style_rule.cc b/verilog/analysis/checkers/signal_name_style_rule.cc
index 04e5b48..2bb57d5 100644
--- a/verilog/analysis/checkers/signal_name_style_rule.cc
+++ b/verilog/analysis/checkers/signal_name_style_rule.cc
@@ -79,8 +79,7 @@
                                        const SyntaxTreeContext& context) {
   verible::matcher::BoundSymbolManager manager;
   if (PortMatcher().Matches(symbol, &manager)) {
-    const auto* identifier_leaf =
-        GetIdentifierFromModulePortDeclaration(symbol);
+    const auto* identifier_leaf = GetIdentifierFromPortDeclaration(symbol);
     const auto name = ABSL_DIE_IF_NULL(identifier_leaf)->get().text();
     if (!verible::IsLowerSnakeCaseWithDigits(name))
       violations_.insert(
diff --git a/verilog/formatting/formatter_test.cc b/verilog/formatting/formatter_test.cc
index 3898644..bf0d06b 100644
--- a/verilog/formatting/formatter_test.cc
+++ b/verilog/formatting/formatter_test.cc
@@ -5518,6 +5518,43 @@
      "  );\n"
      "endmodule\n"},
 
+    {// comment following a delay in next line
+     "module t;\n"
+     "reg x;\n"
+     "initial begin\n"
+     "#20\n"
+     "//comment\n"
+     "x = 1;\n"
+     "x = 2;\n"
+     "end\n"
+     "endmodule\n",
+     "module t;\n"
+     "  reg x;\n"
+     "  initial begin\n"
+     "    #20\n"
+     "    //comment\n"
+     "    x = 1;\n"
+     "    x = 2;\n"
+     "  end\n"
+     "endmodule\n"},
+    {// comment following a delay in the same line
+     "module t;\n"
+     "reg x;\n"
+     "initial begin\n"
+     "#20 //comment\n"
+     "x = 1;\n"
+     "x = 2;\n"
+     "end\n"
+     "endmodule\n",
+     "module t;\n"
+     "  reg x;\n"
+     "  initial begin\n"
+     "    #20  //comment\n"
+     "    x = 1;\n"
+     "    x = 2;\n"
+     "  end\n"
+     "endmodule\n"},
+
     {
         // test that alternate top-syntax mode works
         "// verilog_syntax: parse-as-module-body\n"
diff --git a/verilog/formatting/tree_unwrapper.cc b/verilog/formatting/tree_unwrapper.cc
index a2b1f1e..d353806 100644
--- a/verilog/formatting/tree_unwrapper.cc
+++ b/verilog/formatting/tree_unwrapper.cc
@@ -971,9 +971,11 @@
     {
       // Single statements directly inside a flow-control construct
       // should be properly indented one level.
-      const int indent = ShouldIndentRelativeToDirectParent(Context())
-                             ? style_.indentation_spaces
-                             : 0;
+      const int indent = Context().IsInside(NodeEnum::kBlockItemStatementList)
+                             ? 0
+                             : ShouldIndentRelativeToDirectParent(Context())
+                                   ? style_.indentation_spaces
+                                   : 0;
       VisitIndentedSection(node, indent,
                            PartitionPolicyEnum::kFitOnLineElseExpand);
       break;
@@ -2876,7 +2878,8 @@
       // RHS may have been further partitioned, e.g. a macro call.
       auto& children = partition.Children();
       if (children.size() == 2 &&
-          verible::is_leaf(children.front()) /* left side */) {
+          verible::is_leaf(children.front()) /* left side */ &&
+          !PartitionIsForcedIntoNewLine(children.back())) {
         verible::MergeLeafIntoNextLeaf(&children.front());
         VLOG(4) << "after merge leaf (left-into-right):\n" << partition;
       }
diff --git a/verilog/tools/kythe/indexing_facts_tree_extractor.cc b/verilog/tools/kythe/indexing_facts_tree_extractor.cc
index d325fd7..9dfb647 100644
--- a/verilog/tools/kythe/indexing_facts_tree_extractor.cc
+++ b/verilog/tools/kythe/indexing_facts_tree_extractor.cc
@@ -753,7 +753,7 @@
   // module m(input a, input b);
   if (tag == NodeEnum::kPortDeclaration) {
     const SyntaxTreeLeaf* leaf =
-        GetIdentifierFromModulePortDeclaration(module_port_node);
+        GetIdentifierFromPortDeclaration(module_port_node);
     if (!leaf) return;
 
     facts_tree_context_.top().Children().emplace_back(