Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PHP 8.3 Support: Dynamic class constant fetch #6701 #6752

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading