From 0a39200932a9143082255e600ff5a7e764520ce8 Mon Sep 17 00:00:00 2001 From: Claudiu Popa Date: Thu, 11 Oct 2018 08:15:20 +0200 Subject: Consider ``range()`` objects for ``undefined-loop-variable`` leaking from iteration. Close #2533 --- ChangeLog | 4 ++++ pylint/checkers/format.py | 6 ++++++ pylint/checkers/variables.py | 11 ++++++++++- pylint/test/functional/cellvar_escaping_loop.py | 14 ++------------ pylint/test/functional/cellvar_escaping_loop.txt | 13 ++++++------- pylint/test/functional/undefined_loop_variable.py | 16 +++++++++++++++- pylint/test/functional/undefined_loop_variable.txt | 3 ++- 7 files changed, 45 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 962141f2f..51f34f002 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,10 @@ What's New in Pylint 2.2? Release date: TBA + * Consider ``range()`` objects for ``undefined-loop-variable`` leaking from iteration. + + Close #2533 + * ``deprecated-method`` can use the attribute name for identifying a deprecated method Previously we were using the fully qualified name, which we still do, but the fully diff --git a/pylint/checkers/format.py b/pylint/checkers/format.py index b5f35cd00..38b6649c5 100644 --- a/pylint/checkers/format.py +++ b/pylint/checkers/format.py @@ -1333,3 +1333,9 @@ class FormatChecker(BaseTokenChecker): def register(linter): """required method to auto register this checker """ linter.register_checker(FormatChecker(linter)) + + +def funkier(): + for val in range(3): + pass + print(val) diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 78d78a913..784568ddd 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -64,6 +64,7 @@ PY3K = sys.version_info >= (3, 0) # for `abc` METACLASS_NAME_TRANSFORMS = {"_py_abc": "abc"} TYPING_TYPE_CHECKS_GUARDS = frozenset({"typing.TYPE_CHECKING", "TYPE_CHECKING"}) +BUILTIN_RANGE = "builtins.range" def _is_from_future_import(stmt, name): @@ -1145,7 +1146,7 @@ class VariablesChecker(BaseChecker): ): return - # For functions we can do more by inferring the length of the iterred object + # For functions we can do more by inferring the length of the itered object if not isinstance(assign, astroid.For): self.add_message("undefined-loop-variable", args=name, node=node) return @@ -1155,6 +1156,14 @@ class VariablesChecker(BaseChecker): except astroid.InferenceError: self.add_message("undefined-loop-variable", args=name, node=node) else: + if ( + isinstance(inferred, astroid.Instance) + and inferred.qname() == BUILTIN_RANGE + ): + # Consider range() objects safe, even if they might not yield any results. + return + + # Consider sequences. sequences = ( astroid.List, astroid.Tuple, diff --git a/pylint/test/functional/cellvar_escaping_loop.py b/pylint/test/functional/cellvar_escaping_loop.py index 29107b575..23c6b4b2e 100644 --- a/pylint/test/functional/cellvar_escaping_loop.py +++ b/pylint/test/functional/cellvar_escaping_loop.py @@ -35,16 +35,6 @@ def good_case5(): def good_case6(): - """Accept use of the variable after the loop. - - There's already a warning about possibly undefined loop variables, and - the value will not change any more.""" - for i in range(10): - print(i) - return lambda: i # [undefined-loop-variable] - - -def good_case7(): """Accept use of the variable inside return.""" for i in range(10): if i == 8: @@ -52,13 +42,13 @@ def good_case7(): return lambda: -1 -def good_case8(): +def good_case7(): """Lambda defined and called in loop.""" for i in range(10): print((lambda x: i + x)(1)) -def good_case9(): +def good_case8(): """Another eager binding of the cell variable.""" funs = [] for i in range(10): diff --git a/pylint/test/functional/cellvar_escaping_loop.txt b/pylint/test/functional/cellvar_escaping_loop.txt index bdd7fe9c6..2ac0b58ef 100644 --- a/pylint/test/functional/cellvar_escaping_loop.txt +++ b/pylint/test/functional/cellvar_escaping_loop.txt @@ -1,7 +1,6 @@ -undefined-loop-variable:44:good_case6.:Using possibly undefined loop variable 'i' -cell-var-from-loop:77:bad_case.:Cell variable i defined in loop -cell-var-from-loop:82:bad_case2.:Cell variable i defined in loop -cell-var-from-loop:90:bad_case3.:Cell variable j defined in loop -cell-var-from-loop:100:bad_case4.nested:Cell variable i defined in loop -cell-var-from-loop:121:bad_case5.:Cell variable i defined in loop -cell-var-from-loop:129:bad_case6.:Cell variable i defined in loop +cell-var-from-loop:67:bad_case.:Cell variable i defined in loop +cell-var-from-loop:72:bad_case2.:Cell variable i defined in loop +cell-var-from-loop:80:bad_case3.:Cell variable j defined in loop +cell-var-from-loop:90:bad_case4.nested:Cell variable i defined in loop +cell-var-from-loop:111:bad_case5.:Cell variable i defined in loop +cell-var-from-loop:119:bad_case6.:Cell variable i defined in loop diff --git a/pylint/test/functional/undefined_loop_variable.py b/pylint/test/functional/undefined_loop_variable.py index 3840003b5..a984898f8 100644 --- a/pylint/test/functional/undefined_loop_variable.py +++ b/pylint/test/functional/undefined_loop_variable.py @@ -1,4 +1,4 @@ -# pylint: disable=missing-docstring +# pylint: disable=missing-docstring,redefined-builtin def do_stuff(some_random_list): for var in some_random_list: @@ -59,3 +59,17 @@ def do_stuff_with_a_tuple(): for var in (1, 2, 3): pass return var + + +def do_stuff_with_a_range(): + for var in range(1, 2): + pass + return var + + +def do_stuff_with_redefined_range(): + def range(key): + yield from [1, key] + for var in range(3): + pass + return var # [undefined-loop-variable] diff --git a/pylint/test/functional/undefined_loop_variable.txt b/pylint/test/functional/undefined_loop_variable.txt index 33022d454..64cf6388b 100644 --- a/pylint/test/functional/undefined_loop_variable.txt +++ b/pylint/test/functional/undefined_loop_variable.txt @@ -1,2 +1,3 @@ undefined-loop-variable:6:do_stuff:Using possibly undefined loop variable 'var' -undefined-loop-variable:25::Using possibly undefined loop variable 'var1' \ No newline at end of file +undefined-loop-variable:25::Using possibly undefined loop variable 'var1' +undefined-loop-variable:75:do_stuff_with_redefined_range:Using possibly undefined loop variable 'var' -- cgit v1.2.1