-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add: Add Plugin for variable redefinition in foreach loop
- Loading branch information
1 parent
9a169db
commit 3e99fba
Showing
3 changed files
with
112 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
) |