diff --git a/docs/configuring.rst b/docs/configuring.rst index 631c4905b..5ace76411 100644 --- a/docs/configuring.rst +++ b/docs/configuring.rst @@ -19,6 +19,7 @@ Configuring configuring_indent_rules.rst configuring_keyword_alignment_rules.rst configuring_length_rules.rst + configuring_library_and_package_name_restriction_rules.rst configuring_move_token_rules.rst configuring_multiline_assert_rule.rst configuring_multiline_constraint_rules.rst diff --git a/docs/configuring_disabled_rules.rst b/docs/configuring_disabled_rules.rst index e68500cfd..b13647e83 100644 --- a/docs/configuring_disabled_rules.rst +++ b/docs/configuring_disabled_rules.rst @@ -59,10 +59,9 @@ Rules Disabled by Default * `generic_map_601 `_ * `instantiation_600 `_ * `instantiation_601 `_ - * `interface_incomplete_type_declaration_600 <../interface_incomplete_type_declaration_rules.html#interface-incomplete-type-declaration-600>`_ * `interface_incomplete_type_declaration_601 <../interface_incomplete_type_declaration_rules.html#interface-incomplete-type-declaration-601>`_ - +* `library_012 `_ * `loop_statement_006 `_ * `loop_statement_007 `_ * `loop_statement_600 `_ @@ -102,6 +101,7 @@ Rules Disabled by Default * `type_100 `_ * `type_200 `_ * `type_600 `_ +* `use_clause_001 `_ * `variable_012 `_ * `variable_100 `_ * `variable_600 `_ diff --git a/docs/configuring_library_and_package_name_restriction_rules.rst b/docs/configuring_library_and_package_name_restriction_rules.rst new file mode 100644 index 000000000..487cd89e9 --- /dev/null +++ b/docs/configuring_library_and_package_name_restriction_rules.rst @@ -0,0 +1,70 @@ + +.. _configuring-library-and-package-name-restriction-rules: + +Configuring Library and Package Name Restriction Rules +------------------------------------------------------ + +There are rules which will check for invalid package names in library and use clauses. +These rules are disabled by default and must be enabled before they will perform any checks. + +There is one option for these rules: + +.. |names| replace:: + :code:`names` + +.. |default| replace:: + :code:`std_logic_arith` for **use_clause_001**. None for **library_012** + +.. |values__names| replace:: + List of strings + +.. |action__names| replace:: + Search for libraries and packages with the user defined names + ++--------------------------------------+-----------------+-----------+------------------------------------------------+ +| Option | Values | Default | Description | ++======================================+=================+===========+================================================+ +| |names| | |values__names| | |default| | * |action__names| | ++--------------------------------------+-----------------+-----------+------------------------------------------------+ + +This is an example of how to configure the option. + +.. code-block:: yaml + + rule : + library_012: + names: + - "work" + - "std_logic_arith" + +.. NOTE:: All examples below are using the rule **use_clause_001**. + +Example: |names| set to list ["std_logic_arith"] +################################################ + +The following code would fail with this option: + +.. code-Block:: vhdl + + library ieee; + use ieee.std_logic_arith.all; + +Example: |names| set to ["std_logic_arith", "my_package"] +############################################## + +The following code would fail three times with this option: + +.. code-block:: vhdl + + library ieee; + use ieee.std_logic_arith.all; + + library work; + use work.my_package.all; + + +Rules Enforcing Valid Names +########################### + +* `library_012 `_ +* `use_clause_001 `_ diff --git a/docs/library_rules.rst b/docs/library_rules.rst index b450f3b81..ccdb29f3b 100644 --- a/docs/library_rules.rst +++ b/docs/library_rules.rst @@ -275,6 +275,23 @@ This rule checks the **use** keyword is on its own line. context c1 is library ieee; use ieee.std_logic_1164.all; end context c1; +library_012 +########### + +|phase_7| |disabled| |error| |unfixable| |naming| + +This rule checks for libraries that have been restricted by the user. + +|configuring_library_and_package_name_restriction_rules_link| + +.. NOTE:: This rule is disabled by default. + +**Violation** + +.. code-block:: vhdl + + library bad_lib; + library_500 ########### diff --git a/docs/links.rst b/docs/links.rst index 73dea7f22..a69ca489a 100644 --- a/docs/links.rst +++ b/docs/links.rst @@ -100,3 +100,6 @@ .. |configuring_comment_indenting_link| replace:: Refer to :ref:`configuring-comment-indenting` for configuration options. + +.. |configuring_library_and_package_name_restriction_rules_link| replace:: + Refer to :ref:`configuring-library-and-package-name-restriction-rules` for configuration options. diff --git a/docs/rule_groups/naming_rule_group.rst b/docs/rule_groups/naming_rule_group.rst index 246ecd632..3d486c056 100644 --- a/docs/rule_groups/naming_rule_group.rst +++ b/docs/rule_groups/naming_rule_group.rst @@ -24,10 +24,9 @@ Rules Enforcing Naming Rule Group * `generic_map_601 <../generic_map_rules.html#generic-map-601>`_ * `instantiation_600 <../instantiation_rules.html#instantiation-600>`_ * `instantiation_601 <../instantiation_rules.html#instantiation-601>`_ - * `interface_incomplete_type_declaration_600 <../interface_incomplete_type_declaration_rules.html#interface-incomplete-type-declaration-600>`_ * `interface_incomplete_type_declaration_601 <../interface_incomplete_type_declaration_rules.html#interface-incomplete-type-declaration-601>`_ - +* `library_012 <../library_rules.html#library-012>`_ * `loop_statement_600 <../loop_statement_rules.html#loop-statement-600>`_ * `loop_statement_601 <../loop_statement_rules.html#loop-statement-601>`_ * `loop_statement_602 <../loop_statement_rules.html#loop-statement-602>`_ @@ -58,5 +57,6 @@ Rules Enforcing Naming Rule Group * `subtype_600 <../subtype_rules.html#subtype-600>`_ * `type_015 <../type_rules.html#type-015>`_ * `type_600 <../type_rules.html#type-600>`_ +* `use_clause_001 <../use_clause_rules.html#use-clause-001>`_ * `variable_012 <../variable_rules.html#variable-012>`_ * `variable_600 <../variable_rules.html#variable-600>`_ diff --git a/docs/unfixable_rules.rst b/docs/unfixable_rules.rst index 16390e1fc..037d2b1fb 100644 --- a/docs/unfixable_rules.rst +++ b/docs/unfixable_rules.rst @@ -55,6 +55,8 @@ With multiple options available, the user is required to make the decision. * `architecture_025 `_ * `instantiation_036 `_ +* `library_012 <../library_rules.html#library-012>`_ +* `use_clause_001 <../use_clause_rules.html#use-clause-001>`_ Lengths ------- @@ -104,10 +106,8 @@ With multiple options available, the user is required to make the decision. * `generic_map_601 `_ * `instantiation_600 `_ * `instantiation_601 `_ - * `interface_incomplete_type_declaration_600 <../interface_incomplete_type_declaration_rules.html#interface-incomplete-type-declaration-600>`_ * `interface_incomplete_type_declaration_601 <../interface_incomplete_type_declaration_rules.html#interface-incomplete-type-declaration-601>`_ - * `loop_statement_600 `_ * `loop_statement_601 `_ * `loop_statement_602 `_ diff --git a/docs/use_clause_rules.rst b/docs/use_clause_rules.rst index 30eebb2ce..03d1fece8 100644 --- a/docs/use_clause_rules.rst +++ b/docs/use_clause_rules.rst @@ -3,6 +3,25 @@ Use Clause Rules ---------------- +use_clause_001 +############## + +|phase_7| |disabled| |error| |unfixable| |naming| + +This rule checks for packages that have been restricted by the user. + +|configuring_library_and_package_name_restriction_rules_link| + +.. NOTE:: This rule is disabled by default. + +.. NOTE:: This rule is configured to restrict the std_logic_arith package by default. + +**Violation** + +.. code-block:: vhdl + + use ieee.std_logic_arith.all; + use_clause_500 ############## diff --git a/tests/library/rule_012_test_input.vhd b/tests/library/rule_012_test_input.vhd new file mode 100644 index 000000000..171b49429 --- /dev/null +++ b/tests/library/rule_012_test_input.vhd @@ -0,0 +1,5 @@ + +library ieee; +library work; +library std; +library bad_lib; diff --git a/tests/library/test_rule_012.py b/tests/library/test_rule_012.py new file mode 100644 index 000000000..3cbc220eb --- /dev/null +++ b/tests/library/test_rule_012.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- + +import os +import unittest + +from tests import utils +from vsg import vhdlFile +from vsg.rules import library + +sTestDir = os.path.dirname(__file__) + +lFile, eError = vhdlFile.utils.read_vhdlfile(os.path.join(sTestDir, "rule_012_test_input.vhd")) + + +class test_rule(unittest.TestCase): + def setUp(self): + self.oFile = vhdlFile.vhdlFile(lFile) + self.assertIsNone(eError) + + def test_rule_012(self): + oRule = library.rule_012() + self.assertTrue(oRule) + self.assertEqual(oRule.name, "library") + self.assertEqual(oRule.identifier, "012") + self.assertFalse(oRule.fixable) + self.assertTrue(oRule.disable) + self.assertEqual(oRule.groups, ["naming"]) + + lExpected = [] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Library name is on list of restricted names: ", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = [] + oRule.names.append("ieee") + lExpected = [2] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Library name is on list of restricted names: ieee", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = ["work"] + lExpected = [3] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Library name is on list of restricted names: work", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = ["std"] + lExpected = [4] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Library name is on list of restricted names: std", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = ["bad_lib"] + lExpected = [5] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Library name is on list of restricted names: bad_lib", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = ["ieee", "bad_lib"] + lExpected = [2, 5] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Library name is on list of restricted names: ieee, bad_lib", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = ["ieee", "work", "std"] + lExpected = [2, 3, 4] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Library name is on list of restricted names: ieee, work, std", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = ["ieee", "work", "std", "bad_lib"] + lExpected = [2, 3, 4, 5] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Library name is on list of restricted names: ieee, work, std, bad_lib", oRule._get_solution(None)) diff --git a/tests/use_clause/rule_001_test_input.vhd b/tests/use_clause/rule_001_test_input.vhd new file mode 100644 index 000000000..54937ba90 --- /dev/null +++ b/tests/use_clause/rule_001_test_input.vhd @@ -0,0 +1,10 @@ + +library ieee; + use ieee.std_logic_arith.all; + use ieee.std_logic_1164.std_logic; + +library std; + use std.env.all; + +library bad_lib; + use bad_lib.bad_pkg.bad_obj; diff --git a/tests/use_clause/test_rule_001.py b/tests/use_clause/test_rule_001.py new file mode 100644 index 000000000..db246709a --- /dev/null +++ b/tests/use_clause/test_rule_001.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- + +import os +import unittest + +from tests import utils +from vsg import vhdlFile +from vsg.rules import use_clause + +sTestDir = os.path.dirname(__file__) + +lFile, eError = vhdlFile.utils.read_vhdlfile(os.path.join(sTestDir, "rule_001_test_input.vhd")) + + +class test_rule(unittest.TestCase): + def setUp(self): + self.oFile = vhdlFile.vhdlFile(lFile) + self.assertIsNone(eError) + + def test_rule_001(self): + oRule = use_clause.rule_001() + self.assertTrue(oRule) + self.assertEqual(oRule.names, ["std_logic_arith"]) + self.assertEqual(oRule.name, "use_clause") + self.assertEqual(oRule.identifier, "001") + self.assertFalse(oRule.fixable) + self.assertTrue(oRule.disable) + self.assertEqual(oRule.groups, ["naming"]) + + lExpected = [] + oRule.names = [] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Package name is on list of restricted names: ", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = [] + oRule.names.append("std_logic_arith") + lExpected = [3] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Package name is on list of restricted names: std_logic_arith", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = ["std_logic_1164"] + lExpected = [4] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Package name is on list of restricted names: std_logic_1164", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = ["env"] + lExpected = [7] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Package name is on list of restricted names: env", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = ["bad_pkg"] + lExpected = [10] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Package name is on list of restricted names: bad_pkg", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = ["std_logic_arith", "bad_pkg"] + lExpected = [3, 10] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Package name is on list of restricted names: std_logic_arith, bad_pkg", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = ["std_logic_arith", "std_logic_1164", "env"] + lExpected = [3, 4, 7] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Package name is on list of restricted names: std_logic_arith, std_logic_1164, env", oRule._get_solution(None)) + + oRule.violations = [] + oRule.names = ["std_logic_arith", "std_logic_1164", "env", "bad_pkg"] + lExpected = [3, 4, 7, 10] + oRule.analyze(self.oFile) + self.assertEqual(lExpected, utils.extract_violation_lines_from_violation_object(oRule.violations)) + self.assertEqual("Package name is on list of restricted names: std_logic_arith, std_logic_1164, env, bad_pkg", oRule._get_solution(None)) diff --git a/vsg/rules/__init__.py b/vsg/rules/__init__.py index 9e53363e9..aad0a093e 100644 --- a/vsg/rules/__init__.py +++ b/vsg/rules/__init__.py @@ -32,6 +32,7 @@ from .insert_token_next_to_token_if_it_does_not_exist_between_tokens_using_value_from_token import ( insert_token_next_to_token_if_it_does_not_exist_between_tokens_using_value_from_token, ) +from .does_token_value_match_none_of import does_token_value_match_none_of from .does_token_value_match_one_of import does_token_value_match_one_of from .align_tokens_in_region_between_tokens import align_tokens_in_region_between_tokens from .align_tokens_in_region_between_tokens_unless_between_tokens import align_tokens_in_region_between_tokens_unless_between_tokens diff --git a/vsg/rules/does_token_value_match_none_of.py b/vsg/rules/does_token_value_match_none_of.py new file mode 100644 index 000000000..42b55cb12 --- /dev/null +++ b/vsg/rules/does_token_value_match_none_of.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from vsg.rules import does_token_value_match_one_of as Rule + + +class does_token_value_match_none_of(Rule.does_token_value_match_one_of): + """ + Checks if a token value matches none of provided regex patterns. + """ + + def __init__(self, oToken): + super().__init__(oToken) + + def _check_for_violation(self, sToken, lRegexNames): + return not self._token_matches_at_least_one(sToken, lRegexNames) diff --git a/vsg/rules/does_token_value_match_one_of.py b/vsg/rules/does_token_value_match_one_of.py index e23e36710..6d377e0a8 100644 --- a/vsg/rules/does_token_value_match_one_of.py +++ b/vsg/rules/does_token_value_match_one_of.py @@ -11,13 +11,13 @@ class does_token_value_match_one_of(naming.Rule): Checks if a token value matches one of provided regex patterns. """ - def __init__(self, token): + def __init__(self, oToken): super().__init__() self.names = [] self.fixable = False self.disable = True self.configuration.append("names") - self.token = token + self.token = oToken self.configuration_documentation_link = None def _get_tokens_of_interest(self, oFile): @@ -33,6 +33,9 @@ def _analyze(self, lToi): self.add_violation(violation.New(oToi.get_line_number(), oToi, self.solution)) def _check_for_violation(self, sToken, lRegexNames): + return self._token_matches_at_least_one(sToken, lRegexNames) + + def _token_matches_at_least_one(self, sToken, lRegexNames): for regex in lRegexNames: if regex.fullmatch(sToken) is not None: return False diff --git a/vsg/rules/library/__init__.py b/vsg/rules/library/__init__.py index 243c5bc98..ad8b67189 100644 --- a/vsg/rules/library/__init__.py +++ b/vsg/rules/library/__init__.py @@ -11,5 +11,6 @@ from .rule_009 import rule_009 from .rule_010 import rule_010 from .rule_011 import rule_011 +from .rule_012 import rule_012 from .rule_500 import rule_500 from .rule_600 import rule_600 diff --git a/vsg/rules/library/rule_012.py b/vsg/rules/library/rule_012.py new file mode 100644 index 000000000..880121d3f --- /dev/null +++ b/vsg/rules/library/rule_012.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +from vsg.rules import does_token_value_match_none_of +from vsg.token import logical_name_list + + +class rule_012(does_token_value_match_none_of): + """ + This rule checks for libraries that have been restricted by the user. + + |configuring_library_and_package_name_restriction_rules_link| + + .. NOTE:: This rule is disabled by default. + + **Violation** + + .. code-block:: vhdl + + library bad_lib; + """ + + def __init__(self): + super().__init__(logical_name_list.logical_name) + + def _get_solution(self, iLineNumber): + return "Library name is on list of restricted names: " + ", ".join(self.names) diff --git a/vsg/rules/use_clause/__init__.py b/vsg/rules/use_clause/__init__.py index 48b48eb1d..13a39efd6 100644 --- a/vsg/rules/use_clause/__init__.py +++ b/vsg/rules/use_clause/__init__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +from .rule_001 import rule_001 from .rule_500 import rule_500 from .rule_501 import rule_501 from .rule_502 import rule_502 diff --git a/vsg/rules/use_clause/rule_001.py b/vsg/rules/use_clause/rule_001.py new file mode 100644 index 000000000..d966227cc --- /dev/null +++ b/vsg/rules/use_clause/rule_001.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +from vsg.rules import does_token_value_match_none_of +from vsg.token import use_clause + + +class rule_001(does_token_value_match_none_of): + """ + This rule checks for packages that have been restricted by the user. + + |configuring_library_and_package_name_restriction_rules_link| + + .. NOTE:: This rule is disabled by default. + + .. NOTE:: This rule is configured to restrict the std_logic_arith package by default. + + **Violation** + + .. code-block:: vhdl + + use ieee.std_logic_arith.all; + """ + + def __init__(self): + super().__init__(use_clause.package_name) + self.names = ["std_logic_arith"] + + def _get_solution(self, iLineNumber): + return "Package name is on list of restricted names: " + ", ".join(self.names)