From 72fd895f636f7d0c62569c39dd74227ed28c8c8b Mon Sep 17 00:00:00 2001 From: Lucas Cimon Date: Wed, 30 Jan 2019 15:04:55 +0100 Subject: Add a new option 'check-str-concat-over-line-jumps' to check 'implicit-str-concat-in-sequence' --- ChangeLog | 2 ++ pylint/checkers/strings.py | 40 +++++++++++++++++----- .../implicit_str_concat_in_sequence_multiline.py | 4 +++ .../implicit_str_concat_in_sequence_multiline.rc | 2 ++ .../implicit_str_concat_in_sequence_multiline.txt | 1 + 5 files changed, 40 insertions(+), 9 deletions(-) create mode 100755 pylint/test/functional/implicit_str_concat_in_sequence_multiline.py create mode 100755 pylint/test/functional/implicit_str_concat_in_sequence_multiline.rc create mode 100755 pylint/test/functional/implicit_str_concat_in_sequence_multiline.txt diff --git a/ChangeLog b/ChangeLog index 5a5d268e9..2b8e64441 100644 --- a/ChangeLog +++ b/ChangeLog @@ -90,6 +90,8 @@ Release date: TBA * Avoid popping __main__ when using multiple jobs Close #2689 + + * Add a new option 'check-str-concat-over-line-jumps' to check 'implicit-str-concat-in-sequence' What's New in Pylint 2.2.2? =========================== diff --git a/pylint/checkers/strings.py b/pylint/checkers/strings.py index 92dcbbeec..eeefc6efe 100644 --- a/pylint/checkers/strings.py +++ b/pylint/checkers/strings.py @@ -572,6 +572,20 @@ class StringConstantChecker(BaseTokenChecker): "maybe a comma is missing ?", ), } + options = ( + ( + "check-str-concat-over-line-jumps", + { + "default": False, + "type": "yn", + "metavar": "", + "help": "This flag controls whether the " + "implicit-str-concat-in-sequence should generate a warning " + "on implicit string concatenation in sequences defined over " + "several lines.", + }, + ), + ) # Characters that have a special meaning after a backslash in either # Unicode or byte strings. @@ -601,22 +615,30 @@ class StringConstantChecker(BaseTokenChecker): # 'token' is the whole un-parsed token; we can look at the start # of it to see whether it's a raw or unicode string etc. self.process_string_token(token, start[0]) - next_token = tokens[i + 1] if i + 1 < len(tokens) else None + # We figure the next token, ignoring comments & newlines: + j = i + 1 + while j < len(tokens) and tokens[j].type in ( + tokenize.NEWLINE, + tokenize.NL, + tokenize.COMMENT, + ): + j += 1 + next_token = tokens[j] if j < len(tokens) else None if encoding != "ascii": # We convert `tokenize` character count into a byte count, # to match with astroid `.col_offset` start = (start[0], len(line[: start[1]].encode(encoding))) self.string_tokens[start] = (str_eval(token), next_token) - @check_messages(*(MSGS.keys())) + @check_messages(*(msgs.keys())) def visit_list(self, node): self.check_for_concatenated_strings(node, "list") - @check_messages(*(MSGS.keys())) + @check_messages(*(msgs.keys())) def visit_set(self, node): self.check_for_concatenated_strings(node, "set") - @check_messages(*(MSGS.keys())) + @check_messages(*(msgs.keys())) def visit_tuple(self, node): self.check_for_concatenated_strings(node, "tuple") @@ -633,12 +655,12 @@ class StringConstantChecker(BaseTokenChecker): matching_token, next_token = self.string_tokens[ (elt.lineno, elt.col_offset) ] + # We detect string concatenation: the AST Const is the + # combination of 2 string tokens if matching_token != elt.value and next_token is not None: - next_token_type, next_token_pos = next_token[0], next_token[2] - # We do not warn if string concatenation happens over a newline - if ( - next_token_type == tokenize.STRING - and next_token_pos[0] == elt.lineno + if next_token.type == tokenize.STRING and ( + next_token.start[0] == elt.lineno + or self.config.check_str_concat_over_line_jumps ): self.add_message( "implicit-str-concat-in-sequence", diff --git a/pylint/test/functional/implicit_str_concat_in_sequence_multiline.py b/pylint/test/functional/implicit_str_concat_in_sequence_multiline.py new file mode 100755 index 000000000..0f8d1fcdf --- /dev/null +++ b/pylint/test/functional/implicit_str_concat_in_sequence_multiline.py @@ -0,0 +1,4 @@ +#pylint: disable=bad-continuation,missing-docstring + +TEST_TUPLE = ('a', 'b' # [implicit-str-concat-in-sequence] + 'c') diff --git a/pylint/test/functional/implicit_str_concat_in_sequence_multiline.rc b/pylint/test/functional/implicit_str_concat_in_sequence_multiline.rc new file mode 100755 index 000000000..e5b344774 --- /dev/null +++ b/pylint/test/functional/implicit_str_concat_in_sequence_multiline.rc @@ -0,0 +1,2 @@ +[STRING_CONSTANT] +check-str-concat-over-line-jumps=yes diff --git a/pylint/test/functional/implicit_str_concat_in_sequence_multiline.txt b/pylint/test/functional/implicit_str_concat_in_sequence_multiline.txt new file mode 100755 index 000000000..b37cf624b --- /dev/null +++ b/pylint/test/functional/implicit_str_concat_in_sequence_multiline.txt @@ -0,0 +1 @@ +implicit-str-concat-in-sequence:3::Implicit string concatenation found in tuple \ No newline at end of file -- cgit v1.2.1