diff options
author | Nick Drozd <nicholasdrozd@gmail.com> | 2023-02-23 16:01:10 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-23 22:01:10 +0100 |
commit | 8f24c69d3f6f9ff19d4b867c840bc1dd560ddddb (patch) | |
tree | e4466d030b95e4189bc343a26d77b907af9ab88b | |
parent | d064010c324cb20a83928c5bae02386ea73fe8d7 (diff) | |
download | pylint-git-8f24c69d3f6f9ff19d4b867c840bc1dd560ddddb.tar.gz |
Only count obviously non-terminating while-loops as return-ended (#8292)
4 files changed, 61 insertions, 4 deletions
diff --git a/doc/whatsnew/fragments/8280.false_negative b/doc/whatsnew/fragments/8280.false_negative new file mode 100644 index 000000000..848b71d7c --- /dev/null +++ b/doc/whatsnew/fragments/8280.false_negative @@ -0,0 +1,3 @@ +Fix false negative for inconsistent-returns with while-loops. + +Closes #8280 diff --git a/pylint/checkers/refactoring/refactoring_checker.py b/pylint/checkers/refactoring/refactoring_checker.py index 0caa2fbb5..5aaedf794 100644 --- a/pylint/checkers/refactoring/refactoring_checker.py +++ b/pylint/checkers/refactoring/refactoring_checker.py @@ -20,6 +20,7 @@ from astroid.util import Uninferable from pylint import checkers from pylint.checkers import utils +from pylint.checkers.base.basic_error_checker import _loop_exits_early from pylint.checkers.utils import node_frame_class from pylint.interfaces import HIGH, INFERENCE, Confidence @@ -1945,10 +1946,12 @@ class RefactoringChecker(checkers.BaseTokenChecker): return True except astroid.InferenceError: pass - # Avoid the check inside while loop as we don't know - # if they will be completed if isinstance(node, nodes.While): - return True + # A while-loop is considered return-ended if it has a + # truthy test and no break statements + return (node.test.bool_value() and not _loop_exits_early(node)) or any( + self._is_node_return_ended(child) for child in node.orelse + ) if isinstance(node, nodes.Raise): return self._is_raise_node_return_ended(node) if isinstance(node, nodes.If): diff --git a/tests/functional/i/inconsistent/inconsistent_returns.py b/tests/functional/i/inconsistent/inconsistent_returns.py index c1183b288..4e9a68377 100644 --- a/tests/functional/i/inconsistent/inconsistent_returns.py +++ b/tests/functional/i/inconsistent/inconsistent_returns.py @@ -1,5 +1,5 @@ #pylint: disable=missing-docstring, no-else-return, no-else-break, invalid-name, unused-variable, superfluous-parens, try-except-raise -#pylint: disable=disallowed-name +#pylint: disable=disallowed-name,too-few-public-methods,no-member,useless-else-on-loop """Testing inconsistent returns""" import math import sys @@ -353,3 +353,52 @@ def bug_pylint_4019_wrong(x): # [inconsistent-return-statements] if x == 1: return 42 assert True + + +# https://github.com/PyCQA/pylint/issues/8280 +class A: + def get_the_answer(self): # [inconsistent-return-statements] + while self.is_running: + self.read_message() + if self.comunication_finished(): + return "done" + + +def bug_1772_break(): # [inconsistent-return-statements] + counter = 1 + while True: + counter += 1 + if counter == 100: + return 7 + if counter is None: + break + + +def while_break_in_for(): + counter = 1 + while True: + counter += 1 + if counter == 100: + return 7 + for i in range(10): + if i == 5: + break + + +def while_break_in_while(): + counter = 1 + while True: + counter += 1 + if counter == 100: + return 7 + while True: + if counter == 5: + break + + +def wait_for_apps_ready(event, main_thread): + while main_thread.is_alive(): + if event.wait(timeout=0.1): + return True + else: + return False diff --git a/tests/functional/i/inconsistent/inconsistent_returns.txt b/tests/functional/i/inconsistent/inconsistent_returns.txt index 8e67a83f8..125f3dec7 100644 --- a/tests/functional/i/inconsistent/inconsistent_returns.txt +++ b/tests/functional/i/inconsistent/inconsistent_returns.txt @@ -15,3 +15,5 @@ inconsistent-return-statements:267:0:267:12:bug_3468:Either all return statement inconsistent-return-statements:277:0:277:20:bug_3468_variant:Either all return statements in a function should return an expression, or none of them should.:UNDEFINED inconsistent-return-statements:322:0:322:21:bug_pylint_3873_1:Either all return statements in a function should return an expression, or none of them should.:UNDEFINED inconsistent-return-statements:349:0:349:25:bug_pylint_4019_wrong:Either all return statements in a function should return an expression, or none of them should.:UNDEFINED +inconsistent-return-statements:360:4:360:22:A.get_the_answer:Either all return statements in a function should return an expression, or none of them should.:UNDEFINED +inconsistent-return-statements:367:0:367:18:bug_1772_break:Either all return statements in a function should return an expression, or none of them should.:UNDEFINED |