Repository: MarketSquare/robotframework-robocop
Pull request #1019 (2023-12-26 09:16:13)

Fix after RF 7 [Return] model changes

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/MarketSquare/robotframework-robocop/pull/1019?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MarketSquare) Report
Attention: `1 lines` in your changes are missing coverage. Please review.
> Comparison is base [(`03e2704`)](https://app.codecov.io/gh/MarketSquare/robotframework-robocop/commit/03e2704ae5753d0eb5ad233ab800b889bcd73091?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MarketSquare) 96.66% compared to head [(`2e23ef9`)](https://app.codecov.io/gh/MarketSquare/robotframework-robocop/pull/1019?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MarketSquare) 96.51%.

| [Files](https://app.codecov.io/gh/MarketSquare/robotframework-robocop/pull/1019?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MarketSquare) | Patch % | Lines |
|---|---|---|
| [robocop/checkers/naming.py](https://app.codecov.io/gh/MarketSquare/robotframework-robocop/pull/1019?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MarketSquare#diff-cm9ib2NvcC9jaGVja2Vycy9uYW1pbmcucHk=) | 80.00% | [1 Missing :warning: ](https://app.codecov.io/gh/MarketSquare/robotframework-robocop/pull/1019?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MarketSquare) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #1019      +/-   ##
==========================================
- Coverage   96.66%   96.51%   -0.15%     
==========================================
  Files          37       37              
  Lines        4521     4535      +14     
==========================================
+ Hits         4370     4377       +7     
- Misses        151      158       +7     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/MarketSquare/robotframework-robocop/pull/1019?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MarketSquare).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MarketSquare).


Patch:
diff --git a/docs/releasenotes/unreleased/fixes.2.rst b/docs/releasenotes/unreleased/fixes.2.rst
new file mode 100644
index 0000000..4a02d04
--- /dev/null
+++ b/docs/releasenotes/unreleased/fixes.2.rst
@@ -0,0 +1,12 @@
+[Return] setting deprecation
+----------------------------
+
+``[Return]`` setting is now visibly deprecated. The internal Robot Framework model also changed and several Robocop
+rules had to be updated:
+
+- W0306 ``setting-name-not-in-title-case``
+- W0319 ``deprecated-statement``
+- W0510 ``number-of-returned-values``
+- W0903 ``empty-return``
+- W0919 ``unused-argument``
+- I0920 ``unused-variable``
diff --git a/robocop/checkers/lengths.py b/robocop/checkers/lengths.py
index eda6743..832c131 100644
--- a/robocop/checkers/lengths.py
+++ b/robocop/checkers/lengths.py
@@ -572,7 +572,7 @@ class NumberOfReturnedArgsChecker(VisitorChecker):
     def visit_Return(self, node):  # noqa
         self.check_node_returns(len(node.values), node)
 
-    visit_ReturnStatement = visit_Return
+    visit_ReturnStatement = visit_ReturnSetting = visit_Return
 
     def visit_KeywordCall(self, node):  # noqa
         if not node.keyword:
diff --git a/robocop/checkers/misc.py b/robocop/checkers/misc.py
index 2504103..58d6e2d 100644
--- a/robocop/checkers/misc.py
+++ b/robocop/checkers/misc.py
@@ -21,6 +21,10 @@ try:
     from robot.api.parsing import Break, Continue, InlineIfHeader, ReturnStatement
 except ImportError:
     ReturnStatement, InlineIfHeader, Break, Continue = None, None, None, None
+try:
+    from robot.api.parsing import ReturnSetting  # RF 7.0 [Return]
+except ImportError:
+    ReturnSetting = None
 
 from robocop.checkers import VisitorChecker
 from robocop.rules import Rule, RuleParam, RuleSeverity, SeverityThreshold
@@ -595,13 +599,17 @@ class ReturnChecker(VisitorChecker):
         "empty-return",
     )
 
+    def __init__(self):
+        self.return_class = Return if ROBOT_VERSION.major < 7 else ReturnSetting
+        super().__init__()
+
     def visit_Keyword(self, node):  # noqa
         return_setting_node = None
         keyword_after_return = False
         return_from = False
         error = ""
         for child in node.body:
