Repository: prettier/plugin-php
Pull request #669 (2018-09-24 14:26:51)

feat: consistently print assign node with lookup nodes
Why? Because `::` in js is not same in `php`


Patch:
diff --git a/src/needs-parens.js b/src/needs-parens.js
index 868a841..c424d4f 100644
--- a/src/needs-parens.js
+++ b/src/needs-parens.js
@@ -179,6 +179,10 @@ function needsParens(path) {
         case "cast":
           return true;
         case "retif":
+          if (name === "test" && !parent.trueExpr) {
+            return false;
+          }
+
           return true;
         case "propertylookup":
         case "staticlookup":
diff --git a/src/printer.js b/src/printer.js
index 3a7c7f8..9c2bcbd 100644
--- a/src/printer.js
+++ b/src/printer.js
@@ -1026,81 +1026,247 @@ function printLines(path, options, print, childrenAttribute = "children") {
   return concat(wrappedParts);
 }
 
-function printDeclarationBlock({
-  declaration,
-  argumentsList = [],
-  returnTypeContents = "",
-  bodyContents = "",
-  node,
-  path,
-  options
-}) {
-  const isClassLikeNode = ["class", "interface", "trait"].includes(node.kind);
-  const printedDeclaration = group(declaration);
-  const printedSignature = !isClassLikeNode
-    ? group(
+function printClass(path, options, print) {
+  const node = path.getValue();
+  const parentNode = path.getParentNode();
+
+  const declaration = [];
+
+  if (node.isFinal) {
+    declaration.push("final ");
+  }
+
+  if (node.isAbstract) {
+    declaration.push("abstract ");
+  }
+
+  declaration.push(node.kind);
+
+  if (node.name) {
+    declaration.push(" ", node.name);
+  }
+
+  const isAnonymousClass = node.kind === "class" && node.isAnonymous;
+
+  // if this is an anonymous class, we need to check if the parent was a
+  // "new" node. if it was, we need to get the arguments from that node
+  // ex: $test = new class($arg1, $arg2) extends TestClass {};
+  if (
+    isAnonymousClass &&
+    parentNode.kind === "new" &&
+    parentNode.arguments.length > 0
+  ) {
+    declaration.push(printArgumentsList(path, options, print));
+  }
+
+  const partsDeclarationGroup = [];
+
+  if (node.extends) {
+    if (!Array.isArray(node.extends)) {
+      partsDeclarationGroup.push(
+        group(
+          concat([
+            // check if the extends node has a comment
+            hasDanglingComments(node.extends)
+              ? concat([
+                  hardline,
+                  path.call(
+                    extendsPath =>
+                      comments.printDanglingComments(
+                        extendsPath,
+                        options,
+                        true
+                      ),
+                    "extends"
+                  ),
+                  hardline
+                ])
+              : line,
+            "extends ",
+            path.call(print, "extends")
+          ])
+        )
+      );
+    } else {
+      partsDeclarationGroup.push(
         concat([
-          "(",
-          argumentsList.length
-            ? concat([
-                indent(
-                  concat([softline, join(concat([",", line]), argumentsList)])
-                ),
-                softline
+          line,
+          "extends",
+          group(
+            indent(
+              concat([
+                join(
+                  ",",
+                  path.map(extendPath => {
+                    // check if any of the implements nodes have comments
+                    return hasDanglingComments(extendPath.getValue())
+                      ? concat([
+                          hardline,
+                          comments.printDanglingComments(
+                            extendPath,
+                            options,
+                            true
+                          ),
+                          hardline,
+                          print(extendPath)
+                        ])
+                      : concat([line, print(extendPath)]);
+                  }, "extends")
+                )
               ])
-            : "",
-          ")",
-          returnTypeContents ? concat([": ", returnTypeContents]) : ""
+            )
+          )
         ])
-      )
-    : "";
+      );
+    }
+  }
+
+  if (node.implements) {
+    partsDeclarationGroup.push(
+      concat([
+        isAnonymousClass ? " " : line,
+        "implements",
+        group(
+          indent(
+            concat([
+              join(
+                ",",
+                path.map(implementPath => {
+                  // check if any of the implements nodes have comments
+                  return hasDanglingComments(implementPath.getValue())
+                    ? concat([
+                        hardline,
+                        comments.printDanglingComments(
+                          implementPath,
+                          options,
+                          true
+                        ),
+                        hardline,
+                        print(implementPath)
+                      ])
+                    : concat([line, print(implementPath)]);
+                }, "implements")
+              )
+            ])
+          )
+        )
+      ])
+    );
+  }
+
+  if (partsDeclarationGroup.length > 0) {
+    declaration.push(group(indent(concat(partsDeclarationGroup))));
+  }
+
+  const printedDeclaration = group(
+    concat([group(concat(declaration)), isAnonymousClass ? line : hardline])
+  );
 
   const hasEmptyBody =
-    ((node.kind === "function" || node.kind === "method") &&
-      node.body &&
-      node.body.children &&
-      node.body.children.length === 0 &&
-      !node.body.comments) ||
-    (isClassLikeNode && node.body && node.body.length === 0 && !node.comments);
-
-  const printedBody = bodyContents
+    node.body &&
+    node.body.length === 0 &&
+    (!node.comments || node.comments.length === 0);
+  const printedBody = concat([
+    "{",
+    indent(
+      concat([
+        hasEmptyBody ? "" : hardline,
+        printLines(path, options, print, "body")
+      ])
+    ),
+    comments.printDanglingComments(path, options, true),
+    isAnonymousClass && hasEmptyBody ? "" : hardline,
+    "}"
+  ]);
+
+  return concat([printedDeclaration, printedBody]);
+}
+
+function printFunction(path, options, print) {
+  const node = path.getValue();
+  const declaration = [];
+
+  if (node.isFinal) {
+    declaration.push("final ");
+  }
+
+  if (node.isAbstract) {
+    declaration.push("abstract ");
+  }
+
+  if (node.visibility) {
+    declaration.push(node.visibility, " ");
+  }
+
+  if (node.isStatic) {
+    declaration.push("static ");
+  }
+
+  declaration.push("function ");
+
+  if (node.byref) {
+    declaration.push("&");
+  }
+
+  if (node.name) {
+    declaration.push(node.name);
+  }
+
+  declaration.push(printArgumentsList(path, options, print));
+
+  if (node.uses && node.uses.length > 0) {
+    declaration.push(
+      group(concat([" use ", printArgumentsList(path, options, print, "uses")]))
+    );
+  }
+
+  if (node.type) {
+    declaration.push(
+      concat([
+        ": ",
+        hasDanglingComments(node.type)
+          ? concat([
+              path.call(
+                typePath =>
+                  comments.printDanglingComments(typePath, options, true),
+                "type"
+              ),
+              " "
+            ])
+          : "",
+        node.nullable ? "?" : "",
+        path.call(print, "type")
+      ])
+    );
+  }
+
+  const printedDeclaration = concat(declaration);
+  const hasEmptyBody =
+    node.body &&
+    node.body.children &&
+    node.body.children.length === 0 &&
+    !node.body.comments;
+  const isClosure = node.kind === "closure";
+  const printedBody = node.body
     ? concat([
         "{",
-        indent(concat([hasEmptyBody ? "" : hardline, bodyContents])),
-        comments.printDanglingComments(path, options, true),
-        node.kind === "class" && node.isAnonymous && hasEmptyBody
-          ? ""
-          : hardline,
+        indent(
+          concat([hasEmptyBody ? "" : hardline, path.call(print, "body")])
+        ),
+        isClosure && hasEmptyBody ? "" : hardline,
         "}"
       ])
     : "";
 
-  if (isClassLikeNode) {
-    return concat([
-      group(
-        concat([
-          printedDeclaration,
-          printedSignature,
-          bodyContents && node.kind === "class" && node.isAnonymous
-            ? line
-            : hardline
-        ])
-      ),
-      printedBody
-    ]);
+  if (isClosure) {
+    return concat([printedDeclaration, " ", printedBody]);
   }
 
   return conditionalGroup([
+    concat([printedDeclaration, node.body ? hardline : "", printedBody]),
     concat([
       printedDeclaration,
-      printedSignature,
-      bodyContents ? hardline : "",
-      printedBody
-    ]),
-    concat([
-      printedDeclaration,
-      printedSignature,
-      bodyContents ? (argumentsList.length === 0 ? hardline : " ") : "",
+      node.body ? (node.arguments.length === 0 ? hardline : " ") : "",
       printedBody
     ])
   ]);
@@ -1108,9 +1274,9 @@ function printDeclarationBlock({
 
 function printBodyControlStructure(
   path,
+  options,
   print,
-  bodyProperty = "body",
-  options = {}
+  bodyProperty = "body"
 ) {
   const node = path.getValue();
 
@@ -1176,7 +1342,7 @@ function isLookupNodeChain(node) {
     return false;
   }
 
-  if (node.what.kind === "variable") {
+  if (["variable", "identifier"].includes(node.what.kind)) {
     return true;
   }
 
@@ -1334,141 +1500,10 @@ function printNode(path, options, print) {
           : "",
         node.alias ? concat([" as ", node.alias]) : ""
       ]);
-    case "class": {
-      const classPrefixes = [
-        ...(node.isFinal ? ["final"] : []),
-        ...(node.isAbstract ? ["abstract"] : [])
-      ];
-      const parentNode = path.getParentNode();
-      // if this is an anonymous class, we need to check if the parent was a
-      // "new" node. if it was, we need to get the arguments from that node
-      // ex: $test = new class($arg1, $arg2) extends TestClass {};
-      const anonymousArguments =
-        node.isAnonymous &&
-        parentNode.kind === "new" &&
-        parentNode.arguments.length > 0
-          ? printArgumentsList(path, options, print)
-          : "";
-
-      return printDeclarationBlock({
-        declaration: concat([
-          classPrefixes.join(" "),
-          classPrefixes.length > 0 ? " " : "",
-          concat([
-            "class",
-            anonymousArguments,
-            node.name ? concat([" ", node.name]) : ""
-          ]),
-          group(
-            indent(
-              concat([
-                node.extends
-                  ? group(
-                      concat([
-                        // check if the extends node has a comment
-                        hasDanglingComments(node.extends)
-                          ? concat([
-                              hardline,
-                              path.call(
-                                extendsPath =>
-                                  comments.printDanglingComments(
-                                    extendsPath,
-                                    options,
-                                    true
-                                  ),
-                                "extends"
-                              ),
-                              hardline
-                            ])
-                          : line,
-                        "extends ",
-                        path.call(print, "extends")
-                      ])
-                    )
-                  : "",
-                node.implements
-                  ? concat([
-                      line,
-                      "implements",
-                      group(
-                        indent(
-                          concat([
-                            join(
-                              ",",
-                              path.map(implementsPath => {
-                                // check if any of the implements nodes have comments
-                                return hasDanglingComments(
-                                  implementsPath.getValue()
-                                )
-                                  ? concat([
-                                      hardline,
-                                      comments.printDanglingComments(
-                                        implementsPath,
-                                        options,
-                                        true
-                                      ),
-                                      hardline,
-                                      print(implementsPath)
-                                    ])
-                                  : concat([line, print(implementsPath)]);
-                              }, "implements")
-                            )
-                          ])
-                        )
-                      )
-                    ])
-                  : ""
-              ])
-            )
-          )
-        ]),
-        bodyContents: printLines(path, options, print, "body"),
-        node,
-        path,
-        options
-      });
-    }
+    case "class":
     case "interface":
-      return printDeclarationBlock({
-        declaration: concat([
-          concat(["interface ", node.name]),
-          node.extends
-            ? indent(
-                concat([
-                  line,
-                  "extends ",
-                  join(", ", path.map(print, "extends"))
-                ])
-              )
-            : ""
-        ]),
-        bodyContents: printLines(path, options, print, "body"),
-        node,
-        path,
-        options
-      });
     case "trait":
-      return printDeclarationBlock({
-        declaration: concat([
-          concat(["trait ", node.name]),
-          node.extends
-            ? indent(concat([line, "extends ", path.call(print, "extends")]))
-            : "",
-          node.implements
-            ? indent(
-                concat([
-                  line,
-                  "implements ",
-                  join(", ", path.map(print, "implements"))
-                ])
-              )
-            : ""
-        ]),
-        bodyContents: printLines(path, options, print, "body"),
-        node,
-        path,
-        options
-      });
+      return printClass(path, options, print);
     case "traitprecedence":
       return concat([
         path.call(print, "trait"),
@@ -1509,113 +1544,9 @@ function printNode(path, options, print) {
         ])
       );
     case "function":
-      return printDeclarationBlock({
-        declaration: concat(["function ", node.byref ? "&" : "", node.name]),
-        argumentsList: path.map(print, "arguments"),
-        returnTypeContents: node.type
-          ? concat([
-              hasDanglingComments(node.type)
-                ? concat([
-                    path.call(
-                      typePath =>
-                        comments.printDanglingComments(typePath, options, true),
-                      "type"
-                    ),
-                    " "
-                  ])
-                : "",
-              node.nullable ? "?" : "",
-              path.call(print, "type")
-            ])
-          : "",
-        bodyContents: node.body ? path.call(print, "body") : "",
-        node,
-        path,
-        options
-      });
-    case "closure": {
-      const hasEmptyBody =
-        node.body &&
-        node.body.children &&
-        node.body.children.length === 0 &&
-        !node.body.comments;
-
-      return concat([
-        node.isStatic ? "static " : "",
-        "function ",
-        node.byref ? "&" : "",
-        printArgumentsList(path, options, print),
-        node.uses && node.uses.length > 0
-          ? group(
-              concat([
-                " use ",
-                printArgumentsList(path, options, print, "uses")
-              ])
-            )
-          : "",
-        node.type
-          ? concat([
-              ": ",
-              hasDanglingComments(node.type)
-                ? concat([
-                    path.call(
-                      typePath =>
-                        comments.printDanglingComments(typePath, options, true),
-                      "type"
-                    ),
-                    " "
-                  ])
-                : "",
-              node.nullable ? "?" : "",
-              path.call(print, "type")
-            ])
-          : "",
-        " {",
-        indent(
-          concat([hasEmptyBody ? "" : hardline, path.call(print, "body")])
-        ),
-        concat([hasEmptyBody ? "" : hardline, "}"])
-      ]);
-    }
-    case "method": {
-      const methodPrefixes = [
-        ...(node.isFinal ? ["final"] : []),
-        ...(node.isAbstract ? ["abstract"] : []),
-        ...(node.visibility ? [node.visibility] : []),
-        ...(node.isStatic ? ["static"] : [])
-      ];
-
-      return printDeclarationBlock({
-        declaration: concat([
-          methodPrefixes.join(" "),
-          methodPrefixes.length > 0 ? " " : "",
-          "function ",
-          node.byref ? "&" : "",
-          node.name
-        ]),
-        argumentsList: path.map(print, "arguments"),
-        returnTypeContents: node.type
-          ? concat([
-              hasDanglingComments(node.type)
-                ? concat([
-                    path.call(
-                      typePath =>
-                        comments.printDanglingComments(typePath, options, true),
-                      "type"
-                    ),
-                    " "
-                  ])
-                : "",
-              node.nullable ? "?" : "",
-              path.call(print, "type")
-            ])
-          : "",
-        bodyContents: node.body ? concat([path.call(print, "body")]) : "",
-        node,
-        path,
-        options
-      });
-    }
+    case "closure":
+    case "method":
+      return printFunction(path, options, print);
     case "parameter": {
       const name = concat([
         node.nullable ? "?" : "",
@@ -1683,7 +1614,7 @@ function printNode(path, options, print) {
       ]);
     case "if": {
       const parts = [];
-      const body = printBodyControlStructure(path, print, "body", options);
+      const body = printBodyControlStructure(path, options, print, "body");
       const opening = group(
         concat([
           "if (",
@@ -1725,7 +1656,7 @@ function printNode(path, options, print) {
           group(
             node.alternate.kind === "if"
               ? path.call(print, "alternate")
-              : printBodyControlStructure(path, print, "alternate", options)
+              : printBodyControlStructure(path, options, print, "alternate")
           )
         );
       } else {
@@ -1737,7 +1668,7 @@ function printNode(path, options, print) {
     case "do":
       return concat([
         "do",
-        printBodyControlStructure(path, print, "body", options),
+        printBodyControlStructure(path, options, print, "body"),
         " while (",
         group(
           concat([
@@ -1758,11 +1689,11 @@ function printNode(path, options, print) {
             ])
           ),
           ")",
-          printBodyControlStructure(path, print, "body", options)
+          printBodyControlStructure(path, options, print, "body")
         ])
       );
     case "for": {
-      const body = printBodyControlStructure(path, print, "body", options);
+      const body = printBodyControlStructure(path, options, print, "body");
 
       // We want to keep dangling comments above the loop to stay consistent.
       // Any comment positioned between the for statement and the parentheses
@@ -1817,7 +1748,7 @@ function printNode(path, options, print) {
       ]);
     }
     case "foreach": {
-      const body = printBodyControlStructure(path, print, "body", options);
+      const body = printBodyControlStructure(path, options, print, "body");
 
       // We want to keep dangling comments above the loop to stay consistent.
       // Any comment positioned between the for statement and the parentheses
@@ -1873,7 +1804,7 @@ function printNode(path, options, print) {
             ")"
           ])
         ),
-        printBodyControlStructure(path, print, "body", options)
+        printBodyControlStructure(path, options, print, "body")
       ]);
     case "case":
       return concat([
@@ -2526,8 +2457,20 @@ function printNode(path, options, print) {
       ]);
     case "identifier": {
       const parent = path.getParentNode();
+      const normalizedName = node.name.toLowerCase();
+
+      if (
+        (parent.kind === "staticlookup" &&
+          parent.what === node &&
+          ["self", "parent", "static"].includes(normalizedName)) ||
+        (parent.kind === "parameter" &&
+          parent.type === node &&
+          ["self", "parent", "static"].includes(normalizedName))
+      ) {
+        return node.name.toLowerCase();
+      }
 
-      if (parent.kind === "constref" && node.name.toLowerCase() !== "null") {
+      if (parent.kind === "constref" && normalizedName !== "null") {
         return node.name;
       }
 
@@ -2539,7 +2482,6 @@ function printNode(path, options, print) {
         return "callable";
       }
 
-      const lowerCasedName = node.name.toLowerCase();
       const isLowerCase =
         [
           "int",
@@ -2549,12 +2491,10 @@ function printNode(path, options, print) {
           "null",
           "void",
           "iterable",
-          "object",
-          "self",
-          "parent"
-        ].indexOf(lowerCasedName) !== -1;
+          "object"
+        ].indexOf(normalizedName) !== -1;
 
-      return isLowerCase ? lowerCasedName : node.name;
+      return isLowerCase ? normalizedName : node.name;
     }
     case "error":
     default:


Test patch:
diff --git a/tests/assign/__snapshots__/jsfmt.spec.js.snap b/tests/assign/__snapshots__/jsfmt.spec.js.snap
index 0973c08..22f8b77 100644
--- a/tests/assign/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/assign/__snapshots__/jsfmt.spec.js.snap
@@ -75,6 +75,25 @@ $obj->veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongProperty = $obj->veryVeryV
 $obj->veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongProperty->veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongProperty = (new MyClass())->call($arg);
 $obj->loooooooooooong->lookup = $this->getRequest()->getParam('instance-resource-id');
 $obj->loooooooooooong->lookup = (int) $this->getRequest()->getParam('instance-resource-id');
+
+$component = $var->insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = $var->insertReallyReallyReally{$ReallyReallyReallyReallyReallyLongName};
+$component = Foo::$insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = $a::$insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = (new Foo())->insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = (clone $a)->insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+
+$component = $var->insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = $var->insertReallyReallyReallyReallyReallyReallyReallyReallyReally{$ReallyReallyReallyReallyReallyReallyLongName};
+$component = Foo::$insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = $a::$insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = (new Foo())->insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = (clone $a)->insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+
+$component = $var->insertReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
+$component = Foo::$insertReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
+$component = $var->insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
+$component = Foo::$insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 $var = 1;
@@ -210,4 +229,43 @@ $obj->loooooooooooong->lookup = (int) $this->getRequest()->getParam(
     'instance-resource-id'
 );
 
+$component =
+    $var->insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component =
+    $var->insertReallyReallyReally{$ReallyReallyReallyReallyReallyLongName};
+$component =
+    Foo::$insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component =
+    $a::$insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = (new Foo())
+    ->insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = (clone $a)
+    ->insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+
+$component =
+    $var->insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component =
+    $var->insertReallyReallyReallyReallyReallyReallyReallyReallyReally{
+        $ReallyReallyReallyReallyReallyReallyLongName
+    };
+$component =
+    Foo::$insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component =
+    $a::$insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = (new Foo())
+    ->insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = (clone $a)
+    ->insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+
+$component =
+    $var->insertReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
+$component =
+    Foo::$insertReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
+$component =
+    $var
+        ->insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
+$component =
+    Foo
+        ::$insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
+
 `;
diff --git a/tests/assign/assign.php b/tests/assign/assign.php
index 48d6ea4..9525371 100644
--- a/tests/assign/assign.php
+++ b/tests/assign/assign.php
@@ -72,3 +72,22 @@ $obj->veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongProperty = $obj->veryVeryV
 $obj->veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongProperty->veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongProperty = (new MyClass())->call($arg);
 $obj->loooooooooooong->lookup = $this->getRequest()->getParam('instance-resource-id');
 $obj->loooooooooooong->lookup = (int) $this->getRequest()->getParam('instance-resource-id');
+
+$component = $var->insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = $var->insertReallyReallyReally{$ReallyReallyReallyReallyReallyLongName};
+$component = Foo::$insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = $a::$insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = (new Foo())->insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = (clone $a)->insertReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+
+$component = $var->insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = $var->insertReallyReallyReallyReallyReallyReallyReallyReallyReally{$ReallyReallyReallyReallyReallyReallyLongName};
+$component = Foo::$insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = $a::$insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = (new Foo())->insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+$component = (clone $a)->insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName;
+
+$component = $var->insertReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
+$component = Foo::$insertReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
+$component = $var->insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
+$component = Foo::$insertReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
diff --git a/tests/class/__snapshots__/jsfmt.spec.js.snap b/tests/class/__snapshots__/jsfmt.spec.js.snap
index d87886e..daa5e20 100644
--- a/tests/class/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/class/__snapshots__/jsfmt.spec.js.snap
@@ -176,8 +176,10 @@ $instance = new class extends \\Foo implements \\HandleableInterface {
 };
 
 // Parenthesis on the next line
-$instance = new class extends \\Foo
-    implements \\ArrayAccess, \\Countable, \\Serializable
+$instance = new class extends \\Foo implements
+        \\ArrayAccess,
+        \\Countable,
+        \\Serializable
 {
     // Class content
 };
diff --git a/tests/identifier/__snapshots__/jsfmt.spec.js.snap b/tests/identifier/__snapshots__/jsfmt.spec.js.snap
index 2983301..0884e2a 100644
--- a/tests/identifier/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/identifier/__snapshots__/jsfmt.spec.js.snap
@@ -43,6 +43,11 @@ class A {
         static::who();
         sTaTic::who();
     }
+
+    public function foo(self $arg) {}
+    public function foo2(sElF $arg) {}
+    public function foo3(parent $arg) {}
+    public function foo4(pArEnT $arg) {}
 }
 
 // Should don't change
@@ -52,6 +57,11 @@ $var = $array[iNt];
 
 $var = $array->{int};
 $var = $array->{iNt};
+
+self();
+sElF();
+parent();
+pArEnT();
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 
@@ -157,6 +167,19 @@ class A
         static::who();
         static::who();
     }
+
+    public function foo(self $arg)
+    {
+    }
+    public function foo2(self $arg)
+    {
+    }
+    public function foo3(parent $arg)
+    {
+    }
+    public function foo4(parent $arg)
+    {
+    }
 }
 
 // Should don't change
@@ -167,4 +190,9 @@ $var = $array[iNt];
 $var = $array->{int};
 $var = $array->{iNt};
 
+self();
+sElF();
+parent();
+pArEnT();
+
 `;
diff --git a/tests/identifier/identifier.php b/tests/identifier/identifier.php
index 8d45e7d..dea9b6c 100644
--- a/tests/identifier/identifier.php
+++ b/tests/identifier/identifier.php
@@ -40,6 +40,11 @@ class A {
         static::who();
         sTaTic::who();
     }
+
+    public function foo(self $arg) {}
+    public function foo2(sElF $arg) {}
+    public function foo3(parent $arg) {}
+    public function foo4(pArEnT $arg) {}
 }
 
 // Should don't change
@@ -49,3 +54,8 @@ $var = $array[iNt];
 
 $var = $array->{int};
 $var = $array->{iNt};
+
+self();
+sElF();
+parent();
+pArEnT();
diff --git a/tests/member_chain/__snapshots__/jsfmt.spec.js.snap b/tests/member_chain/__snapshots__/jsfmt.spec.js.snap
index e3ae0ec..6d9356c 100644
--- a/tests/member_chain/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/member_chain/__snapshots__/jsfmt.spec.js.snap
@@ -834,8 +834,9 @@ $page = TableRegistry::insertReallyReallyReallyLongName('Pages')
     ::insertReallyReallyReallyLongName();
 
 $page = TableRegistry::insertReallyReallyReallyLongName[0];
-$page = TableRegistry
-    ::insertReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
+$page =
+    TableRegistry
+        ::insertReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
 $page = TableRegistry::insertReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName()
     ::insertReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
 $page = TableRegistry::insertReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName()
@@ -859,7 +860,8 @@ $component = Foo::test([
     'foobar' => 'barfoo',
     'barfoo' => 'foobar'
 ]);
-$component = Foo
-    ::$insertReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
+$component =
+    Foo
+        ::$insertReallyReallyReallyReallyReallyReallyReallyReallyReallyLongName[0];
 
 `;
diff --git a/tests/parens/__snapshots__/jsfmt.spec.js.snap b/tests/parens/__snapshots__/jsfmt.spec.js.snap
index a34a7dd..f9f0897 100644
--- a/tests/parens/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/parens/__snapshots__/jsfmt.spec.js.snap
@@ -2322,6 +2322,14 @@ $var = +(+$var ? 1 : 2);
 $var = +($var++ ? 1 : 2);
 $var = ((true ? 'true' : false) ? (true ? 'true' : false) : (true ? 'true' : false));
 $var = $var ? $var1 ? 1 : 2 : $var2 ? 3 : 4;
+
+$var = $var ?: $var ?: $var ?: 'string';
+$var = ($var ?: $var) ?: $var ?: 'string';
+$var = (($var ?: $var) ?: $var) ?: 'string';
+$var = ((($var ?: $var) ?: $var) ?: 'string');
+$var = ($var ?: ($var ?: $var)) ?: 'string';
+$var = ($var ?: (($var ?: $var) ?: 'string'));
+$var = ($var ?: ($var ?: ($var ?: 'string')));
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 <?php
 
@@ -2380,6 +2388,14 @@ $var = (true
         : false);
 $var = ($var ? ($var1 ? 1 : 2) : $var2) ? 3 : 4;
 
+$var = $var ?: $var ?: $var ?: 'string';
+$var = $var ?: $var ?: $var ?: 'string';
+$var = $var ?: $var ?: $var ?: 'string';
+$var = $var ?: $var ?: $var ?: 'string';
+$var = $var ?: ($var ?: $var) ?: 'string';
+$var = $var ?: ($var ?: $var ?: 'string');
+$var = $var ?: ($var ?: ($var ?: 'string'));
+
 `;
 
 exports[`return.php - php-verify: return.php 1`] = `
diff --git a/tests/parens/retif.php b/tests/parens/retif.php
index 418e6a3..ec36587 100644
--- a/tests/parens/retif.php
+++ b/tests/parens/retif.php
@@ -42,3 +42,11 @@ $var = +(+$var ? 1 : 2);
 $var = +($var++ ? 1 : 2);
 $var = ((true ? 'true' : false) ? (true ? 'true' : false) : (true ? 'true' : false));
 $var = $var ? $var1 ? 1 : 2 : $var2 ? 3 : 4;
+
+$var = $var ?: $var ?: $var ?: 'string';
+$var = ($var ?: $var) ?: $var ?: 'string';
+$var = (($var ?: $var) ?: $var) ?: 'string';
+$var = ((($var ?: $var) ?: $var) ?: 'string');
+$var = ($var ?: ($var ?: $var)) ?: 'string';
+$var = ($var ?: (($var ?: $var) ?: 'string'));
+$var = ($var ?: ($var ?: ($var ?: 'string')));