diff --git a/verilog/analysis/checkers/always_comb_blocking_rule.cc b/verilog/analysis/checkers/always_comb_blocking_rule.cc index 048da2b82..b1383188c 100644 --- a/verilog/analysis/checkers/always_comb_blocking_rule.cc +++ b/verilog/analysis/checkers/always_comb_blocking_rule.cc @@ -1,4 +1,4 @@ -// Copyright 2017-2020 The Verible Authors. +// Copyright 2017-2023 The Verible Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -33,6 +33,7 @@ namespace verilog { namespace analysis { +using verible::AutoFix; using verible::down_cast; using verible::LintRuleStatus; using verible::LintViolation; @@ -46,7 +47,7 @@ VERILOG_REGISTER_LINT_RULE(AlwaysCombBlockingRule); static constexpr absl::string_view kMessage = "Use only blocking assignments in \'always_comb\' combinational blocks."; -const LintRuleDescriptor& AlwaysCombBlockingRule::GetDescriptor() { +const LintRuleDescriptor &AlwaysCombBlockingRule::GetDescriptor() { static const LintRuleDescriptor d{ .name = "always-comb-blocking", .topic = "combinational-logic", @@ -58,27 +59,32 @@ const LintRuleDescriptor& AlwaysCombBlockingRule::GetDescriptor() { } // Matches always_comb blocks. -static const Matcher& AlwaysCombMatcher() { +static const Matcher &AlwaysCombMatcher() { static const Matcher matcher(NodekAlwaysStatement(AlwaysCombKeyword())); return matcher; } -void AlwaysCombBlockingRule::HandleSymbol(const verible::Symbol& symbol, - const SyntaxTreeContext& context) { +void AlwaysCombBlockingRule::HandleSymbol(const verible::Symbol &symbol, + const SyntaxTreeContext &context) { verible::matcher::BoundSymbolManager manager; if (AlwaysCombMatcher().Matches(symbol, &manager)) { - for (const auto& match : + for (const auto &match : SearchSyntaxTree(symbol, NodekNonblockingAssignmentStatement())) { if (match.match->Kind() != verible::SymbolKind::kNode) continue; - const auto* node = down_cast(match.match); + const auto *node = + down_cast(match.match); - const verible::SyntaxTreeLeaf* leaf = verible::GetSubtreeAsLeaf( + const verible::SyntaxTreeLeaf *leaf = verible::GetSubtreeAsLeaf( *node, NodeEnum::kNonblockingAssignmentStatement, 1); if (leaf && leaf->get().token_enum() == TK_LE) { - violations_.insert(LintViolation(*leaf, kMessage, match.context)); + violations_.insert( + LintViolation(*leaf, kMessage, match.context, + {AutoFix("Use blocking assignment '=' instead of " + "nonblocking assignment '<='", + {leaf->get(), "="})})); } } } diff --git a/verilog/analysis/checkers/always_comb_blocking_rule_test.cc b/verilog/analysis/checkers/always_comb_blocking_rule_test.cc index 76a20d0fd..b1276476d 100644 --- a/verilog/analysis/checkers/always_comb_blocking_rule_test.cc +++ b/verilog/analysis/checkers/always_comb_blocking_rule_test.cc @@ -1,4 +1,4 @@ -// Copyright 2017-2020 The Verible Authors. +// Copyright 2017-2023 The Verible Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ namespace analysis { namespace { using verible::LintTestCase; +using verible::RunApplyFixCases; using verible::RunLintTestCases; TEST(AlwaysCombBlockingRule, FunctionFailures) { @@ -62,6 +63,25 @@ TEST(AlwaysCombBlockingRule, FunctionFailures) { kAlwaysCombBlockingTestCases); } +TEST(AlwaysCombBlockingTest, AutoFixAlwaysCombBlocking) { + const std::initializer_list kTestCases = { + {"module m;\nalways_comb a <= b;\nendmodule", + "module m;\nalways_comb a = b;\nendmodule"}, + {"module m;\nalways_comb begin a <= b; end\nendmodule", + "module m;\nalways_comb begin a = b; end\nendmodule"}, + {"module m;\nalways_comb begin if (sel == 0) a <= b; else a = 1'b0; " + "end\nendmodule", + "module m;\nalways_comb begin if (sel == 0) a = b; else a = 1'b0; " + "end\nendmodule"}, + {"module m;\nalways_comb begin\n`ifdef RST\nf <= g;\n`else\nf = " + "1'b1;\n`endif\nend\nendmodule", + "module m;\nalways_comb begin\n`ifdef RST\nf = g;\n`else\nf = " + "1'b1;\n`endif\nend\nendmodule"}, + }; + + RunApplyFixCases(kTestCases, ""); +} + } // namespace } // namespace analysis } // namespace verilog