| // 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/expression.h" | |
| #include <memory> | |
| #include <utility> | |
| #include "common/analysis/syntax_tree_search.h" | |
| #include "common/analysis/syntax_tree_search_test_utils.h" | |
| #include "common/text/symbol.h" | |
| #include "common/text/tree_utils.h" | |
| #include "common/util/logging.h" | |
| #include "gtest/gtest.h" | |
| #include "verilog/CST/match_test_utils.h" | |
| #include "verilog/CST/verilog_nonterminals.h" | |
| #include "verilog/CST/verilog_tree_print.h" | |
| #include "verilog/analysis/verilog_analyzer.h" | |
| #include "verilog/analysis/verilog_excerpt_parse.h" | |
| namespace verilog { | |
| namespace { | |
| static constexpr VerilogPreprocess::Config kDefaultPreprocess; | |
| using verible::SyntaxTreeSearchTestCase; | |
| using verible::TextStructureView; | |
| using verible::TreeSearchMatch; | |
| TEST(IsZeroTest, NonZero) { | |
| const char* kTestCases[] = { | |
| "a", | |
| "a0", | |
| "1", | |
| "-1", | |
| // no constant expression evaluation yet | |
| "1-1", | |
| "a-a", | |
| "0+0", | |
| "(0)", | |
| }; | |
| for (auto code : kTestCases) { | |
| const auto analyzer_ptr = | |
| AnalyzeVerilogExpression(code, "<file>", kDefaultPreprocess); | |
| const auto& node = ABSL_DIE_IF_NULL(analyzer_ptr)->SyntaxTree(); | |
| const auto tag = node->Tag(); | |
| EXPECT_EQ(tag.kind, verible::SymbolKind::kNode); | |
| EXPECT_EQ(NodeEnum(tag.tag), NodeEnum::kExpression); | |
| EXPECT_FALSE(IsZero(*node)); | |
| } | |
| } | |
| TEST(IsZeroTest, Zero) { | |
| const char* kTestCases[] = { | |
| "0", | |
| "00", | |
| "00000", | |
| "'0", | |
| }; | |
| for (auto code : kTestCases) { | |
| const auto analyzer_ptr = | |
| AnalyzeVerilogExpression(code, "<file>", kDefaultPreprocess); | |
| const auto& node = ABSL_DIE_IF_NULL(analyzer_ptr)->SyntaxTree(); | |
| const auto tag = node->Tag(); | |
| EXPECT_EQ(tag.kind, verible::SymbolKind::kNode); | |
| EXPECT_EQ(NodeEnum(tag.tag), NodeEnum::kExpression); | |
| EXPECT_TRUE(IsZero(*node)); | |
| } | |
| } | |
| TEST(ConstantIntegerValueTest, NotInteger) { | |
| const char* kTestCases[] = { | |
| "a", | |
| "1+1", | |
| "(2)", | |
| }; | |
| for (auto code : kTestCases) { | |
| const auto analyzer_ptr = | |
| AnalyzeVerilogExpression(code, "<file>", kDefaultPreprocess); | |
| const auto& node = ABSL_DIE_IF_NULL(analyzer_ptr)->SyntaxTree(); | |
| const auto tag = node->Tag(); | |
| EXPECT_EQ(tag.kind, verible::SymbolKind::kNode); | |
| EXPECT_EQ(NodeEnum(tag.tag), NodeEnum::kExpression); | |
| int value; | |
| EXPECT_FALSE(ConstantIntegerValue(*node, &value)); | |
| } | |
| } | |
| TEST(ConstantIntegerValueTest, IsInteger) { | |
| const std::pair<const char*, int> kTestCases[] = { | |
| {"0", 0}, | |
| {"1", 1}, | |
| {"666", 666}, | |
| }; | |
| for (auto test : kTestCases) { | |
| const auto analyzer_ptr = | |
| AnalyzeVerilogExpression(test.first, "<file>", kDefaultPreprocess); | |
| const auto& node = ABSL_DIE_IF_NULL(analyzer_ptr)->SyntaxTree(); | |
| const auto tag = node->Tag(); | |
| EXPECT_EQ(tag.kind, verible::SymbolKind::kNode); | |
| EXPECT_EQ(NodeEnum(tag.tag), NodeEnum::kExpression); | |
| int value; | |
| EXPECT_TRUE(ConstantIntegerValue(*node, &value)); | |
| EXPECT_EQ(value, test.second); | |
| } | |
| } | |
| TEST(AssociativeBinaryExpressionsTest, FlatTree) { | |
| constexpr int kTag = 1; // value doesn't matter | |
| const SyntaxTreeSearchTestCase kTestCases[] = { | |
| {""}, | |
| {"module m; endmodule\n"}, | |
| {"module m;\ninitial begin end\nendmodule"}, | |
| {"class c; endclass\n"}, | |
| {"function f; endfunction\n"}, | |
| {"function f;\n", "a = ", {kTag, "b + c"}, "; endfunction\n"}, | |
| {"function f;\n", "a = ", {kTag, "b + c + d"}, "; endfunction\n"}, | |
| {"parameter product P = ", {kTag, "q*r"}, ";\n"}, | |
| {"parameter product P = ", {kTag, "q*r*s"}, ";\n"}, | |
| {"function f;\n", "a = ", {kTag, "b | c | d | e"}, "; endfunction\n"}, | |
| {"function f;\n", "a = ", {kTag, "b & c & d & e"}, "; endfunction\n"}, | |
| {"function f;\n", "a = ", {kTag, "b || c || d || e"}, "; endfunction\n"}, | |
| {"function f;\n", "a = ", {kTag, "b && c && d && e"}, "; endfunction\n"}, | |
| {"function f;\n", "a = ", {kTag, "b ^ c ^ d ^ e"}, "; endfunction\n"}, | |
| {"function f;\n", "a = ", {kTag, "b ~^ c ~^ d ~^ e"}, "; endfunction\n"}, | |
| }; | |
| for (const auto& test : kTestCases) { | |
| TestVerilogSyntaxRangeMatches( | |
| __FUNCTION__, test, [](const TextStructureView& text_structure) { | |
| const auto& root = text_structure.SyntaxTree(); | |
| return FindAllBinaryOperations(*ABSL_DIE_IF_NULL(root)); | |
| }); | |
| } | |
| } | |
| TEST(AssociativeBinaryExpressionsTest, ThreeFlatOperands) { | |
| constexpr int kTag = 1; // value doesn't matter | |
| const SyntaxTreeSearchTestCase kTestCases[] = { | |
| {"function f;\n", "a = ", {kTag, "b | c | d"}, "; endfunction\n"}, | |
| {"function f;\n", | |
| "a = ", | |
| {kTag, "b(x) | c(y) | d(z)"}, | |
| "; endfunction\n"}, | |
| {"function f;\n", | |
| "a = ", | |
| {kTag, "b(x) ^ c(y) ^ d(z)"}, | |
| "; endfunction\n"}, | |
| {"function f;\n", | |
| "a = ", | |
| {kTag, "b(x) + c(y) + d(z)"}, | |
| "; endfunction\n"}, | |
| {"function f;\n", "a = g(", {kTag, "b | c | d"}, "); endfunction\n"}, | |
| {"function f;\n", | |
| "a = g(", | |
| {kTag, "b|c|d"}, | |
| ", ", | |
| {kTag, "x*y*z"}, | |
| "); endfunction\n"}, | |
| }; | |
| for (const auto& test : kTestCases) { | |
| TestVerilogSyntaxRangeMatches( | |
| __FUNCTION__, test, [](const TextStructureView& text_structure) { | |
| const auto& root = text_structure.SyntaxTree(); | |
| const auto matches = FindAllBinaryOperations(*ABSL_DIE_IF_NULL(root)); | |
| for (const auto& match : matches) { | |
| // "A op B op C" is 5 sibling tokens, due to flattening | |
| EXPECT_EQ(verible::SymbolCastToNode(*ABSL_DIE_IF_NULL(match.match)) | |
| .children() | |
| .size(), | |
| 5); | |
| } | |
| return matches; | |
| }); | |
| } | |
| } | |
| TEST(GetConditionExpressionPredicateTest, Various) { | |
| constexpr int kTag = 1; // value doesn't matter | |
| const SyntaxTreeSearchTestCase kTestCases[] = { | |
| {""}, | |
| {"module m; endmodule\n"}, | |
| {"module m;\ninitial begin end\nendmodule"}, | |
| {"class c; endclass\n"}, | |
| {"function f; endfunction\n"}, | |
| {"function f;\n", "a = ", {kTag, "b"}, " ? c : d", "; endfunction\n"}, | |
| {"module m;\n", | |
| " assign foo = ", | |
| {kTag, "condition_a"}, | |
| " ? b : c", | |
| ";\n", | |
| "endmodule\n"}, | |
| {"module m;\n", | |
| "parameter foo = ", | |
| {kTag, "condition_a"}, | |
| "? a : b", | |
| ";\nendmodule"}, | |
| {"module m;\n", | |
| "always @(posedge clk) begin\n left <= ", | |
| {kTag, "condition_a"}, | |
| "? a : b", | |
| "; \nend", | |
| "\nendmodule"}, | |
| {"function f;\n g = h(", | |
| {kTag, "condition_a"}, | |
| "? a : b", | |
| "); \nendfunction"}, | |
| {"module m;\n", | |
| "always @(posedge clk)\n", | |
| "case (", | |
| {kTag, "condition_a"}, | |
| "? a : b", | |
| ")\n", | |
| "default :;\n", | |
| "endcase\n", | |
| "\nendmodule"}, | |
| }; | |
| for (const auto& test : kTestCases) { | |
| TestVerilogSyntaxRangeMatches( | |
| __FUNCTION__, test, [](const TextStructureView& text_structure) { | |
| const auto& root = text_structure.SyntaxTree(); | |
| const auto exprs = | |
| FindAllConditionExpressions(*ABSL_DIE_IF_NULL(root)); | |
| std::vector<TreeSearchMatch> predicates; | |
| for (const auto& expr : exprs) { | |
| const auto* predicate = | |
| GetConditionExpressionPredicate(*expr.match); | |
| if (predicate != nullptr) { | |
| predicates.push_back( | |
| TreeSearchMatch{predicate, {/* ignored context */}}); | |
| } else { | |
| EXPECT_NE(predicate, nullptr) | |
| << "predicate:\n" | |
| << verible::RawTreePrinter(*expr.match); | |
| } | |
| } | |
| return predicates; | |
| }); | |
| } | |
| } | |
| TEST(GetConditionExpressionTrueCaseTest, Various) { | |
| constexpr int kTag = 1; // value doesn't matter | |
| const SyntaxTreeSearchTestCase kTestCases[] = { | |
| {""}, | |
| {"module m; endmodule\n"}, | |
| {"module m;\ninitial begin end\nendmodule"}, | |
| {"class c; endclass\n"}, | |
| {"function f; endfunction\n"}, | |
| {"function f;\n", | |
| "a = ", | |
| "b ? ", | |
| {kTag, "c"}, | |
| " : d", | |
| "; endfunction\n"}, | |
| {"function f;\n", | |
| "a = ", | |
| "b ? ", | |
| {kTag, "(c + d)"}, | |
| " : d", | |
| "; endfunction\n"}, | |
| {"function f;\n", | |
| "a = ", | |
| "b ? ", | |
| {kTag, "(c << d)"}, | |
| " : d", | |
| "; endfunction\n"}, | |
| {"module m;\n", | |
| " assign foo = ", | |
| "condition_a ? ", | |
| {kTag, "b"}, | |
| " : c", | |
| ";\n", | |
| "endmodule\n"}, | |
| {"module m;\n", | |
| "parameter foo = ", | |
| "condition_a ? ", | |
| {kTag, "a"}, | |
| " : b", | |
| ";\nendmodule"}, | |
| {"module m;\n", | |
| "always @(posedge clk) begin\n left <= ", | |
| "condition_a ? ", | |
| {kTag, "a"}, | |
| " : b", | |
| "; \nend", | |
| "\nendmodule"}, | |
| {"function f;\n g = h(", | |
| "condition_a ? ", | |
| {kTag, "a"}, | |
| " : b", | |
| "); \nendfunction"}, | |
| {"module m;\n", | |
| "always @(posedge clk)\n", | |
| "case (", | |
| "condition_a ? ", | |
| {kTag, "a"}, | |
| " : b", | |
| ")\n", | |
| "default :;\n", | |
| "endcase\n", | |
| "\nendmodule"}, | |
| }; | |
| for (const auto& test : kTestCases) { | |
| TestVerilogSyntaxRangeMatches( | |
| __FUNCTION__, test, [](const TextStructureView& text_structure) { | |
| const auto& root = text_structure.SyntaxTree(); | |
| const auto exprs = | |
| FindAllConditionExpressions(*ABSL_DIE_IF_NULL(root)); | |
| std::vector<TreeSearchMatch> predicates; | |
| for (const auto& expr : exprs) { | |
| const auto* predicate = GetConditionExpressionTrueCase(*expr.match); | |
| if (predicate != nullptr) { | |
| predicates.push_back( | |
| TreeSearchMatch{predicate, {/* ignored context */}}); | |
| } else { | |
| EXPECT_NE(predicate, nullptr) | |
| << "predicate:\n" | |
| << verible::RawTreePrinter(*expr.match); | |
| } | |
| } | |
| return predicates; | |
| }); | |
| } | |
| } | |
| TEST(GetConditionExpressionFalseCaseTest, Various) { | |
| constexpr int kTag = 1; // value doesn't matter | |
| const SyntaxTreeSearchTestCase kTestCases[] = { | |
| {""}, | |
| {"module m; endmodule\n"}, | |
| {"module m;\ninitial begin end\nendmodule"}, | |
| {"class c; endclass\n"}, | |
| {"function f; endfunction\n"}, | |
| {"function f;\n", | |
| "a = ", | |
| "b ? ", | |
| "c : ", | |
| {kTag, "d"}, | |
| "; endfunction\n"}, | |
| {"function f;\n", | |
| "a = ", | |
| "b ? ", | |
| "c : ", | |
| {kTag, "(c + d)"}, | |
| "; endfunction\n"}, | |
| {"function f;\n", | |
| "a = ", | |
| "b ? ", | |
| "c : ", | |
| {kTag, "(c << d)"}, | |
| "; endfunction\n"}, | |
| {"module m;\n", | |
| " assign foo = ", | |
| "condition_a ? ", | |
| "b : ", | |
| {kTag, "c"}, | |
| ";\n", | |
| "endmodule\n"}, | |
| {"module m;\n", | |
| "parameter foo = ", | |
| "condition_a ? ", | |
| "a : ", | |
| {kTag, "b"}, | |
| ";\nendmodule"}, | |
| {"module m;\n", | |
| "always @(posedge clk) begin\n left <= ", | |
| "condition_a ? ", | |
| "a : ", | |
| {kTag, "b"}, | |
| "; \nend", | |
| "\nendmodule"}, | |
| {"function f;\n g = h(", | |
| "condition_a ? ", | |
| "a : ", | |
| {kTag, "b"}, | |
| "); \nendfunction"}, | |
| {"module m;\n", | |
| "always @(posedge clk)\n", | |
| "case (", | |
| "condition_a ? ", | |
| "a : ", | |
| {kTag, "b"}, | |
| ")\n", | |
| "default :;\n", | |
| "endcase\n", | |
| "\nendmodule"}, | |
| }; | |
| for (const auto& test : kTestCases) { | |
| TestVerilogSyntaxRangeMatches( | |
| __FUNCTION__, test, [](const TextStructureView& text_structure) { | |
| const auto& root = text_structure.SyntaxTree(); | |
| const auto exprs = | |
| FindAllConditionExpressions(*ABSL_DIE_IF_NULL(root)); | |
| std::vector<TreeSearchMatch> predicates; | |
| for (const auto& expr : exprs) { | |
| const auto* predicate = | |
| GetConditionExpressionFalseCase(*expr.match); | |
| if (predicate != nullptr) { | |
| predicates.push_back( | |
| TreeSearchMatch{predicate, {/* ignored context */}}); | |
| } else { | |
| EXPECT_NE(predicate, nullptr) | |
| << "predicate:\n" | |
| << verible::RawTreePrinter(*expr.match); | |
| } | |
| } | |
| return predicates; | |
| }); | |
| } | |
| } | |
| TEST(FindAllConditionExpressionsTest, Various) { | |
| constexpr int kTag = 1; // value doesn't matter | |
| const SyntaxTreeSearchTestCase kTestCases[] = { | |
| {""}, | |
| {"module m; endmodule\n"}, | |
| {"module m;\ninitial begin end\nendmodule"}, | |
| {"class c; endclass\n"}, | |
| {"function f; endfunction\n"}, | |
| {"function f;\n", "a = ", {kTag, "b ? c : d"}, "; endfunction\n"}, | |
| {"module m;\n", | |
| " assign foo = ", | |
| {kTag, "condition_a ? b : c"}, | |
| ";\n", | |
| "endmodule\n"}, | |
| {"module m;\n", | |
| "parameter foo = ", | |
| {kTag, "condition_a? a : b"}, | |
| ";\nendmodule"}, | |
| {"module m;\n", | |
| "always @(posedge clk) begin\n left <= ", | |
| {kTag, "condition_a? a : b"}, | |
| "; \nend", | |
| "\nendmodule"}, | |
| {"function f;\n g = h(", | |
| {kTag, "condition_a? a : b"}, | |
| "); \nendfunction"}, | |
| {"module m;\n", | |
| "always @(posedge clk)\n", | |
| "case (", | |
| {kTag, "condition_a? a : b"}, | |
| ")\n", | |
| "default :;\n", | |
| "endcase\n", | |
| "\nendmodule"}, | |
| }; | |
| for (const auto& test : kTestCases) { | |
| TestVerilogSyntaxRangeMatches( | |
| __FUNCTION__, test, [](const TextStructureView& text_structure) { | |
| const auto& root = text_structure.SyntaxTree(); | |
| return FindAllConditionExpressions(*ABSL_DIE_IF_NULL(root)); | |
| }); | |
| } | |
| } | |
| TEST(FindAllReferenceExpressionsTest, Various) { | |
| constexpr int kTag = 1; // value doesn't matter | |
| const SyntaxTreeSearchTestCase kTestCases[] = { | |
| {""}, | |
| {"module m; endmodule\n"}, | |
| {"class c; endclass\n"}, | |
| {"function f; endfunction\n"}, | |
| {"function f;\n", {kTag, "a"}, " = 1;\n", "endfunction\n"}, | |
| {"function f;\n", | |
| {kTag, "a"}, | |
| " = ", | |
| {kTag, "z"}, | |
| ";\n", | |
| "endfunction\n"}, | |
| {"function f;\n", | |
| {kTag, "a.b"}, | |
| " = ", | |
| {kTag, "z.y.x"}, | |
| ";\n", | |
| "endfunction\n"}, | |
| {"task t;\n", | |
| {kTag, "a[0][0]"}, | |
| " = ", | |
| {kTag, "z[1][1]"}, | |
| ";\n", | |
| "endtask\n"}, | |
| {"module m;\n" | |
| " foo bar(", | |
| {kTag, "v.w"}, | |
| ");\n" | |
| "endmodule\n"}, | |
| {"module m;\n" | |
| " foo bar(.clk(", | |
| {kTag, "v.w"}, | |
| "));\n" | |
| "endmodule\n"}, | |
| {"module m;\n" // continuous assignment | |
| " assign ", | |
| {kTag, "v"}, | |
| " = 1'b1;\n" | |
| "endmodule\n"}, | |
| {"module m;\n" // continuous assignment | |
| " assign ", | |
| {kTag, "v"}, | |
| " = ", | |
| {kTag, "w"}, | |
| ";\n" | |
| "endmodule\n"}, | |
| {"module m;\n" // continuous assignment | |
| " assign ", | |
| {kTag, "v[1]"}, | |
| " = ", | |
| {kTag, "w.d"}, | |
| ";\n" | |
| "endmodule\n"}, | |
| {"module m;\n" // blocking assignment | |
| " initial ", | |
| {kTag, "v"}, | |
| " = 1'b1;\n" | |
| "endmodule\n"}, | |
| {"module m;\n" // blocking assignment | |
| " initial ", | |
| {kTag, "v"}, | |
| " = ", | |
| {kTag, "zz"}, | |
| ";\n" | |
| "endmodule\n"}, | |
| {"module m;\n" // blocking assignment | |
| " initial begin\n", | |
| {kTag, "v[2]"}, | |
| " = ", | |
| {kTag, "zz.f"}, | |
| ";\n" | |
| " end\n" | |
| "endmodule\n"}, | |
| {"module m;\n" // non blocking assignment | |
| " always @(posedge ", | |
| {kTag, "clk"}, | |
| ")\n", | |
| {kTag, "v.g"}, | |
| " <= ", | |
| {kTag, "zz[3][4]"}, | |
| ";\n" | |
| "endmodule\n"}, | |
| {"function f;\n", | |
| " for (int i = 0; ", | |
| {kTag, "i"}, | |
| "<", | |
| {kTag, "N"}, | |
| "; ++", | |
| {kTag, "i"}, | |
| ")\n", | |
| // Note: "int i = 0" is a declaration, where "i" also serves as a | |
| // reference in an assignment, but is not tagged as such. | |
| {kTag, "a"}, | |
| " = ", | |
| {kTag, "z"}, | |
| " + ", | |
| {kTag, "i"}, | |
| ";\n", | |
| "endfunction\n"}, | |
| // reference could contain other references like "a[a]", but the testing | |
| // framework doesn't support nested expected ranges... yet. | |
| }; | |
| for (const auto& test : kTestCases) { | |
| TestVerilogSyntaxRangeMatches( | |
| __FUNCTION__, test, [](const TextStructureView& text_structure) { | |
| const auto& root = text_structure.SyntaxTree(); | |
| return FindAllReferenceFullExpressions(*ABSL_DIE_IF_NULL(root)); | |
| }); | |
| } | |
| } | |
| TEST(ReferenceIsSimpleTest, Simple) { | |
| const char* kTestCases[] = { | |
| "a", | |
| "bbb", | |
| "z1", | |
| "_y", | |
| }; | |
| for (auto code : kTestCases) { | |
| const auto analyzer_ptr = | |
| AnalyzeVerilogExpression(code, "<file>", kDefaultPreprocess); | |
| const auto& node = ABSL_DIE_IF_NULL(analyzer_ptr)->SyntaxTree(); | |
| { | |
| const auto status = analyzer_ptr->LexStatus(); | |
| ASSERT_TRUE(status.ok()) << status.message(); | |
| } | |
| { | |
| const auto status = analyzer_ptr->ParseStatus(); | |
| ASSERT_TRUE(status.ok()) << status.message(); | |
| } | |
| const std::vector<TreeSearchMatch> refs( | |
| FindAllReferenceFullExpressions(*ABSL_DIE_IF_NULL(node))); | |
| for (const auto& ref : refs) { | |
| const verible::TokenInfo* token = ReferenceIsSimpleIdentifier(*ref.match); | |
| ASSERT_NE(token, nullptr) << "reference: " << code; | |
| EXPECT_EQ(token->text(), code); | |
| } | |
| } | |
| } | |
| TEST(ReferenceIsSimpleTest, NotSimple) { | |
| const char* kTestCases[] = { | |
| "a[0]", "a[4][6]", "bbb[3:0]", "x.y", "x.y.z", "x[0].y[1].z[2]", | |
| "x()", "x.y()", "x()[0]", "x(1)", "f(0,1)", "j[9].k(3, 2, 1)", | |
| }; | |
| for (auto code : kTestCases) { | |
| VLOG(1) << __FUNCTION__ << " test: " << code; | |
| const auto analyzer_ptr = | |
| AnalyzeVerilogExpression(code, "<file>", kDefaultPreprocess); | |
| const auto& node = ABSL_DIE_IF_NULL(analyzer_ptr)->SyntaxTree(); | |
| { | |
| const auto status = analyzer_ptr->LexStatus(); | |
| ASSERT_TRUE(status.ok()) << status.message(); | |
| } | |
| { | |
| const auto status = analyzer_ptr->ParseStatus(); | |
| ASSERT_TRUE(status.ok()) << status.message(); | |
| } | |
| const std::vector<TreeSearchMatch> refs( | |
| FindAllReferenceFullExpressions(*ABSL_DIE_IF_NULL(node))); | |
| for (const auto& ref : refs) { | |
| VLOG(1) << "match: " << verible::StringSpanOfSymbol(*ref.match); | |
| EXPECT_FALSE(ReferenceIsSimpleIdentifier(*ref.match)) | |
| << "reference: " << code; | |
| } | |
| } | |
| } | |
| } // namespace | |
| } // namespace verilog |