Skip to content

Commit

Permalink
Add: Add Plugin for variable redefinition in foreach loop
Browse files Browse the repository at this point in the history
  • Loading branch information
NiklasHargarter authored and mbrinkhoff committed Jun 11, 2024
1 parent 9a169db commit 3e99fba
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 0 deletions.
55 changes: 55 additions & 0 deletions tests/plugins/test_variable_redefinition_in_foreach.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2024 Greenbone AG

from pathlib import Path

from tests.plugins import PluginTestCase
from troubadix.plugin import LinterWarning
from troubadix.plugins.variable_redefinition_in_foreach import (
CheckVariableRedefinitionInForeach,
)


class CheckVariableRedefinitionInForeachTestCase(PluginTestCase):
def test_ok(self):
nasl_file = Path(__file__).parent / "test.nasl"
content = (
"urls = ['foo', 'bar']\n"
"foreach url ( urls ) {}\n"
"url1 = 'foo'\n"
"foreach url(make_list(url1,'bar'))"
)
fake_context = self.create_file_plugin_context(
nasl_file=nasl_file, file_content=content
)
plugin = CheckVariableRedefinitionInForeach(fake_context)
results = list(plugin.run())

self.assertEqual(len(results), 0)

def test_fail(self):
nasl_file = Path(__file__).parent / "test.nasl"
content = (
"url1 = 'foo'\n"
"foreach url ( url ) {}\n"
"foreach url(make_list(url1,url)) {}\n"
)
fake_context = self.create_file_plugin_context(
nasl_file=nasl_file, file_content=content
)
plugin = CheckVariableRedefinitionInForeach(fake_context)
results = list(plugin.run())
self.assertEqual(len(results), 2)
self.assertIsInstance(results[0], LinterWarning)
self.assertEqual(
"The variable 'url' is redefined "
"by being the identifier\nand the iterator in the"
" same foreach loop 'foreach url ( url )'",
results[0].message,
)
self.assertEqual(
"The variable 'url' is used as identifier and\n"
"as part of the iterator in the"
" same foreach loop\n'foreach url(make_list(url1,url))'",
results[1].message,
)
4 changes: 4 additions & 0 deletions troubadix/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
from troubadix.plugin import FilePlugin, FilesPlugin, Plugin
from troubadix.plugins.multiple_re_parameters import CheckMultipleReParameters
from troubadix.plugins.spaces_in_filename import CheckSpacesInFilename
from troubadix.plugins.variable_redefinition_in_foreach import (
CheckVariableRedefinitionInForeach,
)

from .badwords import CheckBadwords
from .copyright_text import CheckCopyrightText
Expand Down Expand Up @@ -138,6 +141,7 @@
CheckOverlongDescriptionLines,
CheckSpacesInFilename,
CheckMultipleReParameters,
CheckVariableRedefinitionInForeach,
]

# plugins checking all files
Expand Down
53 changes: 53 additions & 0 deletions troubadix/plugins/variable_redefinition_in_foreach.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2024 Greenbone AG

import re
from pathlib import Path
from typing import Iterator

from troubadix.plugin import FileContentPlugin, LinterResult, LinterWarning

foreach_pattern = re.compile(r"foreach\s+(\w+)\s*\((.+)\)")
make_list_pattern = re.compile(r"^(?:make_list|make_list_unique)\((.+)\)$")


class CheckVariableRedefinitionInForeach(FileContentPlugin):
name = "check_variable_redefinition_in_foreach"

def check_content(
self, nasl_file: Path, file_content: str
) -> Iterator[LinterResult]:
"""This plugin checks for a redefinition of the variable
that is passed to the foreach loop.
This can be caused by using same variable name
for both the list and the element being iterated over.
Incorrect uses of foreach loops that are covered by this plugin are:
foreach foo(foo){}
foreach foo(make_list(bar,foo)){}
foreach foo(make_list_unique(bar,foo)){}
"""

for foreach_match in foreach_pattern.finditer(file_content):
identifier = foreach_match.group(1)
iterator = foreach_match.group(2).replace(" ", "")

if make_list_match := make_list_pattern.fullmatch(iterator):
make_list_params = make_list_match.group(1).split(",")
if identifier in make_list_params:
yield LinterWarning(
f"The variable '{foreach_match.group(1)}' "
f"is used as identifier and\n"
f"as part of the iterator in the"
f" same foreach loop\n'{foreach_match.group()}'",
plugin=self.name,
file=nasl_file,
)
else:
if identifier == iterator:
yield LinterWarning(
f"The variable '{foreach_match.group(1)}' is redefined "
f"by being the identifier\nand the iterator in the"
f" same foreach loop '{foreach_match.group()}'",
plugin=self.name,
file=nasl_file,
)

0 comments on commit 3e99fba

Please sign in to comment.