Skip to content

Commit 9bf3674

Browse files
authored
Merge pull request apache#8117 from junichi11/php84-new-without-parentheses
PHP 8.4 Support: new MyClass()->method() without parentheses
2 parents 4c229c6 + cbb5c44 commit 9bf3674

File tree

372 files changed

+77357
-54972
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

372 files changed

+77357
-54972
lines changed

php/php.api.phpmodule/manifest.mf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
Manifest-Version: 1.0
22
OpenIDE-Module: org.netbeans.modules.php.api.phpmodule
33
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/php/api/phpmodule/resources/Bundle.properties
4-
OpenIDE-Module-Specification-Version: 2.99
4+
OpenIDE-Module-Specification-Version: 2.100

php/php.api.phpmodule/nbproject/project.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717
is.autoload=true
18-
javac.source=1.8
18+
javac.release=17
1919
javac.compilerargs=-Xlint -Xlint:-serial
2020

2121
test.config.stableBTD.includes=**/*Test.class

php/php.api.phpmodule/src/org/netbeans/modules/php/api/PhpVersion.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"PhpVersion.PHP_81=PHP 8.1",
4141
"PhpVersion.PHP_82=PHP 8.2",
4242
"PhpVersion.PHP_83=PHP 8.3",
43+
"PhpVersion.PHP_84=PHP 8.4",
4344
})
4445
public enum PhpVersion {
4546

@@ -109,6 +110,11 @@ public enum PhpVersion {
109110
* @since 2.93
110111
*/
111112
PHP_83(Bundle.PhpVersion_PHP_83()),
113+
/**
114+
* PHP 8.4.
115+
* @since 2.100
116+
*/
117+
PHP_84(Bundle.PhpVersion_PHP_84()),
112118
;
113119

