| // Copyright 2017-2020 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. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "verilog/CST/verilog_matchers.h" |
| |
| #include "gtest/gtest.h" |
| #include "common/analysis/matcher/core_matchers.h" |
| #include "common/analysis/matcher/matcher.h" |
| #include "common/analysis/matcher/matcher_builders.h" |
| #include "common/analysis/matcher/matcher_test_utils.h" |
| #include "verilog/CST/verilog_treebuilder_utils.h" |
| #include "verilog/analysis/verilog_analyzer.h" |
| |
| namespace verilog { |
| namespace { |
| |
| // Tests for SystemTFIdentifierLeaf matching |
| TEST(VerilogMatchers, SystemTFIdentifierLeafTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {SystemTFIdentifierLeaf(), EmbedInClassMethod("$psprintf(\"foo\");"), 1}, |
| {SystemTFIdentifierLeaf(), EmbedInClassMethod("psprintf(\"foo\");"), 0}, |
| {SystemTFIdentifierLeaf(), EmbedInClass(""), 0}, |
| {SystemTFIdentifierLeaf(), "", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for MacroCallIdLeaf matching |
| TEST(VerilogMatchers, MacroCallIdLeafTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {MacroCallIdLeaf(), "", 0}, |
| {MacroCallIdLeaf(), EmbedInClass(""), 0}, |
| {MacroCallIdLeaf(), EmbedInClassMethod("`uvm_foo"), 0}, // not a call |
| {MacroCallIdLeaf(), "`uvm_foo(\"foo\");", 1}, |
| {MacroCallIdLeaf(), "`uvm_foo(\"foo\")\n", 1}, |
| {MacroCallIdLeaf(), EmbedInClassMethod("`uvm_foo(\"foo\");"), 1}, |
| {MacroCallIdLeaf(), EmbedInClassMethod("`uvm_foo(\"foo\")\n"), 1}, |
| {MacroCallIdLeaf(), EmbedInClassMethod("uvm_foo(\"foo\");"), 0}, |
| {MacroCallIdLeaf(), EmbedInClassMethod("$uvm_foo(\"foo\");"), 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for NodekVoidcast matching |
| TEST(VerilogMatchers, VoidCastNodeTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {NodekVoidcast(), EmbedInClassMethod("void'(bad());"), 1}, |
| {NodekVoidcast(), EmbedInClassMethod("rar(bad());"), 0}, |
| {NodekVoidcast(), EmbedInClass(""), 0}, |
| {NodekVoidcast(), "", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for NodekExpression matching |
| TEST(VerilogMatchers, ExpressionNodeTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {NodekExpression(), EmbedInClassMethod("x = 1;"), 1}, |
| {NodekExpression(), EmbedInClassMethod("foo();"), 0}, |
| {NodekExpression(), EmbedInClass(""), 0}, |
| {NodekExpression(), "", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for ExpressionHasFunctionCall matching |
| TEST(VerilogMatchers, ExpressionHasFunctionCallTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {ExpressionHasFunctionCall(), EmbedInClassMethod("foo();"), 1}, |
| {ExpressionHasFunctionCall(), EmbedInClassMethod("x = foo();"), 1}, |
| {ExpressionHasFunctionCall(), EmbedInClassMethod("foo(bar);"), 1}, |
| {ExpressionHasFunctionCall(), EmbedInClassMethod("foo(bar, baz);"), 1}, |
| {ExpressionHasFunctionCall(), EmbedInClassMethod("x = foo;"), 0}, |
| {ExpressionHasFunctionCall(), EmbedInClass(""), 0}, |
| {ExpressionHasFunctionCall(), "", 0}, |
| // Qualified Id function call: |
| {ExpressionHasFunctionCall(), EmbedInClassMethod("bar::foo();"), 1}, |
| {ExpressionHasFunctionCall(), EmbedInClassMethod("x = bar::foo();"), 1}, |
| // This is a method call, different from a function call: |
| {ExpressionHasFunctionCall(), EmbedInClassMethod("bar.foo();"), 0}, |
| {ExpressionHasFunctionCall(), EmbedInClassMethod("x = bar.foo();"), 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for ExpressionHasRandomizeCallExtension matching |
| TEST(VerilogMatchers, ExpressionHasRandomizeCallExtensionTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {ExpressionHasRandomizeCallExtension(), |
| EmbedInClassMethod("foo().randomize();"), 1}, |
| {ExpressionHasRandomizeCallExtension(), EmbedInClassMethod("foo;"), 0}, |
| {ExpressionHasRandomizeCallExtension(), |
| EmbedInClassMethod("randomize();"), 0}, |
| {ExpressionHasRandomizeCallExtension(), EmbedInClass(""), 0}, |
| {ExpressionHasRandomizeCallExtension(), "", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for ExpressionHasRandomizeFunction matching |
| TEST(VerilogMatchers, ExpressionHasRandomizeFunctionTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {ExpressionHasRandomizeFunction(), EmbedInClassMethod("randomize();"), 1}, |
| {ExpressionHasRandomizeFunction(), EmbedInClassMethod("foo.randomize();"), |
| 0}, |
| {ExpressionHasRandomizeFunction(), EmbedInClass(""), 0}, |
| {ExpressionHasRandomizeFunction(), "", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for FunctionCallHasId matching |
| TEST(VerilogMatchers, FunctionCallHasIdTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {FunctionCallHasId(), EmbedInClassMethod("foo();"), 1}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for NumberHasConstantWidth matching |
| TEST(VerilogMatchers, NumberHasConstantWidthTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {NumberHasConstantWidth(), "", 0}, |
| {NumberHasConstantWidth(), "localparam x = 1'bx;", 1}, |
| {NumberHasConstantWidth(), "localparam x = 2'b 01;", 1}, |
| {NumberHasConstantWidth(), "localparam x = 8'b0000_1111;", 1}, |
| {NumberHasConstantWidth(), "localparam x = `WIDTH'bx;", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for NumberHasBasedLiteral matching |
| TEST(VerilogMatchers, NumberHasBasedLiteralTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {NumberHasBasedLiteral(), "", 0}, |
| {NumberHasBasedLiteral(), "localparam x = 1'0;", 0}, |
| {NumberHasBasedLiteral(), "localparam x = 1'b0;", 1}, |
| {NumberHasBasedLiteral(), "localparam x = 1'B1;", 1}, |
| {NumberHasBasedLiteral(), "localparam x = 4'b 10_10;", 1}, |
| {NumberHasBasedLiteral(), "localparam x = 8'b0000_1111;", 1}, |
| {NumberHasBasedLiteral(), "localparam x = `WIDTH'bx;", 1}, |
| {NumberHasBasedLiteral(), "localparam x = 2'sb0;", 1}, |
| {NumberHasBasedLiteral(), "localparam x = 2'SB1;", 1}, |
| {NumberHasBasedLiteral(), "localparam x = 32'd 2000;", 1}, |
| {NumberHasBasedLiteral(), "localparam x = 32'D 4095;", 1}, |
| {NumberHasBasedLiteral(), "localparam x = 32'o 66666;", 1}, |
| {NumberHasBasedLiteral(), "localparam x = 32'O 777_777;", 1}, |
| {NumberHasBasedLiteral(), "localparam x = 32'h 0000_4321;", 1}, |
| {NumberHasBasedLiteral(), "localparam x = 64'H aaaa_bbbb_cccc_dddd;", 1}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for NumberIsBinary matching |
| TEST(VerilogMatchers, NumberIsBinaryTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {NumberIsBinary(), "", 0}, |
| {NumberIsBinary(), "localparam x = 1'0;", 0}, |
| {NumberIsBinary(), "localparam x = 1'b0;", 1}, |
| {NumberIsBinary(), "localparam x = 1'B1;", 1}, |
| {NumberIsBinary(), "localparam x = 4'b 10_10;", 1}, |
| {NumberIsBinary(), "localparam x = 8'b0000_1111;", 1}, |
| {NumberIsBinary(), "localparam x = `WIDTH'bx;", 1}, |
| {NumberIsBinary(), "localparam x = `WIDTH'b`DIGITS;", 1}, |
| {NumberIsBinary(), "localparam x = 2'sb0;", 1}, |
| {NumberIsBinary(), "localparam x = 2'SB1;", 1}, |
| {NumberIsBinary(), "localparam x = 32'd 2000;", 0}, |
| {NumberIsBinary(), "localparam x = 32'D 4095;", 0}, |
| {NumberIsBinary(), "localparam x = 32'o 66666;", 0}, |
| {NumberIsBinary(), "localparam x = 32'O 777_777;", 0}, |
| {NumberIsBinary(), "localparam x = 32'h 0000_4321;", 0}, |
| {NumberIsBinary(), "localparam x = 64'H aaaa_bbbb_cccc_dddd;", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for NumberHasBInaryDigits matching |
| TEST(VerilogMatchers, NumberHasBinaryDigitsTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {NumberHasBinaryDigits(), "", 0}, |
| {NumberHasBinaryDigits(), "localparam x = 1'0;", 0}, |
| {NumberHasBinaryDigits(), "localparam x = 1'b0;", 1}, |
| {NumberHasBinaryDigits(), "localparam x = 1'B1;", 1}, |
| {NumberHasBinaryDigits(), "localparam x = 4'b 10_10;", 1}, |
| {NumberHasBinaryDigits(), "localparam x = 8'b0000_1111;", 1}, |
| {NumberHasBinaryDigits(), "localparam x = `WIDTH'bx;", 1}, |
| {NumberHasBinaryDigits(), "localparam x = `WIDTH'b`DIGITS;", 0}, |
| {NumberHasBinaryDigits(), "localparam x = 2'sb0;", 1}, |
| {NumberHasBinaryDigits(), "localparam x = 2'SB1;", 1}, |
| {NumberHasBinaryDigits(), "localparam x = 32'd 2000;", 0}, |
| {NumberHasBinaryDigits(), "localparam x = 32'D 4095;", 0}, |
| {NumberHasBinaryDigits(), "localparam x = 32'o 66666;", 0}, |
| {NumberHasBinaryDigits(), "localparam x = 32'O 777_777;", 0}, |
| {NumberHasBinaryDigits(), "localparam x = 32'h 0000_4321;", 0}, |
| {NumberHasBinaryDigits(), "localparam x = 64'H aaaa_bbbb_cccc_dddd;", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for NodekActualParameterList matching |
| TEST(VerilogMatchers, ActualParameterListNodeTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {NodekActualParameterList(), EmbedInModule("foo #(1, 2) bar;"), 1}, |
| {NodekActualParameterList(), |
| EmbedInModule("foo #(.foo(1), .bar(5)) bar;"), 1}, |
| {NodekActualParameterList(), EmbedInModule("foo bar;"), 0}, |
| {NodekActualParameterList(), EmbedInModule(""), 0}, |
| {NodekActualParameterList(), "", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for ActualParameterListHasPositionalParameterList matching |
| TEST(VerilogMatchers, ActualParameterListHasPositionalParameterListTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {ActualParameterListHasPositionalParameterList(), |
| EmbedInModule("foo #(1, 2) bar;"), 1}, |
| {ActualParameterListHasPositionalParameterList(), |
| EmbedInModule("foo #(.foo(1), .bar(5)) bar;"), 0}, |
| {ActualParameterListHasPositionalParameterList(), EmbedInModule(""), 0}, |
| {ActualParameterListHasPositionalParameterList(), "", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for NodekGateInstance matching |
| TEST(VerilogMatchers, GateInstanceNodeTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {NodekGateInstance(), EmbedInModule("foo bar(1, 2);"), 1}, |
| {NodekGateInstance(), EmbedInModule("foo bar;"), 0}, |
| {NodekGateInstance(), EmbedInModule("and a0(a, b, x1);"), 0}, |
| {NodekGateInstance(), EmbedInModule(""), 0}, |
| {NodekGateInstance(), "", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for GateInstanceHasPortList matching |
| TEST(VerilogMatchers, GateInstanceHasPortListTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {GateInstanceHasPortList(), EmbedInModule("foo bar(1, 2);"), 1}, |
| {GateInstanceHasPortList(), EmbedInModule("foo bar;"), 0}, |
| {GateInstanceHasPortList(), EmbedInModule(""), 0}, |
| {GateInstanceHasPortList(), "", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for NodekGenerateBlock matching |
| TEST(VerilogMatchers, GenerateBlockNodeTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {NodekGenerateBlock(), |
| EmbedInModule("generate\n" |
| "if (TypeIsPosedge) begin : gen_posedge\n" |
| " always @(posedge clk) foo <= bar;\n" |
| "end\n" |
| "endgenerate"), |
| 1}, |
| {NodekGenerateBlock(), |
| EmbedInModule("generate\n" |
| "endgenerate"), |
| 0}, |
| {NodekGenerateBlock(), EmbedInModule(""), 0}, |
| {NodekGenerateBlock(), "", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for GenerateRegionNode matching |
| TEST(VerilogMatchers, GenerateRegionNodeTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {NodekGenerateRegion(), |
| EmbedInModule("generate\n" |
| "if (TypeIsPosedge) begin : foobar\n" |
| " foo bar;\n" |
| "end\n" |
| "endgenerate"), |
| 1}, |
| {NodekGenerateRegion(), |
| EmbedInModule("generate\n" |
| "endgenerate"), |
| 1}, |
| {NodekGenerateRegion(), EmbedInModule("wire rats_nest;"), 0}, |
| {NodekGenerateRegion(), EmbedInModule(""), 0}, |
| {NodekGenerateRegion(), "", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for HasBeginLabel matching |
| TEST(VerilogMatchers, HasBeginLabelTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {HasBeginLabel(), |
| EmbedInModule("generate\n" |
| "if (TypeIsPosedge) begin : gen_posedge\n" |
| " always @(posedge clk) foo <= bar;\n" |
| "end\n" |
| "endgenerate"), |
| 1}, |
| {HasBeginLabel(), |
| EmbedInModule("generate\n" |
| "if (TypeIsPosedge) begin\n" |
| " always @(posedge clk) foo <= bar;\n" |
| "end\n" |
| "endgenerate"), |
| 0}, |
| {HasBeginLabel(), EmbedInModule(""), 0}, |
| {HasBeginLabel(), "", 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for HasGenerateBlock matching |
| TEST(VerilogMatchers, HasGenerateBlockTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {HasGenerateBlock(), "", 0}, |
| {HasGenerateBlock(), EmbedInModule(""), 0}, |
| {HasGenerateBlock(), |
| EmbedInModule("generate\n" |
| "begin\n" |
| " always @(posedge clk) foo <= bar;\n" |
| "end\n" |
| "endgenerate"), |
| 1}, |
| {HasGenerateBlock(), |
| EmbedInModule("generate\n" |
| "begin\n" |
| " genvar j;\n" |
| "end\n" |
| "endgenerate"), |
| 1}, |
| {HasGenerateBlock(), |
| EmbedInModule("generate\n" |
| "if (TypeIsPosedge) begin : gen_posedge\n" |
| " always @(posedge clk) foo <= bar;\n" |
| "end\n" |
| "endgenerate"), |
| 0}, |
| {HasGenerateBlock(), |
| EmbedInModule("generate\n" |
| "if (TypeIsPosedge) begin\n" |
| " always @(posedge clk) foo <= bar;\n" |
| "end\n" |
| "endgenerate"), |
| 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for integration between NodekGenerateBlock and HasBeginLabel |
| TEST(VerilogMatchers, GenerateBlockHasBeginLabelTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {NodekGenerateBlock(verible::matcher::Unless(HasBeginLabel())), |
| EmbedInModule("generate\n" |
| "if (TypeIsPosedge) begin\n" |
| " always @(posedge clk) foo <= bar;\n" |
| "end\n" |
| "endgenerate"), |
| 1}, |
| {NodekGenerateBlock(verible::matcher::Unless(HasBeginLabel())), |
| EmbedInModule("generate\n" |
| "if (TypeIsPosedge) begin : gen_posedge\n" |
| " always @(posedge clk) foo <= bar;\n" |
| "end\n" |
| "endgenerate"), |
| 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for NodekAlwaysStatement matching |
| TEST(VerilogMatchers, AlwaysStatementNodeTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {NodekAlwaysStatement(), EmbedInModule(""), 0}, |
| {NodekAlwaysStatement(), EmbedInModule("initial begin a <= 0; end"), 0}, |
| {NodekAlwaysStatement(), EmbedInModule("always_ff begin a <= b; end"), 1}, |
| {NodekAlwaysStatement(), EmbedInModule("always_comb begin a = b; end"), |
| 1}, |
| {NodekAlwaysStatement(), EmbedInModule("always @* begin a = b; end"), 1}, |
| {NodekAlwaysStatement(), EmbedInModule("always @(*) begin a = b; end"), |
| 1}, |
| {NodekAlwaysStatement(), |
| EmbedInModule("always @(posedge foo) begin a <= b; end"), 1}, |
| {NodekAlwaysStatement(), |
| EmbedInModule("always_ff begin a <= b; end\n" |
| "always_comb begin a = b; end"), |
| 2}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for AlwaysKeyword matching |
| TEST(VerilogMatchers, AlwaysKeywordTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {AlwaysKeyword(), EmbedInModule(""), 0}, |
| {AlwaysKeyword(), EmbedInModule("initial begin a <= 0; end"), 0}, |
| {AlwaysKeyword(), EmbedInModule("always_ff begin a <= b; end"), 0}, |
| {AlwaysKeyword(), EmbedInModule("always_comb begin a = b; end"), 0}, |
| {AlwaysKeyword(), EmbedInModule("always @* begin a = b; end"), 1}, |
| {AlwaysKeyword(), EmbedInModule("always @(*) begin a = b; end"), 1}, |
| {AlwaysKeyword(), |
| EmbedInModule("always @(posedge foo) begin a <= b; end"), 1}, |
| {AlwaysKeyword(), |
| EmbedInModule("always_ff begin a <= b; end\n" |
| "always_comb begin a = b; end"), |
| 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for AlwaysCombKeyword matching |
| TEST(VerilogMatchers, AlwaysCombKeywordTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {AlwaysCombKeyword(), EmbedInModule(""), 0}, |
| {AlwaysCombKeyword(), EmbedInModule("initial begin a <= 0; end"), 0}, |
| {AlwaysCombKeyword(), EmbedInModule("always_ff begin a <= b; end"), 0}, |
| {AlwaysCombKeyword(), EmbedInModule("always_comb begin a = b; end"), 1}, |
| {AlwaysCombKeyword(), EmbedInModule("always @* begin a = b; end"), 0}, |
| {AlwaysCombKeyword(), EmbedInModule("always @(*) begin a = b; end"), 0}, |
| {AlwaysCombKeyword(), |
| EmbedInModule("always @(posedge foo) begin a <= b; end"), 0}, |
| {AlwaysCombKeyword(), |
| EmbedInModule("always_ff begin a <= b; end\n" |
| "always_comb begin a = b; end"), |
| 1}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for AlwaysFFKeyword matching |
| TEST(VerilogMatchers, AlwaysFFKeywordTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {AlwaysFFKeyword(), EmbedInModule(""), 0}, |
| {AlwaysFFKeyword(), EmbedInModule("initial begin a <= 0; end"), 0}, |
| {AlwaysFFKeyword(), EmbedInModule("always_ff begin a <= b; end"), 1}, |
| {AlwaysFFKeyword(), EmbedInModule("always_comb begin a = b; end"), 0}, |
| {AlwaysFFKeyword(), EmbedInModule("always @* begin a = b; end"), 0}, |
| {AlwaysFFKeyword(), EmbedInModule("always @(*) begin a = b; end"), 0}, |
| {AlwaysFFKeyword(), |
| EmbedInModule("always @(posedge foo) begin a <= b; end"), 0}, |
| {AlwaysFFKeyword(), |
| EmbedInModule("always_ff begin a <= b; end\n" |
| "always_comb begin a = b; end"), |
| 1}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for AlwaysStatementHasEventControlStar matching |
| TEST(VerilogMatchers, AlwaysStatementHasEventControlStarTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {AlwaysStatementHasEventControlStar(), EmbedInModule(""), 0}, |
| {AlwaysStatementHasEventControlStar(), |
| EmbedInModule("initial begin a <= 0; end"), 0}, |
| {AlwaysStatementHasEventControlStar(), |
| EmbedInModule("always_ff begin a <= b; end"), 0}, |
| {AlwaysStatementHasEventControlStar(), |
| EmbedInModule("always_comb begin a = b; end"), 0}, |
| {AlwaysStatementHasEventControlStar(), |
| EmbedInModule("always @* begin a = b; end"), 1}, |
| {AlwaysStatementHasEventControlStar(), |
| EmbedInModule("always @(*) begin a = b; end"), 1}, |
| {AlwaysStatementHasEventControlStar(), |
| EmbedInModule("always @(posedge foo) begin a <= b; end"), 0}, |
| {AlwaysStatementHasEventControlStar(), |
| EmbedInModule("always_ff begin a <= b; end\n" |
| "always_comb begin a = b; end"), |
| 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests that matcher finds left-hand-sides of assignments. |
| TEST(VerilogMatchers, LValueOfAssignmentTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {LValueOfAssignment(), EmbedInClassMethod(""), 0}, |
| {LValueOfAssignment(), EmbedInClassMethod("foo();"), 0}, |
| {LValueOfAssignment(), EmbedInClassMethod("x = 1;"), 1}, |
| {LValueOfAssignment(), EmbedInClassMethod("x = a + b;"), 1}, |
| {LValueOfAssignment(), EmbedInModule("initial begin\nfoo();\nend\n"), 0}, |
| {LValueOfAssignment(), EmbedInModule("initial begin\nx = 1;\nend\n"), 1}, |
| {LValueOfAssignment(), EmbedInClassMethod("x[1] = 1;"), 1}, |
| {LValueOfAssignment(), EmbedInClassMethod("x.y = 2;"), 1}, |
| {LValueOfAssignment(), EmbedInClassMethod("x[0].y = 3;"), 1}, |
| {LValueOfAssignment(), EmbedInClassMethod("x.y[2] = 4;"), 1}, |
| {LValueOfAssignment(), EmbedInClassMethod("x[0].y[0] = 5;"), 1}, |
| {LValueOfAssignment(), EmbedInClassMethod("if (0) x = 1;"), 1}, |
| {LValueOfAssignment(), EmbedInClassMethod("forever x = y;"), 1}, |
| {LValueOfAssignment(), EmbedInClassMethod("x = 1;\ny = two();"), 2}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests that matcher finds assignments values that are function calls. |
| TEST(VerilogMatchers, RValueIsFunctionCallTest) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {RValueIsFunctionCall(), EmbedInModule(""), 0}, |
| {RValueIsFunctionCall(), EmbedInClassMethod(""), 0}, |
| {RValueIsFunctionCall(), EmbedInClassMethod("x = 1;"), 0}, |
| {RValueIsFunctionCall(), EmbedInClassMethod("x = y / z;"), 0}, |
| {RValueIsFunctionCall(), EmbedInClassMethod("x = y / z();"), 0}, |
| {RValueIsFunctionCall(), EmbedInClassMethod("x = foo();"), 1}, |
| {RValueIsFunctionCall(), EmbedInClassMethod("x = bar::foo();"), 1}, |
| {RValueIsFunctionCall(), EmbedInClassMethod("x = bar::foo(a);"), 1}, |
| {RValueIsFunctionCall(), EmbedInClassMethod("x.y = bar::foo(a);"), 1}, |
| {RValueIsFunctionCall(), EmbedInClassMethod("x = bar.foo();"), 0}, |
| {RValueIsFunctionCall(), EmbedInClassMethod("z = pkg::bar::foo();"), 1}, |
| {RValueIsFunctionCall(), EmbedInClassMethod("x = bar::foo() -12;"), 0}, |
| {RValueIsFunctionCall(), EmbedInClassMethod("x = a + bar::foo();"), 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests that qualified function calls are found. |
| TEST(VerilogMatchers, FunctionCallIsQualifiedTest) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {FunctionCallIsQualified(), EmbedInModule(""), 0}, |
| {FunctionCallIsQualified(), EmbedInClassMethod(""), 0}, |
| {FunctionCallIsQualified(), EmbedInClassMethod("x = 1;"), 0}, |
| {FunctionCallIsQualified(), EmbedInClassMethod("x = y / z;"), 0}, |
| {FunctionCallIsQualified(), EmbedInClassMethod("x = y / z();"), 0}, |
| {FunctionCallIsQualified(), EmbedInClassMethod("x = foo();"), 0}, |
| {FunctionCallIsQualified(), EmbedInClassMethod("x = bar::foo();"), 1}, |
| {FunctionCallIsQualified(), EmbedInClassMethod("x = bar::foo(a);"), 1}, |
| {FunctionCallIsQualified(), EmbedInClassMethod("x.y = bar::foo(a);"), 1}, |
| {FunctionCallIsQualified(), EmbedInClassMethod("x = bar.foo();"), 0}, |
| {FunctionCallIsQualified(), EmbedInClassMethod("z = pkg::bar::foo();"), |
| 1}, |
| {FunctionCallIsQualified(), EmbedInClassMethod("x = bar::foo() -12;"), 1}, |
| {FunctionCallIsQualified(), EmbedInClassMethod("x = a + bar::foo();"), 1}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests that assignments to qualified function calls are found. |
| TEST(VerilogMatchers, RValueFunctionCallIsQualifiedTest) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {RValueIsFunctionCall(FunctionCallIsQualified()), EmbedInModule(""), 0}, |
| {RValueIsFunctionCall(FunctionCallIsQualified()), EmbedInClassMethod(""), |
| 0}, |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("x = 1;"), 0}, |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("x = y / z;"), 0}, |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("x = y / z();"), 0}, |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("x = foo();"), 0}, |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("x = bar::foo();"), 1}, |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("bar::foo();"), 0}, // no assignment |
| // TODO(fangism): The following test case wrongly matches, but only |
| // because the matcher matches two different function calls: qqq is the |
| // outermost match, but the recursive inner match finds a qualified |
| // function call deeper in the syntax tree. Solution is to use a direct |
| // inner matcher that does not search recursively. |
| // {RValueIsFunctionCall(FunctionCallIsQualified()), |
| // EmbedInClassMethod("qqq(bar::foo(), 1, 2);"), 0}, |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("y = z();\nbar::foo();"), |
| 0}, // no matching assignment |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("x = bar::foo(a);"), 1}, |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("x.y = bar::foo(a);"), 1}, |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("x = bar.foo();"), 0}, |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("z = pkg::bar::foo();"), 1}, |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("z = pkg::bar::foo(\"a\", b, cc);"), 1}, |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("x = bar::foo() -12;"), 0}, // outermost rvalue is - |
| {RValueIsFunctionCall(FunctionCallIsQualified()), |
| EmbedInClassMethod("x = a + bar::foo();"), 0}, // outermost rvalue is + |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests that function call arguments are matched. |
| TEST(VerilogMatchers, FunctionCallArgumentsTest) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {FunctionCallArguments(), EmbedInModule(""), 0}, |
| {FunctionCallArguments(), EmbedInClassMethod(""), 0}, |
| {FunctionCallArguments(), EmbedInClassMethod("a = 1 + 2;"), 0}, |
| {FunctionCallArguments(), EmbedInClassMethod("foobar();"), 0}, |
| {FunctionCallArguments(), EmbedInClassMethod("foobar(1);"), 1}, |
| {FunctionCallArguments(), EmbedInClassMethod("foobar(a, b, c);"), 1}, |
| {FunctionCallArguments(), EmbedInClassMethod("`foobar();"), |
| 0}, // macro call arguments are different |
| {FunctionCallArguments(), EmbedInClassMethod("`foobar(1);"), 0}, |
| {FunctionCallArguments(), EmbedInClassMethod("`foobar(a, b, c);"), 0}, |
| {FunctionCallArguments(), EmbedInClassMethod("foo(bar());"), 1}, |
| {FunctionCallArguments(), EmbedInClassMethod("x = foobar();"), 0}, |
| {FunctionCallArguments(), EmbedInClassMethod("f.g.h = foobar(g);"), 1}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests that ranged dimensions are matched. |
| TEST(VerilogMatchers, DeclarationDimensionsHasRanges) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {DeclarationDimensionsHasRanges(), "", 0}, |
| {DeclarationDimensionsHasRanges(), EmbedInModule(""), 0}, |
| {DeclarationDimensionsHasRanges(), "wire w;", 0}, |
| {DeclarationDimensionsHasRanges(), "wire [1:0] w;", 1}, |
| {DeclarationDimensionsHasRanges(), "wire w [1:0];", 1}, |
| {DeclarationDimensionsHasRanges(), "wire [1:2] w [1:0];", 2}, |
| {DeclarationDimensionsHasRanges(), EmbedInModule("wire w;"), 0}, |
| {DeclarationDimensionsHasRanges(), EmbedInModule("wire [1:0] w;"), 1}, |
| {DeclarationDimensionsHasRanges(), EmbedInModule("wire w [1:0];"), 1}, |
| {DeclarationDimensionsHasRanges(), EmbedInModule("wire [1:2] w [1:0];"), |
| 2}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| // Tests for HasDefaultCase matching. |
| TEST(VerilogMatchers, HasDefaultCaseTests) { |
| const verible::matcher::RawMatcherTestCase tests[] = { |
| {HasDefaultCase(), "", 0}, |
| {HasDefaultCase(), |
| R"( |
| function automatic int foo (input in); |
| case (in) |
| default: return 0; |
| endcase |
| endfunction |
| )", |
| 1}, |
| {HasDefaultCase(), |
| R"( |
| function automatic int foo (input in); |
| case (in) |
| 1: return 0; |
| endcase |
| endfunction |
| )", |
| 0}, |
| }; |
| for (const auto& test : tests) |
| verible::matcher::RunRawMatcherTestCase<VerilogAnalyzer>(test); |
| } |
| |
| } // namespace |
| } // namespace verilog |