-            if isinstance(child, Return):
+            if isinstance(child, self.return_class):
                 return_setting_node = child
                 error = (
                     "[Return] is not defined at the end of keyword. "
@@ -645,11 +653,15 @@ class UnreachableCodeChecker(VisitorChecker):
 
     reports = ("unreachable-code",)
 
+    def __init__(self):
+        self.return_class = ReturnStatement if ROBOT_VERSION.major < 7 else Return
+        super().__init__()
+
     def visit_Keyword(self, node):  # noqa
         statement_node = None
 
         for child in node.body:
-            if ReturnStatement and isinstance(child, (ReturnStatement, Break, Continue)):  # type: ignore[arg-type]
+            if isinstance(child, (self.return_class, Break, Continue)):
                 statement_node = child
             elif not isinstance(child, (EmptyLine, Comment, Teardown)):
                 if statement_node is not None:
@@ -1211,7 +1223,7 @@ class UnusedVariablesChecker(VisitorChecker):
         for token in node.get_tokens(Token.ARGUMENT):
             self.find_not_nested_variable(token.value, is_var=False)
 
-    visit_ReturnStatement = visit_Teardown = visit_Timeout = visit_Return
+    visit_ReturnStatement = visit_ReturnSetting = visit_Teardown = visit_Timeout = visit_Return
 
     def visit_TemplateArguments(self, node):  # noqa
         for argument in node.data_tokens:
diff --git a/robocop/checkers/naming.py b/robocop/checkers/naming.py
index 44ab586..c9b5d25 100644
--- a/robocop/checkers/naming.py
+++ b/robocop/checkers/naming.py
@@ -839,7 +839,9 @@ class SettingsNamingChecker(VisitorChecker):
         visit_ResourceImport
     ) = (
         visit_VariablesImport
-    ) = visit_Documentation = visit_Tags = visit_Timeout = visit_Template = visit_Arguments = visit_Return = visit_Setup
+    ) = (
+        visit_Documentation
+    ) = visit_Tags = visit_Timeout = visit_Template = visit_Arguments = visit_ReturnSetting = visit_Return = visit_Setup
 
     def visit_LibraryImport(self, node):  # noqa
         self.check_setting_name(node.data_tokens[0].value, node)
@@ -1275,8 +1277,14 @@ class DeprecatedStatementChecker(VisitorChecker):
 
     def visit_Return(self, node):  # noqa
         """For RETURN use visit_ReturnStatement - visit_Return will most likely visit RETURN in the future"""
-        if ROBOT_VERSION.major < 5:
+        if ROBOT_VERSION.major not in (5, 6):
             return
