summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorƁukasz Sznuk <ls@rdprojekt.pl>2017-07-17 15:29:23 +0200
committerClaudiu Popa <pcmanticore@gmail.com>2017-07-19 16:20:11 +0200
commita53028da4f370e0ac94f4b11d74bdd2da2f1f610 (patch)
treed7ba794e70e838b8a2aa5d443f26743e8e746e3c
parent0fc0440b67935488e779ca2a8ab8ba6a407704f5 (diff)
downloadpylint-git-a53028da4f370e0ac94f4b11d74bdd2da2f1f610.tar.gz
Fix ifs in formatted strings crashing Pylint
-rw-r--r--pylint/checkers/refactoring.py22
-rw-r--r--pylint/test/functional/formatted_string_literal_with_if_py36.py8
-rw-r--r--pylint/test/functional/formatted_string_literal_with_if_py36.rc2
3 files changed, 19 insertions, 13 deletions
diff --git a/pylint/checkers/refactoring.py b/pylint/checkers/refactoring.py
index 8bbdb902a..2ac7eefae 100644
--- a/pylint/checkers/refactoring.py
+++ b/pylint/checkers/refactoring.py
@@ -118,7 +118,6 @@ class RefactoringChecker(checkers.BaseTokenChecker):
def _init(self):
self._nested_blocks = []
self._elifs = []
- self._if_counter = 0
self._nested_blocks_msg = None
@decorators.cachedproperty
@@ -144,7 +143,7 @@ class RefactoringChecker(checkers.BaseTokenChecker):
orelse = node.parent.orelse
# current if node must directly follow a "else"
if orelse and orelse == [node]:
- if self._elifs[self._if_counter]:
+ if (node.lineno, node.col_offset) in self._elifs:
return True
return False
@@ -208,9 +207,13 @@ class RefactoringChecker(checkers.BaseTokenChecker):
for index, token in enumerate(tokens):
token_string = token[1]
if token_string == 'elif':
- self._elifs.append(True)
- elif token_string == 'if':
- self._elifs.append(False)
+ # AST exists by the time process_tokens is called, so
+ # it's safe to assume tokens[index+1]
+ # exists. tokens[index+1][2] is the elif's position as
+ # reported by cPython, Jython and PyPy,
+ # tokens[index][2] is the actual position and also is
+ # reported by IronPython.
+ self._elifs.extend([tokens[index][2], tokens[index+1][2]])
elif six.PY3 and token.exact_type == tokenize.COMMA:
self._check_one_element_trailing_comma_tuple(tokens, token, index)
@@ -282,12 +285,6 @@ class RefactoringChecker(checkers.BaseTokenChecker):
for name in names.nodes_of_class(astroid.AssignName):
self._check_redefined_argument_from_local(name)
- def visit_ifexp(self, _):
- self._if_counter += 1
-
- def visit_comprehension(self, node):
- self._if_counter += len(node.ifs)
-
def _check_superfluous_else_return(self, node):
if not node.orelse:
# Not interested in if statements without else.
@@ -302,7 +299,6 @@ class RefactoringChecker(checkers.BaseTokenChecker):
self._check_simplifiable_if(node)
self._check_nested_blocks(node)
self._check_superfluous_else_return(node)
- self._if_counter += 1
@utils.check_messages('too-many-nested-blocks')
def leave_functiondef(self, _):
@@ -329,7 +325,7 @@ class RefactoringChecker(checkers.BaseTokenChecker):
break
self._nested_blocks.pop()
# if the node is a elif, this should not be another nesting level
- if isinstance(node, astroid.If) and self._elifs[self._if_counter]:
+ if isinstance(node, astroid.If) and self._is_actual_elif(node):
if self._nested_blocks:
self._nested_blocks.pop()
self._nested_blocks.append(node)
diff --git a/pylint/test/functional/formatted_string_literal_with_if_py36.py b/pylint/test/functional/formatted_string_literal_with_if_py36.py
new file mode 100644
index 000000000..8feb4e293
--- /dev/null
+++ b/pylint/test/functional/formatted_string_literal_with_if_py36.py
@@ -0,0 +1,8 @@
+"""Test that `if` in formatted string literal won't break Pylint."""
+# pylint: disable=missing-docstring, pointless-statement, using-constant-test
+
+f'{"+" if True else "-"}'
+if True:
+ pass
+elif True:
+ pass
diff --git a/pylint/test/functional/formatted_string_literal_with_if_py36.rc b/pylint/test/functional/formatted_string_literal_with_if_py36.rc
new file mode 100644
index 000000000..0ba2b6333
--- /dev/null
+++ b/pylint/test/functional/formatted_string_literal_with_if_py36.rc
@@ -0,0 +1,2 @@
+[testoptions]
+min_pyver=3.6