Repository: asottile/yesqa

Issue:
False positive: removes `noqa` on multi-line string
```python
"""
aaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
"""  # noqa
```

```console
$ flake8 test.py
$ yesqa test.py
Rewriting test.py
$ flake8 test.py
test.py:2:80: E501 line too long (82 > 79 characters)
```

Discussion:

Patch:
diff --git a/yesqa.py b/yesqa.py
index 008dc57..40cf153 100644
--- a/yesqa.py
+++ b/yesqa.py
@@ -43,14 +43,28 @@ def _remove_comments(tokens):
 
 
 def _rewrite_noqa_comment(tokens, i, flake8_results):
+    # find logical lines that this noqa comment may affect
+    lines = set()
+    j = i
+    while j >= 0 and tokens[j].name not in {'NL', 'NEWLINE'}:
+        t = tokens[j]
+        if t.line is not None:
+            lines.update(range(t.line, t.line + t.src.count('\n') + 1))
+        j -= 1
+
+    lints = set()
+    for line in lines:
+        lints.update(flake8_results[line])
+
     token = tokens[i]
     match = NOQA_RE.match(token.src)
+
     # exclude all lints on the line but no lints
-    if token.line not in flake8_results:
+    if not lints:
         _remove_comment(tokens, i)
     elif match.group().lower() != '# noqa':
         codes = set(SEP_RE.split(match.group(1)[2:]))
-        expected_codes = codes & flake8_results[token.line]
+        expected_codes = codes & lints
         if expected_codes != codes:
             comment = '# noqa: {}'.format(','.join(sorted(expected_codes)))
             tokens[i] = token._replace(src=NOQA_RE.sub(comment, token.src))


Test patch:
diff --git a/tests/yesqa_test.py b/tests/yesqa_test.py
index e0225c8..9043a86 100644
--- a/tests/yesqa_test.py
+++ b/tests/yesqa_test.py
@@ -32,9 +32,11 @@ def test_non_utf8_bytes(tmpdir, capsys):
     (
         '',  # noop
         '# hello\n',  # comment at beginning of file
-        'import os  # noqa\n',  # still needed
-        'import os  # NOQA\n',  # still needed
-        'import os  # noqa: F401\n',  # still needed
+        # still needed
+        'import os  # noqa\n',
+        'import os  # NOQA\n',
+        'import os  # noqa: F401\n',
+        '"""\n' + 'a' * 40 + ' ' + 'b' * 60 + '\n""" # noqa\n',
     ),
 )
 def test_ok(assert_rewrite, src):