Skip to content

Commit

Permalink
Merge pull request #6752 from junichi11/php83-dynamic-class-constant-…
Browse files Browse the repository at this point in the history
…fetch

PHP 8.3 Support: Dynamic class constant fetch #6701
  • Loading branch information
junichi11 authored Nov 28, 2023
2 parents 0b3757b + 7e70563 commit 16b9fc1
Show file tree
Hide file tree
Showing 195 changed files with 52,846 additions and 46,820 deletions.
2 changes: 1 addition & 1 deletion php/php.api.phpmodule/manifest.mf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Manifest-Version: 1.0
OpenIDE-Module: org.netbeans.modules.php.api.phpmodule
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/php/api/phpmodule/resources/Bundle.properties
OpenIDE-Module-Specification-Version: 2.92
OpenIDE-Module-Specification-Version: 2.93
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"PhpVersion.PHP_80=PHP 8.0",
"PhpVersion.PHP_81=PHP 8.1",
"PhpVersion.PHP_82=PHP 8.2",
"PhpVersion.PHP_83=PHP 8.3",
})
public enum PhpVersion {

Expand Down Expand Up @@ -103,6 +104,11 @@ public enum PhpVersion {
* @since 2.87
*/
PHP_82(Bundle.PhpVersion_PHP_82()),
/**
* PHP 8.3.
* @since 2.93
*/
PHP_83(Bundle.PhpVersion_PHP_83()),
;

private final String displayName;
Expand Down Expand Up @@ -284,6 +290,7 @@ private enum Period {
PHP_80(LocalDate.of(2020, 11, 26), LocalDate.of(2022, 11, 26), LocalDate.of(2023, 11, 26)),
PHP_81(LocalDate.of(2021, 11, 25), LocalDate.of(2023, 11, 25), LocalDate.of(2024, 11, 25)),
PHP_82(LocalDate.of(2022, 12, 8), LocalDate.of(2024, 12, 8), LocalDate.of(2025, 12, 8)),
PHP_83(LocalDate.of(2023, 11, 23), LocalDate.of(2025, 11, 23), LocalDate.of(2026, 11, 23)),
;

private final LocalDate initialRelease;
Expand Down
2 changes: 1 addition & 1 deletion php/php.editor/nbproject/project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ javac.source=1.8
javac.compilerargs=-Xlint -Xlint:-serial
nbjavac.ignore.missing.enclosing=**/CUP$ASTPHP5Parser$actions.class
nbm.needs.restart=true
spec.version.base=2.28.0
spec.version.base=2.29.0
release.external/predefined_vars-1.0.zip=docs/predefined_vars.zip
sigtest.gen.fail.on.error=false

Expand Down
2 changes: 1 addition & 1 deletion php/php.editor/nbproject/project.xml
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
<specification-version>2.92</specification-version>
<specification-version>2.93</specification-version>
</run-dependency>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ final class CompletionContextFinder {
private static final String MULTI_CATCH_EXCEPTION_TOKENS = "MULTI_CATCH_EXCEPTION_TOKENS"; //NOI18N
private static final String COMBINED_USE_STATEMENT_TOKENS = "COMBINED_USE_STATEMENT_TOKENS"; //NOI18N
private static final String CONST_STATEMENT_TOKENS = "CONST_STATEMENT_TOKENS"; //NOI18N
private static final String ENUM_CASE_STATEMENT_TOKENS = "ENUM_CASE_STATEMENT_TOKENS"; //NOI18N
private static final String FIELD_UNION_OR_INTERSECTION_TYPE_TOKENS = "FIELD_UNION_TYPE_TOKENS"; //NOI18N
private static final String FIELD_MODIFIERS_TOKENS = "FIELD_MODIFIERS_TOKENS"; //NOI18N
private static final String OBJECT_OPERATOR_TOKEN = "OBJECT_OPERATOR_TOKEN"; //NOI18N
Expand Down Expand Up @@ -204,14 +205,18 @@ final class CompletionContextFinder {
new Object[]{PHPTokenId.PHP_CONST, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING, PHPTokenId.WHITESPACE, CONST_STATEMENT_TOKENS},
new Object[]{PHPTokenId.PHP_CONST, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING, CONST_STATEMENT_TOKENS}
);
private static final List<Object[]> ENUM_CASE_TOKENCHAINS = Arrays.asList(
new Object[]{PHPTokenId.PHP_CASE, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING, PHPTokenId.WHITESPACE, CONST_STATEMENT_TOKENS},
new Object[]{PHPTokenId.PHP_CASE, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING, CONST_STATEMENT_TOKENS}
);
private static final List<Object[]> SERVER_ARRAY_TOKENCHAINS = Collections.singletonList(
new Object[]{PHPTokenId.PHP_VARIABLE, PHPTokenId.PHP_TOKEN});
private static final List<String> SERVER_ARRAY_TOKENTEXTS =
Arrays.asList(new String[]{"$_SERVER", "["}); //NOI18N

public static enum CompletionContext {

EXPRESSION, GLOBAL_CONST_EXPRESSION, CLASS_CONST_EXPRESSION, MATCH_EXPRESSION,
EXPRESSION, GLOBAL_CONST_EXPRESSION, CLASS_CONST_EXPRESSION, MATCH_EXPRESSION, ENUM_CASE_EXPRESSION,
HTML, CLASS_NAME, INTERFACE_NAME, BACKING_TYPE,
TYPE_NAME, RETURN_TYPE_NAME, RETURN_UNION_OR_INTERSECTION_TYPE_NAME, FIELD_TYPE_NAME, VISIBILITY_MODIFIER_OR_TYPE_NAME, STRING,
CLASS_MEMBER, STATIC_CLASS_MEMBER, PHPDOC, INHERITANCE, EXTENDS, IMPLEMENTS, METHOD_NAME,
Expand Down Expand Up @@ -328,6 +333,8 @@ static CompletionContext findCompletionContext(ParserResult info, int caretOffse
return CompletionContext.FIELD_TYPE_NAME;
} else if (acceptTokenChains(tokenSequence, CONST_TOKENCHAINS, moveNextSucces)) {
return CompletionContext.CLASS_CONST_EXPRESSION;
} else if (acceptTokenChains(tokenSequence, ENUM_CASE_TOKENCHAINS, moveNextSucces)) {
return CompletionContext.ENUM_CASE_EXPRESSION;
} else if (acceptTokenChains(tokenSequence, CLASS_CONTEXT_KEYWORDS_TOKENCHAINS, moveNextSucces)) {
return CompletionContext.CLASS_CONTEXT_KEYWORDS;
}
Expand Down Expand Up @@ -540,6 +547,11 @@ private static boolean acceptTokenChain(TokenSequence tokenSequence, Object[] to
accept = false;
break;
}
} else if (tokenID == ENUM_CASE_STATEMENT_TOKENS) {
if (!consumeUntilEnumCaseEqual(tokenSequence)) {
accept = false;
break;
}
} else if (tokenID == OBJECT_OPERATOR_TOKEN) {
if (!consumeObjectOperator(tokenSequence)) {
accept = false;
Expand Down Expand Up @@ -749,9 +761,25 @@ private static boolean consumeUntilTypeKeyword(TokenSequence tokenSequence) {
private static boolean consumeUntilConstEqual(TokenSequence tokenSequence) {
boolean hasEqual = false;
do {
if (tokenSequence.token().id() == PHPTokenId.PHP_SEMICOLON
|| tokenSequence.token().id() == PHPTokenId.PHP_CURLY_OPEN
|| tokenSequence.token().id() == PHPTokenId.PHP_CURLY_CLOSE) {
if (tokenSequence.token().id() == PHPTokenId.PHP_CONST
|| tokenSequence.token().id() == PHPTokenId.PHP_SEMICOLON) {
break;
}
if (isEqualSign(tokenSequence.token())) {
hasEqual = true;
tokenSequence.movePrevious();
break;
}
} while (tokenSequence.movePrevious());

return hasEqual;
}

private static boolean consumeUntilEnumCaseEqual(TokenSequence tokenSequence) {
boolean hasEqual = false;
do {
if (tokenSequence.token().id() == PHPTokenId.PHP_CASE
|| tokenSequence.token().id() == PHPTokenId.PHP_SEMICOLON) {
break;
}
if (isEqualSign(tokenSequence.token())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,8 @@ public CodeCompletionResult complete(CodeCompletionContext completionContext) {
autoCompleteConstants(completionResult, request);
autoCompleteKeywords(completionResult, request, PHP_GLOBAL_CONST_KEYWORDS);
break;
case CLASS_CONST_EXPRESSION:
case CLASS_CONST_EXPRESSION: // no break
case ENUM_CASE_EXPRESSION:
autoCompleteNamespaces(completionResult, request);
autoCompleteTypeNames(completionResult, request, null, true);
autoCompleteConstants(completionResult, request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -906,13 +906,15 @@ public void visit(StaticConstantAccess node) {
if (isCancelled()) {
return;
}
Identifier constant = node.getConstantName();
if (constant != null) {
ASTNodeColoring item = privateUnusedConstants.remove(new UnusedIdentifier(constant.getName(), typeInfo));
if (item != null) {
addColoringForNode(item.identifier, item.coloring);
if (!node.isDynamicName()) {
Identifier constant = node.getConstantName();
if (constant != null) {
ASTNodeColoring item = privateUnusedConstants.remove(new UnusedIdentifier(constant.getName(), typeInfo));
if (item != null) {
addColoringForNode(item.identifier, item.coloring);
}
addColoringForNode(constant, ColoringAttributes.STATIC_FIELD_SET);
}
addColoringForNode(constant, ColoringAttributes.STATIC_FIELD_SET);
}
super.visit(node);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,10 @@ public boolean spaceAroundAssignOps() {
return preferences.getBoolean(SPACE_AROUND_ASSIGN_OPS, getDefaultAsBoolean(SPACE_AROUND_ASSIGN_OPS));
}

public boolean spaceAroundScopeResolutionOps() {
return preferences.getBoolean(SPACE_AROUND_SCOPE_RESOLUTION_OPS, getDefaultAsBoolean(SPACE_AROUND_SCOPE_RESOLUTION_OPS));
}

public boolean spaceAroundObjectOps() {
return preferences.getBoolean(SPACE_AROUND_OBJECT_OPS, getDefaultAsBoolean(SPACE_AROUND_OBJECT_OPS));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public final class FmtOptions {
public static final String SPACE_AROUND_STRING_CONCAT_OPS = "spaceAroundStringConcatOps"; //NOI18N
public static final String SPACE_AROUND_ASSIGN_OPS = "spaceAroundAssignOps"; //NOI18N
public static final String SPACE_AROUND_KEY_VALUE_OPS = "spaceAroundKeyValueOps"; //NOI18N
public static final String SPACE_AROUND_SCOPE_RESOLUTION_OPS = "spaceAroundScopeResolutionOps"; //NOI18N
public static final String SPACE_AROUND_OBJECT_OPS = "spaceAroundObjectOps"; //NOI18N
public static final String SPACE_AROUND_NULLSAFE_OBJECT_OPS = "spaceAroundNullsafeObjectOps"; //NOI18N
public static final String SPACE_AROUND_DECLARE_EQUAL = "spaceAroundDeclareEqual"; //NOI18N
Expand Down Expand Up @@ -333,6 +334,7 @@ private static void createDefaults() {
{SPACE_AROUND_STRING_CONCAT_OPS, TRUE},
{SPACE_AROUND_KEY_VALUE_OPS, TRUE},
{SPACE_AROUND_ASSIGN_OPS, TRUE},
{SPACE_AROUND_SCOPE_RESOLUTION_OPS, FALSE},
{SPACE_AROUND_OBJECT_OPS, FALSE},
{SPACE_AROUND_NULLSAFE_OBJECT_OPS, FALSE},
{SPACE_AROUND_DECLARE_EQUAL, FALSE},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public enum Kind {
WHITESPACE_AFTER_USE,
WHITESPACE_BEFORE_CLASS_LEFT_BRACE,
WHITESPACE_BEFORE_ANONYMOUS_CLASS_LEFT_BRACE,
WHITESPACE_AROUND_SCOPE_RESOLUTION_OP, // ::
WHITESPACE_AROUND_OBJECT_OP,
WHITESPACE_AROUND_NULLSAFE_OBJECT_OP,
WHITESPACE_AROUND_DECLARE_EQUAL,
Expand Down Expand Up @@ -125,6 +126,7 @@ public enum Kind {
WHITESPACE_WITHIN_ATTRIBUTE_BRACKETS,
WHITESPACE_WITHIN_ATTRIBUTE_DECL_PARENS,
WHITESPACE_WITHIN_TYPE_CAST_PARENS,
WHITESPACE_WITHIN_DYNAMIC_NAME_BRACES, // {$example}
WHITESPACE_BEFORE_COMMA,
WHITESPACE_AFTER_COMMA,
WHITESPACE_BEFORE_SEMI,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
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.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;
Expand Down Expand Up @@ -2505,6 +2506,26 @@ public void visit(IntersectionType node) {
processUnionOrIntersectionType(node.getTypes());
}

@Override
public void visit(ReflectionVariable node) {
// e.g. {$name}
while (moveNext() && ts.offset() < node.getName().getStartOffset()) {
addFormatToken(formatTokens);
if (ts.token().id() == PHPTokenId.PHP_CURLY_OPEN) {
formatTokens.add(new FormatToken(FormatToken.Kind.WHITESPACE_WITHIN_DYNAMIC_NAME_BRACES, ts.offset() + ts.token().length()));
}
}
ts.movePrevious();
scan(node.getName());
while (moveNext() && ts.offset() < node.getEndOffset()) {
if (ts.token().id() == PHPTokenId.PHP_CURLY_CLOSE) {
formatTokens.add(new FormatToken(FormatToken.Kind.WHITESPACE_WITHIN_DYNAMIC_NAME_BRACES, ts.offset()));
}
addFormatToken(formatTokens);
}
ts.movePrevious();
}

private void processUnionOrIntersectionType(List<Expression> types) {
assert !types.isEmpty();
final Expression lastType = types.get(types.size() - 1);
Expand Down Expand Up @@ -2604,6 +2625,11 @@ private void addFormatToken(List<FormatToken> tokens) {
case PHPDOC_COMMENT_END:
tokens.add(new FormatToken(FormatToken.Kind.DOC_COMMENT_END, ts.offset(), ts.token().text().toString()));
break;
case PHP_PAAMAYIM_NEKUDOTAYIM:
tokens.add(new FormatToken(FormatToken.Kind.WHITESPACE_AROUND_SCOPE_RESOLUTION_OP, ts.offset()));
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
tokens.add(new FormatToken(FormatToken.Kind.WHITESPACE_AROUND_SCOPE_RESOLUTION_OP, ts.offset() + ts.token().length()));
break;
case PHP_OBJECT_OPERATOR:
tokens.add(new FormatToken(FormatToken.Kind.WHITESPACE_AROUND_OBJECT_OP, ts.offset()));
tokens.add(new FormatToken(FormatToken.Kind.TEXT, ts.offset(), ts.token().text().toString()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ protected static class DocumentOptions {
public boolean spaceBeforeElse;
public boolean spaceBeforeCatch;
public boolean spaceBeforeFinally;
public boolean spaceAroundScopeResolutionOp;
public boolean spaceAroundObjectOp;
public boolean spaceAroundNullsafeObjectOp;
public boolean spaceAroundDeclareEqual;
Expand Down Expand Up @@ -274,6 +275,7 @@ public DocumentOptions(BaseDocument doc) {
spaceBeforeCatch = codeStyle.spaceBeforeCatch();
spaceBeforeFinally = codeStyle.spaceBeforeFinally();

spaceAroundScopeResolutionOp = codeStyle.spaceAroundScopeResolutionOps();
spaceAroundObjectOp = codeStyle.spaceAroundObjectOps();
spaceAroundNullsafeObjectOp = codeStyle.spaceAroundNullsafeObjectOps();
spaceAroundDeclareEqual = codeStyle.spaceAroundDeclareEqual();
Expand Down Expand Up @@ -1077,6 +1079,9 @@ public void run() {
}
}
break;
case WHITESPACE_AROUND_SCOPE_RESOLUTION_OP:
countSpaces = docOptions.spaceAroundScopeResolutionOp ? 1 : 0;
break;
case WHITESPACE_AROUND_OBJECT_OP:
countSpaces = docOptions.spaceAroundObjectOp ? 1 : 0;
break;
Expand Down Expand Up @@ -1550,6 +1555,10 @@ && countOfNewLines(formatTokens.get(index + 1).getOldText()) > 0) {
case WHITESPACE_WITHIN_TYPE_CAST_PARENS:
countSpaces = docOptions.spaceWithinTypeCastParens ? 1 : 0;
break;
case WHITESPACE_WITHIN_DYNAMIC_NAME_BRACES:
// change here if we add the option for it
countSpaces = 0;
break;
case WHITESPACE_AFTER_TYPE_CAST:
countSpaces = docOptions.spaceAfterTypeCast ? 1 : 0;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ LBL_spaceAroundTernaryOps=Ternary Operators
LBL_spaceAroundCoalescingOps=Coalescing Operators
LBL_spaceAroundAssignOps=Assignment Operators
LBL_spaceAroundKeyValueOps=Key => Value Operator
LBL_spaceAroundObjectOps=Object Operator
LBL_spaceAroundNullsafeObjectOps=Nullsafe Object Operator
LBL_spaceAroundScopeResolutionOps=Scope Resolution Operator (::)
LBL_spaceAroundObjectOps=Object Operator (->)
LBL_spaceAroundNullsafeObjectOps=Nullsafe Object Operator (?->)
LBL_spaceAroundStringConcatOps=String Concatenation Operator
LBL_spaceAroundDeclareEqual="=" in Declare Statement
LBL_spaceAroundUnionTypeSeparator="|" in Union Type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ private DefaultTreeModel createModel() {
new Item(SPACE_AROUND_STRING_CONCAT_OPS),
new Item(SPACE_AROUND_KEY_VALUE_OPS),
new Item(SPACE_AROUND_ASSIGN_OPS),
new Item(SPACE_AROUND_SCOPE_RESOLUTION_OPS),
new Item(SPACE_AROUND_OBJECT_OPS),
new Item(SPACE_AROUND_NULLSAFE_OBJECT_OPS),
new Item(SPACE_AROUND_DECLARE_EQUAL),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,9 @@ public void visit(NamespaceName namespaceName) {
&& !(parent instanceof TraitMethodAliasDeclaration) && !(parent instanceof IntersectionType)) {
occurencesBuilder.prepare(Kind.CONSTANT, namespaceName, fileScope);
}
occurencesBuilder.prepare(namespaceName, modelBuilder.getCurrentScope());
if (!(parent instanceof FunctionName)) {
occurencesBuilder.prepare(namespaceName, modelBuilder.getCurrentScope());
}
}

@Override
Expand Down Expand Up @@ -737,6 +739,10 @@ public void visit(StaticConstantAccess node) {
scan(access1.getDimension());
name = access1.getExpression();
}
} else if (constant instanceof ReflectionVariable) {
// PHP 8.3: Dynamic class constant fetch
// e.g. Example::{$example};
scan(constant);
}
}

Expand Down Expand Up @@ -1266,7 +1272,16 @@ public void visit(FunctionInvocation node) {
} else {
occurencesBuilder.prepare(node, scope);
if (functionName instanceof NamespaceName) {
occurencesBuilder.prepare((NamespaceName) functionName, scope);
NamespaceName namespaceName = (NamespaceName) functionName;
QualifiedName qualifiedName = QualifiedName.create(CodeUtils.extractQualifiedName(namespaceName));
if (!VariousUtils.isSpecialClassName(qualifiedName.toString())
&& VariousUtils.isAliased(qualifiedName, namespaceName.getStartOffset(), scope)) {
// avoid adding normal function names to classIds, and so on
// e.g. avoid highlighting both "Test"(class name) and "test"(function name) in the following case
// class Test {}
// test();
occurencesBuilder.prepare(namespaceName, scope);
}
}
}
ASTNodeInfo<FunctionInvocation> nodeInfo = ASTNodeInfo.create(node);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ void prepare(StaticFieldAccess staticFieldAccess, Scope scope) {
}

void prepare(StaticConstantAccess staticConstantAccess, Scope scope) {
if (canBePrepared(staticConstantAccess, scope)) {
if (!staticConstantAccess.isDynamicName() && canBePrepared(staticConstantAccess, scope)) {
ASTNodeInfo<StaticConstantAccess> node = ASTNodeInfo.create(staticConstantAccess);
staticConstantInvocations.put(node, scope);
}
Expand Down Expand Up @@ -336,7 +336,6 @@ private void prepareOccurences(final Kind[] kinds, final Expression expression,
void prepare(Kind kind, Expression node, Scope scope) {
ASTNodeInfo<Expression> nodeInfo = null;
if (node instanceof Identifier) {

nodeInfo = ASTNodeInfo.create(kind, (Identifier) node);
} else if (node instanceof NamespaceName) {
nodeInfo = ASTNodeInfo.create(kind, (NamespaceName) node);
Expand Down
Loading

0 comments on commit 16b9fc1

Please sign in to comment.