From: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Date: Thu, 27 Jan 2022 00:47:36 +0000 (-0800)
Subject: Fix crash on some power hugging cases (#2806)
X-Git-Url: https://git.madduck.net/etc/vim.git/commitdiff_plain/889a8d5dd27a73aa780e989a850bbdaaa9946a13?hp=32dd9ecb2e9dec8b29c07726d5713ed5b4c36547

Fix crash on some power hugging cases (#2806)

Found by the fuzzer. Repro case:

	python -m black -c 'importA;()<<0**0#'
---

diff --git a/src/black/linegen.py b/src/black/linegen.py
index 9fbdfad..ac60ed1 100644
--- a/src/black/linegen.py
+++ b/src/black/linegen.py
@@ -942,6 +942,7 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf
                 if (
                     prev
                     and prev.type == token.COMMA
+                    and leaf.opening_bracket is not None
                     and not is_one_tuple_between(
                         leaf.opening_bracket, leaf, line.leaves
                     )
@@ -969,6 +970,7 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf
             if (
                 prev
                 and prev.type == token.COMMA
+                and leaf.opening_bracket is not None
                 and not is_one_tuple_between(leaf.opening_bracket, leaf, line.leaves)
             ):
                 # Never omit bracket pairs with trailing commas.
diff --git a/src/black/lines.py b/src/black/lines.py
index c602aa6..7d50f02 100644
--- a/src/black/lines.py
+++ b/src/black/lines.py
@@ -277,7 +277,9 @@ class Line:
         if self.is_import:
             return True
 
-        if not is_one_tuple_between(closing.opening_bracket, closing, self.leaves):
+        if closing.opening_bracket is not None and not is_one_tuple_between(
+            closing.opening_bracket, closing, self.leaves
+        ):
             return True
 
         return False
diff --git a/src/blib2to3/pytree.py b/src/blib2to3/pytree.py
index bd86270..b203ce5 100644
--- a/src/blib2to3/pytree.py
+++ b/src/blib2to3/pytree.py
@@ -386,7 +386,8 @@ class Leaf(Base):
     value: Text
     fixers_applied: List[Any]
     bracket_depth: int
-    opening_bracket: "Leaf"
+    # Changed later in brackets.py
+    opening_bracket: Optional["Leaf"] = None
     used_names: Optional[Set[Text]]
     _prefix = ""  # Whitespace and comments preceding this token in the input
     lineno: int = 0  # Line where this token starts in the input
@@ -399,6 +400,7 @@ class Leaf(Base):
         context: Optional[Context] = None,
         prefix: Optional[Text] = None,
         fixers_applied: List[Any] = [],
+        opening_bracket: Optional["Leaf"] = None,
     ) -> None:
         """
         Initializer.
@@ -416,6 +418,7 @@ class Leaf(Base):
             self._prefix = prefix
         self.fixers_applied: Optional[List[Any]] = fixers_applied[:]
         self.children = []
+        self.opening_bracket = opening_bracket
 
     def __repr__(self) -> str:
         """Return a canonical string representation."""
@@ -448,6 +451,7 @@ class Leaf(Base):
             self.value,
             (self.prefix, (self.lineno, self.column)),
             fixers_applied=self.fixers_applied,
+            opening_bracket=self.opening_bracket,
         )
 
     def leaves(self) -> Iterator["Leaf"]:
diff --git a/tests/data/power_op_newline.py b/tests/data/power_op_newline.py
new file mode 100644
index 0000000..85d434d
--- /dev/null
+++ b/tests/data/power_op_newline.py
@@ -0,0 +1,10 @@
+importA;()<<0**0#
+
+# output
+
+importA
+(
+    ()
+    << 0
+    ** 0
+)  #
diff --git a/tests/test_format.py b/tests/test_format.py
index a4619b4..88f084e 100644
--- a/tests/test_format.py
+++ b/tests/test_format.py
@@ -256,3 +256,9 @@ def test_python38() -> None:
 def test_python39() -> None:
     source, expected = read_data("python39")
     assert_format(source, expected, minimum_version=(3, 9))
+
+
+def test_power_op_newline() -> None:
+    # requires line_length=0
+    source, expected = read_data("power_op_newline")
+    assert_format(source, expected, mode=black.Mode(line_length=0))