diff --git a/php.editor/src/org/netbeans/modules/php/editor/api/ElementQuery.java b/php.editor/src/org/netbeans/modules/php/editor/api/ElementQuery.java --- a/php.editor/src/org/netbeans/modules/php/editor/api/ElementQuery.java +++ b/php.editor/src/org/netbeans/modules/php/editor/api/ElementQuery.java @@ -242,6 +242,8 @@ Set getAccessibleTypeMembers(TypeElement typeElement, TypeElement calledFromEnclosingType); + Set getAccessibleMixinTypeMembers(TypeElement typeElement, TypeElement calledFromEnclosingType); + /** * @param typeElement * @param insideEnclosingType false means that private, protected elements are filtered. True diff --git a/php.editor/src/org/netbeans/modules/php/editor/api/elements/AliasedClass.java b/php.editor/src/org/netbeans/modules/php/editor/api/elements/AliasedClass.java --- a/php.editor/src/org/netbeans/modules/php/editor/api/elements/AliasedClass.java +++ b/php.editor/src/org/netbeans/modules/php/editor/api/elements/AliasedClass.java @@ -86,6 +86,11 @@ } @Override + public Collection getFQMixinClassNames() { + return getClassElement().getFQMixinClassNames(); + } + + @Override public Collection getUsedTraits() { return getClassElement().getUsedTraits(); } diff --git a/php.editor/src/org/netbeans/modules/php/editor/api/elements/ClassElement.java b/php.editor/src/org/netbeans/modules/php/editor/api/elements/ClassElement.java --- a/php.editor/src/org/netbeans/modules/php/editor/api/elements/ClassElement.java +++ b/php.editor/src/org/netbeans/modules/php/editor/api/elements/ClassElement.java @@ -56,6 +56,7 @@ @CheckForNull QualifiedName getSuperClassName(); Collection getPossibleFQSuperClassNames(); + Collection getFQMixinClassNames(); boolean isFinal(); boolean isAbstract(); boolean isAnonymous(); diff --git a/php.editor/src/org/netbeans/modules/php/editor/completion/PHPCodeCompletion.java b/php.editor/src/org/netbeans/modules/php/editor/completion/PHPCodeCompletion.java --- a/php.editor/src/org/netbeans/modules/php/editor/completion/PHPCodeCompletion.java +++ b/php.editor/src/org/netbeans/modules/php/editor/completion/PHPCodeCompletion.java @@ -125,6 +125,7 @@ import org.netbeans.modules.php.editor.model.impl.Type; import org.netbeans.modules.php.editor.model.impl.VariousUtils; import org.netbeans.modules.php.editor.NavUtils; +import org.netbeans.modules.php.editor.api.elements.TypeMemberElement; import org.netbeans.modules.php.editor.options.CodeCompletionPanel.VariablesScope; import org.netbeans.modules.php.editor.options.OptionsUtils; import org.netbeans.modules.php.editor.parser.PHPParseResult; @@ -1183,7 +1184,17 @@ ElementFilter.forKind(PhpElementKind.TYPE_CONSTANT), ElementFilter.forName(NameKind.caseInsensitivePrefix(request.prefix)), ElementFilter.forInstanceOf(TypeConstantElement.class)); - for (final PhpElement phpElement : request.index.getAccessibleTypeMembers(typeScope, enclosingType)) { + HashSet accessibleTypeMembers = new HashSet<>(); + accessibleTypeMembers.addAll(request.index.getAccessibleTypeMembers(typeScope, enclosingType)); + // for @mixin tag #241740 + if (typeScope instanceof ClassElement) { + ClassElement classElement = (ClassElement) typeScope; + if (!classElement.getFQMixinClassNames().isEmpty()) { + // XXX currently, only when mixins are used directly in the class. should support all cases? + accessibleTypeMembers.addAll(request.index.getAccessibleMixinTypeMembers(typeScope, enclosingType)); + } + } + for (final PhpElement phpElement : accessibleTypeMembers) { if (CancelSupport.getDefault().isCancelled()) { return; } diff --git a/php.editor/src/org/netbeans/modules/php/editor/elements/ClassElementImpl.java b/php.editor/src/org/netbeans/modules/php/editor/elements/ClassElementImpl.java --- a/php.editor/src/org/netbeans/modules/php/editor/elements/ClassElementImpl.java +++ b/php.editor/src/org/netbeans/modules/php/editor/elements/ClassElementImpl.java @@ -72,8 +72,9 @@ public static final String IDX_FIELD = PHPIndexer.FIELD_CLASS; private final QualifiedName superClass; - private Collection possibleFQSuperClassNames; - private Collection usedTraits; + private final Collection possibleFQSuperClassNames; + private final Collection fqMixinClassNames; + private final Collection usedTraits; private ClassElementImpl( final QualifiedName qualifiedName, @@ -86,11 +87,13 @@ final Collection usedTraits, final String fileUrl, final ElementQuery elementQuery, - final boolean isDeprecated) { + final boolean isDeprecated, + final Collection fqMixinClassNames) { super(qualifiedName, offset, ifaceNames, fqSuperInterfaces, flags, fileUrl, elementQuery, isDeprecated); this.superClass = superClsName; this.possibleFQSuperClassNames = possibleFQSuperClassNames; this.usedTraits = usedTraits; + this.fqMixinClassNames = fqMixinClassNames; } public static Set fromSignature(final IndexQueryImpl indexScopeQuery, final IndexResult indexResult) { @@ -120,7 +123,7 @@ signParser.getSuperClassName(), signParser.getPossibleFQSuperClassName(), signParser.getSuperInterfaces(), signParser.getFQSuperInterfaces(), signParser.getFlags(), signParser.getUsedTraits(), signParser.getFileUrl(), indexScopeQuery, - signParser.isDeprecated()); + signParser.isDeprecated(), signParser.getFQMixinClassNames()); } return retval; } @@ -130,11 +133,13 @@ Parameters.notNull("fileQuery", fileQuery); ClassDeclarationInfo info = ClassDeclarationInfo.create(node); final QualifiedName fullyQualifiedName = namespace != null ? namespace.getFullyQualifiedName() : QualifiedName.createForDefaultNamespaceName(); + // XXX mixin return new ClassElementImpl( fullyQualifiedName.append(info.getName()), info.getRange().getStart(), info.getSuperClassName(), Collections.emptySet(), info.getInterfaceNames(), Collections.emptySet(), info.getAccessModifiers().toFlags(), info.getUsedTraits(), - fileQuery.getURL().toExternalForm(), fileQuery, VariousUtils.isDeprecatedFromPHPDoc(fileQuery.getResult().getProgram(), node)); + fileQuery.getURL().toExternalForm(), fileQuery, VariousUtils.isDeprecatedFromPHPDoc(fileQuery.getResult().getProgram(), node), + Collections.emptySet()); } public static ClassElement fromFrameworks(final PhpClass clz, final ElementQuery elementQuery) { @@ -143,7 +148,8 @@ String fullyQualifiedName = clz.getFullyQualifiedName(); ClassElementImpl retval = new ClassElementImpl(QualifiedName.create(fullyQualifiedName == null ? clz.getName() : fullyQualifiedName), clz.getOffset(), null, Collections.emptySet(), Collections.emptySet(), - Collections.emptySet(), PhpModifiers.NO_FLAGS, Collections.emptySet(), null, elementQuery, false); + Collections.emptySet(), PhpModifiers.NO_FLAGS, Collections.emptySet(), null, elementQuery, false, + Collections.emptySet()); retval.setFileObject(clz.getFile()); return retval; } @@ -169,6 +175,11 @@ } @Override + public Collection getFQMixinClassNames() { + return Collections.unmodifiableCollection(fqMixinClassNames); + } + + @Override public String getSignature() { StringBuilder sb = new StringBuilder(); sb.append(getName().toLowerCase()).append(Separator.SEMICOLON); //NOI18N @@ -214,6 +225,15 @@ sb.append(";"); //NOI18N sb.append(isDeprecated() ? 1 : 0).append(";"); //NOI18N sb.append(getFilenameUrl()).append(Separator.SEMICOLON); + StringBuilder mixinSb = new StringBuilder(); + fqMixinClassNames.forEach((mixinClassName) -> { + if (mixinSb.length() > 0) { + mixinSb.append(Separator.COMMA); + } + mixinSb.append(mixinClassName.toString()); + }); + sb.append(mixinSb.toString()); + sb.append(Separator.SEMICOLON); checkClassSignature(sb); return sb.toString(); } @@ -393,5 +413,15 @@ String getFileUrl() { return signature.string(9); } + + public Collection getFQMixinClassNames() { + Collection retval = new HashSet<>(); + String mixins = signature.string(10); + final String[] mixinNames = mixins.split(Separator.COMMA.toString()); + for (String mixinName : mixinNames) { + retval.add(QualifiedName.create(mixinName)); + } + return retval; + } } } diff --git a/php.editor/src/org/netbeans/modules/php/editor/elements/IndexQueryImpl.java b/php.editor/src/org/netbeans/modules/php/editor/elements/IndexQueryImpl.java --- a/php.editor/src/org/netbeans/modules/php/editor/elements/IndexQueryImpl.java +++ b/php.editor/src/org/netbeans/modules/php/editor/elements/IndexQueryImpl.java @@ -1039,41 +1039,15 @@ EnumSet typeKinds, EnumSet memberKinds) { final Set directTypes = new LinkedHashSet<>(); if (typeKinds.contains(PhpElementKind.CLASS) && (typeElement instanceof ClassElement)) { - final Set classTypes = new LinkedHashSet<>(); + ClassElement classElement = (ClassElement) typeElement; QualifiedName superClassName; - Collection possibleFQSuperClassNames = ((ClassElement) typeElement).getPossibleFQSuperClassNames(); + Collection possibleFQSuperClassNames = classElement.getPossibleFQSuperClassNames(); if (possibleFQSuperClassNames.size() == 1) { superClassName = possibleFQSuperClassNames.iterator().next(); } else { - superClassName = ((ClassElement) typeElement).getSuperClassName(); + superClassName = classElement.getSuperClassName(); } - if (superClassName != null) { - classTypes.addAll(extendedQuery.getFields(NameKind.exact(superClassName), NameKind.empty())); - classTypes.addAll(extendedQuery.getMethods(NameKind.exact(superClassName), NameKind.empty())); - classTypes.addAll(extendedQuery.getTypeConstants(NameKind.exact(superClassName), NameKind.empty())); - if (memberKinds.size() != 1) { - classTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getTypeMembers(NameKind.exact(superClassName), NameKind.empty()))); - } else { - switch(memberKinds.iterator().next()) { - case METHOD: - classTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer( - getMethodsImpl(NameKind.exact(superClassName), NameKind.empty(), EnumSet.of(PhpElementKind.CLASS)))); - break; - case FIELD: - classTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getFields(NameKind.exact(superClassName), NameKind.empty()))); - break; - case TYPE_CONSTANT: - classTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer( - getTypeConstantsImpl(NameKind.exact(superClassName), NameKind.empty(), EnumSet.of(PhpElementKind.CLASS)))); - break; - default: - //no-op - } - } - if (classTypes.isEmpty()) { - insertEmptyElement(classTypes, getClasses(NameKind.exact(superClassName))); - } - } + Set classTypes = getDirectInheritedClassTypes(superClassName, memberKinds, typeElement); directTypes.addAll(classTypes); } if (typeKinds.contains(PhpElementKind.IFACE)) { @@ -1140,6 +1114,51 @@ return directTypes; } + private Set getDirectMixinTypeMembers(final TypeElement typeElement, + EnumSet typeKinds, EnumSet memberKinds) { + final Set directTypes = new LinkedHashSet<>(); + if (typeKinds.contains(PhpElementKind.CLASS) && (typeElement instanceof ClassElement)) { + ClassElement classElement = (ClassElement) typeElement; + Collection mixinNames = classElement.getFQMixinClassNames(); + mixinNames.stream() + .map(mixinName -> getDirectInheritedClassTypes(mixinName, memberKinds, typeElement)) + .forEach(classTypes -> directTypes.addAll(classTypes)); + } + return directTypes; + } + + private Set getDirectInheritedClassTypes(QualifiedName superClassName, EnumSet memberKinds, final TypeElement typeElement) { + final Set classTypes = new LinkedHashSet<>(); + if (superClassName != null) { + classTypes.addAll(extendedQuery.getFields(NameKind.exact(superClassName), NameKind.empty())); + classTypes.addAll(extendedQuery.getMethods(NameKind.exact(superClassName), NameKind.empty())); + classTypes.addAll(extendedQuery.getTypeConstants(NameKind.exact(superClassName), NameKind.empty())); + if (memberKinds.size() != 1) { + classTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getTypeMembers(NameKind.exact(superClassName), NameKind.empty()))); + } else { + switch (memberKinds.iterator().next()) { + case METHOD: + classTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer( + getMethodsImpl(NameKind.exact(superClassName), NameKind.empty(), EnumSet.of(PhpElementKind.CLASS)))); + break; + case FIELD: + classTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getFields(NameKind.exact(superClassName), NameKind.empty()))); + break; + case TYPE_CONSTANT: + classTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer( + getTypeConstantsImpl(NameKind.exact(superClassName), NameKind.empty(), EnumSet.of(PhpElementKind.CLASS)))); + break; + default: + //no-op + } + } + if (classTypes.isEmpty()) { + insertEmptyElement(classTypes, getClasses(NameKind.exact(superClassName))); + } + } + return classTypes; + } + private void insertEmptyElement(final Set where, final Set exactTypeName) { TypeElement exactType = ModelUtils.getFirst(exactTypeName); if (exactType != null) { @@ -1243,6 +1262,17 @@ new LinkedHashSet<>(getDeclaredTypeMembers(typeElement)), typeKinds, memberKinds); } + private Set getAllMixinTypeMembers(TypeElement typeElement) { + final EnumSet typeKinds = EnumSet.of(PhpElementKind.CLASS); + final EnumSet memberKinds = EnumSet.of( + PhpElementKind.METHOD, + PhpElementKind.FIELD, + PhpElementKind.TYPE_CONSTANT + ); + return getMixinTypeMembers(typeElement, new LinkedHashSet<>(), + new LinkedHashSet<>(getDeclaredTypeMembers(typeElement)), typeKinds, memberKinds); + } + @Override public Set getInheritedTypeMembers(final TypeElement typeElement) { final EnumSet typeKinds = EnumSet.of( @@ -1263,6 +1293,14 @@ public Set getAccessibleTypeMembers(TypeElement typeElement, TypeElement calledFromEnclosingType) { final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0; final Set allTypeMembers = getAllTypeMembers(typeElement); + Set retval = getAccessibleTypeMembers(typeElement, calledFromEnclosingType, allTypeMembers); + if (LOG.isLoggable(Level.FINE)) { + logQueryTime("Set getAccessibleTypeMembers", NameKind.exact(typeElement.getFullyQualifiedName()), start); //NOI18N + } + return Collections.unmodifiableSet(retval); + } + + private Set getAccessibleTypeMembers(TypeElement typeElement, TypeElement calledFromEnclosingType, final Set allTypeMembers) { Collection subTypes = Collections.emptySet(); if (calledFromEnclosingType != null) { if (typeElement instanceof TraitElement @@ -1275,8 +1313,16 @@ retval.addAll(filterForAccessible.filter(allTypeMembers)); ElementFilter allOf = ElementFilter.allOf(ElementFilter.forVirtualExtensions(), ElementFilter.forMembersOfTypeName(typeElement)); retval.addAll(allOf.filter(allTypeMembers)); + return retval; + } + + @Override + public Set getAccessibleMixinTypeMembers(TypeElement typeElement, TypeElement calledFromEnclosingType) { + final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0; + final Set allTypeMembers = getAllMixinTypeMembers(typeElement); + Set retval = getAccessibleTypeMembers(typeElement, calledFromEnclosingType, allTypeMembers); if (LOG.isLoggable(Level.FINE)) { - logQueryTime("Set getAccessibleTypeMembers", NameKind.exact(typeElement.getFullyQualifiedName()), start); //NOI18N + logQueryTime("Set getAccessibleMixinTypeMembers", NameKind.exact(typeElement.getFullyQualifiedName()), start); // NOI18N } return Collections.unmodifiableSet(retval); } @@ -1293,6 +1339,18 @@ return forPrefereMethodImplementation(retval).filter(retval); } + private Set getMixinTypeMembers(final TypeElement typeElement, final Set recursionPrevention, + Set retval, EnumSet typeKinds, EnumSet memberKinds) { + if (recursionPrevention.add(typeElement)) { + final Set typeMembers = getDirectMixinTypeMembers(typeElement, typeKinds, memberKinds); + retval.addAll(forEmptyElements().filter(forComparingNonAbstractNameKinds(retval).reverseFilter(typeMembers))); + Set types = toTypes(typeMembers); + types.addAll(getDirectInheritedTypes(typeElement)); + types.forEach(type -> retval.addAll(getMixinTypeMembers(type, recursionPrevention, retval, typeKinds, memberKinds))); + } + return forPrefereMethodImplementation(retval).filter(retval); + } + @Override public Set getAllMethods(final Exact typeQuery, final NameKind methodQuery) { Set retval = new HashSet<>(); diff --git a/php.editor/src/org/netbeans/modules/php/editor/index/PHPIndexer.java b/php.editor/src/org/netbeans/modules/php/editor/index/PHPIndexer.java --- a/php.editor/src/org/netbeans/modules/php/editor/index/PHPIndexer.java +++ b/php.editor/src/org/netbeans/modules/php/editor/index/PHPIndexer.java @@ -239,7 +239,7 @@ public static final class Factory extends EmbeddingIndexerFactory { public static final String NAME = "php"; // NOI18N - public static final int VERSION = 27; + public static final int VERSION = 28; @Override public EmbeddingIndexer createIndexer(final Indexable indexable, final Snapshot snapshot) { diff --git a/php.editor/src/org/netbeans/modules/php/editor/model/impl/ClassScopeImpl.java b/php.editor/src/org/netbeans/modules/php/editor/model/impl/ClassScopeImpl.java --- a/php.editor/src/org/netbeans/modules/php/editor/model/impl/ClassScopeImpl.java +++ b/php.editor/src/org/netbeans/modules/php/editor/model/impl/ClassScopeImpl.java @@ -89,6 +89,8 @@ */ class ClassScopeImpl extends TypeScopeImpl implements ClassScope, VariableNameFactory { private final Collection possibleFQSuperClassNames; + // @GuardedBy("this") + private final Collection mixinClassNames = new HashSet<>(); private final Collection usedTraits = new HashSet<>(); private final Set superRecursionDetection = new HashSet<>(); private final Set subRecursionDetection = new HashSet<>(); @@ -180,6 +182,20 @@ return this.possibleFQSuperClassNames; } + /** + * Add fully qualified names for @mixin tag. + * + * @param names fully qualified names + */ + synchronized void addFQMixinClassNames(Collection names) { + mixinClassNames.addAll(names); + } + + @Override + public synchronized Collection getFQMixinClassNames() { + return Collections.unmodifiableCollection(mixinClassNames); + } + @NonNull @Override public Collection getSuperClasses() { @@ -514,6 +530,16 @@ sb.append(Signature.ITEM_DELIMITER); sb.append(isDeprecated() ? 1 : 0).append(Signature.ITEM_DELIMITER); sb.append(getFilenameUrl()).append(Signature.ITEM_DELIMITER); + // mixin + StringBuilder mixinSb = new StringBuilder(); + for (QualifiedName mixinClassName : mixinClassNames) { + if (mixinSb.length() > 0) { + mixinSb.append(","); // NOI18N + } + mixinSb.append(mixinClassName.toString()); + } + sb.append(mixinSb); + sb.append(Signature.ITEM_DELIMITER); return sb.toString(); } @@ -541,6 +567,8 @@ QualifiedName qualifiedName = namespaceScope.getQualifiedName(); sb.append(qualifiedName.toString()).append(Signature.ITEM_DELIMITER); sb.append(isDeprecated() ? 1 : 0).append(Signature.ITEM_DELIMITER); + sb.append(getFilenameUrl()).append(Signature.ITEM_DELIMITER); + sb.append(Signature.ITEM_DELIMITER); // mixin return sb.toString(); diff --git a/php.editor/src/org/netbeans/modules/php/editor/model/impl/ModelVisitor.java b/php.editor/src/org/netbeans/modules/php/editor/model/impl/ModelVisitor.java --- a/php.editor/src/org/netbeans/modules/php/editor/model/impl/ModelVisitor.java +++ b/php.editor/src/org/netbeans/modules/php/editor/model/impl/ModelVisitor.java @@ -1200,6 +1200,24 @@ @Override public void visit(PHPDocTypeTag node) { + // #241740 for @mixin tag + if (node.getKind().equals(PHPDocTag.Type.MIXIN)) { + Scope currentScope = modelBuilder.getCurrentScope(); + if (currentScope instanceof ClassScopeImpl) { + ClassScopeImpl classScope = (ClassScopeImpl) currentScope; + List tagInfos = PhpDocTypeTagInfo.create(node, classScope); + Set names = new HashSet<>(); + tagInfos.stream() + .filter(tagInfo -> !tagInfo.getName().isEmpty()) + .map(tagInfo -> tagInfo.getTypeName()) + .filter(typeName -> (typeName != null && !typeName.isEmpty())) + .map(typeName -> VariousUtils.qualifyTypeNames(typeName, node.getStartOffset(), classScope)) + .forEach(qualifiedTypeName -> names.add(QualifiedName.create(qualifiedTypeName))); + if (!names.isEmpty()) { + classScope.addFQMixinClassNames(names); + } + } + } occurencesBuilder.prepare(node, modelBuilder.getCurrentScope()); super.visit(node); } diff --git a/php.editor/src/org/netbeans/modules/php/editor/parser/PHPDocCommentParser.java b/php.editor/src/org/netbeans/modules/php/editor/parser/PHPDocCommentParser.java --- a/php.editor/src/org/netbeans/modules/php/editor/parser/PHPDocCommentParser.java +++ b/php.editor/src/org/netbeans/modules/php/editor/parser/PHPDocCommentParser.java @@ -255,7 +255,7 @@ } } return null; - } else if (type.equals(PHPDocTag.Type.RETURN) || type.equals(PHPDocTag.Type.VAR)) { + } else if (type.equals(PHPDocTag.Type.RETURN) || type.equals(PHPDocTag.Type.VAR) || type.equals(PHPDocTag.Type.MIXIN)) { return new PHPDocTypeTag(start, end, type, description, docTypes); } return new PHPDocTag(start, end, type, description); diff --git a/php.editor/src/org/netbeans/modules/php/editor/parser/astnodes/PHPDocTag.java b/php.editor/src/org/netbeans/modules/php/editor/parser/astnodes/PHPDocTag.java --- a/php.editor/src/org/netbeans/modules/php/editor/parser/astnodes/PHPDocTag.java +++ b/php.editor/src/org/netbeans/modules/php/editor/parser/astnodes/PHPDocTag.java @@ -59,6 +59,7 @@ PARAM("param"), //NOI18N RETURN("return"), //NOI18N VAR("var"), //NOI18N + MIXIN("mixin"), // NOI18N DEPRECATED("deprecated"); //NOI18N private final String name; diff --git a/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php b/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php @@ -0,0 +1,226 @@ +protectedMethodC1(); // CC + Mixin::protectedStaticMethodC1(); // CC + } +} + +$mixin = new Mixin(); +$mixin->publicMethodC1(); // CC +Mixin::publicStaticMethodC1(); // CC diff --git a/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixin.completion b/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixin.completion new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixin.completion @@ -0,0 +1,20 @@ +Code completion result for source line: +$mixin->|publicMethodC1(); // CC +(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true) +METHOD publicMethodC1() [PUBLIC] C1 +METHOD publicMethodC2() [PUBLIC] C2 +METHOD publicMethodC3() [PUBLIC] C3 +METHOD publicMethodC4() [PUBLIC] C4 +METHOD publicMethodC5() [PUBLIC] C5 +METHOD publicStaticMethodC1() [STATIC] C1 +METHOD publicStaticMethodC2() [STATIC] C2 +METHOD publicStaticMethodC3() [STATIC] C3 +METHOD publicStaticMethodC4() [STATIC] C4 +METHOD publicStaticMethodC5() [STATIC] C5 +METHOD test() [PUBLIC] Mixin +METHOD testParent() [PUBLIC] MixinParent +VARIABLE ? publicFieldC1 [PUBLIC] C1 +VARIABLE ? publicFieldC2 [PUBLIC] C2 +VARIABLE ? publicFieldC3 [PUBLIC] C3 +VARIABLE ? publicFieldC4 [PUBLIC] C4 +VARIABLE ? publicFieldC5 [PUBLIC] C5 diff --git a/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixinEnclosing.completion b/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixinEnclosing.completion new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixinEnclosing.completion @@ -0,0 +1,35 @@ +Code completion result for source line: +$this->|protectedMethodC1(); // CC +(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true) +METHOD protectedMethodC1() [PROTECTE C1 +METHOD protectedMethodC2() [PROTECTE C2 +METHOD protectedMethodC3() [PROTECTE C3 +METHOD protectedMethodC4() [PROTECTE C4 +METHOD protectedMethodC5() [PROTECTE C5 +METHOD protectedStaticMethodC1() [PROTECTE C1 +METHOD protectedStaticMethodC2() [PROTECTE C2 +METHOD protectedStaticMethodC3() [PROTECTE C3 +METHOD protectedStaticMethodC4() [PROTECTE C4 +METHOD protectedStaticMethodC5() [PROTECTE C5 +METHOD publicMethodC1() [PUBLIC] C1 +METHOD publicMethodC2() [PUBLIC] C2 +METHOD publicMethodC3() [PUBLIC] C3 +METHOD publicMethodC4() [PUBLIC] C4 +METHOD publicMethodC5() [PUBLIC] C5 +METHOD publicStaticMethodC1() [STATIC] C1 +METHOD publicStaticMethodC2() [STATIC] C2 +METHOD publicStaticMethodC3() [STATIC] C3 +METHOD publicStaticMethodC4() [STATIC] C4 +METHOD publicStaticMethodC5() [STATIC] C5 +METHOD test() [PUBLIC] Mixin +METHOD testParent() [PUBLIC] MixinParent +VARIABLE ? protectedFieldC1 [PROTECTE C1 +VARIABLE ? protectedFieldC2 [PROTECTE C2 +VARIABLE ? protectedFieldC3 [PROTECTE C3 +VARIABLE ? protectedFieldC4 [PROTECTE C4 +VARIABLE ? protectedFieldC5 [PROTECTE C5 +VARIABLE ? publicFieldC1 [PUBLIC] C1 +VARIABLE ? publicFieldC2 [PUBLIC] C2 +VARIABLE ? publicFieldC3 [PUBLIC] C3 +VARIABLE ? publicFieldC4 [PUBLIC] C4 +VARIABLE ? publicFieldC5 [PUBLIC] C5 diff --git a/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixinEnclosingWithStaticAccess.completion b/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixinEnclosingWithStaticAccess.completion new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixinEnclosingWithStaticAccess.completion @@ -0,0 +1,34 @@ +Code completion result for source line: +Mixin::|protectedStaticMethodC1(); // CC +(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true) +METHOD protectedStaticMethodC1() [PROTECTE C1 +METHOD protectedStaticMethodC2() [PROTECTE C2 +METHOD protectedStaticMethodC3() [PROTECTE C3 +METHOD protectedStaticMethodC4() [PROTECTE C4 +METHOD protectedStaticMethodC5() [PROTECTE C5 +METHOD publicStaticMethodC1() [STATIC] C1 +METHOD publicStaticMethodC2() [STATIC] C2 +METHOD publicStaticMethodC3() [STATIC] C3 +METHOD publicStaticMethodC4() [STATIC] C4 +METHOD publicStaticMethodC5() [STATIC] C5 +VARIABLE ? $protectedStaticFieldC1 [PROTECTE C1 +VARIABLE ? $protectedStaticFieldC2 [PROTECTE C2 +VARIABLE ? $protectedStaticFieldC3 [PROTECTE C3 +VARIABLE ? $protectedStaticFieldC4 [PROTECTE C4 +VARIABLE ? $protectedStaticFieldC5 [PROTECTE C5 +VARIABLE ? $publicStaticFieldC1 [STATIC] C1 +VARIABLE ? $publicStaticFieldC2 [STATIC] C2 +VARIABLE ? $publicStaticFieldC3 [STATIC] C3 +VARIABLE ? $publicStaticFieldC4 [STATIC] C4 +VARIABLE ? $publicStaticFieldC5 [STATIC] C5 +CONSTANT PROTECTED_CONST_C1 "PROTECTED_ [PROTECTE C1 +CONSTANT PROTECTED_CONST_C2 "PROTECTED_ [PROTECTE C2 +CONSTANT PROTECTED_CONST_C3 "PROTECTED_ [PROTECTE C3 +CONSTANT PROTECTED_CONST_C4 "PROTECTED_ [PROTECTE C4 +CONSTANT PROTECTED_CONST_C5 "PROTECTED_ [PROTECTE C5 +CONSTANT PUBLIC_CONST_C1 "PUBLIC_CONST_ [PUBLIC] C1 +CONSTANT PUBLIC_CONST_C2 "PUBLIC_CONST_ [PUBLIC] C2 +CONSTANT PUBLIC_CONST_C3 "PUBLIC_CONST_ [PUBLIC] C3 +CONSTANT PUBLIC_CONST_C4 "PUBLIC_CONST_ [PUBLIC] C4 +CONSTANT PUBLIC_CONST_C5 "PUBLIC_CONST_ [PUBLIC] C5 +CONSTANT class \Mixin [PUBLIC] Magic Constant diff --git a/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixinTagType.completion b/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixinTagType.completion new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixinTagType.completion @@ -0,0 +1,30 @@ +Code completion result for source line: +* @mixin |C3 +(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true) +CLASS C1 [PUBLIC] mixin.php +CLASS C2 [PUBLIC] mixin.php +CLASS C3 [PUBLIC] mixin.php +CLASS C4 [PUBLIC] mixin.php +CLASS C5 [PUBLIC] mixin.php +CLASS Mixin [PUBLIC] mixin.php +CLASS MixinParent [PUBLIC] mixin.php +------------------------------------ +KEYWORD array null +KEYWORD bool null +KEYWORD boolean null +KEYWORD callable null +KEYWORD callback null +KEYWORD double null +KEYWORD false null +KEYWORD float null +KEYWORD int null +KEYWORD integer null +KEYWORD iterable null +KEYWORD mixed null +KEYWORD null null +KEYWORD object null +KEYWORD resource null +KEYWORD self null +KEYWORD string null +KEYWORD true null +KEYWORD void null diff --git a/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixinWithStaticAccess.completion b/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixinWithStaticAccess.completion new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/completion/lib/mixin/mixin.php.testMixinWithStaticAccess.completion @@ -0,0 +1,19 @@ +Code completion result for source line: +Mixin::|publicStaticMethodC1(); // CC +(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true) +METHOD publicStaticMethodC1() [STATIC] C1 +METHOD publicStaticMethodC2() [STATIC] C2 +METHOD publicStaticMethodC3() [STATIC] C3 +METHOD publicStaticMethodC4() [STATIC] C4 +METHOD publicStaticMethodC5() [STATIC] C5 +VARIABLE ? $publicStaticFieldC1 [STATIC] C1 +VARIABLE ? $publicStaticFieldC2 [STATIC] C2 +VARIABLE ? $publicStaticFieldC3 [STATIC] C3 +VARIABLE ? $publicStaticFieldC4 [STATIC] C4 +VARIABLE ? $publicStaticFieldC5 [STATIC] C5 +CONSTANT PUBLIC_CONST_C1 "PUBLIC_CONST_ [PUBLIC] C1 +CONSTANT PUBLIC_CONST_C2 "PUBLIC_CONST_ [PUBLIC] C2 +CONSTANT PUBLIC_CONST_C3 "PUBLIC_CONST_ [PUBLIC] C3 +CONSTANT PUBLIC_CONST_C4 "PUBLIC_CONST_ [PUBLIC] C4 +CONSTANT PUBLIC_CONST_C5 "PUBLIC_CONST_ [PUBLIC] C5 +CONSTANT class \Mixin [PUBLIC] Magic Constant diff --git a/php.editor/test/unit/data/testfiles/gotodeclaration/testMixin/testMixin.php b/php.editor/test/unit/data/testfiles/gotodeclaration/testMixin/testMixin.php new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/gotodeclaration/testMixin/testMixin.php @@ -0,0 +1,30 @@ +/testClassConstantVisibility.php; + clz : classconstantvisibility;ClassConstantVisibility;13;;;;1;;0;/testClassConstantVisibility.php;; clz.const : implicit_public_const;IMPLICIT_PUBLIC_CONST;50;0;0;/testClassConstantVisibility.php;32; clz.const : private_bar;PRIVATE_BAR;225;?;0;/testClassConstantVisibility.php;2; clz.const : private_const;PRIVATE_CONST;130;2;0;/testClassConstantVisibility.php;2; diff --git a/php.editor/test/unit/data/testfiles/index/testGetClasses/testGetClasses.php.indexed b/php.editor/test/unit/data/testfiles/index/testGetClasses/testGetClasses.php.indexed --- a/php.editor/test/unit/data/testfiles/index/testGetClasses/testGetClasses.php.indexed +++ b/php.editor/test/unit/data/testfiles/index/testGetClasses/testGetClasses.php.indexed @@ -8,7 +8,7 @@ Document 1 Searchable Keys: - clz : aaa;AAA;12;;;IAAA|\IAAA;1;;0;/testGetClasses.php; + clz : aaa;AAA;12;;;IAAA|\IAAA;1;;0;/testGetClasses.php;; superiface : iaaa;IAAA; top : aaa @@ -17,7 +17,7 @@ Document 2 Searchable Keys: - clz : bbb;BBB;40;AAA|\AAA;;IBBB|\IBBB;1;;0;/testGetClasses.php; + clz : bbb;BBB;40;AAA|\AAA;;IBBB|\IBBB;1;;0;/testGetClasses.php;; superclz : aaa;AAA; superiface : ibbb;IBBB; top : bbb @@ -27,7 +27,7 @@ Document 3 Searchable Keys: - clz : ccc;CCC;80;BBB|\BBB;;ICCC|\ICCC;1;;0;/testGetClasses.php; + clz : ccc;CCC;80;BBB|\BBB;;ICCC|\ICCC;1;;0;/testGetClasses.php;; superclz : bbb;BBB; superiface : iccc;ICCC; top : ccc diff --git a/php.editor/test/unit/data/testfiles/index/testGetClassesWithNsInterfaces/testGetClassesWithNsInterfaces.php.indexed b/php.editor/test/unit/data/testfiles/index/testGetClassesWithNsInterfaces/testGetClassesWithNsInterfaces.php.indexed --- a/php.editor/test/unit/data/testfiles/index/testGetClassesWithNsInterfaces/testGetClassesWithNsInterfaces.php.indexed +++ b/php.editor/test/unit/data/testfiles/index/testGetClassesWithNsInterfaces/testGetClassesWithNsInterfaces.php.indexed @@ -2,7 +2,7 @@ Document 0 Searchable Keys: - clz : nonsclassname;NoNsClassName;132;;No\Ns;NsInterfaceName|\NsFoo\NsBar\NsInterfaceName;1;;0;/testGetClassesWithNsInterfaces.php; + clz : nonsclassname;NoNsClassName;132;;No\Ns;NsInterfaceName|\NsFoo\NsBar\NsInterfaceName;1;;0;/testGetClassesWithNsInterfaces.php;; superiface : nsinterfacename;NsInterfaceName;NsFoo\NsBar top : nonsclassname diff --git a/php.editor/test/unit/data/testfiles/index/testGetFunctions/testGetFunctions.php.indexed b/php.editor/test/unit/data/testfiles/index/testGetFunctions/testGetFunctions.php.indexed --- a/php.editor/test/unit/data/testfiles/index/testGetFunctions/testGetFunctions.php.indexed +++ b/php.editor/test/unit/data/testfiles/index/testGetFunctions/testGetFunctions.php.indexed @@ -14,7 +14,7 @@ Document 1 Searchable Keys: - clz : parameterclass;ParameterClass;14;;;;1;;0;/testGetFunctions.php; + clz : parameterclass;ParameterClass;14;;;;1;;0;/testGetFunctions.php;; top : parameterclass Not Searchable Keys: diff --git a/php.editor/test/unit/data/testfiles/index/testGetMethods/testGetMethods.php.indexed b/php.editor/test/unit/data/testfiles/index/testGetMethods/testGetMethods.php.indexed --- a/php.editor/test/unit/data/testfiles/index/testGetMethods/testGetMethods.php.indexed +++ b/php.editor/test/unit/data/testfiles/index/testGetMethods/testGetMethods.php.indexed @@ -8,7 +8,7 @@ Document 1 Searchable Keys: - clz : testmethoddeclaration;testMethodDeclaration;12;;;;1;;0;/testGetMethods.php; + clz : testmethoddeclaration;testMethodDeclaration;12;;;;1;;0;/testGetMethods.php;; method : testmethoddeclaration;testMethodDeclaration;56;;;1;0;/testGetMethods.php; top : testmethoddeclaration diff --git a/php.editor/test/unit/data/testfiles/index/testIssue240824/testIssue240824.php.indexed b/php.editor/test/unit/data/testfiles/index/testIssue240824/testIssue240824.php.indexed --- a/php.editor/test/unit/data/testfiles/index/testIssue240824/testIssue240824.php.indexed +++ b/php.editor/test/unit/data/testfiles/index/testIssue240824/testIssue240824.php.indexed @@ -8,7 +8,7 @@ Document 1 Searchable Keys: - clz : myconfig;MyConfig;13;;;;1;;0;/testIssue240824.php; + clz : myconfig;MyConfig;13;;;;1;;0;/testIssue240824.php;; method : functionname;functionName;109;$param::0::1:0:0;;1;0;/testIssue240824.php; top : myconfig diff --git a/php.editor/test/unit/data/testfiles/index/testMixin/testMixin.php b/php.editor/test/unit/data/testfiles/index/testMixin/testMixin.php new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/index/testMixin/testMixin.php @@ -0,0 +1,34 @@ +/testMixin.php;\A\B\C3,\A\C2; + top : c1 + +Not Searchable Keys: + + +Document 1 +Searchable Keys: + clz : c2;C2;66;;A;;1;;0;/testMixin.php;; + top : c2 + +Not Searchable Keys: + + +Document 2 +Searchable Keys: + clz : c3;C3;95;;A\B;;1;;0;/testMixin.php;; + top : c3 + +Not Searchable Keys: + + +Document 3 +Searchable Keys: + clz : mixin;Mixin;200;MixinParent|\Mixin\MixinParent;Mixin;;1;;0;/testMixin.php;\A\C1; + superclz : mixinparent;MixinParent;Mixin + top : mixin + +Not Searchable Keys: + + +Document 4 +Searchable Keys: + clz : mixinparent;MixinParent;153;;Mixin;;1;;0;/testMixin.php;\A\B\C3; + top : mixinparent + +Not Searchable Keys: + + +Document 5 +Searchable Keys: + identifier_used : a; + identifier_used : a; + identifier_used : b; + identifier_used : c1; + identifier_used : c1; + identifier_used : c2; + identifier_used : c2; + identifier_used : c3; + identifier_used : c3; + identifier_used : c3; + identifier_used : mixin; + identifier_used : mixin; + identifier_used : mixinparent; + identifier_used : mixinparent; + +Not Searchable Keys: + + +Document 6 +Searchable Keys: + ns : a;A;;0;/testMixin.php; + ns : b;B;A;0;/testMixin.php; + ns : mixin;Mixin;;0;/testMixin.php; + top : a + top : a\b + top : mixin + +Not Searchable Keys: diff --git a/php.editor/test/unit/data/testfiles/index/testNullableTypesForMethods/testNullableTypesForMethods.php.indexed b/php.editor/test/unit/data/testfiles/index/testNullableTypesForMethods/testNullableTypesForMethods.php.indexed --- a/php.editor/test/unit/data/testfiles/index/testNullableTypesForMethods/testNullableTypesForMethods.php.indexed +++ b/php.editor/test/unit/data/testfiles/index/testNullableTypesForMethods/testNullableTypesForMethods.php.indexed @@ -8,7 +8,7 @@ Document 1 Searchable Keys: - clz : nullabletypes;NullableTypes;12;;;;1;;0;/testNullableTypesForMethods.php; + clz : nullabletypes;NullableTypes;12;;;;1;;0;/testNullableTypesForMethods.php;; method : parametertype;parameterType;49;$param:?string:1::1:0:0;;1;0;/testNullableTypesForMethods.php; method : parametertypestatic;parameterTypeStatic;115;$param:?string:1::1:0:0;;9;0;/testNullableTypesForMethods.php; method : returntype;returnType;180;$num:int:1::1:0:0;?\Foo;1;0;/testNullableTypesForMethods.php; diff --git a/php.editor/test/unit/data/testfiles/markoccurences/testMixin/testMixin.php b/php.editor/test/unit/data/testfiles/markoccurences/testMixin/testMixin.php new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/markoccurences/testMixin/testMixin.php @@ -0,0 +1,30 @@ +MARK_OCCURRENCES:MixinA^1<| + * @mixin \Mixin\A\|>MARK_OCCURRENCES:MixinA1<| diff --git a/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_02.occurrences b/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_02.occurrences new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_02.occurrences @@ -0,0 +1,2 @@ +class |>MARK_OCCURRENCES:MixinA1<| + * @mixin \Mixin\A\|>MARK_OCCURRENCES:Mixi^nA1<| diff --git a/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_03.occurrences b/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_03.occurrences new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_03.occurrences @@ -0,0 +1,3 @@ + * @mixin |>MARK_OCCURRENCES:MixinA2<| +class |>MARK_OCCURRENCES:MixinA^2<| + * @mixin \Mixin\A\|>MARK_OCCURRENCES:MixinA2<||MixinB1 diff --git a/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_04.occurrences b/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_04.occurrences new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_04.occurrences @@ -0,0 +1,3 @@ + * @mixin |>MARK_OCCURRENCES:MixinA2<| +class |>MARK_OCCURRENCES:MixinA2<| + * @mixin \Mixin\A\|>MARK_OCCURRENCES:Mixin^A2<||MixinB1 diff --git a/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_05.occurrences b/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_05.occurrences new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_05.occurrences @@ -0,0 +1,3 @@ + * @mixin ^|>MARK_OCCURRENCES:MixinA2<| +class |>MARK_OCCURRENCES:MixinA2<| + * @mixin \Mixin\A\|>MARK_OCCURRENCES:MixinA2<||MixinB1 diff --git a/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_06.occurrences b/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_06.occurrences new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_06.occurrences @@ -0,0 +1,2 @@ +class |>MARK_OCCURRENCES:Mix^inB1<| + * @mixin \Mixin\A\MixinA2||>MARK_OCCURRENCES:MixinB1<| diff --git a/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_07.occurrences b/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_07.occurrences new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/data/testfiles/testMixin.php.testMixin_07.occurrences @@ -0,0 +1,2 @@ +class |>MARK_OCCURRENCES:MixinB1<| + * @mixin \Mixin\A\MixinA2||>MARK_OCCURRENCES:Mixin^B1<| diff --git a/php.editor/test/unit/src/org/netbeans/modules/php/editor/completion/PHPCodeCompletionMixinTest.java b/php.editor/test/unit/src/org/netbeans/modules/php/editor/completion/PHPCodeCompletionMixinTest.java new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/src/org/netbeans/modules/php/editor/completion/PHPCodeCompletionMixinTest.java @@ -0,0 +1,89 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + */ +package org.netbeans.modules.php.editor.completion; + +import java.io.File; +import java.util.Collections; +import java.util.Map; +import org.netbeans.api.java.classpath.ClassPath; +import org.netbeans.modules.php.project.api.PhpSourcePath; +import org.netbeans.spi.java.classpath.support.ClassPathSupport; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; + + +public class PHPCodeCompletionMixinTest extends PHPCodeCompletionTestBase { + + public PHPCodeCompletionMixinTest(String testName) { + super(testName); + } + + @Override + protected Map createClassPathsForTest() { + return Collections.singletonMap( + PhpSourcePath.SOURCE_CP, + ClassPathSupport.createClassPath(new FileObject[]{ + FileUtil.toFileObject(new File(getDataDir(), "/testfiles/completion/lib/mixin/")) + }) + ); + } + + // #241740 for @mixin tag + public void testMixinTagType() throws Exception { + checkCompletion("testfiles/completion/lib/mixin/mixin.php", " * @mixin ^C3", false); + } + + public void testMixin() throws Exception { + checkCompletion("testfiles/completion/lib/mixin/mixin.php", "$mixin->^publicMethodC1(); // CC", false); + } + + public void testMixinWithStaticAccess() throws Exception { + checkCompletion("testfiles/completion/lib/mixin/mixin.php", "Mixin::^publicStaticMethodC1(); // CC", false); + } + + public void testMixinEnclosing() throws Exception { + checkCompletion("testfiles/completion/lib/mixin/mixin.php", " $this->^protectedMethodC1(); // CC", false); + } + + public void testMixinEnclosingWithStaticAccess() throws Exception { + checkCompletion("testfiles/completion/lib/mixin/mixin.php", " Mixin::^protectedStaticMethodC1(); // CC", false); + } + +} diff --git a/php.editor/test/unit/src/org/netbeans/modules/php/editor/csl/GotoDeclarationMixinTest.java b/php.editor/test/unit/src/org/netbeans/modules/php/editor/csl/GotoDeclarationMixinTest.java new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/src/org/netbeans/modules/php/editor/csl/GotoDeclarationMixinTest.java @@ -0,0 +1,65 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + */ +package org.netbeans.modules.php.editor.csl; + + +public class GotoDeclarationMixinTest extends GotoDeclarationTestBase { + + public GotoDeclarationMixinTest(String testName) { + super(testName); + } + + public void testMixin_01() throws Exception { + checkDeclaration(getTestPath(), " * @mixin \\Mixin\\A\\Mixin^A1", "class ^MixinA1"); + } + + public void testMixin_02() throws Exception { + checkDeclaration(getTestPath(), " * @mixin Mi^xinA2", "class ^MixinA2"); + } + + public void testMixin_03() throws Exception { + checkDeclaration(getTestPath(), " * @mixin \\Mixin\\A\\MixinA^2|MixinB1", "class ^MixinA2"); + } + + public void testMixin_04() throws Exception { + checkDeclaration(getTestPath(), " * @mixin \\Mixin\\A\\MixinA2|Mi^xinB1", "class ^MixinB1"); + } + +} diff --git a/php.editor/test/unit/src/org/netbeans/modules/php/editor/csl/OccurrencesFinderImplMixinTest.java b/php.editor/test/unit/src/org/netbeans/modules/php/editor/csl/OccurrencesFinderImplMixinTest.java new file mode 100644 --- /dev/null +++ b/php.editor/test/unit/src/org/netbeans/modules/php/editor/csl/OccurrencesFinderImplMixinTest.java @@ -0,0 +1,77 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + */ +package org.netbeans.modules.php.editor.csl; + + +public class OccurrencesFinderImplMixinTest extends OccurrencesFinderImplTestBase { + + public OccurrencesFinderImplMixinTest(String testName) { + super(testName); + } + + public void testMixin_01() throws Exception { + checkOccurrences(getTestPath(), "class MixinA^1", true); + } + + public void testMixin_02() throws Exception { + checkOccurrences(getTestPath(), " * @mixin \\Mixin\\A\\Mixi^nA1", true); + } + + public void testMixin_03() throws Exception { + checkOccurrences(getTestPath(), "class MixinA^2", true); + } + + public void testMixin_04() throws Exception { + checkOccurrences(getTestPath(), " * @mixin \\Mixin\\A\\Mixin^A2|MixinB1", true); + } + + public void testMixin_05() throws Exception { + checkOccurrences(getTestPath(), " * @mixin ^MixinA2", true); + } + + public void testMixin_06() throws Exception { + checkOccurrences(getTestPath(), "class Mix^inB1", true); + } + + public void testMixin_07() throws Exception { + checkOccurrences(getTestPath(), " * @mixin \\Mixin\\A\\MixinA2|Mixin^B1", true); + } + +} diff --git a/php.editor/test/unit/src/org/netbeans/modules/php/editor/index/PHPIndexTest.java b/php.editor/test/unit/src/org/netbeans/modules/php/editor/index/PHPIndexTest.java --- a/php.editor/test/unit/src/org/netbeans/modules/php/editor/index/PHPIndexTest.java +++ b/php.editor/test/unit/src/org/netbeans/modules/php/editor/index/PHPIndexTest.java @@ -598,6 +598,11 @@ checkIndexer(getTestPath()); } + // #241740 + public void testMixin() throws Exception { + checkIndexer(getTestPath()); + } + @Override protected FileObject[] createSourceClassPathsForTest() { final File folder = new File(getDataDir(), getTestFolderPath());