+        self.check_deprecated_return(node)
+
+    def visit_ReturnSetting(self, node):  # noqa
+        self.check_deprecated_return(node)
+
+    def check_deprecated_return(self, node):
         self.report(
             "deprecated-statement",
             statement_name="[Return]",


Test patch:
diff --git a/tests/atest/rules/naming/deprecated_statement/expected_output_force_tags.txt b/tests/atest/rules/naming/deprecated_statement/expected_output_force_tags.txt
new file mode 100644
index 0000000..5bc3fc9
--- /dev/null
+++ b/tests/atest/rules/naming/deprecated_statement/expected_output_force_tags.txt
@@ -0,0 +1,1 @@
+force_tags.robot:2:1 [W] 0319 'Force Tags' is deprecated since Robot Framework version 6.0, use 'Test Tags' instead
\ No newline at end of file
diff --git a/tests/atest/rules/naming/deprecated_statement/expected_output_rf5.txt b/tests/atest/rules/naming/deprecated_statement/expected_output_rf5.txt
index 37b2d2a..d8cb082 100644
--- a/tests/atest/rules/naming/deprecated_statement/expected_output_rf5.txt
+++ b/tests/atest/rules/naming/deprecated_statement/expected_output_rf5.txt
@@ -1,6 +1,5 @@
 test.robot:2:14 [W] 0319 'Run Keyword If' is deprecated since Robot Framework version 5.*, use 'IF' instead
 test.robot:3:17 [W] 0319 'Run Keyword If' is deprecated since Robot Framework version 5.*, use 'IF' instead
-test.robot:4:1 [W] 0319 'Force Tags' is deprecated since Robot Framework version 6.0, use 'Test Tags' instead
 test.robot:6:13 [W] 0319 'Run Keyword If' is deprecated since Robot Framework version 5.*, use 'IF' instead
 test.robot:7:16 [W] 0319 'Run Keyword If' is deprecated since Robot Framework version 5.*, use 'IF' instead
 test.robot:11:14 [W] 0319 'Run Keyword Unless' is deprecated since Robot Framework version 5.*, use 'IF' instead
diff --git a/tests/atest/rules/naming/deprecated_statement/expected_output_rf6.txt b/tests/atest/rules/naming/deprecated_statement/expected_output_rf6.txt
index 5bc3fc9..37b2d2a 100644
--- a/tests/atest/rules/naming/deprecated_statement/expected_output_rf6.txt
+++ b/tests/atest/rules/naming/deprecated_statement/expected_output_rf6.txt
@@ -1,1 +1,19 @@
-force_tags.robot:2:1 [W] 0319 'Force Tags' is deprecated since Robot Framework version 6.0, use 'Test Tags' instead
\ No newline at end of file
+test.robot:2:14 [W] 0319 'Run Keyword If' is deprecated since Robot Framework version 5.*, use 'IF' instead
+test.robot:3:17 [W] 0319 'Run Keyword If' is deprecated since Robot Framework version 5.*, use 'IF' instead
+test.robot:4:1 [W] 0319 'Force Tags' is deprecated since Robot Framework version 6.0, use 'Test Tags' instead
+test.robot:6:13 [W] 0319 'Run Keyword If' is deprecated since Robot Framework version 5.*, use 'IF' instead
+test.robot:7:16 [W] 0319 'Run Keyword If' is deprecated since Robot Framework version 5.*, use 'IF' instead
+test.robot:11:14 [W] 0319 'Run Keyword Unless' is deprecated since Robot Framework version 5.*, use 'IF' instead
+test.robot:12:17 [W] 0319 'Run Keyword Unless' is deprecated since Robot Framework version 5.*, use 'IF' instead
+test.robot:13:5 [W] 0319 'Run Keyword Unless' is deprecated since Robot Framework version 5.*, use 'IF' instead
+test.robot:14:5 [W] 0319 'Run Keyword If' is deprecated since Robot Framework version 5.*, use 'IF' instead
+test.robot:15:5 [W] 0319 'run_keyword_unless' is deprecated since Robot Framework version 5.*, use 'IF' instead
+test.robot:16:5 [W] 0319 'builtin.run_KeywoRD_UNLESS' is deprecated since Robot Framework version 5.*, use 'IF' instead
+test.robot:17:5 [W] 0319 'BuiltIn.Run Keyword Unless' is deprecated since Robot Framework version 5.*, use 'IF' instead
+test.robot:23:13 [W] 0319 'Continue For Loop' is deprecated since Robot Framework version 5.*, use 'CONTINUE' instead
+test.robot:24:13 [W] 0319 'Continue For Loop If' is deprecated since Robot Framework version 5.*, use 'IF and CONTINUE' instead
+test.robot:25:13 [W] 0319 'Exit For Loop If' is deprecated since Robot Framework version 5.*, use 'IF and BREAK' instead
+test.robot:26:13 [W] 0319 'BuiltIn.Exit For Loop' is deprecated since Robot Framework version 5.*, use 'BREAK' instead
+test.robot:31:5 [W] 0319 'Return From Keyword If' is deprecated since Robot Framework version 5.*, use 'IF and RETURN' instead
+test.robot:32:5 [W] 0319 'BuiltIn.Return From Keyword' is deprecated since Robot Framework version 5.*, use 'RETURN' instead
+test.robot:34:5 [W] 0319 '[Return]' is deprecated since Robot Framework version 5.*, use 'RETURN' instead
\ No newline at end of file
diff --git a/tests/atest/rules/naming/deprecated_statement/test_rule.py b/tests/atest/rules/naming/deprecated_statement/test_rule.py
index 3a0f8ee..a45b4ca 100644
--- a/tests/atest/rules/naming/deprecated_statement/test_rule.py
+++ b/tests/atest/rules/naming/deprecated_statement/test_rule.py
@@ -3,10 +3,15 @@ from tests.atest.utils import RuleAcceptance
 
 class TestRuleAcceptance(RuleAcceptance):
     def test_rule(self):
-        self.check_rule(src_files=["test.robot"], expected_file="expected_output_rf5.txt", target_version="==5.0")
+        self.check_rule(src_files=["test.robot"], expected_file="expected_output_rf6.txt", target_version=">=6")
+
+    def test_rule_rf5(self):
+        self.check_rule(src_files=["test.robot"], expected_file="expected_output_rf5.txt", target_version="==5.*")
 
     def test_pre_rf5(self):
         self.check_rule(src_files=["test.robot"], expected_file=None, target_version="<5.0")
 
     def test_force_tags(self):
-        self.check_rule(src_files=["force_tags.robot"], expected_file="expected_output_rf6.txt", target_version=">=6")
+        self.check_rule(
+            src_files=["force_tags.robot"], expected_file="expected_output_force_tags.txt", target_version=">=6"
+        )
diff --git a/tests/atest/rules/naming/setting_name_not_in_title_case/test.robot b/tests/atest/rules/naming/setting_name_not_in_title_case/test.robot
index dc384b5..1286a4e 100644
--- a/tests/atest/rules/naming/setting_name_not_in_title_case/test.robot
+++ b/tests/atest/rules/naming/setting_name_not_in_title_case/test.robot
@@ -82,3 +82,6 @@ Keyword Uppercase Settings
     Fail
     [TEARDOWN]  Teardown
     [RETURN]  value
+
+New Return
+    RETURN
diff --git a/tests/rf_versions_matrix/requirements_rf7.txt b/tests/rf_versions_matrix/requirements_rf7.txt
index 9537b90..982d99d 100644
--- a/tests/rf_versions_matrix/requirements_rf7.txt
+++ b/tests/rf_versions_matrix/requirements_rf7.txt
@@ -1,1 +1,1 @@
-robotframework==7.0a1
\ No newline at end of file
+robotframework==7.0rc1
\ No newline at end of file