Skip to content

Commit

Permalink
Merge pull request #6793 from junichi11/php83-typed-class-constants
Browse files Browse the repository at this point in the history
PHP 8.3 Support: Typed class constants #6701
  • Loading branch information
junichi11 authored Dec 8, 2023
2 parents 16b9fc1 + 450cb20 commit 480ad74
Show file tree
Hide file tree
Showing 295 changed files with 74,018 additions and 56,005 deletions.
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.29.0
spec.version.base=2.31.0
release.external/predefined_vars-1.0.zip=docs/predefined_vars.zip
sigtest.gen.fail.on.error=false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/

package org.netbeans.modules.php.editor.api.elements;

import org.netbeans.api.annotations.common.CheckForNull;
Expand All @@ -26,8 +25,20 @@
* @author Radek Matous
*/
public interface TypeConstantElement extends TypeMemberElement {

PhpElementKind KIND = PhpElementKind.TYPE_CONSTANT;

@CheckForNull
String getValue();

boolean isMagic();

/**
* Get the declared type.
*
* @return the declared type, if there is no type, {@code null}
* @since 2.31.0
*/
@CheckForNull
String getDeclaredType();
}
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 CONST_DECLARED_TYPE_TOKENS = "CONST_DECLARED_TYPE_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
Expand Down Expand Up @@ -161,10 +162,12 @@ final class CompletionContextFinder {
new Object[]{PHPTokenId.PHP_FUNCTION, PHPTokenId.WHITESPACE},
new Object[]{PHPTokenId.PHP_FUNCTION, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING});
private static final List<Object[]> FIELD_TYPE_TOKENCHAINS = Arrays.asList(
new Object[]{FIELD_MODIFIERS_TOKENS, PHPTokenId.WHITESPACE, FIELD_MODIFIERS_TOKENS}, // readonly public, public readonly
new Object[]{FIELD_MODIFIERS_TOKENS, PHPTokenId.WHITESPACE, FIELD_MODIFIERS_TOKENS, PHPTokenId.WHITESPACE},
new Object[]{FIELD_MODIFIERS_TOKENS, PHPTokenId.WHITESPACE, NAMESPACE_FALSE_TOKEN},
new Object[]{FIELD_MODIFIERS_TOKENS, PHPTokenId.WHITESPACE, PHPTokenId.PHP_TOKEN},
new Object[]{FIELD_MODIFIERS_TOKENS, PHPTokenId.WHITESPACE, PHPTokenId.PHP_TOKEN, NAMESPACE_FALSE_TOKEN},
new Object[]{FIELD_MODIFIERS_TOKENS, FIELD_UNION_OR_INTERSECTION_TYPE_TOKENS}
new Object[]{FIELD_MODIFIERS_TOKENS, PHPTokenId.WHITESPACE, FIELD_UNION_OR_INTERSECTION_TYPE_TOKENS}
);
private static final List<Object[]> CLASS_CONTEXT_KEYWORDS_TOKENCHAINS = Arrays.asList(
new Object[]{PHPTokenId.PHP_PRIVATE},
Expand Down Expand Up @@ -203,7 +206,19 @@ final class CompletionContextFinder {
new Object[]{PHPTokenId.PHP_SEMICOLON, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING});
private static final List<Object[]> CONST_TOKENCHAINS = Arrays.asList(
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}
new Object[]{PHPTokenId.PHP_CONST, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING, CONST_STATEMENT_TOKENS},
new Object[]{PHPTokenId.PHP_CONST, PHPTokenId.WHITESPACE, CONST_DECLARED_TYPE_TOKENS, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING, PHPTokenId.WHITESPACE, CONST_STATEMENT_TOKENS},
new Object[]{PHPTokenId.PHP_CONST, PHPTokenId.WHITESPACE, CONST_DECLARED_TYPE_TOKENS, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING, CONST_STATEMENT_TOKENS}
);
private static final List<Object[]> CONST_TYPE_TOKENCHAINS = Arrays.asList(
new Object[]{PHPTokenId.PHP_CONST},
new Object[]{PHPTokenId.PHP_CONST, PHPTokenId.WHITESPACE},
new Object[]{PHPTokenId.PHP_CONST, PHPTokenId.WHITESPACE, NAMESPACE_FALSE_TOKEN},
new Object[]{PHPTokenId.PHP_CONST, PHPTokenId.WHITESPACE, CONST_DECLARED_TYPE_TOKENS}
);
private static final List<Object[]> CONST_NAME_TOKENCHAINS = Arrays.asList(
new Object[]{PHPTokenId.PHP_CONST, PHPTokenId.WHITESPACE, CONST_DECLARED_TYPE_TOKENS, PHPTokenId.WHITESPACE},
new Object[]{PHPTokenId.PHP_CONST, PHPTokenId.WHITESPACE, CONST_DECLARED_TYPE_TOKENS, PHPTokenId.WHITESPACE, PHPTokenId.PHP_STRING}
);
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},
Expand All @@ -218,7 +233,7 @@ public static enum CompletionContext {

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,
TYPE_NAME, RETURN_TYPE_NAME, RETURN_UNION_OR_INTERSECTION_TYPE_NAME, FIELD_TYPE_NAME, CONST_TYPE_NAME, VISIBILITY_MODIFIER_OR_TYPE_NAME, STRING,
CLASS_MEMBER, STATIC_CLASS_MEMBER, PHPDOC, INHERITANCE, EXTENDS, IMPLEMENTS, METHOD_NAME,
CLASS_MEMBER_PARAMETER_NAME, STATIC_CLASS_MEMBER_PARAMETER_NAME, FUNCTION_PARAMETER_NAME,
CLASS_CONTEXT_KEYWORDS, SERVER_ENTRY_CONSTANTS, NONE, NEW_CLASS, GLOBAL, NAMESPACE_KEYWORD,
Expand Down Expand Up @@ -318,6 +333,13 @@ static CompletionContext findCompletionContext(ParserResult info, int caretOffse
if (paramContext != null) {
return paramContext;
}
if (acceptTokenChains(tokenSequence, CONST_TYPE_TOKENCHAINS, moveNextSucces)) {
return CompletionContext.CONST_TYPE_NAME;
} else if (acceptTokenChains(tokenSequence, CONST_NAME_TOKENCHAINS, moveNextSucces)) {
return CompletionContext.NONE;
} else if (acceptTokenChains(tokenSequence, CONST_TOKENCHAINS, moveNextSucces)) {
return CompletionContext.CLASS_CONST_EXPRESSION;
}
return CompletionContext.INTERFACE_CONTEXT_KEYWORDS;
} else if (isInsideClassOrTraitOrEnumDeclarationBlock(info, caretOffset, tokenSequence)) {
if (acceptTokenChains(tokenSequence, USE_KEYWORD_TOKENS, moveNextSucces)) {
Expand All @@ -331,6 +353,10 @@ static CompletionContext findCompletionContext(ParserResult info, int caretOffse
} else if (acceptTokenChains(tokenSequence, FIELD_TYPE_TOKENCHAINS, moveNextSucces)) {
// \Namespace\ClassName, ?, ?ClassName, ?\Namespace\ClassName etc.
return CompletionContext.FIELD_TYPE_NAME;
} else if (acceptTokenChains(tokenSequence, CONST_TYPE_TOKENCHAINS, moveNextSucces)) {
return CompletionContext.CONST_TYPE_NAME;
} else if (acceptTokenChains(tokenSequence, CONST_NAME_TOKENCHAINS, moveNextSucces)) {
return CompletionContext.NONE;
} else if (acceptTokenChains(tokenSequence, CONST_TOKENCHAINS, moveNextSucces)) {
return CompletionContext.CLASS_CONST_EXPRESSION;
} else if (acceptTokenChains(tokenSequence, ENUM_CASE_TOKENCHAINS, moveNextSucces)) {
Expand Down Expand Up @@ -527,8 +553,9 @@ private static boolean acceptTokenChain(TokenSequence tokenSequence, Object[] to
accept = false;
break;
}
moreTokens = tokenSequence.movePrevious();
} else if (tokenID == FIELD_UNION_OR_INTERSECTION_TYPE_TOKENS) {
if (!consumeFieldUnionOrIntersectionType(tokenSequence)) {
if (!consumeFieldDeclaredTypes(tokenSequence)) {
accept = false;
break;
}
Expand All @@ -547,6 +574,11 @@ private static boolean acceptTokenChain(TokenSequence tokenSequence, Object[] to
accept = false;
break;
}
} else if (tokenID == CONST_DECLARED_TYPE_TOKENS) {
if (!consumeConstDeclaredTypes(tokenSequence)) {
accept = false;
break;
}
} else if (tokenID == ENUM_CASE_STATEMENT_TOKENS) {
if (!consumeUntilEnumCaseEqual(tokenSequence)) {
accept = false;
Expand Down Expand Up @@ -643,39 +675,82 @@ private static boolean consumeClassesConstFunctionInGroupUse(TokenSequence token
return hasCurlyOpen;
}

private static boolean consumeFieldUnionOrIntersectionType(TokenSequence tokenSequence) {
if (tokenSequence.token().id() == PHPTokenId.WHITESPACE) {
// e.g. private int ^, private int|string ^, private const ^
if (!tokenSequence.movePrevious()) {
return false;
private static boolean consumeFieldDeclaredTypes(TokenSequence tokenSequence) {
if (!isTypeSeparator(tokenSequence.token())
&& tokenSequence.token().id() != PHPTokenId.WHITESPACE
&& tokenSequence.token().id() != PHPTokenId.PHP_STRING
&& !isType(tokenSequence.token())
&& !consumeNameSpace(tokenSequence)) {
return false;
}
boolean isFieldType = false;
boolean hasTypeSeparator = false;
do {
if (isTypeSeparator(tokenSequence.token())) {
hasTypeSeparator = true;
}
if (isType(tokenSequence.token())
|| isFieldModifier(tokenSequence.token())
|| tokenSequence.token().id() == PHPTokenId.PHP_CONST
|| consumeNameSpace(tokenSequence)) {
if (!tokenSequence.movePrevious()) {
return false;
}
} while (isTypeSeparator(tokenSequence.token())
|| tokenSequence.token().id() == PHPTokenId.WHITESPACE
|| tokenSequence.token().id() == PHPTokenId.PHP_STRING
|| isType(tokenSequence.token())
|| consumeNameSpace(tokenSequence));
if (hasTypeSeparator && isFieldModifier(tokenSequence.token())) {
tokenSequence.moveNext();
isFieldType = true;
}
boolean first = true;
boolean isFieldType = true;
while (tokenSequence.movePrevious()) {
// "|", " ", "Foo", "int", "\Foo\Bar", etc.
if (!isVerticalBar(tokenSequence.token())
&& !isReference(tokenSequence.token())
&& tokenSequence.token().id() != PHPTokenId.WHITESPACE
&& tokenSequence.token().id() != PHPTokenId.PHP_STRING
&& !isType(tokenSequence.token())
&& !consumeNameSpace(tokenSequence)) {
if (first) {
isFieldType = false;
return isFieldType;
}

private static boolean consumeConstDeclaredTypes(TokenSequence tokenSequence) {
if (!isTypeSeparator(tokenSequence.token()) // |&()
&& tokenSequence.token().id() != PHPTokenId.WHITESPACE
&& tokenSequence.token().id() != PHPTokenId.PHP_STRING
&& !isType(tokenSequence.token())
&& !isNullableTypesPrefix(tokenSequence.token())
&& !consumeNameSpace(tokenSequence)) {
return false;
}
boolean isConstType = false;
TokenId lastTokenId = null;
Token lastTokenExceptForWS = null;
do {
if (lastTokenId == PHPTokenId.WHITESPACE) {
if (!isTypeSeparator(tokenSequence.token())
|| (isRightBracket(tokenSequence.token()) && !isVerticalBar(lastTokenExceptForWS))) {
// check the following case: const string CONST_NAME
// ^
isConstType = false;
break;
}
break;
}
if (first) {
first = false;
lastTokenId = tokenSequence.token().id();
if (lastTokenId != PHPTokenId.WHITESPACE) {
lastTokenExceptForWS = tokenSequence.token();
}
if (!tokenSequence.movePrevious()) {
return false;
}
} while (isTypeSeparator(tokenSequence.token()) // |&()
|| tokenSequence.token().id() == PHPTokenId.WHITESPACE
|| tokenSequence.token().id() == PHPTokenId.PHP_STRING
|| isType(tokenSequence.token())
|| isNullableTypesPrefix(tokenSequence.token())
|| consumeNameSpace(tokenSequence));
if (tokenSequence.token().id() == PHPTokenId.PHP_CONST) {
tokenSequence.moveNext();
isConstType = true;
}
return isFieldType;
return isConstType;
}

private static boolean isTypeSeparator(Token<PHPTokenId> token) {
return isVerticalBar(token)
|| isReference(token)
|| isLeftBracket(token)
|| isRightBracket(token);
}

private static boolean consumeMultiCatchExceptions(TokenSequence tokenSequence) {
Expand Down Expand Up @@ -1145,7 +1220,7 @@ private static boolean isVariadic(Token<PHPTokenId> token) {
&& TokenUtilities.textEquals(token.text(), "..."); // NOI18N
}

private static boolean isLeftBracket(Token<? extends PHPTokenId> token) {
static boolean isLeftBracket(Token<? extends PHPTokenId> token) {
return token.id().equals(PHPTokenId.PHP_TOKEN)
&& TokenUtilities.textEquals(token.text(), "("); // NOI18N
}
Expand All @@ -1169,7 +1244,7 @@ private static boolean isReturnTypeSeparator(Token<PHPTokenId> token) {
&& TokenUtilities.textEquals(token.text(), ":"); // NOI18N
}

private static boolean isVerticalBar(Token<PHPTokenId> token) {
static boolean isVerticalBar(Token<?extends PHPTokenId> token) {
return token.id() == PHPTokenId.PHP_OPERATOR
&& TokenUtilities.textEquals(token.text(), Type.SEPARATOR);
}
Expand Down Expand Up @@ -1262,7 +1337,7 @@ private static boolean isType(Token<PHPTokenId> token) {
|| id == PHPTokenId.PHP_CALLABLE;
}

private static boolean isComma(Token<? extends PHPTokenId> token) {
static boolean isComma(Token<? extends PHPTokenId> token) {
return token.id().equals(PHPTokenId.PHP_TOKEN)
&& TokenUtilities.textEquals(token.text(), ","); // NOI18N
}
Expand Down
Loading

0 comments on commit 480ad74

Please sign in to comment.