diff --git a/src/printer.mjs b/src/printer.mjs index a9f06c170..7a05593e5 100644 --- a/src/printer.mjs +++ b/src/printer.mjs @@ -1622,6 +1622,27 @@ function printAssignmentRight( return [" ", ref, printedRight]; } +// Without parentheses, `new` only accepts a class name or a variable, +// possibly with property and static property lookups. Anything else, like +// `new ($a ?? $b)()`, must keep them or it changes meaning or stops parsing. +function isNewClassReference(node) { + switch (node.kind) { + case "name": + case "variable": + case "selfreference": + case "staticreference": + case "parentreference": + return true; + case "propertylookup": + case "nullsafepropertylookup": + return isNewClassReference(node.what); + case "staticlookup": + return node.offset.kind === "variable" && isNewClassReference(node.what); + default: + return false; + } +} + function needsHardlineAfterDanglingComment(node) { if (!node.comments) { return false; @@ -2223,7 +2244,7 @@ function printNode(path, options, print) { group(print("what")) ); } else { - const isExpression = ["call", "offsetlookup"].includes(node.what.kind); + const isExpression = !isNewClassReference(node.what); const printed = [ isExpression ? "(" : "", print("what"), diff --git a/tests/new/__snapshots__/jsfmt.spec.mjs.snap b/tests/new/__snapshots__/jsfmt.spec.mjs.snap index 177c147da..1abbca35e 100644 --- a/tests/new/__snapshots__/jsfmt.spec.mjs.snap +++ b/tests/new/__snapshots__/jsfmt.spec.mjs.snap @@ -1,5 +1,82 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing +exports[`class-expression.php 1`] = ` +====================================options===================================== +parsers: ["php"] +phpVersion: "8.3" +printWidth: 80 + | printWidth +=====================================input====================================== +factory()->class)(); +$h = new (static::$classes[$k] ?? Fallback::class)($z); +$i = new ($a->b)(); +$j = new (static::$class)(); +$k = new ($classes[$k])(); +$l = new ($this->factory())(); + +=====================================output===================================== +factory()->class)(); +$h = new (static::$classes[$k] ?? Fallback::class)($z); +$i = new $a->b(); +$j = new static::$class(); +$k = new ($classes[$k])(); +$l = new ($this->factory())(); + +================================================================================ +`; + +exports[`class-expression.php 2`] = ` +====================================options===================================== +parsers: ["php"] +printWidth: 80 + | printWidth +=====================================input====================================== +factory()->class)(); +$h = new (static::$classes[$k] ?? Fallback::class)($z); +$i = new ($a->b)(); +$j = new (static::$class)(); +$k = new ($classes[$k])(); +$l = new ($this->factory())(); + +=====================================output===================================== +factory()->class)(); +$h = new (static::$classes[$k] ?? Fallback::class)($z); +$i = new $a->b(); +$j = new static::$class(); +$k = new ($classes[$k])(); +$l = new ($this->factory())(); + +================================================================================ +`; + exports[`new.php 1`] = ` ====================================options===================================== parsers: ["php"] diff --git a/tests/new/class-expression.php b/tests/new/class-expression.php new file mode 100644 index 000000000..cac9b3af7 --- /dev/null +++ b/tests/new/class-expression.php @@ -0,0 +1,13 @@ +factory()->class)(); +$h = new (static::$classes[$k] ?? Fallback::class)($z); +$i = new ($a->b)(); +$j = new (static::$class)(); +$k = new ($classes[$k])(); +$l = new ($this->factory())();