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.2 Support: Constants in Traits and Disjunctive Normal Form Types #5302

Merged
merged 7 commits into from
Jan 17, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ private enum Period {
PHP_74(LocalDate.of(2019, 11, 28), LocalDate.of(2021, 11, 28), LocalDate.of(2022, 11, 28)),
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, 11, 24), LocalDate.of(2024, 11, 24), LocalDate.of(2025, 11, 24)),
PHP_82(LocalDate.of(2022, 12, 8), LocalDate.of(2024, 12, 8), LocalDate.of(2025, 12, 8)),
;

private final LocalDate initialRelease;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ private static String getParamDefaultValue(Expression expr) {
}
return expr == null ? null : " "; //NOI18N
}

private static String getParamDefaultValue(ArrayCreation param) {
StringBuilder sb = new StringBuilder("["); //NOI18N
List<ArrayElement> arrayElements = param.getElements();
Expand Down Expand Up @@ -826,4 +826,15 @@ public static String removeNullableTypePrefix(String typeName) {
public static OffsetRange getOffsetRagne(@NonNull ASTNode node) {
return new OffsetRange(node.getStartOffset(), node.getEndOffset());
}

public static boolean isDnfType(UnionType unionType) {
if (unionType != null) {
for (Expression type : unionType.getTypes()) {
if (type instanceof IntersectionType) {
return true;
}
}
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,11 @@ private static List<TypeConstantElement> getAllOverriddenConstants(TypeConstantE
}

private static void getOverriddenConstants(TypeConstantElement constant, List<TypeConstantElement> constants) {
if (constant.isMagic()) {
// e.g. A::class
// prevent NPE in getIndex()
return;
}
Set<TypeConstantElement> overriddenConstants = getOverriddenConstants(constant);
constants.addAll(overriddenConstants);
for (TypeConstantElement overriddenConstant : overriddenConstants) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
import org.netbeans.modules.php.editor.model.NamespaceScope;
import org.netbeans.modules.php.editor.model.ParameterInfoSupport;
import org.netbeans.modules.php.editor.model.Scope;
import org.netbeans.modules.php.editor.model.TraitScope;
import org.netbeans.modules.php.editor.model.TypeScope;
import org.netbeans.modules.php.editor.model.VariableName;
import org.netbeans.modules.php.editor.model.VariableScope;
Expand Down Expand Up @@ -1508,6 +1509,16 @@ public boolean isAccepted(PhpElement element) {
if (CancelSupport.getDefault().isCancelled()) {
return;
}
// https://wiki.php.net/rfc/deprecations_php_8_1 Accessing static members on traits
// e.g. T::$staticField, T::staticMethod() : deprecated since PHP 8.1
// we can fix this here in the future
if (typeScope instanceof TraitScope
&& !specialVariable
&& phpElement instanceof TypeConstantElement) {
// PHP 8.2: prohibit direct access through a trait name
// e.g. T::CONSTANT;
continue;
}
if (duplicateElementCheck.add(phpElement)) {
if (methodsFilter.isAccepted(phpElement)) {
MethodElement method = (MethodElement) phpElement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,7 @@ public void visit(TraitDeclaration node) {
if (isCancelled()) {
return;
}
addToPath(node);
scan(node.getAttributes());
typeInfo = new TypeDeclarationTypeInfo(node);
Identifier name = node.getName();
Expand All @@ -646,6 +647,7 @@ public void visit(TraitDeclaration node) {
}
addColoringForUnusedPrivateFields();
}
removeFromPath();
}

@Override
Expand Down Expand Up @@ -810,13 +812,14 @@ public void visit(ConstantDeclaration node) {
}
if (parentNode instanceof ClassDeclaration
|| parentNode instanceof InterfaceDeclaration
|| parentNode instanceof TraitDeclaration
|| parentNode instanceof ClassInstanceCreation
|| parentNode instanceof EnumDeclaration) {
boolean isPrivate = Modifier.isPrivate(node.getModifier());
List<Identifier> names = node.getNames();
for (Identifier identifier : names) {
Set<ColoringAttributes> coloring = createConstantDeclarationColoring(identifier);
if (!isPrivate) {
if (!isPrivate || parentNode instanceof TraitDeclaration) {
addColoringForNode(identifier, coloring);
} else {
privateUnusedConstants.put(new UnusedIdentifier(identifier.getName(), typeInfo), new ASTNodeColoring(identifier, coloring));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,12 +544,14 @@ public Set<TypeMemberElement> getDeclaredTypeMembers(TypeElement typeElement) {
new String[]{
TraitElementImpl.IDX_FIELD,
FieldElementImpl.IDX_FIELD,
TypeConstantElementImpl.IDX_FIELD,
MethodElementImpl.IDX_FIELD
});
for (final IndexResult indexResult : traitResults) {
for (final TypeElement traitElement : TraitElementImpl.fromSignature(typeQuery, this, indexResult)) {
members.addAll(MethodElementImpl.fromSignature(traitElement, memberQuery, this, indexResult));
members.addAll(FieldElementImpl.fromSignature(traitElement, memberQuery, this, indexResult));
members.addAll(TypeConstantElementImpl.fromSignature(traitElement, memberQuery, this, indexResult));
}
}
break;
Expand Down Expand Up @@ -683,12 +685,14 @@ public Set<TypeMemberElement> getTypeMembers(final NameKind.Exact typeQuery, fin
new String[] {
TraitElementImpl.IDX_FIELD,
MethodElementImpl.IDX_FIELD,
FieldElementImpl.IDX_FIELD
FieldElementImpl.IDX_FIELD,
TypeConstantElementImpl.IDX_FIELD
});
for (IndexResult indexResult : traitResults) {
for (final TypeElement typeElement : TraitElementImpl.fromSignature(typeQuery, this, indexResult)) {
members.addAll(MethodElementImpl.fromSignature(typeElement, memberQuery, this, indexResult));
members.addAll(FieldElementImpl.fromSignature(typeElement, memberQuery, this, indexResult));
members.addAll(TypeConstantElementImpl.fromSignature(typeElement, memberQuery, this, indexResult));
}
}
final Collection<? extends IndexResult> enumResults = results(EnumElementImpl.IDX_FIELD, typeQuery,
Expand Down Expand Up @@ -870,6 +874,16 @@ public Set<TypeConstantElement> getDeclaredTypeConstants(TypeElement typeElement
}
}
break;
case TRAIT:
// [GH-4725] PHP 8.2 Support: Constants in Traits
final Collection<? extends IndexResult> traitResults = results(TraitElementImpl.IDX_FIELD, typeQuery,
new String[]{TraitElementImpl.IDX_FIELD, TypeConstantElementImpl.IDX_FIELD});
for (final IndexResult indexResult : traitResults) {
for (final TypeElement traitElement : TraitElementImpl.fromSignature(typeQuery, this, indexResult)) {
constants.addAll(TypeConstantElementImpl.fromSignature(traitElement, constantQuery, this, indexResult));
}
}
break;
case ENUM:
final Collection<? extends IndexResult> enumResults = results(EnumElementImpl.IDX_FIELD, typeQuery,
new String[]{EnumElementImpl.IDX_FIELD, TypeConstantElementImpl.IDX_FIELD});
Expand All @@ -893,7 +907,7 @@ public Set<TypeConstantElement> getTypeConstants(NameKind constantQuery) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<TypeConstantElement> constants = new HashSet<>();
final Collection<? extends IndexResult> constantResults = results(TypeConstantElementImpl.IDX_FIELD, constantQuery,
new String[]{ClassElementImpl.IDX_FIELD, InterfaceElementImpl.IDX_FIELD, EnumElementImpl.IDX_FIELD, TypeConstantElementImpl.IDX_FIELD});
new String[]{ClassElementImpl.IDX_FIELD, TraitElementImpl.IDX_FIELD, InterfaceElementImpl.IDX_FIELD, EnumElementImpl.IDX_FIELD, TypeConstantElementImpl.IDX_FIELD});
for (final IndexResult indexResult : constantResults) {
final Set<TypeElement> types = new HashSet<>();
types.addAll(ClassElementImpl.fromSignature(this, indexResult));
Expand All @@ -910,7 +924,7 @@ public Set<TypeConstantElement> getTypeConstants(NameKind constantQuery) {

@Override
public Set<TypeConstantElement> getTypeConstants(NameKind.Exact typeQuery, NameKind constantQuery) {
return getTypeConstantsImpl(typeQuery, constantQuery, EnumSet.of(PhpElementKind.CLASS, PhpElementKind.IFACE, PhpElementKind.ENUM));
return getTypeConstantsImpl(typeQuery, constantQuery, EnumSet.of(PhpElementKind.CLASS, PhpElementKind.TRAIT, PhpElementKind.IFACE, PhpElementKind.ENUM));
}

private Set<TypeConstantElement> getTypeConstantsImpl(NameKind.Exact typeQuery, NameKind constantQuery, EnumSet<PhpElementKind> typeKinds) {
Expand All @@ -935,6 +949,16 @@ private Set<TypeConstantElement> getTypeConstantsImpl(NameKind.Exact typeQuery,
}
}
}
// [GH-4725] PHP 8.2 Support: Constatns in Traits
if (typeKinds.contains(PhpElementKind.TRAIT)) {
final Collection<? extends IndexResult> traitResults = results(TraitElementImpl.IDX_FIELD, typeQuery,
new String[]{TraitElementImpl.IDX_FIELD, TypeConstantElementImpl.IDX_FIELD});
for (final IndexResult indexResult : traitResults) {
for (final TypeElement typeElement : TraitElementImpl.fromSignature(typeQuery, this, indexResult)) {
constants.addAll(TypeConstantElementImpl.fromSignature(typeElement, constantQuery, this, indexResult));
}
}
}
if (typeKinds.contains(PhpElementKind.ENUM)) {
final Collection<? extends IndexResult> enumResults = results(EnumElementImpl.IDX_FIELD, typeQuery,
new String[]{EnumElementImpl.IDX_FIELD, TypeConstantElementImpl.IDX_FIELD});
Expand Down Expand Up @@ -1242,6 +1266,10 @@ private Set<TypeMemberElement> getDirectInheritedTypeMembers(final TypeElement t
case FIELD:
traitTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getFields(NameKind.exact(trait), NameKind.empty())));
break;
case TYPE_CONSTANT:
// [GH-4725] PHP 8.2 Support: Constatns in Traits
traitTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getTypeConstantsImpl(NameKind.exact(trait), NameKind.empty(), EnumSet.of(PhpElementKind.TRAIT))));
break;
default:
//no-op
}
Expand Down Expand Up @@ -1311,8 +1339,8 @@ private void insertEmptyElement(final Set<TypeMemberElement> where, final Set<?
public Set<MethodElement> getInheritedMethods(final TypeElement typeElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<TypeMemberElement> typeMembers =
getInheritedTypeMembers(typeElement, new LinkedHashSet<TypeElement>(),
new LinkedHashSet<TypeMemberElement>(),
getInheritedTypeMembers(typeElement, new LinkedHashSet<>(),
new LinkedHashSet<>(),
EnumSet.of(PhpElementKind.CLASS, PhpElementKind.IFACE, PhpElementKind.TRAIT),
EnumSet.of(PhpElementKind.METHOD));
final Set<MethodElement> retval = new HashSet<>();
Expand Down Expand Up @@ -1351,8 +1379,8 @@ public Set<MethodElement> getAllMethods(TypeElement typeElement) {
public Set<FieldElement> getAlllFields(TypeElement typeElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<TypeMemberElement> typeMembers =
getInheritedTypeMembers(typeElement, new LinkedHashSet<TypeElement>(),
new LinkedHashSet<TypeMemberElement>(getDeclaredFields(typeElement)),
getInheritedTypeMembers(typeElement, new LinkedHashSet<>(),
new LinkedHashSet<>(getDeclaredFields(typeElement)),
EnumSet.of(PhpElementKind.CLASS, PhpElementKind.TRAIT),
EnumSet.of(PhpElementKind.FIELD));
final Set<FieldElement> retval = new HashSet<>();
Expand All @@ -1374,7 +1402,7 @@ public Set<TypeConstantElement> getAllTypeConstants(TypeElement typeElement) {
typeElement,
new LinkedHashSet<>(),
new LinkedHashSet<>(getDeclaredTypeConstants(typeElement)),
EnumSet.of(PhpElementKind.CLASS, PhpElementKind.IFACE, PhpElementKind.ENUM),
EnumSet.of(PhpElementKind.CLASS, PhpElementKind.TRAIT, PhpElementKind.IFACE, PhpElementKind.ENUM),
EnumSet.of(PhpElementKind.TYPE_CONSTANT)
);
final Set<TypeConstantElement> retval = new HashSet<>();
Expand Down Expand Up @@ -1537,6 +1565,7 @@ public Set<TypeConstantElement> getAllTypeConstants(final Exact typeQuery, final
Set<TypeElement> types = new HashSet<>();
types.addAll(getClassesImpl(typeQuery));
types.addAll(getInterfacesImpl(typeQuery));
types.addAll(getTraitsImpl(typeQuery)); // GH-4725 PHP 8.2 Constants In Traits
types.addAll(getEnumsImpl(typeQuery));
for (TypeElement typeElement : types) {
retval.addAll(ElementFilter.forName(constantQuery).filter(getAllTypeConstants(typeElement)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ private void addSignature(final IdentifierSignature signature) {
public static final class Factory extends EmbeddingIndexerFactory {

public static final String NAME = "php"; // NOI18N
public static final int VERSION = 33;
public static final int VERSION = 34;

@Override
public EmbeddingIndexer createIndexer(final Indexable indexable, final Snapshot snapshot) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ public Collection<? extends FieldElement> getInheritedFields() {

@Override
public final Collection<? extends ClassConstantElement> getInheritedConstants() {
// show items in Navigator Window
Set<ClassConstantElement> allConstants = new HashSet<>();
IndexScope indexScope = ModelUtils.getIndexScope(this);
ElementQuery.Index index = indexScope.getIndex();
Expand All @@ -349,7 +350,12 @@ public final Collection<? extends ClassConstantElement> getInheritedConstants()
Set<TypeConstantElement> indexedConstants = filterForPrivate.filter(index.getAllTypeConstants(classScope));
for (TypeConstantElement classMember : indexedConstants) {
TypeConstantElement constant = classMember;
allConstants.add(new ClassConstantElementImpl(classScope, constant));
TypeElement type = constant.getType();
Scope inScope = classScope;
if (type instanceof TraitElement) {
inScope = new TraitScopeImpl(indexScope, (TraitElement) type);
}
allConstants.add(new ClassConstantElementImpl(inScope, constant));
}
}
Set<InterfaceScope> interfaceScopes = new HashSet<>();
Expand All @@ -361,6 +367,16 @@ public final Collection<? extends ClassConstantElement> getInheritedConstants()
allConstants.add(new ClassConstantElementImpl(iface, constant));
}
}

// [GH-4725] PHP 8.2 Support: Constants in Traits
Set<TraitScope> traits = new HashSet<>(getTraits());
for (TraitScope trait : traits) {
// do not filter private constants (private constants are available)
Set<TypeConstantElement> indexedConstants = index.getAllTypeConstants(trait);
for (TypeConstantElement constant : indexedConstants) {
allConstants.add(new ClassConstantElementImpl(trait, constant));
}
}
return allConstants;
}

Expand Down Expand Up @@ -391,7 +407,7 @@ public QualifiedName getSuperClassName() {
return QualifiedName.create(superClasName);

}
} else if (retval.size() > 0) {
} else if (!retval.isEmpty()) {
ClassScope cls = ModelUtils.getFirst(retval);
if (cls != null) {
return QualifiedName.create(cls.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.netbeans.modules.php.api.editor.PhpBaseElement;
import org.netbeans.modules.php.api.editor.PhpType;
import org.netbeans.modules.php.api.editor.PhpVariable;
import org.netbeans.modules.php.api.util.StringUtils;
import org.netbeans.modules.php.editor.Cache;
import org.netbeans.modules.php.editor.CodeUtils;
import org.netbeans.modules.php.editor.NavUtils;
Expand Down Expand Up @@ -313,14 +314,15 @@ public void visit(ReturnStatement node) {
} else if (expression instanceof Scalar) {
typeName = VariousUtils.extractVariableTypeFromExpression(expression, null);
}
if (typeName != null) {
if (!StringUtils.isEmpty(typeName)) {
functionScope.addReturnType(QualifiedName.create(typeName).toString());
}
}
}

private static final Set<String> recursionDetection = new HashSet<>(); //#168868

@CheckForNull
private String resolveVariableType(String varName, FunctionScopeImpl varScope, ReturnStatement node) {
try {
if (varName != null && recursionDetection.add(varName)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1773,6 +1773,12 @@ private void buildStaticConstantInvocations(ElementInfo nodeCtxInfo, FileScopeIm
matchingTypeNames.add(constantElement.getType().getFullyQualifiedName());
QualifiedName typeQualifiedName = nodeCtxInfo.getTypeQualifiedName();
if (typeQualifiedName != null) {
if (isParent(typeQualifiedName)) {
TypeScope scope = ModelUtils.getTypeScope(nodeCtxInfo.getModelElemnt());
if (scope != null) {
typeQualifiedName = resolveClassName(typeQualifiedName, scope);
}
}
matchingTypeNames.add(typeQualifiedName);
}
final Exact constantName = NameKind.exact(phpElement.getName());
Expand All @@ -1783,6 +1789,11 @@ private void buildStaticConstantInvocations(ElementInfo nodeCtxInfo, FileScopeIm
ASTNodeInfo<StaticConstantAccess> nodeInfo = entry.getKey();
final Expression dispatcher = nodeInfo.getOriginalNode().getDispatcher();
QualifiedName clzName = QualifiedName.create(dispatcher);
// $this::CONSTANT;
if (dispatcher instanceof Variable
&& "this".equalsIgnoreCase(CodeUtils.extractQualifiedName(((Variable) dispatcher).getName()))) { // NOI18N
clzName = QualifiedName.create(Type.SELF);
}
if (clzName != null) {
final TypeScope scope = ModelUtils.getTypeScope(entry.getValue());
clzName = resolveClassName(clzName, scope);
Expand Down
Loading