Merge pull request #2595 from wsnyder/bug2571_typedef_space
Add --class_parameter_space (#2571)
diff --git a/verible/verilog/formatting/format-style-init.cc b/verible/verilog/formatting/format-style-init.cc
index 2dde818..a6d010b 100644
--- a/verible/verilog/formatting/format-style-init.cc
+++ b/verible/verilog/formatting/format-style-init.cc
@@ -140,6 +140,13 @@
"Use compact binary expressions inside indexing / bit selection "
"operators");
+ABSL_FLAG(bool, class_parameter_space, false,
+ "If true, keep/insert a space before '#' in a class"
+ "parameterized typedef, e.g. \"typedef my_class #(.P(P)) "
+ "my_class_t;\". If false (default), no space is inserted, "
+ "matching the convention used for IEEE parameterized class "
+ "instantiations, e.g. \"type#(params...)::method(...)\".");
+
ABSL_FLAG(bool, wrap_end_else_clauses, false,
"Split end and else keywords into separate lines");
@@ -197,6 +204,7 @@
STYLE_FROM_FLAG(try_wrap_long_lines);
STYLE_FROM_FLAG(expand_coverpoints);
STYLE_FROM_FLAG(compact_indexing_and_selections);
+ STYLE_FROM_FLAG(class_parameter_space);
STYLE_FROM_FLAG(wrap_end_else_clauses);
STYLE_FROM_FLAG(alignment_group_boundary);
diff --git a/verible/verilog/formatting/format-style.h b/verible/verilog/formatting/format-style.h
index 2fad329..55347c5 100644
--- a/verible/verilog/formatting/format-style.h
+++ b/verible/verilog/formatting/format-style.h
@@ -146,6 +146,9 @@
// Compact binary expressions inside indexing / bit selection operators
bool compact_indexing_and_selections = true;
+ // Keep/insert a space before '#' in a parameterized class typedef
+ bool class_parameter_space = false;
+
// Split with a \n end and else clauses
bool wrap_end_else_clauses = false;
diff --git a/verible/verilog/formatting/formatter_test.cc b/verible/verilog/formatting/formatter_test.cc
index 55c9509..c9b1579 100644
--- a/verible/verilog/formatting/formatter_test.cc
+++ b/verible/verilog/formatting/formatter_test.cc
@@ -4478,19 +4478,30 @@
" .L(L),\n"
" .W(W)\n"
") bar_t;\n"},
- // unqualified parameterized type keeps a space before '#'
+ // By default (class_parameter_space == false), no space before '#'
{"typedef dv_base_env_cov #(.CFG_T(tl_agent_env_cfg)) tl_agent_env_cov;\n",
- "typedef dv_base_env_cov #(\n"
+ "typedef dv_base_env_cov#(\n"
" .CFG_T(tl_agent_env_cfg)\n"
") tl_agent_env_cov;\n"},
- // ... and is inserted when absent
{"typedef dv_base_env_cov#(.CFG_T(tl_agent_env_cfg)) tl_agent_env_cov;\n",
- "typedef dv_base_env_cov #(\n"
+ "typedef dv_base_env_cov#(\n"
" .CFG_T(tl_agent_env_cfg)\n"
") tl_agent_env_cov;\n"},
// single short parameter stays on one line
{"typedef my_class #(.P(P)) my_class_t;\n",
- "typedef my_class #(.P(P)) my_class_t;\n"},
+ "typedef my_class#(.P(P)) my_class_t;\n"},
+
+ // let declarations each stay on their own line
+ {"module t;\n"
+ "let OFF = 4;\n"
+ "let UNIQUE = 32;\n"
+ "let PP(a) = 30 + a;\n"
+ "endmodule\n",
+ "module t;\n"
+ " let OFF = 4;\n"
+ " let UNIQUE = 32;\n"
+ " let PP(a) = 30 + a;\n"
+ "endmodule\n"},
// let declarations each stay on their own line
{"module t;\n"
@@ -18800,6 +18811,50 @@
}
}
+static constexpr FormatterTestCase
+ kSpaceBeforeHashInUnqualifiedTypedefTestCases[] = {
+ // unqualified parameterized type keeps a space before '#'
+ {"typedef dv_base_env_cov #(.CFG_T(tl_agent_env_cfg)) "
+ "tl_agent_env_cov;\n",
+ "typedef dv_base_env_cov #(\n"
+ " .CFG_T(tl_agent_env_cfg)\n"
+ ") tl_agent_env_cov;\n"},
+ // ... and is inserted when absent
+ {"typedef dv_base_env_cov#(.CFG_T(tl_agent_env_cfg)) "
+ "tl_agent_env_cov;\n",
+ "typedef dv_base_env_cov #(\n"
+ " .CFG_T(tl_agent_env_cfg)\n"
+ ") tl_agent_env_cov;\n"},
+ // single short parameter stays on one line
+ {"typedef my_class #(.P(P)) my_class_t;\n",
+ "typedef my_class #(.P(P)) my_class_t;\n"},
+ // package-qualified types are unaffected (no space before '#')
+ {"typedef foo_pkg::baz_t#(.L(L), .W(W)) bar_t;\n",
+ "typedef foo_pkg::baz_t#(\n"
+ " .L(L),\n"
+ " .W(W)\n"
+ ") bar_t;\n"},
+};
+
+TEST(FormatterEndToEndTest, SpaceBeforeHashInUnqualifiedTypedefTestCases) {
+ // Use a fixed style.
+ FormatStyle style;
+ style.column_limit = 40;
+ style.indentation_spaces = 2;
+ style.wrap_spaces = 4;
+ style.class_parameter_space = true;
+
+ for (const auto &test_case : kSpaceBeforeHashInUnqualifiedTypedefTestCases) {
+ VLOG(1) << "code-to-format:\n" << test_case.input << "<EOF>";
+ std::ostringstream stream;
+ const auto status =
+ FormatVerilog(test_case.input, "<filename>", style, stream);
+ // Require these test cases to be valid.
+ EXPECT_OK(status) << status.message();
+ EXPECT_EQ(stream.str(), test_case.expected) << "code:\n" << test_case.input;
+ }
+}
+
static constexpr FormatterTestCase kFunctionCallsWithComments[] = {
{// no comments
"module foo;\n"
diff --git a/verible/verilog/formatting/token-annotator.cc b/verible/verilog/formatting/token-annotator.cc
index def1349..ebaeb21 100644
--- a/verible/verilog/formatting/token-annotator.cc
+++ b/verible/verilog/formatting/token-annotator.cc
@@ -510,7 +510,8 @@
// This may be controversial or context-dependent, as parameterized
// classes often appear with method calls like:
// type#(params...)::method(...);
- // A parameterized type in a typedef keeps the space before '#':
+ // If style.class_parameter_space is enabled, a
+ // parameterized type in a typedef keeps the space before '#':
// typedef my_class #(.P(P)) my_class_t;
// but a package-qualified type does not, matching the existing
// "type#(params...)::method(...)" convention:
@@ -518,6 +519,7 @@
// Kept as separate IsInsideFirst() calls because MatchesTagAnyOf()
// only unrolls up to four tags.
const bool inside_unqualified_typedef =
+ style.class_parameter_space &&
left_context.IsInsideFirst({NodeEnum::kTypeDeclaration}, {}) &&
!left_context.IsInsideFirst({NodeEnum::kQualifiedId}, {});
diff --git a/verible/verilog/tools/formatter/README.md b/verible/verilog/tools/formatter/README.md
index 01b2869..a3ffb45 100644
--- a/verible/verilog/tools/formatter/README.md
+++ b/verible/verilog/tools/formatter/README.md
@@ -42,6 +42,11 @@
{align,flush-left,preserve,infer}); default: infer;
--class_member_variable_alignment (Format class member variables:
{align,flush-left,preserve,infer}); default: infer;
+ --class_parameter_space (If true, keep/insert a space
+ before '#' in a class parameterized typedef, e.g. "typedef
+ my_class #(.P(P)) my_class_t;". If false (default), no space is
+ inserted, matching the IEEE convention used for parameterized class
+ instantiations, e.g. "type#(params...)::method(...)".); default: false;
--compact_indexing_and_selections (Use compact binary expressions inside
indexing / bit selection operators); default: true;
--distribution_items_alignment (Align distribution items: