| // 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/context_functions.h" |
| |
| #include "gtest/gtest.h" |
| #include "common/text/concrete_syntax_tree.h" |
| #include "common/text/symbol.h" |
| #include "common/text/syntax_tree_context.h" |
| #include "common/text/tree_builder_test_util.h" |
| #include "common/util/casts.h" |
| #include "verilog/CST/verilog_nonterminals.h" |
| |
| namespace verilog { |
| namespace analysis { |
| namespace { |
| |
| using verible::down_cast; |
| using verible::SymbolPtr; |
| using verible::SyntaxTreeContext; |
| using verible::SyntaxTreeNode; |
| using verible::TNode; |
| |
| const SyntaxTreeNode& CastAsNode(const SymbolPtr& p) { |
| return down_cast<const SyntaxTreeNode&>(*p.get()); |
| } |
| |
| // Test that empty context is handled correctly. |
| TEST(ContextIsInsideClassTest, EmptyContext) { |
| SyntaxTreeContext empty_context; |
| EXPECT_FALSE(ContextIsInsideClass(empty_context)); |
| } |
| |
| // Test that matching context node tag is detected. |
| TEST(ContextIsInsideClassTest, ClassContextOnly) { |
| const auto class_node = TNode(NodeEnum::kClassDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop(&context, &CastAsNode(class_node)); |
| EXPECT_TRUE(ContextIsInsideClass(context)); |
| } |
| |
| // Test that non-matching context node tag is not detected. |
| TEST(ContextIsInsideClassTest, ModuleContextOnly) { |
| const auto module_node = TNode(NodeEnum::kModuleDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop(&context, &CastAsNode(module_node)); |
| EXPECT_FALSE(ContextIsInsideClass(context)); |
| } |
| |
| // Test that matching context ignores inner context. |
| TEST(ContextIsInsideClassTest, OtherInsideClass) { |
| const auto class_node = TNode(NodeEnum::kClassDeclaration); |
| const auto module_node = TNode(NodeEnum::kModuleDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop1(&context, &CastAsNode(class_node)); |
| SyntaxTreeContext::AutoPop pop2(&context, &CastAsNode(module_node)); |
| EXPECT_TRUE(ContextIsInsideClass(context)); |
| } |
| |
| // Test that matching inner context works. |
| TEST(ContextIsInsideClassTest, ClassInsideOther) { |
| const auto class_node = TNode(NodeEnum::kClassDeclaration); |
| const auto module_node = TNode(NodeEnum::kModuleDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop1(&context, &CastAsNode(module_node)); |
| SyntaxTreeContext::AutoPop pop2(&context, &CastAsNode(class_node)); |
| EXPECT_TRUE(ContextIsInsideClass(context)); |
| } |
| |
| // Test that non-matching context node tag is not detected. |
| TEST(ContextIsInsideModuleTest, ClassContextOnly) { |
| const auto class_node = TNode(NodeEnum::kClassDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop(&context, &CastAsNode(class_node)); |
| EXPECT_FALSE(ContextIsInsideModule(context)); |
| } |
| |
| // Test that matching context node tag is detected. |
| TEST(ContextIsInsideModuleTest, ModuleContextOnly) { |
| const auto module_node = TNode(NodeEnum::kModuleDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop(&context, &CastAsNode(module_node)); |
| EXPECT_TRUE(ContextIsInsideModule(context)); |
| } |
| |
| // Test that matching context ignores inner context. |
| TEST(ContextIsInsideModuleTest, OtherInsideModule) { |
| const auto class_node = TNode(NodeEnum::kClassDeclaration); |
| const auto module_node = TNode(NodeEnum::kModuleDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop1(&context, &CastAsNode(class_node)); |
| SyntaxTreeContext::AutoPop pop2(&context, &CastAsNode(module_node)); |
| EXPECT_TRUE(ContextIsInsideModule(context)); |
| } |
| |
| // Test that matching inner context works. |
| TEST(ContextIsInsideModuleTest, ModuleInsideOther) { |
| const auto class_node = TNode(NodeEnum::kClassDeclaration); |
| const auto module_node = TNode(NodeEnum::kModuleDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop1(&context, &CastAsNode(module_node)); |
| SyntaxTreeContext::AutoPop pop2(&context, &CastAsNode(class_node)); |
| EXPECT_TRUE(ContextIsInsideModule(context)); |
| } |
| |
| // Test that packed dimensions are found in context. |
| TEST(ContextIsInsidePackedDimensionsTest, PackedNotUnpacked) { |
| const auto data_node = TNode(NodeEnum::kDataDeclaration); |
| const auto dimensions_node = TNode(NodeEnum::kPackedDimensions); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop1(&context, &CastAsNode(data_node)); |
| SyntaxTreeContext::AutoPop pop2(&context, &CastAsNode(dimensions_node)); |
| EXPECT_TRUE(ContextIsInsidePackedDimensions(context)); |
| EXPECT_FALSE(ContextIsInsideUnpackedDimensions(context)); |
| } |
| |
| // Test that unpacked dimensions are found in context. |
| TEST(ContextIsInsidePackedDimensionsTest, UnpackedNotPacked) { |
| const auto data_node = TNode(NodeEnum::kDataDeclaration); |
| const auto dimensions_node = TNode(NodeEnum::kUnpackedDimensions); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop1(&context, &CastAsNode(data_node)); |
| SyntaxTreeContext::AutoPop pop2(&context, &CastAsNode(dimensions_node)); |
| EXPECT_TRUE(ContextIsInsideUnpackedDimensions(context)); |
| EXPECT_FALSE(ContextIsInsidePackedDimensions(context)); |
| } |
| |
| // Test that non-matching context node tag is not detected. |
| TEST(ContextIsInsidePackageTest, ClassContextOnly) { |
| const auto class_node = TNode(NodeEnum::kClassDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop(&context, &CastAsNode(class_node)); |
| EXPECT_FALSE(ContextIsInsidePackage(context)); |
| } |
| |
| // Test that matching context node tag is detected. |
| TEST(ContextIsInsidePackageTest, PackageContextOnly) { |
| const auto package_node = TNode(NodeEnum::kPackageDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop(&context, &CastAsNode(package_node)); |
| EXPECT_TRUE(ContextIsInsidePackage(context)); |
| } |
| |
| // Test that matching context ignores inner context. |
| TEST(ContextIsInsidePackageTest, OtherInsidePackage) { |
| const auto package_node = TNode(NodeEnum::kPackageDeclaration); |
| const auto module_node = TNode(NodeEnum::kModuleDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop1(&context, &CastAsNode(package_node)); |
| SyntaxTreeContext::AutoPop pop2(&context, &CastAsNode(module_node)); |
| EXPECT_TRUE(ContextIsInsidePackage(context)); |
| } |
| |
| // Test that matching inner context works. |
| TEST(ContextIsInsidePackageTest, PackageInsideOther) { |
| const auto package_node = TNode(NodeEnum::kPackageDeclaration); |
| const auto module_node = TNode(NodeEnum::kModuleDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop1(&context, &CastAsNode(module_node)); |
| SyntaxTreeContext::AutoPop pop2(&context, &CastAsNode(package_node)); |
| EXPECT_TRUE(ContextIsInsidePackage(context)); |
| } |
| |
| // Test that non-matching context node tag is not detected. |
| TEST(ContextIsInsideFormalParameterListTest, NotAContext) { |
| const auto package_node = TNode(NodeEnum::kPackageDeclaration); |
| const auto parameter_node = TNode(NodeEnum::kParamDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop1(&context, &CastAsNode(package_node)); |
| SyntaxTreeContext::AutoPop pop2(&context, &CastAsNode(parameter_node)); |
| EXPECT_FALSE(ContextIsInsideFormalParameterList(context)); |
| } |
| |
| // Test that matching context node tag is detected. |
| TEST(ContextIsInsideFormalParameterListTest, FormalContext) { |
| const auto module_node = TNode(NodeEnum::kModuleDeclaration); |
| const auto formal_param_node = TNode(NodeEnum::kFormalParameterList); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop1(&context, &CastAsNode(module_node)); |
| SyntaxTreeContext::AutoPop pop2(&context, &CastAsNode(formal_param_node)); |
| EXPECT_TRUE(ContextIsInsideFormalParameterList(context)); |
| } |
| |
| // Testing that the matching context node tag is detected. |
| TEST(ContextIsInsideTaskFunctionPortListTest, PortListInsideFunction) { |
| const auto port_list_node = TNode(NodeEnum::kPortList); |
| const auto function_node = TNode(NodeEnum::kFunctionDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop1(&context, &CastAsNode(function_node)); |
| EXPECT_FALSE(ContextIsInsideTaskFunctionPortList(context)); |
| SyntaxTreeContext::AutoPop pop2(&context, &CastAsNode(port_list_node)); |
| EXPECT_TRUE(ContextIsInsideTaskFunctionPortList(context)); |
| } |
| |
| // Testing that the matching context node tag is detected. |
| TEST(ContextIsInsideTaskFunctionPortListTest, PortListInsideTask) { |
| const auto port_list_node = TNode(NodeEnum::kPortList); |
| const auto task_node = TNode(NodeEnum::kTaskDeclaration); |
| SyntaxTreeContext context; |
| SyntaxTreeContext::AutoPop pop1(&context, &CastAsNode(task_node)); |
| EXPECT_FALSE(ContextIsInsideTaskFunctionPortList(context)); |
| SyntaxTreeContext::AutoPop pop2(&context, &CastAsNode(port_list_node)); |
| EXPECT_TRUE(ContextIsInsideTaskFunctionPortList(context)); |
| } |
| |
| } // namespace |
| } // namespace analysis |
| } // namespace verilog |