Skip to content

Commit

Permalink
PHP 8.4 Support: new MyClass()->method() without parentheses (Part 2)
Browse files Browse the repository at this point in the history
- apache#8035
- https://wiki.php.net/rfc#php_84
- https://wiki.php.net/rfc/new_without_parentheses
- Fix the formatter
- Add `Other` to spaces within parentheses option e.g. `($a + $b);`, `new (trim(' Example '))()->field;`
- Add/Fix unit tests
  • Loading branch information
junichi11 authored and jhorvath committed Jan 10, 2025
1 parent ac5ea1f commit 201a1d8
Show file tree
Hide file tree
Showing 27 changed files with 2,078 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,10 @@ public boolean spaceWithinAttributeDeclParens() {
return preferences.getBoolean(SPACE_WITHIN_ATTRIBUTE_DECL_PARENS, getDefaultAsBoolean(SPACE_WITHIN_ATTRIBUTE_DECL_PARENS));
}

public boolean spaceWithinOtherParens() {
return preferences.getBoolean(SPACE_WITHIN_OTHER_PARENS, getDefaultAsBoolean(SPACE_WITHIN_OTHER_PARENS));
}

public boolean spaceBeforeComma() {
return preferences.getBoolean(SPACE_BEFORE_COMMA, getDefaultAsBoolean(SPACE_BEFORE_COMMA));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ public final class FmtOptions {
public static final String SPACE_WITHIN_ARRAY_BRACKETS = "spaceWithinArrayBrackets"; //NOI18N
public static final String SPACE_WITHIN_ATTRIBUTE_BRACKETS = "spaceWithinAttributeBrackets"; //NOI18N
public static final String SPACE_WITHIN_ATTRIBUTE_DECL_PARENS = "spaceWithinAttributeDeclParens"; //NOI18N
public static final String SPACE_WITHIN_OTHER_PARENS = "spaceWithinOtherParens"; //NOI18N
public static final String SPACE_BEFORE_COMMA = "spaceBeforeComma"; //NOI18N
public static final String SPACE_AFTER_COMMA = "spaceAfterComma"; //NOI18N
public static final String SPACE_BEFORE_SEMI = "spaceBeforeSemi"; //NOI18N
Expand Down Expand Up @@ -370,6 +371,7 @@ private static void createDefaults() {
{SPACE_WITHIN_ARRAY_BRACKETS, FALSE},
{SPACE_WITHIN_ATTRIBUTE_BRACKETS, FALSE},
{SPACE_WITHIN_ATTRIBUTE_DECL_PARENS, FALSE},
{SPACE_WITHIN_OTHER_PARENS, FALSE},
{SPACE_BEFORE_COMMA, FALSE},
{SPACE_AFTER_COMMA, TRUE},
{SPACE_BEFORE_SEMI, FALSE},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ public enum Kind {
WHITESPACE_WITHIN_ATTRIBUTE_DECL_PARENS,
WHITESPACE_WITHIN_TYPE_CAST_PARENS,
WHITESPACE_WITHIN_DNF_TYPE_PARENS, // (A&B)|C
WHITESPACE_WITHIN_OTHER_PARENS, // e.g. new (trim(' Example '))()
WHITESPACE_WITHIN_DYNAMIC_NAME_BRACES, // {$example}
WHITESPACE_BEFORE_COMMA,
WHITESPACE_AFTER_COMMA,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,13 @@
import org.netbeans.modules.php.editor.parser.astnodes.CatchClause;
import org.netbeans.modules.php.editor.parser.astnodes.ClassDeclaration;
import org.netbeans.modules.php.editor.parser.astnodes.ClassInstanceCreation;
import org.netbeans.modules.php.editor.parser.astnodes.ClassInstanceCreationVariable;
import org.netbeans.modules.php.editor.parser.astnodes.ConditionalExpression;
import org.netbeans.modules.php.editor.parser.astnodes.ConstantDeclaration;
import org.netbeans.modules.php.editor.parser.astnodes.DeclareStatement;
import org.netbeans.modules.php.editor.parser.astnodes.DereferencableVariable;
import org.netbeans.modules.php.editor.parser.astnodes.DereferencedArrayAccess;
import org.netbeans.modules.php.editor.parser.astnodes.Dispatch;
import org.netbeans.modules.php.editor.parser.astnodes.DoStatement;
import org.netbeans.modules.php.editor.parser.astnodes.EnumDeclaration;
import org.netbeans.modules.php.editor.parser.astnodes.Expression;
Expand Down Expand Up @@ -89,12 +93,14 @@
import org.netbeans.modules.php.editor.parser.astnodes.NamedArgument;
import org.netbeans.modules.php.editor.parser.astnodes.NamespaceDeclaration;
import org.netbeans.modules.php.editor.parser.astnodes.NullableType;
import org.netbeans.modules.php.editor.parser.astnodes.ParenthesisExpression;
import org.netbeans.modules.php.editor.parser.astnodes.Program;
import org.netbeans.modules.php.editor.parser.astnodes.ReflectionVariable;
import org.netbeans.modules.php.editor.parser.astnodes.ReturnStatement;
import org.netbeans.modules.php.editor.parser.astnodes.SingleFieldDeclaration;
import org.netbeans.modules.php.editor.parser.astnodes.SingleUseStatementPart;
import org.netbeans.modules.php.editor.parser.astnodes.Statement;
import org.netbeans.modules.php.editor.parser.astnodes.StaticDispatch;
import org.netbeans.modules.php.editor.parser.astnodes.StaticFieldAccess;
import org.netbeans.modules.php.editor.parser.astnodes.StaticMethodInvocation;
import org.netbeans.modules.php.editor.parser.astnodes.StaticStatement;
Expand Down Expand Up @@ -299,7 +305,7 @@ public void visit(StaticStatement node) {
@Override
public void visit(AnonymousObjectVariable node) {
// (new Test)->method();
super.visit(node);
scan(node.getName());
// avoid adding incorrect space for "within a method call"
// e.g. (new Test)->method(); -> (new Test )->method();
addAllUntilOffset(node.getEndOffset());
Expand Down Expand Up @@ -876,7 +882,7 @@ public void visit(ClassInstanceCreation node) {
ts.movePrevious();
scan(node.getBody());
} else {
if (node.ctorParams() != null && node.ctorParams().size() > 0) {
if (node.ctorParams() != null && !node.ctorParams().isEmpty()) {
boolean addIndentation = !(path.get(1) instanceof ReturnStatement
|| path.get(1) instanceof Assignment
|| path.get(1) instanceof ExpressionStatement)
Expand All @@ -890,7 +896,10 @@ public void visit(ClassInstanceCreation node) {
}
addAllUntilOffset(node.getEndOffset());
} else {
super.visit(node);
// e.g. new Example(); new $className();
// ctorParams() is empty, so, add tokens until the end offset
// to add WHITESPACE_WITHIN_METHOD_CALL_PARENS
addAllUntilOffset(node.getEndOffset());
}
}
}
Expand Down Expand Up @@ -1259,7 +1268,9 @@ public void visit(ExpressionStatement node) {
if (moveNext() && lastIndex < ts.index()) {
addFormatToken(formatTokens); // add the first token of the expression and then add the indentation
Expression expression = node.getExpression();
boolean addIndent = !(expression instanceof MethodInvocation || expression instanceof StaticMethodInvocation);
boolean addIndent = !(expression instanceof MethodInvocation
|| expression instanceof StaticMethodInvocation
|| isAnonymousClass(expression));
if (expression instanceof Assignment) {
// anonymous classes
Assignment assignment = (Assignment) expression;
Expand Down Expand Up @@ -2681,6 +2692,18 @@ public void visit(ReflectionVariable node) {
ts.movePrevious();
}

@Override
public void visit(DereferencableVariable node) {
scan(node.getExpression());
addAllUntilOffset(node.getEndOffset());
}

@Override
public void visit(ParenthesisExpression node) {
scan(node.getExpression());
addAllUntilOffset(node.getEndOffset());
}

private void processUnionOrIntersectionType(List<Expression> types) {
assert !types.isEmpty();
final Expression lastType = types.get(types.size() - 1);
Expand Down Expand Up @@ -2896,6 +2919,12 @@ private void addFormatToken(List<FormatToken> tokens) {
} else if (parent instanceof UnionType) {
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
tokens.add(new FormatToken(FormatToken.Kind.WHITESPACE_WITHIN_DNF_TYPE_PARENS, ts.offset() + ts.token().length()));
} else if (isParenthesisExpression(parent)
|| parent instanceof DereferencableVariable
|| isAnonymousObjectVariable(parent)
) {
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
tokens.add(new FormatToken(FormatToken.Kind.WHITESPACE_WITHIN_OTHER_PARENS, ts.offset() + ts.token().length()));
} else {
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
}
Expand Down Expand Up @@ -2937,6 +2966,11 @@ private void addFormatToken(List<FormatToken> tokens) {
} else if (parent instanceof UnionType) {
tokens.add(new FormatToken(FormatToken.Kind.WHITESPACE_WITHIN_DNF_TYPE_PARENS, ts.offset()));
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
} else if (parent instanceof ParenthesisExpression
|| parent instanceof DereferencableVariable
|| parent instanceof AnonymousObjectVariable) {
tokens.add(new FormatToken(FormatToken.Kind.WHITESPACE_WITHIN_OTHER_PARENS, ts.offset()));
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
} else {
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
}
Expand Down Expand Up @@ -3652,11 +3686,50 @@ private static boolean isCloseParen(Token<? extends PHPTokenId> token) {
return TokenUtilities.textEquals(")", token.text()); // NOI18N
}

private static boolean isParenthesisExpression(ASTNode astNode) {
ASTNode node = astNode;
if (node instanceof ExpressionStatement) {
// ($example == 1);
node = ((ExpressionStatement) node).getExpression();
}
return node instanceof ParenthesisExpression;
}

private static boolean isAnonymousObjectVariable(ASTNode astNode) {
ASTNode node = astNode;
if (node instanceof ExpressionStatement) {
// (new $class());
node = ((ExpressionStatement) node).getExpression();
if (node instanceof DereferencedArrayAccess) {
// (new $class())['key'];
node = ((DereferencedArrayAccess) node).getMember();
}
}
return node instanceof AnonymousObjectVariable;
}

private static boolean isAnonymousClass(ASTNode astNode) {
ASTNode node = astNode;
if (astNode instanceof NamedArgument) {
node = ((NamedArgument) astNode).getExpression();
}

// new class(){}['key'], new class(){}->method()
while (node instanceof Dispatch
|| node instanceof StaticDispatch
|| node instanceof ClassInstanceCreationVariable
|| node instanceof FunctionInvocation) {
if (node instanceof Dispatch) {
node = ((Dispatch) node).getDispatcher();
} else if (node instanceof StaticDispatch) {
node = ((StaticDispatch) node).getDispatcher();
} else if (node instanceof ClassInstanceCreationVariable) {
node = ((ClassInstanceCreationVariable) node).getName();
} else if (node instanceof FunctionInvocation) {
// $c = new class{}();
node = ((FunctionInvocation) node).getFunctionName().getName();
}
}
return node instanceof ClassInstanceCreation && ((ClassInstanceCreation) node).isAnonymous();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ protected static class DocumentOptions {
public boolean spaceWithinAttributeBrackets;
public boolean spaceWithinAttributeDeclParens;
public boolean spaceWithinTypeCastParens;
public boolean spaceWithinOtherParens;
public boolean spaceBeforeComma;
public boolean spaceAfterComma;
public boolean spaceBeforeSemi;
Expand Down Expand Up @@ -307,6 +308,7 @@ public DocumentOptions(BaseDocument doc) {
spaceWithinAttributeBrackets = codeStyle.spaceWithinAttributeBrackets();
spaceWithinAttributeDeclParens = codeStyle.spaceWithinAttributeDeclParens();
spaceWithinTypeCastParens = codeStyle.spaceWithinTypeCastParens();
spaceWithinOtherParens = codeStyle.spaceWithinOtherParens();

spaceBeforeComma = codeStyle.spaceBeforeComma();
spaceAfterComma = codeStyle.spaceAfterComma();
Expand Down Expand Up @@ -1617,6 +1619,9 @@ && countOfNewLines(formatTokens.get(index + 1).getOldText()) > 0) {
// change here if we add the option for it
countSpaces = 0;
break;
case WHITESPACE_WITHIN_OTHER_PARENS:
countSpaces = docOptions.spaceWithinOtherParens ? 1 : 0;
break;
case WHITESPACE_WITHIN_DYNAMIC_NAME_BRACES:
// change here if we add the option for it
countSpaces = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ LBL_spaceWithinBraces=Braces
LBL_spaceWithinArrayBrackets=Array Brackets
LBL_spaceWithinAttributeBrackets=Attribute Brackets
LBL_spaceWithinAttributeDeclParens=Attribute Declaration
LBL_spaceWithinOtherParens=Other

LBL_Other=Other
LBL_spaceBeforeComma=Before Comma
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ private DefaultTreeModel createModel() {
new Item(SPACE_WITHIN_TYPE_CAST_PARENS),
new Item(SPACE_WITHIN_ARRAY_BRACKETS),
new Item(SPACE_WITHIN_ATTRIBUTE_BRACKETS),
new Item(SPACE_WITHIN_ATTRIBUTE_DECL_PARENS)
new Item(SPACE_WITHIN_ATTRIBUTE_DECL_PARENS),
new Item(SPACE_WITHIN_OTHER_PARENS)
),


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,5 @@ function namedArguments($a, $b) {}
"loooooong condition" => 2,
default => 0,
};

new (trim(' Example '))()->field;
Loading

0 comments on commit 201a1d8

Please sign in to comment.