114120
private final String displayName;
@@ -310,9 +316,10 @@ private enum Period {
310316
PHP_73(LocalDate.of(2018, 12, 6), LocalDate.of(2020, 12, 6), LocalDate.of(2021, 12, 6)),
311317
PHP_74(LocalDate.of(2019, 11, 28), LocalDate.of(2021, 11, 28), LocalDate.of(2022, 11, 28)),
312318
PHP_80(LocalDate.of(2020, 11, 26), LocalDate.of(2022, 11, 26), LocalDate.of(2023, 11, 26)),
313-
PHP_81(LocalDate.of(2021, 11, 25), LocalDate.of(2023, 11, 25), LocalDate.of(2024, 11, 25)),
314-
PHP_82(LocalDate.of(2022, 12, 8), LocalDate.of(2024, 12, 8), LocalDate.of(2025, 12, 8)),
315-
PHP_83(LocalDate.of(2023, 11, 23), LocalDate.of(2025, 11, 23), LocalDate.of(2026, 11, 23)),
319+
PHP_81(LocalDate.of(2021, 11, 25), LocalDate.of(2023, 11, 25), LocalDate.of(2025, 12, 31)),
320+
PHP_82(LocalDate.of(2022, 12, 8), LocalDate.of(2024, 12, 31), LocalDate.of(2026, 12, 31)),
321+
PHP_83(LocalDate.of(2023, 11, 23), LocalDate.of(2025, 12, 31), LocalDate.of(2027, 12, 31)),
322+
PHP_84(LocalDate.of(2024, 11, 21), LocalDate.of(2026, 12, 31), LocalDate.of(2028, 12, 31)),
316323
;
317324

318325
private final LocalDate initialRelease;

php/php.editor/nbproject/project.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ javac.source=1.8
1818
javac.compilerargs=-Xlint -Xlint:-serial
1919
nbjavac.ignore.missing.enclosing=**/CUP$ASTPHP5Parser$actions.class
2020
nbm.needs.restart=true
21-
spec.version.base=2.42.0
21+
spec.version.base=2.43.0
2222
release.external/predefined_vars-1.0.zip=docs/predefined_vars.zip
2323
sigtest.gen.fail.on.error=false
2424

php/php.editor/nbproject/project.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@
304304
<build-prerequisite/>
305305
<compile-dependency/>
306306
<run-dependency>
307-
<specification-version>2.95</specification-version>
307+
<specification-version>2.100</specification-version>
308308
</run-dependency>
309309
</dependency>
310310
<dependency>

php/php.editor/src/org/netbeans/modules/php/editor/CodeUtils.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,9 @@ public static String extractQualifiedName(Expression typeName) {
330330
return extractQualifiedName((UnionType) typeName);
331331
} else if (typeName instanceof IntersectionType) {
332332
return extractQualifiedName((IntersectionType) typeName);
333+
} else if (typeName instanceof ClassInstanceCreation) {
334+
// PHP 8.4 new without parentheses new A()->method();
335+
return null;
333336
}
334337
assert false : typeName.getClass();
335338
return null;

php/php.editor/src/org/netbeans/modules/php/editor/indent/CodeStyle.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,10 @@ public boolean spaceWithinAttributeDeclParens() {
486486
return preferences.getBoolean(SPACE_WITHIN_ATTRIBUTE_DECL_PARENS, getDefaultAsBoolean(SPACE_WITHIN_ATTRIBUTE_DECL_PARENS));
487487
}
488488

489+
public boolean spaceWithinOtherParens() {
490+
return preferences.getBoolean(SPACE_WITHIN_OTHER_PARENS, getDefaultAsBoolean(SPACE_WITHIN_OTHER_PARENS));
491+
}
492+
489493
public boolean spaceBeforeComma() {
490494
return preferences.getBoolean(SPACE_BEFORE_COMMA, getDefaultAsBoolean(SPACE_BEFORE_COMMA));
491495
}

php/php.editor/src/org/netbeans/modules/php/editor/indent/FmtOptions.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ public final class FmtOptions {
171171
public static final String SPACE_WITHIN_ARRAY_BRACKETS = "spaceWithinArrayBrackets"; //NOI18N
172172
public static final String SPACE_WITHIN_ATTRIBUTE_BRACKETS = "spaceWithinAttributeBrackets"; //NOI18N
173173
public static final String SPACE_WITHIN_ATTRIBUTE_DECL_PARENS = "spaceWithinAttributeDeclParens"; //NOI18N
174+
public static final String SPACE_WITHIN_OTHER_PARENS = "spaceWithinOtherParens"; //NOI18N
174175
public static final String SPACE_BEFORE_COMMA = "spaceBeforeComma"; //NOI18N
175176
public static final String SPACE_AFTER_COMMA = "spaceAfterComma"; //NOI18N
176177
public static final String SPACE_BEFORE_SEMI = "spaceBeforeSemi"; //NOI18N
@@ -370,6 +371,7 @@ private static void createDefaults() {
370371
{SPACE_WITHIN_ARRAY_BRACKETS, FALSE},
371372
{SPACE_WITHIN_ATTRIBUTE_BRACKETS, FALSE},
372373
{SPACE_WITHIN_ATTRIBUTE_DECL_PARENS, FALSE},
374+
{SPACE_WITHIN_OTHER_PARENS, FALSE},
373375
{SPACE_BEFORE_COMMA, FALSE},
374376
{SPACE_AFTER_COMMA, TRUE},
375377
{SPACE_BEFORE_SEMI, FALSE},

php/php.editor/src/org/netbeans/modules/php/editor/indent/FormatToken.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ public enum Kind {
127127
WHITESPACE_WITHIN_ATTRIBUTE_DECL_PARENS,
128128
WHITESPACE_WITHIN_TYPE_CAST_PARENS,
129129
WHITESPACE_WITHIN_DNF_TYPE_PARENS, // (A&B)|C
130+
WHITESPACE_WITHIN_OTHER_PARENS, // e.g. new (trim(' Example '))()
130131
WHITESPACE_WITHIN_DYNAMIC_NAME_BRACES, // {$example}
131132
WHITESPACE_BEFORE_COMMA,
132133
WHITESPACE_AFTER_COMMA,

php/php.editor/src/org/netbeans/modules/php/editor/indent/FormatVisitor.java

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,13 @@
5858
import org.netbeans.modules.php.editor.parser.astnodes.CatchClause;
5959
import org.netbeans.modules.php.editor.parser.astnodes.ClassDeclaration;
6060
import org.netbeans.modules.php.editor.parser.astnodes.ClassInstanceCreation;
61+
import org.netbeans.modules.php.editor.parser.astnodes.ClassInstanceCreationVariable;
6162
import org.netbeans.modules.php.editor.parser.astnodes.ConditionalExpression;
6263
import org.netbeans.modules.php.editor.parser.astnodes.ConstantDeclaration;
6364
import org.netbeans.modules.php.editor.parser.astnodes.DeclareStatement;
65+
import org.netbeans.modules.php.editor.parser.astnodes.DereferencableVariable;
66+
import org.netbeans.modules.php.editor.parser.astnodes.DereferencedArrayAccess;
67+
import org.netbeans.modules.php.editor.parser.astnodes.Dispatch;
6468
import org.netbeans.modules.php.editor.parser.astnodes.DoStatement;
6569
import org.netbeans.modules.php.editor.parser.astnodes.EnumDeclaration;
6670
import org.netbeans.modules.php.editor.parser.astnodes.Expression;
@@ -89,12 +93,14 @@
8993
import org.netbeans.modules.php.editor.parser.astnodes.NamedArgument;
9094
import org.netbeans.modules.php.editor.parser.astnodes.NamespaceDeclaration;
9195
import org.netbeans.modules.php.editor.parser.astnodes.NullableType;
96+
import org.netbeans.modules.php.editor.parser.astnodes.ParenthesisExpression;
9297
import org.netbeans.modules.php.editor.parser.astnodes.Program;
9398
import org.netbeans.modules.php.editor.parser.astnodes.ReflectionVariable;
9499
import org.netbeans.modules.php.editor.parser.astnodes.ReturnStatement;
95100
import org.netbeans.modules.php.editor.parser.astnodes.SingleFieldDeclaration;
96101
import org.netbeans.modules.php.editor.parser.astnodes.SingleUseStatementPart;
97102
import org.netbeans.modules.php.editor.parser.astnodes.Statement;
103+
import org.netbeans.modules.php.editor.parser.astnodes.StaticDispatch;
98104
import org.netbeans.modules.php.editor.parser.astnodes.StaticFieldAccess;
99105
import org.netbeans.modules.php.editor.parser.astnodes.StaticMethodInvocation;
100106
import org.netbeans.modules.php.editor.parser.astnodes.StaticStatement;
@@ -299,7 +305,7 @@ public void visit(StaticStatement node) {
299305
@Override
300306
public void visit(AnonymousObjectVariable node) {
301307
// (new Test)->method();
302-
super.visit(node);
308+
scan(node.getName());
303309
// avoid adding incorrect space for "within a method call"
304310
// e.g. (new Test)->method(); -> (new Test )->method();
305311
addAllUntilOffset(node.getEndOffset());
@@ -876,7 +882,7 @@ public void visit(ClassInstanceCreation node) {
876882
ts.movePrevious();
877883
scan(node.getBody());
878884
} else {
879-
if (node.ctorParams() != null && node.ctorParams().size() > 0) {
885+
if (node.ctorParams() != null && !node.ctorParams().isEmpty()) {
880886
boolean addIndentation = !(path.get(1) instanceof ReturnStatement
881887
|| path.get(1) instanceof Assignment
882888
|| path.get(1) instanceof ExpressionStatement)
@@ -890,7 +896,10 @@ public void visit(ClassInstanceCreation node) {
890896
}
891897
addAllUntilOffset(node.getEndOffset());
892898
} else {
893-
super.visit(node);
899+
// e.g. new Example(); new $className();
900+
// ctorParams() is empty, so, add tokens until the end offset
901+
// to add WHITESPACE_WITHIN_METHOD_CALL_PARENS
902+
addAllUntilOffset(node.getEndOffset());
894903
}
895904
}
896905
}
@@ -1259,7 +1268,9 @@ public void visit(ExpressionStatement node) {
12591268
if (moveNext() && lastIndex < ts.index()) {
12601269
addFormatToken(formatTokens); // add the first token of the expression and then add the indentation
12611270
Expression expression = node.getExpression();
1262-
boolean addIndent = !(expression instanceof MethodInvocation || expression instanceof StaticMethodInvocation);
1271+
boolean addIndent = !(expression instanceof MethodInvocation
1272+
|| expression instanceof StaticMethodInvocation
1273+
|| isAnonymousClass(expression));
12631274
if (expression instanceof Assignment) {
12641275
// anonymous classes
12651276
Assignment assignment = (Assignment) expression;
@@ -2681,6 +2692,18 @@ public void visit(ReflectionVariable node) {
26812692
ts.movePrevious();
26822693
}
26832694

2695+
@Override
2696+
public void visit(DereferencableVariable node) {
2697+
scan(node.getExpression());
2698+
addAllUntilOffset(node.getEndOffset());
2699+
}
2700+
2701+
@Override
2702+
public void visit(ParenthesisExpression node) {
2703+
scan(node.getExpression());
2704+
addAllUntilOffset(node.getEndOffset());
2705+
}
2706+
26842707
private void processUnionOrIntersectionType(List<Expression> types) {
26852708
assert !types.isEmpty();
26862709
final Expression lastType = types.get(types.size() - 1);
@@ -2896,6 +2919,12 @@ private void addFormatToken(List<FormatToken> tokens) {
28962919
} else if (parent instanceof UnionType) {
28972920
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
28982921
tokens.add(new FormatToken(FormatToken.Kind.WHITESPACE_WITHIN_DNF_TYPE_PARENS, ts.offset() + ts.token().length()));
2922+
} else if (isParenthesisExpression(parent)
2923+
|| parent instanceof DereferencableVariable
2924+
|| isAnonymousObjectVariable(parent)
2925+
) {
2926+
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
2927+
tokens.add(new FormatToken(FormatToken.Kind.WHITESPACE_WITHIN_OTHER_PARENS, ts.offset() + ts.token().length()));
28992928
} else {
29002929
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
29012930
}
@@ -2937,6 +2966,11 @@ private void addFormatToken(List<FormatToken> tokens) {
29372966
} else if (parent instanceof UnionType) {
29382967
tokens.add(new FormatToken(FormatToken.Kind.WHITESPACE_WITHIN_DNF_TYPE_PARENS, ts.offset()));
29392968
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
2969+
} else if (parent instanceof ParenthesisExpression
2970+
|| parent instanceof DereferencableVariable
2971+
|| parent instanceof AnonymousObjectVariable) {
2972+
tokens.add(new FormatToken(FormatToken.Kind.WHITESPACE_WITHIN_OTHER_PARENS, ts.offset()));
2973+
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
29402974
} else {
29412975
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
29422976
}
@@ -3652,11 +3686,50 @@ private static boolean isCloseParen(Token<? extends PHPTokenId> token) {
36523686
return TokenUtilities.textEquals(")", token.text()); // NOI18N
36533687
}
36543688

3689+
private static boolean isParenthesisExpression(ASTNode astNode) {
3690+
ASTNode node = astNode;
3691+
if (node instanceof ExpressionStatement) {
3692+
// ($example == 1);
3693+
node = ((ExpressionStatement) node).getExpression();
3694+
}
3695+
return node instanceof ParenthesisExpression;
3696+
}
3697+
3698+
private static boolean isAnonymousObjectVariable(ASTNode astNode) {
3699+
ASTNode node = astNode;
3700+
if (node instanceof ExpressionStatement) {
3701+
// (new $class());
3702+
node = ((ExpressionStatement) node).getExpression();
3703+
if (node instanceof DereferencedArrayAccess) {
3704+
// (new $class())['key'];
3705+
node = ((DereferencedArrayAccess) node).getMember();
3706+
}
3707+
}
3708+
return node instanceof AnonymousObjectVariable;
3709+
}
3710+
36553711
private static boolean isAnonymousClass(ASTNode astNode) {
36563712
ASTNode node = astNode;
36573713
if (astNode instanceof NamedArgument) {
36583714
node = ((NamedArgument) astNode).getExpression();
36593715
}
3716+
3717+
// new class(){}['key'], new class(){}->method()
3718+
while (node instanceof Dispatch
3719+
|| node instanceof StaticDispatch
3720+
|| node instanceof ClassInstanceCreationVariable
3721+
|| node instanceof FunctionInvocation) {
3722+
if (node instanceof Dispatch) {
3723+
node = ((Dispatch) node).getDispatcher();
3724+
} else if (node instanceof StaticDispatch) {
3725+
node = ((StaticDispatch) node).getDispatcher();
3726+
} else if (node instanceof ClassInstanceCreationVariable) {
3727+
node = ((ClassInstanceCreationVariable) node).getName();
3728+
} else if (node instanceof FunctionInvocation) {
3729+
// $c = new class{}();
3730+
node = ((FunctionInvocation) node).getFunctionName().getName();
3731+
}
3732+
}
36603733
return node instanceof ClassInstanceCreation && ((ClassInstanceCreation) node).isAnonymous();
36613734
}
36623735

0 commit comments

Comments
 (0)