blob: 14d42daa3db731203098687cad6962ee4bed8a9a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.php.editor.elements;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.modules.parsing.spi.indexing.support.IndexResult;
import org.netbeans.modules.parsing.spi.indexing.support.QuerySupport;
import org.netbeans.modules.parsing.spi.indexing.support.QuerySupport.Kind;
import org.netbeans.modules.php.api.editor.PhpBaseElement;
import org.netbeans.modules.php.api.editor.PhpClass;
import org.netbeans.modules.php.api.editor.PhpType;
import org.netbeans.modules.php.api.editor.PhpVariable;
import org.netbeans.modules.php.editor.api.AbstractElementQuery;
import org.netbeans.modules.php.editor.api.AliasedName;
import org.netbeans.modules.php.editor.api.ElementQuery;
import org.netbeans.modules.php.editor.api.NameKind;
import org.netbeans.modules.php.editor.api.NameKind.Exact;
import org.netbeans.modules.php.editor.api.PhpElementKind;
import org.netbeans.modules.php.editor.api.QualifiedName;
import org.netbeans.modules.php.editor.api.elements.AliasedClass;
import org.netbeans.modules.php.editor.api.elements.AliasedConstant;
import org.netbeans.modules.php.editor.api.elements.AliasedElement;
import org.netbeans.modules.php.editor.api.elements.AliasedElement.Trait;
import org.netbeans.modules.php.editor.api.elements.AliasedFunction;
import org.netbeans.modules.php.editor.api.elements.AliasedInterface;
import org.netbeans.modules.php.editor.api.elements.AliasedNamespace;
import org.netbeans.modules.php.editor.api.elements.AliasedTrait;
import org.netbeans.modules.php.editor.api.elements.AliasedType;
import org.netbeans.modules.php.editor.api.elements.ClassElement;
import org.netbeans.modules.php.editor.api.elements.ConstantElement;
import org.netbeans.modules.php.editor.api.elements.ElementFilter;
import org.netbeans.modules.php.editor.api.elements.FieldElement;
import org.netbeans.modules.php.editor.api.elements.FunctionElement;
import org.netbeans.modules.php.editor.api.elements.InterfaceElement;
import org.netbeans.modules.php.editor.api.elements.MethodElement;
import org.netbeans.modules.php.editor.api.elements.NamespaceElement;
import org.netbeans.modules.php.editor.api.elements.PhpElement;
import org.netbeans.modules.php.editor.api.elements.TraitElement;
import org.netbeans.modules.php.editor.api.elements.TraitedElement;
import org.netbeans.modules.php.editor.api.elements.TreeElement;
import org.netbeans.modules.php.editor.api.elements.TypeConstantElement;
import org.netbeans.modules.php.editor.api.elements.TypeElement;
import org.netbeans.modules.php.editor.api.elements.TypeMemberElement;
import org.netbeans.modules.php.editor.api.elements.VariableElement;
import org.netbeans.modules.php.editor.index.PHPIndexer;
import org.netbeans.modules.php.editor.index.Signature;
import org.netbeans.modules.php.editor.model.Model;
import org.netbeans.modules.php.editor.model.ModelUtils;
import org.netbeans.modules.php.editor.model.NamespaceScope;
import org.netbeans.modules.php.editor.model.UseScope;
import org.netbeans.modules.php.editor.parser.PHPParseResult;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.filesystems.URLMapper;
import org.openide.util.Exceptions;
import org.openide.util.Utilities;
/**
* @author Radek Matous
*/
public final class IndexQueryImpl implements ElementQuery.Index {
public static final String FIELD_TOP_LEVEL = PHPIndexer.FIELD_TOP_LEVEL;
private static final Logger LOG = Logger.getLogger(IndexQueryImpl.class.getName());
private static Collection<NamespaceElement> namespacesCache = null;
private final QuerySupport index;
private final Set<AliasedName> aliases = new HashSet<>();
private final AbstractElementQuery extendedQuery = new AbstractElementQuery(QueryScope.VIRTUAL_SCOPE);
private IndexQueryImpl(QuerySupport index, final Model model) {
this.index = index;
if (model != null) {
init(model);
}
}
private void init(final Model model) {
initExtendedQuery(model);
initAliases(model);
}
/**
* Intended to be used for fake additions of aliases that are returned
* as if they were in index
*/
private void initAliases(final Model model) {
for (final NamespaceScope namespaceScope : model.getFileScope().getDeclaredNamespaces()) {
if (namespaceScope != null) {
for (UseScope useElement : namespaceScope.getAllDeclaredSingleUses()) {
AliasedName aliasedName = useElement.getAliasedName();
if (aliasedName != null) {
aliases.add(aliasedName);
}
}
}
}
}
/**
* Intended to be used for fake additions of frameworks that are returned
* as if they were in index
*/
private void initExtendedQuery(final Model model) {
//TODO: the best approach would be the frameworks returned ElementQuery instance
//and get rid of PhpBaseElement and its subclasses
List<PhpBaseElement> extendedElements = model.getExtendedElements();
for (PhpBaseElement phpBaseElement : extendedElements) {
if (phpBaseElement instanceof PhpVariable) {
PhpVariable variable = (PhpVariable) phpBaseElement;
extendedQuery.addElement(VariableElementImpl.fromFrameworks(variable, extendedQuery));
final PhpType type = variable.getType();
if (type instanceof PhpClass) {
final ClassElement classElement = ClassElementImpl.fromFrameworks((PhpClass) type, extendedQuery);
extendedQuery.addElement(classElement);
for (final PhpType.Field field : type.getFields()) {
final FieldElement fieldElement = FieldElementImpl.fromFrameworks(classElement, field, extendedQuery);
extendedQuery.addElement(fieldElement);
}
}
}
}
}
private IndexQueryImpl(QuerySupport index) {
this(index, null);
}
public static Index create(final QuerySupport querySupport) {
return new IndexQueryImpl(querySupport);
}
public static Index create(final QuerySupport querySupport, final Model model) {
return new IndexQueryImpl(querySupport, model);
}
public static Index getModelInstance(final PHPParseResult parseResult) {
return parseResult.getModel().getIndexScope().getIndex();
}
public static void clearNamespaceCache() {
synchronized (IndexQueryImpl.class) {
namespacesCache = null;
}
}
private Set<ClassElement> getClassesImpl(final NameKind query) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<ClassElement> classes = new HashSet<>();
final Collection<? extends IndexResult> result = results(ClassElementImpl.IDX_FIELD, query);
for (final IndexResult indexResult : result) {
Set<ClassElement> allClasses = ClassElementImpl.fromSignature(query, this, indexResult);
if (query.isPrefix() || query.isCaseInsensitivePrefix()) {
classes.addAll(allClasses);
} else {
for (ClassElement classElement : allClasses) {
if (query.getQuery().getNamespaceName().equals(classElement.getNamespaceName().toString())) {
classes.add(classElement);
}
}
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<ClassElement> getClasses", query, start); //NOI18N
}
return Collections.unmodifiableSet(classes);
}
private Set<InterfaceElement> getInterfacesImpl(final NameKind query) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<InterfaceElement> ifaces = new HashSet<>();
final Collection<? extends IndexResult> result = results(InterfaceElementImpl.IDX_FIELD, query);
for (final IndexResult indexResult : result) {
ifaces.addAll(InterfaceElementImpl.fromSignature(query, this, indexResult));
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<InterfaceElement> getInterfaces", query, start); //NOI18N
}
return Collections.unmodifiableSet(ifaces);
}
private Set<TraitElement> getTraitsImpl(final NameKind query) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<TraitElement> traits = new HashSet<>();
final Collection<? extends IndexResult> result = results(TraitElementImpl.IDX_FIELD, query);
for (final IndexResult indexResult : result) {
traits.addAll(TraitElementImpl.fromSignature(query, this, indexResult));
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<TraitElement> getTraits", query, start); //NOI18N
}
return Collections.unmodifiableSet(traits);
}
private static Set<NameKind> queriesForAlias(final NameKind query, final AliasedName aliasedName, final PhpElementKind elementKind) {
final Set<NameKind> aliasQueries = new HashSet<>();
final boolean fullyQualified = query.getQuery().getKind().isFullyQualified();
final Kind queryKind = query.getQueryKind();
final LinkedList<String> segments = query.getQuery().getSegments();
for (int i = 0; i < segments.size(); i++) {
final String nextSegment = segments.get(i);
if (!nextSegment.isEmpty() && (i == 0 || (i == segments.size() - 1)) && (!nextSegment.isEmpty() || segments.size() == 1)
&& NameKind.create(nextSegment, queryKind).matchesName(elementKind, aliasedName.getAliasName())) {
final LinkedList<String> nSegments = new LinkedList<>();
nSegments.addAll(segments.subList(0, i));
nSegments.addAll(aliasedName.getRealName().getSegments());
if (i + 1 < segments.size()) {
nSegments.addAll(segments.subList(i + 1, segments.size()));
}
aliasQueries.add(NameKind.create(QualifiedName.create(fullyQualified, nSegments), queryKind));
}
}
return aliasQueries;
}
private Set<TypeElement> getTypesImpl(NameKind query) {
final Set<TypeElement> types = new HashSet<>();
types.addAll(getClassesImpl(query));
types.addAll(getInterfacesImpl(query));
types.addAll(getTraitsImpl(query));
return types;
}
@Override
public Set<MethodElement> getAccessibleMagicMethods(final TypeElement type) {
return MethodElementImpl.getMagicMethods(type);
}
@Override
public Set<TypeConstantElement> getAccessibleMagicConstants(TypeElement type) {
return TypeConstantElementImpl.getMagicConstants(type);
}
private Set<FunctionElement> getFunctionsImpl(final NameKind query) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<FunctionElement> functions = new HashSet<>();
final Collection<? extends IndexResult> result = results(FunctionElementImpl.IDX_FIELD, query);
for (final IndexResult indexResult : result) {
functions.addAll(FunctionElementImpl.fromSignature(query, this, indexResult));
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<FunctionElement> getFunctions", query, start); //NOI18N
}
return Collections.unmodifiableSet(functions);
}
private Set<NamespaceElement> getNamespacesImpl(final NameKind query) {
final Set<NamespaceElement> retval = new HashSet<>();
synchronized (IndexQueryImpl.class) {
if (namespacesCache == null) {
final Map<String, NamespaceElement> namespacesMap = new LinkedHashMap<>();
for (final NamespaceElement namespace : namespacesImpl(NameKind.empty())) {
NamespaceElement original = null;
QualifiedName qn = namespace.getFullyQualifiedName();
while (original == null && !qn.isDefaultNamespace()) {
original = namespacesMap.put(
qn.toFullyQualified().toString().toLowerCase(),
new NamespaceElementImpl(
qn,
namespace.getOffset(),
namespace.getFilenameUrl(),
namespace.getElementQuery(),
namespace.isDeprecated()));
qn = qn.toNamespaceName();
}
}
namespacesCache = namespacesMap.values();
}
}
for (final NamespaceElement indexedNamespace : namespacesCache) {
if (query.matchesName(indexedNamespace)) {
retval.add(indexedNamespace);
}
}
return retval;
}
private Set<NamespaceElement> namespacesImpl(NameKind query) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
//TODO: not cached yet
final Set<NamespaceElement> namespaces = new HashSet<>();
final Collection<? extends IndexResult> result = results(NamespaceElementImpl.IDX_FIELD, query);
for (final IndexResult indexResult : result) {
namespaces.addAll(NamespaceElementImpl.fromSignature(query, this, indexResult));
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<NamespaceElement> getNamespaces", query, start); //NOI18N
}
return Collections.unmodifiableSet(namespaces);
}
private Set<ConstantElement> getConstantsImpl(final NameKind query) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<ConstantElement> constants = new HashSet<>();
final Collection<? extends IndexResult> result = results(ConstantElementImpl.IDX_FIELD, query);
for (final IndexResult indexResult : result) {
constants.addAll(ConstantElementImpl.fromSignature(query, this, indexResult));
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<ConstantElement> getConstants", query, start); //NOI18N
}
return Collections.unmodifiableSet(constants);
}
private Set<PhpElement> getTopLevelElementsImpl(NameKind query) {
final boolean isVariable = query.getQueryName().startsWith(VariableElementImpl.DOLLAR_PREFIX);
final String[] fieldsToLoad = isVariable
? new String[] {
PHPIndexer.FIELD_VAR
}
: new String[] {
PHPIndexer.FIELD_BASE,
PHPIndexer.FIELD_CONST,
PHPIndexer.FIELD_CLASS,
PHPIndexer.FIELD_IFACE,
PHPIndexer.FIELD_NAMESPACE,
PHPIndexer.FIELD_TRAIT
};
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<PhpElement> elements = new HashSet<>();
final Collection<? extends IndexResult> result = results(FIELD_TOP_LEVEL, query, fieldsToLoad);
for (final IndexResult indexResult : result) {
if (isVariable) {
elements.addAll(VariableElementImpl.fromSignature(query, this, indexResult));
} else {
elements.addAll(ClassElementImpl.fromSignature(query, this, indexResult));
elements.addAll(InterfaceElementImpl.fromSignature(query, this, indexResult));
elements.addAll(FunctionElementImpl.fromSignature(query, this, indexResult));
elements.addAll(ConstantElementImpl.fromSignature(query, this, indexResult));
elements.addAll(TraitElementImpl.fromSignature(query, this, indexResult));
}
}
if (isVariable) {
elements.addAll(extendedQuery.getTopLevelVariables(query));
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<PhpElement> getTopLevelElements", query, start); //NOI18N
}
return Collections.unmodifiableSet(elements);
}
@Override
public Set<VariableElement> getTopLevelVariables(final NameKind query) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<VariableElement> vars = new HashSet<>();
final Collection<? extends IndexResult> result = results(VariableElementImpl.IDX_FIELD, query);
for (final IndexResult indexResult : result) {
vars.addAll(VariableElementImpl.fromSignature(query, this, indexResult));
}
vars.addAll(extendedQuery.getTopLevelVariables(query));
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<VariableElement> getTopLevelVariables", query, start); //NOI18N
}
return Collections.unmodifiableSet(vars);
}
@Override
public Set<MethodElement> getConstructors(final ClassElement classElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<MethodElement> retval = getConstructorsImpl(classElement, classElement, new LinkedHashSet<ClassElement>());
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<MethodElement> getConstructors", NameKind.exact(classElement.getFullyQualifiedName()), start); //NOI18N
}
return retval.isEmpty() ? getDefaultConstructors(classElement) : retval;
}
private Set<MethodElement> getConstructorsImpl(NameKind typeQuery) {
final Set<MethodElement> retval = new HashSet<>();
final Set<ClassElement> classes = getClassesImpl(typeQuery);
for (ClassElement classElement : classes) {
retval.addAll(getConstructors(classElement));
}
return retval;
}
private Set<MethodElement> getConstructorsImpl(final ClassElement originalClass, final ClassElement inheritedClass, final Set<ClassElement> check) {
final Set<MethodElement> methods = new HashSet<>();
if (!check.contains(inheritedClass)) {
check.add(inheritedClass);
final Exact typeQuery = NameKind.exact(inheritedClass.getFullyQualifiedName());
final Collection<? extends IndexResult> constructorResults = results(ClassElementImpl.IDX_FIELD, typeQuery,
new String[]{ClassElementImpl.IDX_FIELD, MethodElementImpl.IDX_CONSTRUCTOR_FIELD, MethodElementImpl.IDX_FIELD});
final Set<MethodElement> methodsForResult = new HashSet<>();
final ElementFilter forEqualTypes = ElementFilter.forEqualTypes(inheritedClass);
for (final IndexResult indexResult : constructorResults) {
Set<ClassElement> classes = ClassElementImpl.fromSignature(this, indexResult);
for (ClassElement classElement : classes) {
if (forEqualTypes.isAccepted(classElement)) {
methodsForResult.addAll(MethodElementImpl.fromSignature(originalClass, this, indexResult));
}
}
}
methods.addAll(ElementFilter.forConstructor().filter(methodsForResult));
if (methods.isEmpty()) {
for (TypeElement typeElement : getDirectInheritedTypes(inheritedClass, true, false)) {
if (typeElement instanceof ClassElement) {
methods.addAll(getConstructorsImpl(originalClass, (ClassElement) typeElement, check));
if (!methods.isEmpty()) {
break;
}
}
}
}
}
return Collections.unmodifiableSet(methods);
}
private Set<MethodElement> getDefaultConstructors(final ClassElement classElement) {
Set<MethodElement> magicMethods = getAccessibleMagicMethods(classElement);
for (MethodElement methodElement : magicMethods) {
if (methodElement.isConstructor()) {
return Collections.singleton(methodElement);
}
}
throw new IllegalStateException();
}
@Override
public Set<MethodElement> getMethods(final NameKind methodQuery) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<MethodElement> methods = new HashSet<>();
final Collection<? extends IndexResult> methResults = results(MethodElementImpl.IDX_FIELD, methodQuery,
new String[]{ClassElementImpl.IDX_FIELD, InterfaceElementImpl.IDX_FIELD, TraitElementImpl.IDX_FIELD, MethodElementImpl.IDX_FIELD});
for (final IndexResult indexResult : methResults) {
final Set<TypeElement> types = new HashSet<>();
types.addAll(ClassElementImpl.fromSignature(this, indexResult));
types.addAll(InterfaceElementImpl.fromSignature(this, indexResult));
types.addAll(TraitElementImpl.fromSignature(this, indexResult));
for (final TypeElement typeElement : types) {
methods.addAll(MethodElementImpl.fromSignature(typeElement, methodQuery, this, indexResult));
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<MethodElement> getMethods", methodQuery, start); //NOI18N
}
return Collections.unmodifiableSet(methods);
}
@Override
public Set<TypeMemberElement> getDeclaredTypeMembers(TypeElement typeElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final QualifiedName fullyQualifiedName = typeElement.getFullyQualifiedName();
final Set<TypeMemberElement> members = new HashSet<>();
final NameKind.Exact typeQuery = NameKind.exact(fullyQualifiedName);
final NameKind memberQuery = NameKind.empty();
final FileObject typeFo = typeElement.getFileObject();
switch (typeElement.getPhpElementKind()) {
case CLASS:
final Collection<? extends IndexResult> clzResults = results(ClassElementImpl.IDX_FIELD, typeQuery,
new String[]{
ClassElementImpl.IDX_FIELD,
FieldElementImpl.IDX_FIELD,
TypeConstantElementImpl.IDX_FIELD,
MethodElementImpl.IDX_FIELD
});
for (final IndexResult indexResult : clzResults) {
for (final TypeElement clzElement : ClassElementImpl.fromSignature(typeQuery, this, indexResult)) {
if (fullyQualifiedName.getNamespaceName().equals(clzElement.getNamespaceName().toString())) {
members.addAll(MethodElementImpl.fromSignature(clzElement, memberQuery, this, indexResult));
members.addAll(FieldElementImpl.fromSignature(clzElement, memberQuery, this, indexResult));
members.addAll(TypeConstantElementImpl.fromSignature(clzElement, memberQuery, this, indexResult));
}
}
}
break;
case IFACE:
final Collection<? extends IndexResult> ifaceResults = results(InterfaceElementImpl.IDX_FIELD, typeQuery,
new String[]{
InterfaceElementImpl.IDX_FIELD,
TypeConstantElementImpl.IDX_FIELD,
MethodElementImpl.IDX_FIELD
});
for (final IndexResult indexResult : ifaceResults) {
for (final TypeElement ifaceElement : InterfaceElementImpl.fromSignature(typeQuery, this, indexResult)) {
members.addAll(MethodElementImpl.fromSignature(ifaceElement, memberQuery, this, indexResult));
members.addAll(TypeConstantElementImpl.fromSignature(ifaceElement, memberQuery, this, indexResult));
}
}
break;
case TRAIT:
final Collection<? extends IndexResult> traitResults = results(TraitElementImpl.IDX_FIELD, typeQuery,
new String[]{
TraitElementImpl.IDX_FIELD,
FieldElementImpl.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));
}
}
break;
default:
assert false : typeElement.getPhpElementKind();
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<PhpElement> getTypeMembers", typeQuery, memberQuery, start); //NOI18N
}
final Set<TypeMemberElement> retval = new HashSet<>();
final Exact exactTypeName = NameKind.exact(typeElement.getFullyQualifiedName());
retval.addAll(extendedQuery.getFields(exactTypeName, NameKind.empty()));
retval.addAll(extendedQuery.getMethods(exactTypeName, NameKind.empty()));
retval.addAll(extendedQuery.getTypeConstants(exactTypeName, NameKind.empty()));
retval.addAll(ElementFilter.forFiles(typeFo).filter(members));
return retval;
}
@Override
public Set<MethodElement> getDeclaredConstructors(ClassElement typeElement) {
return ElementFilter.forName(NameKind.exact(MethodElementImpl.CONSTRUCTOR_NAME)).
filter(getDeclaredMethods(typeElement));
}
@Override
public Set<MethodElement> getDeclaredMethods(final TypeElement typeElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final QualifiedName fullyQualifiedName = typeElement.getFullyQualifiedName();
final Set<MethodElement> methods = new HashSet<>();
final NameKind.Exact typeQuery = NameKind.exact(fullyQualifiedName);
final NameKind methodQuery = NameKind.empty();
final FileObject typeFo = typeElement.getFileObject();
switch (typeElement.getPhpElementKind()) {
case CLASS:
final Collection<? extends IndexResult> clzResults = results(ClassElementImpl.IDX_FIELD, typeQuery,
new String[]{ClassElementImpl.IDX_FIELD, MethodElementImpl.IDX_FIELD});
for (final IndexResult indexResult : clzResults) {
for (final TypeElement clzElement : ClassElementImpl.fromSignature(typeQuery, this, indexResult)) {
methods.addAll(MethodElementImpl.fromSignature(clzElement, methodQuery, this, indexResult));
}
}
break;
case IFACE:
final Collection<? extends IndexResult> ifaceResults = results(InterfaceElementImpl.IDX_FIELD, typeQuery,
new String[]{InterfaceElementImpl.IDX_FIELD, MethodElementImpl.IDX_FIELD});
for (final IndexResult indexResult : ifaceResults) {
for (final TypeElement ifaceElement : InterfaceElementImpl.fromSignature(typeQuery, this, indexResult)) {
methods.addAll(MethodElementImpl.fromSignature(ifaceElement, methodQuery, this, indexResult));
}
}
break;
case TRAIT:
final Collection<? extends IndexResult> traitResults = results(TraitElementImpl.IDX_FIELD, typeQuery,
new String[]{TraitElementImpl.IDX_FIELD, MethodElementImpl.IDX_FIELD});
for (final IndexResult indexResult : traitResults) {
for (final TypeElement traitElement : TraitElementImpl.fromSignature(typeQuery, this, indexResult)) {
methods.addAll(MethodElementImpl.fromSignature(traitElement, methodQuery, this, indexResult));
}
}
break;
default:
assert false : typeElement.getPhpElementKind();
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<MethodElement> getMethods", typeQuery, methodQuery, start); //NOI18N
}
return ElementFilter.forFiles(typeFo).filter(methods);
}
@Override
public Set<TypeMemberElement> getTypeMembers(final NameKind.Exact typeQuery, final NameKind memberQuery) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<TypeMemberElement> members = new HashSet<>();
//two queries: once for classes, second for ifaces
final Collection<? extends IndexResult> clzResults = results(ClassElementImpl.IDX_FIELD, typeQuery,
new String[]{
ClassElementImpl.IDX_FIELD,
MethodElementImpl.IDX_FIELD,
FieldElementImpl.IDX_FIELD,
TypeConstantElementImpl.IDX_FIELD
});
for (final IndexResult indexResult : clzResults) {
for (final TypeElement typeElement : ClassElementImpl.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> ifaceResults = results(InterfaceElementImpl.IDX_FIELD, typeQuery,
new String[]{
InterfaceElementImpl.IDX_FIELD,
MethodElementImpl.IDX_FIELD,
TypeConstantElementImpl.IDX_FIELD
});
for (final IndexResult indexResult : ifaceResults) {
for (final TypeElement typeElement : InterfaceElementImpl.fromSignature(typeQuery, this, indexResult)) {
members.addAll(MethodElementImpl.fromSignature(typeElement, memberQuery, this, indexResult));
members.addAll(TypeConstantElementImpl.fromSignature(typeElement, memberQuery, this, indexResult));
}
}
final Collection<? extends IndexResult> traitResults = results(TraitElementImpl.IDX_FIELD, typeQuery,
new String[] {
TraitElementImpl.IDX_FIELD,
MethodElementImpl.IDX_FIELD,
FieldElementImpl.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));
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<PhpElement> getTypeMembers", typeQuery, memberQuery, start); //NOI18N
}
return Collections.unmodifiableSet(members);
}
@Override
public Set<MethodElement> getMethods(final NameKind.Exact typeQuery, final NameKind methodQuery) {
return getMethodsImpl(typeQuery, methodQuery, EnumSet.of(PhpElementKind.CLASS, PhpElementKind.IFACE, PhpElementKind.TRAIT));
}
private Set<MethodElement> getMethodsImpl(final NameKind.Exact typeQuery, final NameKind methodQuery, EnumSet<PhpElementKind> typeKinds) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<MethodElement> methods = new HashSet<>();
//two queries: once for classes, second for ifaces
if (typeKinds.contains(PhpElementKind.CLASS)) {
final Collection<? extends IndexResult> clzResults = results(ClassElementImpl.IDX_FIELD, typeQuery,
new String[]{ClassElementImpl.IDX_FIELD, MethodElementImpl.IDX_FIELD});
for (final IndexResult indexResult : clzResults) {
for (final TypeElement typeElement : ClassElementImpl.fromSignature(typeQuery, this, indexResult)) {
methods.addAll(MethodElementImpl.fromSignature(typeElement, methodQuery, this, indexResult));
}
}
}
if (typeKinds.contains(PhpElementKind.IFACE)) {
final Collection<? extends IndexResult> ifaceResults = results(InterfaceElementImpl.IDX_FIELD, typeQuery,
new String[]{InterfaceElementImpl.IDX_FIELD, MethodElementImpl.IDX_FIELD});
for (final IndexResult indexResult : ifaceResults) {
for (final TypeElement typeElement : InterfaceElementImpl.fromSignature(typeQuery, this, indexResult)) {
methods.addAll(MethodElementImpl.fromSignature(typeElement, methodQuery, this, indexResult));
}
}
}
if (typeKinds.contains(PhpElementKind.TRAIT)) {
final Collection<? extends IndexResult> traitResults = results(TraitElementImpl.IDX_FIELD, typeQuery,
new String[]{TraitElementImpl.IDX_FIELD, MethodElementImpl.IDX_FIELD});
for (final IndexResult indexResult : traitResults) {
for (final TypeElement typeElement : TraitElementImpl.fromSignature(typeQuery, this, indexResult)) {
methods.addAll(MethodElementImpl.fromSignature(typeElement, methodQuery, this, indexResult));
}
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<MethodElement> getMethods", typeQuery, methodQuery, start); //NOI18N
}
return Collections.unmodifiableSet(methods);
}
@Override
public Set<FileObject> getLocationsForIdentifiers(String identifierName) {
final Set<FileObject> result = new HashSet<>();
Collection<? extends IndexResult> idIndexResult = search(
PHPIndexer.FIELD_IDENTIFIER,
identifierName.toLowerCase(),
QuerySupport.Kind.PREFIX,
PHPIndexer.FIELD_BASE,
PHPIndexer.FIELD_IDENTIFIER);
for (IndexResult indexResult : idIndexResult) {
String[] values = indexResult.getValues(PHPIndexer.FIELD_IDENTIFIER);
for (String val : values) {
Signature sig = Signature.get(val);
if (identifierName.equalsIgnoreCase(sig.string(0))) {
URL url = indexResult.getUrl();
FileObject fo = null;
try {
fo = "file".equals(url.getProtocol()) ? //NOI18N
FileUtil.toFileObject(Utilities.toFile(url.toURI())) : URLMapper.findFileObject(url);
} catch (URISyntaxException ex) {
Exceptions.printStackTrace(ex);
}
if (fo != null) {
result.add(fo);
}
}
}
}
return result;
}
@Override
public Set<FieldElement> getDeclaredFields(TypeElement typeElement) {
final Set<FieldElement> retval = new HashSet<>();
final Exact typeNameQuery = NameKind.exact(typeElement.getFullyQualifiedName());
retval.addAll(ElementFilter.forFiles(typeElement.getFileObject())
.filter(getFields(typeNameQuery, NameKind.empty())));
retval.addAll(extendedQuery.getFields(typeNameQuery, NameKind.empty()));
return retval;
}
@Override
public Set<FieldElement> getFields(final NameKind fieldQuery) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<FieldElement> fields = new HashSet<>();
final Collection<? extends IndexResult> classFieldResults = results(FieldElementImpl.IDX_FIELD, fieldQuery,
new String[]{ClassElementImpl.IDX_FIELD, FieldElementImpl.IDX_FIELD});
for (final IndexResult indexResult : classFieldResults) {
for (final TypeElement typeElement : ClassElementImpl.fromSignature(this, indexResult)) {
fields.addAll(FieldElementImpl.fromSignature(typeElement, fieldQuery, this, indexResult));
}
}
final Collection<? extends IndexResult> traitFieldResults = results(FieldElementImpl.IDX_FIELD, fieldQuery,
new String[]{TraitElementImpl.IDX_FIELD, FieldElementImpl.IDX_FIELD});
for (final IndexResult indexResult : traitFieldResults) {
for (final TypeElement typeElement : TraitElementImpl.fromSignature(this, indexResult)) {
fields.addAll(FieldElementImpl.fromSignature(typeElement, fieldQuery, this, indexResult));
}
}
fields.addAll(extendedQuery.getFields(fieldQuery));
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<FieldElement> getFields", fieldQuery, start); //NOI18N
}
return Collections.unmodifiableSet(fields);
}
@Override
public Set<FieldElement> getFields(final NameKind.Exact classQuery, final NameKind fieldQuery) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<FieldElement> fields = new HashSet<>();
final Collection<? extends IndexResult> clzResults = results(ClassElementImpl.IDX_FIELD, classQuery,
new String[]{ClassElementImpl.IDX_FIELD, FieldElementImpl.IDX_FIELD});
for (final IndexResult indexResult : clzResults) {
for (final TypeElement typeElement : ClassElementImpl.fromSignature(classQuery, this, indexResult)) {
fields.addAll(FieldElementImpl.fromSignature(typeElement, fieldQuery, this, indexResult));
}
}
final Collection<? extends IndexResult> traitResults = results(TraitElementImpl.IDX_FIELD, classQuery,
new String[]{TraitElementImpl.IDX_FIELD, FieldElementImpl.IDX_FIELD});
for (final IndexResult indexResult : traitResults) {
for (final TypeElement typeElement : TraitElementImpl.fromSignature(classQuery, this, indexResult)) {
fields.addAll(FieldElementImpl.fromSignature(typeElement, fieldQuery, this, indexResult));
}
}
fields.addAll(extendedQuery.getFields(classQuery, fieldQuery));
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<FieldElement> getFields", classQuery, fieldQuery, start); //NOI18N
}
return Collections.unmodifiableSet(fields);
}
@Override
public Set<TypeConstantElement> getDeclaredTypeConstants(TypeElement typeElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final QualifiedName fullyQualifiedName = typeElement.getFullyQualifiedName();
final FileObject typeFo = typeElement.getFileObject();
final Set<TypeConstantElement> constants = new HashSet<>();
final NameKind.Exact typeQuery = NameKind.exact(fullyQualifiedName);
final NameKind constantQuery = NameKind.empty();
switch (typeElement.getPhpElementKind()) {
case CLASS:
final Collection<? extends IndexResult> clzResults = results(ClassElementImpl.IDX_FIELD, typeQuery,
new String[]{ClassElementImpl.IDX_FIELD, TypeConstantElementImpl.IDX_FIELD});
for (final IndexResult indexResult : clzResults) {
for (final TypeElement classElement : ClassElementImpl.fromSignature(typeQuery, this, indexResult)) {
constants.addAll(TypeConstantElementImpl.fromSignature(classElement, constantQuery, this, indexResult));
}
}
break;
case IFACE:
final Collection<? extends IndexResult> ifaceResults = results(InterfaceElementImpl.IDX_FIELD, typeQuery,
new String[]{InterfaceElementImpl.IDX_FIELD, TypeConstantElementImpl.IDX_FIELD});
for (final IndexResult indexResult : ifaceResults) {
for (final TypeElement ifaceElement : InterfaceElementImpl.fromSignature(typeQuery, this, indexResult)) {
constants.addAll(TypeConstantElementImpl.fromSignature(ifaceElement, constantQuery, this, indexResult));
}
}
break;
default:
//noop
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<TypeConstantElement> getTypeConstants", typeQuery, constantQuery, start); //NOI18N
}
return Collections.unmodifiableSet(ElementFilter.forFiles(typeFo).filter(constants));
}
@Override
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, TypeConstantElementImpl.IDX_FIELD});
for (final IndexResult indexResult : constantResults) {
final Set<TypeElement> types = new HashSet<>();
types.addAll(ClassElementImpl.fromSignature(this, indexResult));
types.addAll(InterfaceElementImpl.fromSignature(this, indexResult));
for (final TypeElement typeElement : types) {
constants.addAll(TypeConstantElementImpl.fromSignature(typeElement, constantQuery, this, indexResult));
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<TypeConstantElement> getTypeConstants", constantQuery, start); //NOI18N
}
return Collections.unmodifiableSet(constants);
}
@Override
public Set<TypeConstantElement> getTypeConstants(NameKind.Exact typeQuery, NameKind constantQuery) {
return getTypeConstantsImpl(typeQuery, constantQuery, EnumSet.of(PhpElementKind.CLASS, PhpElementKind.IFACE));
}
private Set<TypeConstantElement> getTypeConstantsImpl(NameKind.Exact typeQuery, NameKind constantQuery, EnumSet<PhpElementKind> typeKinds) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<TypeConstantElement> constants = new HashSet<>();
//two queries: once for classes, second for ifaces
if (typeKinds.contains(PhpElementKind.CLASS)) {
final Collection<? extends IndexResult> clzResults = results(ClassElementImpl.IDX_FIELD, typeQuery,
new String[]{ClassElementImpl.IDX_FIELD, TypeConstantElementImpl.IDX_FIELD});
for (final IndexResult indexResult : clzResults) {
for (final TypeElement typeElement : ClassElementImpl.fromSignature(typeQuery, this, indexResult)) {
constants.addAll(TypeConstantElementImpl.fromSignature(typeElement, constantQuery, this, indexResult));
}
}
}
if (typeKinds.contains(PhpElementKind.IFACE)) {
final Collection<? extends IndexResult> ifaceResults = results(InterfaceElementImpl.IDX_FIELD, typeQuery,
new String[]{InterfaceElementImpl.IDX_FIELD, TypeConstantElementImpl.IDX_FIELD});
for (final IndexResult indexResult : ifaceResults) {
for (final TypeElement typeElement : InterfaceElementImpl.fromSignature(typeQuery, this, indexResult)) {
constants.addAll(TypeConstantElementImpl.fromSignature(typeElement, constantQuery, this, indexResult));
}
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<TypeConstantElement> getTypeConstants", typeQuery, constantQuery, start); //NOI18N
}
return Collections.unmodifiableSet(constants);
}
@Override
public QueryScope getQueryScope() {
return QueryScope.INDEX_SCOPE;
}
@Override
public Set<MethodElement> getStaticInheritedMethods(TypeElement typeElement) {
return ElementFilter.forStaticModifiers(true).filter(getInheritedMethods(typeElement));
}
/**
* @param enclosingType null if not enclosed at all
*/
private static ElementFilter forAccessibleTypeMembers(final TypeElement enclosingType, final Collection<TypeElement> inheritedTypes) {
final ElementFilter publicOnly = ElementFilter.forPublicModifiers(true);
final ElementFilter publicAndProtectedOnly = ElementFilter.forPrivateModifiers(false);
final ElementFilter fromEnclosingType = ElementFilter.forMembersOfType(enclosingType);
// #253290 check used traits except for them of the inherited class
final Set<TypeElement> usedTraits = getAllUsedTraits(enclosingType);
return new ElementFilter() {
private ElementFilter[] subtypesFilters = null;
@Override
public boolean isAccepted(final PhpElement element) {
if (element instanceof TypeMemberElement) {
if (enclosingType != null) {
return isFromEnclosingType(element) || isFromTraitOfEnclosingType(element)
? true
: (isFromSubclassOfEnclosingType(element) ? publicAndProtectedOnly.isAccepted(element) : publicOnly.isAccepted(element));
}
return publicOnly.isAccepted(element);
}
return true;
}
private boolean isFromEnclosingType(final PhpElement element) {
return fromEnclosingType.isAccepted(element);
}
private boolean isFromTraitOfEnclosingType(final PhpElement element) {
if (!usedTraits.isEmpty()) {
for (TypeElement nextType : inheritedTypes) {
if (nextType.isTrait() && usedTraits.contains(nextType) && ElementFilter.forMembersOfType(nextType).isAccepted(element)) {
return true;
}
}
}
return false;
}
private boolean isFromSubclassOfEnclosingType(final PhpElement element) {
for (TypeElement nextType : inheritedTypes) {
if (ElementFilter.forMembersOfType(nextType).isAccepted(element)) {
return true;
}
}
if (subtypesFilters == null) {
subtypesFilters = createSubtypeFilters();
}
return subtypesFilters.length == 0 ? false : ElementFilter.anyOf(subtypesFilters).isAccepted(element);
}
private ElementFilter[] createSubtypeFilters() {
final List<ElementFilter> filters = new ArrayList<>();
final ElementQuery elementQuery = enclosingType.getElementQuery();
if (elementQuery.getQueryScope().isIndexScope()) {
final ElementQuery.Index elementQueryIndex = (ElementQuery.Index) elementQuery;
final Set<TypeElement> inheritedTypes = elementQueryIndex.getInheritedTypes(enclosingType);
for (final TypeElement nextType : inheritedTypes) {
filters.add(ElementFilter.forMembersOfType(nextType));
// GH #3486
for (TypeElement trait : getAllUsedTraits(nextType)) {
filters.add(ElementFilter.forMembersOfType(trait));
}
}
}
return filters.toArray(new ElementFilter[filters.size()]);
}
};
}
/**
* Get all traits directly used from a class or trait recursively.
*
* @param typeElement the type element
* @return Used traits
*/
private static Set<TypeElement> getAllUsedTraits(TypeElement typeElement) {
final Set<TypeElement> usedTraits = new HashSet<>();
if (typeElement instanceof TraitedElement) {
TraitedElement traitedElement = (TraitedElement) typeElement;
Collection<QualifiedName> traits = traitedElement.getUsedTraits();
if (!traits.isEmpty()) {
addAllUsedTraits(usedTraits, traitedElement, traits);
}
}
return usedTraits;
}
private static void addAllUsedTraits(final Set<TypeElement> traits, TraitedElement traitedElement, final Collection<QualifiedName> usedTraits) {
ElementQuery elementQuery = traitedElement.getElementQuery();
if (elementQuery.getQueryScope().isIndexScope()) {
final ElementQuery.Index elementQueryIndex = (ElementQuery.Index) elementQuery;
for (QualifiedName usedTrait : usedTraits) {
Set<TraitElement> usedTraitElements = elementQueryIndex.getTraits(NameKind.exact(usedTrait));
traits.addAll(usedTraitElements);
for (TraitElement usedTraitElement : usedTraitElements) {
// add traits recursively
addAllUsedTraits(traits, usedTraitElement, usedTraitElement.getUsedTraits());
}
}
}
}
@Override
public Set<MethodElement> getAccessibleMethods(final TypeElement typeElement, final TypeElement calledFromEnclosingType) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<MethodElement> allMethods = getAllMethods(typeElement);
Collection<TypeElement> subTypes = Collections.emptySet();
if (calledFromEnclosingType != null && ElementFilter.forEqualTypes(typeElement).isAccepted(calledFromEnclosingType)) {
subTypes = toTypes(allMethods);
}
final ElementFilter filterForAccessible = forAccessibleTypeMembers(calledFromEnclosingType, subTypes);
Set<MethodElement> retval = filterForAccessible.filter(allMethods);
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<MethodElement> getAccessibleMethods", NameKind.exact(typeElement.getFullyQualifiedName()), start); //NOI18N
}
return Collections.unmodifiableSet(retval);
}
@Override
public Set<FieldElement> getAccessibleFields(final TypeElement typeElement, final TypeElement calledFromEnclosingType) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<FieldElement> allFields = getAlllFields(typeElement);
Collection<TypeElement> subTypes = Collections.emptySet();
if (calledFromEnclosingType != null && ElementFilter.forEqualTypes(typeElement).isAccepted(calledFromEnclosingType)) {
subTypes = toTypes(allFields);
}
final ElementFilter filterForAccessible = forAccessibleTypeMembers(calledFromEnclosingType, subTypes);
Set<FieldElement> retval = filterForAccessible.filter(allFields);
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<FieldElement> getAccessibleFields", NameKind.exact(typeElement.getFullyQualifiedName()), start); //NOI18N
}
return Collections.unmodifiableSet(retval);
}
private Set<TypeMemberElement> getDirectInheritedTypeMembers(final TypeElement typeElement,
EnumSet<PhpElementKind> typeKinds, EnumSet<PhpElementKind> memberKinds) {
final Set<TypeMemberElement> directTypes = new LinkedHashSet<>();
if (typeKinds.contains(PhpElementKind.CLASS) && (typeElement instanceof ClassElement)) {
ClassElement classElement = (ClassElement) typeElement;
QualifiedName superClassName;
Collection<QualifiedName> possibleFQSuperClassNames = classElement.getPossibleFQSuperClassNames();
if (possibleFQSuperClassNames.size() == 1) {
superClassName = possibleFQSuperClassNames.iterator().next();
} else {
superClassName = classElement.getSuperClassName();
}
Set<TypeMemberElement> classTypes = getDirectInheritedClassTypes(superClassName, memberKinds, typeElement);
directTypes.addAll(classTypes);
}
if (typeKinds.contains(PhpElementKind.IFACE)) {
Collection<QualifiedName> interfaceNames;
Collection<QualifiedName> fQSuperInterfaceNames = typeElement.getFQSuperInterfaceNames();
if (!fQSuperInterfaceNames.isEmpty()) {
interfaceNames = fQSuperInterfaceNames;
} else {
interfaceNames = typeElement.getSuperInterfaces();
}
for (QualifiedName iface : interfaceNames) {
final Set<TypeMemberElement> ifaceTypes = new LinkedHashSet<>();
ifaceTypes.addAll(extendedQuery.getFields(NameKind.exact(iface), NameKind.empty()));
ifaceTypes.addAll(extendedQuery.getMethods(NameKind.exact(iface), NameKind.empty()));
ifaceTypes.addAll(extendedQuery.getTypeConstants(NameKind.exact(iface), NameKind.empty()));
if (memberKinds.size() != 1) {
ifaceTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getTypeMembers(NameKind.exact(iface), NameKind.empty())));
} else {
switch(memberKinds.iterator().next()) {
case METHOD:
ifaceTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getMethodsImpl(NameKind.exact(iface), NameKind.empty(),
EnumSet.of(PhpElementKind.IFACE))));
break;
case TYPE_CONSTANT:
ifaceTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getTypeConstantsImpl(NameKind.exact(iface), NameKind.empty(),
EnumSet.of(PhpElementKind.IFACE))));
break;
default:
//no-op
}
}
if (ifaceTypes.isEmpty()) {
insertEmptyElement(ifaceTypes, getInterfaces(NameKind.exact(iface)));
}
directTypes.addAll(ifaceTypes);
}
}
if (typeKinds.contains(PhpElementKind.TRAIT) && (typeElement instanceof TraitedElement)) {
TraitedElement traitedElement = (TraitedElement) typeElement;
Collection<QualifiedName> usedTraits = traitedElement.getUsedTraits();
for (QualifiedName trait : usedTraits) {
final Set<TypeMemberElement> traitTypes = new LinkedHashSet<>();
if (memberKinds.size() != 1) {
traitTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getTypeMembers(NameKind.exact(trait), NameKind.empty())));
} else {
switch(memberKinds.iterator().next()) {
case METHOD:
traitTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getMethodsImpl(NameKind.exact(trait), NameKind.empty(),
EnumSet.of(PhpElementKind.TRAIT))));
break;
case FIELD:
traitTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getFields(NameKind.exact(trait), NameKind.empty())));
break;
default:
//no-op
}
}
if (traitTypes.isEmpty()) {
insertEmptyElement(traitTypes, getTraits(NameKind.exact(trait)));
}
directTypes.addAll(traitTypes);
}
}
return directTypes;
}
private Set<TypeMemberElement> getDirectMixinTypeMembers(final TypeElement typeElement,
EnumSet<PhpElementKind> typeKinds, EnumSet<PhpElementKind> memberKinds) {
final Set<TypeMemberElement> directTypes = new LinkedHashSet<>();
if (typeKinds.contains(PhpElementKind.CLASS) && (typeElement instanceof ClassElement)) {
ClassElement classElement = (ClassElement) typeElement;
Collection<QualifiedName> mixinNames = classElement.getFQMixinClassNames();
mixinNames.stream()
.map(mixinName -> getDirectInheritedClassTypes(mixinName, memberKinds, typeElement))
.forEach(classTypes -> directTypes.addAll(classTypes));
}
return directTypes;
}
private Set<TypeMemberElement> getDirectInheritedClassTypes(QualifiedName superClassName, EnumSet<PhpElementKind> memberKinds, final TypeElement typeElement) {
final Set<TypeMemberElement> 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<TypeMemberElement> where, final Set<? extends TypeElement> exactTypeName) {
TypeElement exactType = ModelUtils.getFirst(exactTypeName);
if (exactType != null) {
where.add(new EmptyElement(exactType));
}
}
@Override
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>(),
EnumSet.of(PhpElementKind.CLASS, PhpElementKind.IFACE, PhpElementKind.TRAIT),
EnumSet.of(PhpElementKind.METHOD));
final Set<MethodElement> retval = new HashSet<>();
for (TypeMemberElement member : typeMembers) {
if (member instanceof MethodElement) {
retval.add((MethodElement) member);
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<MethodElement> getInheritedMethods", NameKind.exact(typeElement.getFullyQualifiedName()), start); //NOI18N
}
return Collections.unmodifiableSet(retval);
}
@Override
public Set<MethodElement> getAllMethods(TypeElement typeElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<TypeMemberElement> typeMembers =
getInheritedTypeMembers(typeElement, new LinkedHashSet<TypeElement>(),
new LinkedHashSet<TypeMemberElement>(getDeclaredMethods(typeElement)),
EnumSet.of(PhpElementKind.CLASS, PhpElementKind.IFACE, PhpElementKind.TRAIT),
EnumSet.of(PhpElementKind.METHOD));
final Set<MethodElement> retval = new HashSet<>();
for (TypeMemberElement member : typeMembers) {
if (member instanceof MethodElement) {
retval.add((MethodElement) member);
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<MethodElement> getAllMethods", NameKind.exact(typeElement.getFullyQualifiedName()), start); //NOI18N
}
return Collections.unmodifiableSet(retval);
}
@Override
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)),
EnumSet.of(PhpElementKind.CLASS, PhpElementKind.TRAIT),
EnumSet.of(PhpElementKind.FIELD));
final Set<FieldElement> retval = new HashSet<>();
for (TypeMemberElement member : typeMembers) {
if (member instanceof FieldElement) {
retval.add((FieldElement) member);
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<FieldElement> getAlllFields", NameKind.exact(typeElement.getFullyQualifiedName()), start); //NOI18N
}
return Collections.unmodifiableSet(retval);
}
@Override
public Set<TypeConstantElement> getAllTypeConstants(TypeElement typeElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<TypeMemberElement> typeMembers =
getInheritedTypeMembers(typeElement, new LinkedHashSet<TypeElement>(),
new LinkedHashSet<TypeMemberElement>(getDeclaredTypeConstants(typeElement)),
EnumSet.of(PhpElementKind.CLASS, PhpElementKind.IFACE),
EnumSet.of(PhpElementKind.TYPE_CONSTANT));
final Set<TypeConstantElement> retval = new HashSet<>();
for (TypeMemberElement member : typeMembers) {
if (member instanceof TypeConstantElement) {
retval.add((TypeConstantElement) member);
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<TypeConstantElement> getAllTypeConstants", NameKind.exact(typeElement.getFullyQualifiedName()), start); //NOI18N
}
return Collections.unmodifiableSet(retval);
}
@Override
public Set<TypeMemberElement> getAllTypeMembers(TypeElement typeElement) {
final EnumSet<PhpElementKind> typeKinds = EnumSet.of(
PhpElementKind.CLASS,
PhpElementKind.IFACE,
PhpElementKind.TRAIT
);
final EnumSet<PhpElementKind> memberKinds = EnumSet.of(
PhpElementKind.METHOD,
PhpElementKind.FIELD,
PhpElementKind.TYPE_CONSTANT
);
return getInheritedTypeMembers(typeElement, new LinkedHashSet<TypeElement>(),
new LinkedHashSet<>(getDeclaredTypeMembers(typeElement)), typeKinds, memberKinds);
}
private Set<TypeMemberElement> getAllMixinTypeMembers(TypeElement typeElement) {
final EnumSet<PhpElementKind> typeKinds = EnumSet.of(PhpElementKind.CLASS);
final EnumSet<PhpElementKind> memberKinds = EnumSet.of(
PhpElementKind.METHOD,
PhpElementKind.FIELD,
PhpElementKind.TYPE_CONSTANT
);
return getMixinTypeMembers(typeElement, new LinkedHashSet<>(),
new LinkedHashSet<>(getDeclaredTypeMembers(typeElement)), typeKinds, memberKinds);
}
@Override
public Set<TypeMemberElement> getInheritedTypeMembers(final TypeElement typeElement) {
final EnumSet<PhpElementKind> typeKinds = EnumSet.of(
PhpElementKind.CLASS,
PhpElementKind.IFACE,
PhpElementKind.TRAIT
);
final EnumSet<PhpElementKind> memberKinds = EnumSet.of(
PhpElementKind.METHOD,
PhpElementKind.FIELD,
PhpElementKind.TYPE_CONSTANT
);
return getInheritedTypeMembers(typeElement, new LinkedHashSet<TypeElement>(),
new LinkedHashSet<TypeMemberElement>(), typeKinds, memberKinds);
}
@Override
public Set<TypeMemberElement> getAccessibleTypeMembers(TypeElement typeElement, TypeElement calledFromEnclosingType) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<TypeMemberElement> allTypeMembers = getAllTypeMembers(typeElement);
Set<TypeMemberElement> retval = getAccessibleTypeMembers(typeElement, calledFromEnclosingType, allTypeMembers);
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<TypeMemberElement> getAccessibleTypeMembers", NameKind.exact(typeElement.getFullyQualifiedName()), start); //NOI18N
}
return Collections.unmodifiableSet(retval);
}
private Set<TypeMemberElement> getAccessibleTypeMembers(TypeElement typeElement, TypeElement calledFromEnclosingType, final Set<TypeMemberElement> allTypeMembers) {
Collection<TypeElement> subTypes = Collections.emptySet();
if (calledFromEnclosingType != null) {
if (typeElement instanceof TraitElement
|| ElementFilter.forEqualTypes(typeElement).isAccepted(calledFromEnclosingType)) {
subTypes = toTypes(allTypeMembers);
}
}
final ElementFilter filterForAccessible = forAccessibleTypeMembers(calledFromEnclosingType, subTypes);
Set<TypeMemberElement> retval = new HashSet<>();
retval.addAll(filterForAccessible.filter(allTypeMembers));
ElementFilter allOf = ElementFilter.allOf(ElementFilter.forVirtualExtensions(), ElementFilter.forMembersOfTypeName(typeElement));
retval.addAll(allOf.filter(allTypeMembers));
return retval;
}
@Override
public Set<TypeMemberElement> getAccessibleMixinTypeMembers(TypeElement typeElement, TypeElement calledFromEnclosingType) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<TypeMemberElement> allTypeMembers = getAllMixinTypeMembers(typeElement);
Set<TypeMemberElement> retval = getAccessibleTypeMembers(typeElement, calledFromEnclosingType, allTypeMembers);
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<TypeMemberElement> getAccessibleMixinTypeMembers", NameKind.exact(typeElement.getFullyQualifiedName()), start); // NOI18N
}
return Collections.unmodifiableSet(retval);
}
private Set<TypeMemberElement> getInheritedTypeMembers(final TypeElement typeElement, final Set<TypeElement> recursionPrevention,
Set<TypeMemberElement> retval, EnumSet<PhpElementKind> typeKinds, EnumSet<PhpElementKind> memberKinds) {
if (recursionPrevention.add(typeElement)) {
final Set<TypeMemberElement> typeMembers = getDirectInheritedTypeMembers(typeElement, typeKinds, memberKinds);
retval.addAll(forEmptyElements().filter(forComparingNonAbstractNameKinds(retval).reverseFilter(typeMembers)));
for (final TypeElement tp : typeMembers.isEmpty() ? getDirectInheritedTypes(typeElement) : toTypes(typeMembers)) {
retval.addAll(getInheritedTypeMembers(tp, recursionPrevention, retval, typeKinds, memberKinds));
}
}
return forPrefereMethodImplementation(retval).filter(retval);
}
private Set<TypeMemberElement> getMixinTypeMembers(final TypeElement typeElement, final Set<TypeElement> recursionPrevention,
Set<TypeMemberElement> retval, EnumSet<PhpElementKind> typeKinds, EnumSet<PhpElementKind> memberKinds) {
if (recursionPrevention.add(typeElement)) {
final Set<TypeMemberElement> typeMembers = getDirectMixinTypeMembers(typeElement, typeKinds, memberKinds);
retval.addAll(forEmptyElements().filter(forComparingNonAbstractNameKinds(retval).reverseFilter(typeMembers)));
Set<TypeElement> 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<MethodElement> getAllMethods(final Exact typeQuery, final NameKind methodQuery) {
Set<MethodElement> retval = new HashSet<>();
Set<TypeElement> types = new HashSet<>();
types.addAll(getClassesImpl(typeQuery));
types.addAll(getInterfacesImpl(typeQuery));
types.addAll(getTraitsImpl(typeQuery));
for (TypeElement typeElement : types) {
retval.addAll(ElementFilter.forName(methodQuery).filter(getAllMethods(typeElement)));
}
return retval;
}
@Override
public Set<FieldElement> getAlllFields(final Exact typeQuery, final NameKind fieldQuery) {
Set<FieldElement> retval = new HashSet<>();
Set<ClassElement> types = getClassesImpl(typeQuery);
for (TypeElement typeElement : types) {
retval.addAll(ElementFilter.forName(fieldQuery).filter(getAlllFields(typeElement)));
}
return retval;
}
@Override
public Set<TypeConstantElement> getAllTypeConstants(final Exact typeQuery, final NameKind constantQuery) {
Set<TypeConstantElement> retval = new HashSet<>();
Set<TypeElement> types = new HashSet<>();
types.addAll(getClassesImpl(typeQuery));
types.addAll(getInterfacesImpl(typeQuery));
for (TypeElement typeElement : types) {
retval.addAll(ElementFilter.forName(constantQuery).filter(getAllTypeConstants(typeElement)));
}
return retval;
}
@Override
public Set<FieldElement> getAccessibleStaticFields(final TypeElement classElement, final TypeElement calledFromEnclosingType) {
return ElementFilter.forStaticModifiers(true).filter(getAccessibleFields(classElement, calledFromEnclosingType));
}
@Override
public Set<MethodElement> getAccessibleStaticMethods(final TypeElement typeElement, final TypeElement calledFromEnclosingType) {
return ElementFilter.forStaticModifiers(true).filter(getAccessibleMethods(typeElement, calledFromEnclosingType));
}
private Set<TypeConstantElement> getNotPrivateTypeConstants(TypeElement oneType) {
return ElementFilter.forPrivateModifiers(false).filter(getDeclaredTypeConstants(oneType));
}
private Set<FieldElement> getNotPrivateFields(ClassElement oneClass) {
return ElementFilter.forPrivateModifiers(false).filter(getDeclaredFields(oneClass));
}
@Override
public Set<FieldElement> getStaticInheritedFields(final TypeElement classElement) {
return ElementFilter.forStaticModifiers(true).filter(getInheritedFields(classElement));
}
@Override
public Set<FieldElement> getInheritedFields(final TypeElement classElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<FieldElement> retval = new HashSet<>();
final Set<ClassElement> inheritedClasses = getInheritedClasses(classElement);
for (ClassElement oneClass : inheritedClasses) {
final Set<FieldElement> fields = getNotPrivateFields(oneClass);
for (final FieldElement fieldElement : fields) {
retval.add(fieldElement);
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<FieldElement> getInheritedFields", NameKind.exact(classElement.getFullyQualifiedName()), start); //NOI18N
}
return Collections.unmodifiableSet(retval);
}
@Override
public Set<TypeConstantElement> getInheritedTypeConstants(TypeElement typeElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<TypeConstantElement> retval = new HashSet<>();
final Set<? extends TypeElement> inheritedTypes = getInheritedTypes(typeElement);
for (TypeElement oneType : inheritedTypes) {
final Set<TypeConstantElement> constants = getNotPrivateTypeConstants(oneType);
for (final TypeConstantElement constantElement : constants) {
retval.add(constantElement);
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("Set<TypeConstantElement> getInheritedTypeConstants", NameKind.exact(typeElement.getFullyQualifiedName()), start); //NOI18N
}
return Collections.unmodifiableSet(retval);
}
@Override
public Set<TypeElement> getInheritedByTypes(final TypeElement typeElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<TypeElement> retval = new LinkedHashSet<>();
getInheritedByTypes(typeElement, retval);
retval.remove(typeElement);
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("LinkedHashSet<TypeElement> getInheritedByTypes", NameKind.exact(typeElement.getFullyQualifiedName()), start); //NOI18N
}
return retval;
}
@Override
public Set<TypeElement> getInheritedTypes(final TypeElement typeElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<TypeElement> retval = new LinkedHashSet<>();
getInheritedTypes(typeElement, retval, true, true);
retval.remove(typeElement);
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("LinkedHashSet<TypeElement> getInheritedTypes", NameKind.exact(typeElement.getFullyQualifiedName()), start); //NOI18N
}
return retval;
}
@Override
public Set<ClassElement> getInheritedClasses(final TypeElement classElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<ClassElement> retvalClasses = new LinkedHashSet<>();
final Set<TypeElement> retvalTypes = new LinkedHashSet<>();
getInheritedTypes(classElement, retvalTypes, true, false);
retvalTypes.remove(classElement);
for (TypeElement te : retvalTypes) {
if (te instanceof ClassElement) {
retvalClasses.add((ClassElement) te);
} else {
assert false : te.toString();
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("LinkedHashSet<ClassElement> getInheritedClasses", NameKind.exact(classElement.getFullyQualifiedName()), start); //NOI18N
}
return retvalClasses;
}
@Override
public Set<InterfaceElement> getInheritedInterfaces(TypeElement ifaceElement) {
final long start = (LOG.isLoggable(Level.FINE)) ? System.currentTimeMillis() : 0;
final Set<InterfaceElement> retvalIfaces = new LinkedHashSet<>();
final Set<TypeElement> retvalTypes = new LinkedHashSet<>();
getInheritedTypes(ifaceElement, retvalTypes, false, true);
retvalTypes.remove(ifaceElement);
for (TypeElement te : retvalTypes) {
if (te instanceof InterfaceElement) {
retvalIfaces.add((InterfaceElement) te);
} else {
assert false : te.toString();
}
}
if (LOG.isLoggable(Level.FINE)) {
logQueryTime("LinkedHashSet<InterfaceElement> getInheritedInterfaces", NameKind.exact(ifaceElement.getFullyQualifiedName()), start); //NOI18N
}
return retvalIfaces;
}
private static ElementFilter forComparingNonAbstractNameKinds(final Collection<? extends PhpElement> elements) {
return new ElementFilter() {
@Override
public boolean isAccepted(PhpElement element) {
final ElementFilter forKind = ElementFilter.forKind(element.getPhpElementKind());
final ElementFilter forName = ElementFilter.forName(NameKind.exact(element.getName()));
for (PhpElement nextElement : elements) {
if (forKind.isAccepted(nextElement) && forName.isAccepted(nextElement)) {
if (!nextElement.getPhpModifiers().isAbstract()) {
return true;
}
}
}
return false;
}
};
}
private static ElementFilter forPrefereMethodImplementation(final Collection<? extends PhpElement> elements) {
return new ElementFilter() {
@Override
public boolean isAccepted(PhpElement element) {
boolean isAbstract = element.getPhpModifiers().isAbstract();
boolean isMethod = PhpElementKind.METHOD.equals(element.getPhpElementKind());
if (isAbstract && isMethod) {
final ElementFilter forKind = ElementFilter.forKind(element.getPhpElementKind());
final ElementFilter forName = ElementFilter.forName(NameKind.exact(element.getName()));
for (PhpElement phpElement : elements) {
if (!phpElement.equals(element) && forKind.isAccepted(phpElement) && forName.isAccepted(phpElement) && !phpElement.getPhpModifiers().isAbstract()) {
return false;
}
}
}
return true;
}
};
}
private static ElementFilter forEmptyElements() {
return new ElementFilter() {
@Override
public boolean isAccepted(final PhpElement element) {
boolean result = true;
if (PhpElementKind.EMPTY.equals(element.getPhpElementKind())) {
result = false;
}
return result;
}
};
}
private static Set<TypeElement> toTypes(final Collection<? extends TypeMemberElement> typeMembers) {
final Set<TypeElement> retval = new LinkedHashSet<>();
for (final TypeMemberElement typeMemberElement : typeMembers) {
retval.add(typeMemberElement.getType());
}
return retval;
}
private void getInheritedTypes(final TypeElement typeElement, final Set<TypeElement> retval,
final boolean includeClasses, final boolean includeIfaces) {
if (retval.add(typeElement)) {
Set<TypeElement> directTypes = getDirectInheritedTypes(typeElement, includeClasses, includeIfaces);
for (TypeElement tp : directTypes) {
getInheritedTypes(tp, retval, includeClasses, includeIfaces);
}
}
}
@Override
public Set<ClassElement> getDirectInheritedClasses(final TypeElement typeElement) {
final Set<ClassElement> retval = new LinkedHashSet<>();
final Set<TypeElement> types = getDirectInheritedTypes(typeElement, true, false);
for (final TypeElement nextType : types) {
if (nextType instanceof ClassElement) {
retval.add((ClassElement) nextType);
}
}
return retval;
}
@Override
public Set<InterfaceElement> getDirectInheritedInterfaces(final TypeElement typeElement) {
final Set<InterfaceElement> retval = new LinkedHashSet<>();
final Set<TypeElement> types = getDirectInheritedTypes(typeElement, false, true);
for (final TypeElement nextType : types) {
if (nextType instanceof InterfaceElement) {
retval.add((InterfaceElement) nextType);
}
}
return retval;
}
@Override
public Set<TypeElement> getDirectInheritedTypes(final TypeElement typeElement) {
return getDirectInheritedTypes(typeElement, true, true);
}
private Set<TypeElement> getDirectInheritedTypes(final TypeElement typeElement, final boolean includeClasses, final boolean includeIfaces) {
final Set<TypeElement> directTypes = new LinkedHashSet<>();
if (includeClasses && (typeElement instanceof ClassElement)) {
QualifiedName superClassName;
Collection<QualifiedName> possibleFQSuperClassNames = ((ClassElement) typeElement).getPossibleFQSuperClassNames();
if (possibleFQSuperClassNames.size() == 1) {
superClassName = possibleFQSuperClassNames.iterator().next();
} else {
superClassName = ((ClassElement) typeElement).getSuperClassName();
}
if (superClassName != null) {
directTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getClassesImpl(NameKind.exact(superClassName))));
}
}
if (includeIfaces) {
for (QualifiedName iface : typeElement.getSuperInterfaces()) {
directTypes.addAll(ElementFilter.forFiles(typeElement.getFileObject()).prefer(getInterfacesImpl(NameKind.exact(iface))));
}
}
return directTypes;
}
private void getInheritedByTypes(final TypeElement typeElement, final Set<TypeElement> retval) {
if (retval.add(typeElement)) {
Set<TypeElement> directTypes = getDirectInheritedByTypes(typeElement);
for (TypeElement tp : directTypes) {
getInheritedByTypes(tp, retval);
}
}
}
@Override
public Set<TypeElement> getDirectInheritedByTypes(final TypeElement typeElement) {
final Set<TypeElement> directTypes = new LinkedHashSet<>();
final Exact query = NameKind.exact(typeElement.getFullyQualifiedName());
if (typeElement.isClass()) {
final Collection<? extends IndexResult> result = results(PHPIndexer.FIELD_SUPER_CLASS, query,
new String[] {PHPIndexer.FIELD_SUPER_CLASS, ClassElementImpl.IDX_FIELD});
for (final IndexResult indexResult : result) {
String[] values = indexResult.getValues(PHPIndexer.FIELD_SUPER_CLASS);
for (String value : values) {
Signature signature = Signature.get(value);
final QualifiedName fqnForValue = QualifiedName.createFullyQualified(signature.string(1), signature.string(2));
if (query.matchesName(PhpElementKind.CLASS, fqnForValue)) {
directTypes.addAll(ClassElementImpl.fromSignature(NameKind.empty(), this, indexResult));
}
}
}
} else if (typeElement.isInterface()) {
final Collection<? extends IndexResult> result = results(PHPIndexer.FIELD_SUPER_IFACE, query,
new String[] {PHPIndexer.FIELD_SUPER_IFACE, InterfaceElementImpl.IDX_FIELD, ClassElementImpl.IDX_FIELD});
for (final IndexResult indexResult : result) {
String[] values = indexResult.getValues(PHPIndexer.FIELD_SUPER_IFACE);
for (String value : values) {
Signature signature = Signature.get(value);
final QualifiedName fqnForValue = QualifiedName.createFullyQualified(signature.string(1), signature.string(2));
if (query.matchesName(PhpElementKind.IFACE, fqnForValue)) {
directTypes.addAll(InterfaceElementImpl.fromSignature(NameKind.empty(), this, indexResult));
directTypes.addAll(ClassElementImpl.fromSignature(NameKind.empty(), this, indexResult));
}
}
}
}
return directTypes;
}
private static Set<String> toNames(Set<? extends PhpElement> elements) {
Set<String> names = new HashSet<>();
for (PhpElement elem : elements) {
names.add(elem.getName());
}
return names;
}
private Collection<? extends IndexResult> search(String fieldName, String fieldValue, QuerySupport.Kind kind, String... fieldsToLoad) {
try {
long start = (LOG.isLoggable(Level.FINER)) ? System.currentTimeMillis() : 0;
Collection<? extends IndexResult> results = index.query(fieldName, fieldValue, kind, fieldsToLoad);
if (LOG.isLoggable(Level.FINER)) {
String msg = "IndexQuery.search(" + fieldName + ", " + fieldValue + ", " + kind + ", " //NOI18N
+ (fieldsToLoad == null || fieldsToLoad.length == 0 ? "no terms" : Arrays.asList(fieldsToLoad)) + ")"; //NOI18N
LOG.finer(msg);
if (LOG.isLoggable(Level.FINEST)) {
LOG.log(Level.FINEST, null, new Throwable(msg));
}
for (IndexResult r : results) {
LOG.log(Level.FINER, "Fields in {0} ({1}):", new Object[]{r, r.getFile().getPath()}); //NOI18N
for (String field : PHPIndexer.getAllFields()) {
String value = r.getValue(field);
if (value != null) {
LOG.log(Level.FINEST, " <{0}> = <{1}>", new Object[]{field, value}); //NOI18N
}
}
LOG.finer("----"); //NOI18N
}
LOG.finer(String.format("took: %d [ms]", System.currentTimeMillis() - start)); //NOI18N
LOG.finer("===="); //NOI18N
}
return results;
} catch (IOException ioe) {
Exceptions.printStackTrace(ioe);
return Collections.<IndexResult>emptySet();
}
}
private Collection<? extends IndexResult> results(final String indexField, final NameKind query) {
return results(indexField, query, new String[]{indexField});
}
private Collection<? extends IndexResult> results(final String indexField,
final NameKind query, final String[] fieldsToLoad) {
return search(indexField, prepareIdxQuery(query.getQueryName(), query.getQueryKind()), Kind.CASE_INSENSITIVE_PREFIX, fieldsToLoad);
}
private void logQueryTime(final String queryDescription, final NameKind typeQuery,
final NameKind memberQuery, final long start) {
LOG.fine(String.format("%s for type query: [%s:%s] and took: member query: [%s:%s] %d [ms]", queryDescription, //NOI18N
typeQuery.getQueryKind().toString(), typeQuery.getQuery().toString(),
memberQuery.getQueryKind().toString(), memberQuery.getQuery().toString(),
System.currentTimeMillis() - start)); //NOI18N
}
private void logQueryTime(final String queryDescription, final NameKind query, final long start) {
LOG.fine(String.format("%s for query: [%s:%s] took: %d [ms]", queryDescription, //NOI18N
query.getQueryKind().toString(), query.getQuery().toString(),
System.currentTimeMillis() - start)); //NOI18N
}
private static String prepareIdxQuery(String textForQuery, Kind kind) {
String query = textForQuery.toLowerCase();
if (kind.equals(QuerySupport.Kind.CAMEL_CASE)) {
final int length = textForQuery.length();
if (length > 0 && Character.isLetter(textForQuery.charAt(0))) {
query = query.substring(0, 1); //NOI18N
} else if (length > 1 && textForQuery.charAt(0) == '$') { //NOI18N
query = query.substring(0, 1); //NOI18N
} else {
query = ""; //NOI18N
}
}
return query;
}
@Override
public TreeElement<TypeElement> getInheritedTypesAsTree(TypeElement typeElement) {
return new TypeTreeElementImpl(typeElement, true);
}
@Override
public TreeElement<TypeElement> getInheritedTypesAsTree(TypeElement typeElement, Set<TypeElement> preferredTypes) {
return new TypeTreeElementImpl(typeElement, preferredTypes, true);
}
@Override
public TreeElement<TypeElement> getInheritedByTypesAsTree(TypeElement typeElement) {
return new TypeTreeElementImpl(typeElement, false);
}
@Override
public TreeElement<TypeElement> getInheritedByTypesAsTree(TypeElement typeElement, Set<TypeElement> preferredTypes) {
return new TypeTreeElementImpl(typeElement, preferredTypes, false);
}
@Override
public Set<PhpElement> getTopLevelElements(NameKind query) {
return getTopLevelElements(query, aliases, null);
}
@Override
public Set<ClassElement> getClasses() {
return getClasses(NameKind.empty(), aliases, null);
}
@Override
public Set<ClassElement> getClasses(NameKind query) {
return getClasses(query, aliases, null);
}
@Override
public Set<InterfaceElement> getInterfaces() {
return getInterfaces(NameKind.empty(), aliases, null);
}
@Override
public Set<InterfaceElement> getInterfaces(NameKind query) {
return getInterfaces(query, aliases, null);
}
@Override
public Set<TypeElement> getTypes(NameKind query) {
return getTypes(query, aliases, null);
}
@Override
public Set<FunctionElement> getFunctions() {
return getFunctions(NameKind.empty(), aliases, null);
}
@Override
public Set<FunctionElement> getFunctions(NameKind query) {
return getFunctions(query, aliases, null);
}
@Override
public Set<ConstantElement> getConstants() {
return getConstants(NameKind.empty(), aliases, null);
}
@Override
public Set<ConstantElement> getConstants(NameKind query) {
return getConstants(query, aliases, null);
}
@Override
public Set<MethodElement> getConstructors(NameKind typeQuery) {
return getConstructors(typeQuery, aliases, null);
}
@Override
public Set<NamespaceElement> getNamespaces(NameKind query) {
return getNamespaces(query, aliases, null);
}
@Override
public Set<ClassElement> getClasses(final NameKind query, final Set<AliasedName> aliasedNames, final Trait trait) {
final Set<ClassElement> retval = new HashSet<>();
for (final AliasedName aliasedName : aliasedNames) {
for (final NameKind nextQuery : queriesForAlias(query, aliasedName, PhpElementKind.CLASS)) {
for (final ClassElement nextClass : getClassesImpl(nextQuery)) {
final AliasedClass aliasedClass = new AliasedClass(aliasedName, nextClass);
if (trait != null) {
aliasedClass.setTrait(trait);
}
retval.add(aliasedClass);
}
}
}
retval.addAll(getClassesImpl(query));
return retval;
}
@Override
public Set<NamespaceElement> getNamespaces(final NameKind query, final Set<AliasedName> aliasedNames, final Trait trait) {
final Set<NamespaceElement> retval = new HashSet<>();
for (final AliasedName aliasedName : aliasedNames) {
final Set<NameKind> queriesForAlias = queriesForAlias(query, aliasedName, PhpElementKind.NAMESPACE_DECLARATION);
for (final NameKind nextQuery : queriesForAlias) {
for (final NamespaceElement nextNamespace : getNamespacesImpl(nextQuery)) {
final AliasedNamespace aliasedNamespace = new AliasedNamespace(aliasedName, nextNamespace);
if (trait != null) {
aliasedNamespace.setTrait(trait);
}
retval.add(aliasedNamespace);
}
}
}
retval.addAll(getNamespacesImpl(query));
return retval;
}
@Override
public Set<FunctionElement> getFunctions(final NameKind query, final Set<AliasedName> aliasedNames, final Trait trait) {
final Set<FunctionElement> retval = new HashSet<>();
for (final AliasedName aliasedName : aliasedNames) {
for (final NameKind nextQuery : queriesForAlias(query, aliasedName, PhpElementKind.FUNCTION)) {
for (final FunctionElement nextFunction : getFunctionsImpl(nextQuery)) {
final AliasedFunction aliasedFunction = new AliasedFunction(aliasedName, nextFunction);
if (trait != null) {
aliasedFunction.setTrait(trait);
}
retval.add(aliasedFunction);
}
}
}
retval.addAll(getFunctionsImpl(query));
return retval;
}
@Override
public Set<ConstantElement> getConstants(final NameKind query, final Set<AliasedName> aliasedNames, final Trait trait) {
final Set<ConstantElement> retval = new HashSet<>();
for (final AliasedName aliasedName : aliasedNames) {
for (final NameKind nextQuery : queriesForAlias(query, aliasedName, PhpElementKind.CONSTANT)) {
for (final ConstantElement nextConstant : getConstantsImpl(nextQuery)) {
final AliasedConstant aliasedConstant = new AliasedConstant(aliasedName, nextConstant);
if (trait != null) {
aliasedConstant.setTrait(trait);
}
retval.add(aliasedConstant);
}
}
}
retval.addAll(getConstantsImpl(query));
return retval;
}
@Override
public Set<MethodElement> getConstructors(final NameKind typeQuery, final Set<AliasedName> aliasedNames, final Trait trait) {
final Set<MethodElement> retval = new HashSet<>();
for (final AliasedName aliasedName : aliasedNames) {
for (final NameKind nextQuery : queriesForAlias(typeQuery, aliasedName, PhpElementKind.CLASS)) {
for (ClassElement classElement : getClassesImpl(nextQuery)) {
final AliasedClass aliasedClass = new AliasedClass(aliasedName, classElement);
if (trait != null) {
aliasedClass.setTrait(trait);
}
final Set<MethodElement> constructorsImpl = getConstructorsImpl(aliasedClass, classElement, new LinkedHashSet<ClassElement>());
retval.addAll(constructorsImpl.isEmpty() ? getDefaultConstructors(aliasedClass) : constructorsImpl);
}
}
}
retval.addAll(getConstructorsImpl(typeQuery));
return retval;
}
@Override
public Set<PhpElement> getTopLevelElements(final NameKind query, final Set<AliasedName> aliasedNames, final Trait trait) {
final Set<PhpElement> retval = new HashSet<>();
for (final AliasedName aliasedName : aliasedNames) {
for (final NameKind nextQuery : queriesForAlias(query, aliasedName, PhpElementKind.CLASS)) {
for (final PhpElement nextElement : getTopLevelElementsImpl(nextQuery)) {
AliasedElement aliasedElement = null;
if (nextElement instanceof ConstantElement) {
aliasedElement = new AliasedConstant(aliasedName, (ConstantElement) nextElement);
} else if (nextElement instanceof FunctionElement) {
aliasedElement = new AliasedFunction(aliasedName, (FunctionElement) nextElement);
} else if (nextElement instanceof ClassElement) {
aliasedElement = new AliasedClass(aliasedName, (ClassElement) nextElement);
} else if (nextElement instanceof InterfaceElement) {
aliasedElement = new AliasedInterface(aliasedName, (InterfaceElement) nextElement);
} else if (nextElement instanceof TraitElement) {
aliasedElement = new AliasedTrait(aliasedName, (TraitElement) nextElement);
}
if (aliasedElement != null) {
if (trait != null) {
aliasedElement.setTrait(trait);
}
retval.add(aliasedElement);
}
}
}
}
retval.addAll(getTopLevelElementsImpl(query));
return retval;
}
@Override
public Set<InterfaceElement> getInterfaces(final NameKind query, final Set<AliasedName> aliasedNames, final Trait trait) {
final Set<InterfaceElement> retval = new HashSet<>();
for (final AliasedName aliasedName : aliasedNames) {
for (final NameKind nextQuery : queriesForAlias(query, aliasedName, PhpElementKind.IFACE)) {
for (final InterfaceElement nextIface : getInterfacesImpl(nextQuery)) {
final AliasedInterface aliasedInterface = new AliasedInterface(aliasedName, nextIface);
if (trait != null) {
aliasedInterface.setTrait(trait);
}
retval.add(aliasedInterface);
}
}
}
retval.addAll(getInterfacesImpl(query));
return retval;
}
public Set<TraitElement> getTraits() {
return getTraits(NameKind.empty());
}
@Override
public Set<TraitElement> getTraits(final NameKind query) {
final Set<TraitElement> retval = new HashSet<>();
retval.addAll(getTraitsImpl(query));
return retval;
}
@Override
public Set<TypeElement> getTypes(final NameKind query, final Set<AliasedName> aliasedNames, final Trait trait) {
final Set<TypeElement> retval = new HashSet<>();
for (final AliasedName aliasedName : aliasedNames) {
for (final NameKind nextQuery : queriesForAlias(query, aliasedName, PhpElementKind.CLASS)) {
for (final TypeElement nextType : getTypesImpl(nextQuery)) {
AliasedType aliasedType = null;
if (nextType instanceof ClassElement) {
aliasedType = new AliasedClass(aliasedName, (ClassElement) nextType);
} else if (nextType instanceof InterfaceElement) {
aliasedType = new AliasedInterface(aliasedName, (InterfaceElement) nextType);
} else if (nextType instanceof TraitElement) {
aliasedType = new AliasedTrait(aliasedName, (TraitElement) nextType);
} else {
assert false : nextType.getClass();
}
if (aliasedType != null) {
if (trait != null) {
aliasedType.setTrait(trait);
}
retval.add(aliasedType);
}
}
}
}
retval.addAll(getTypesImpl(query));
return retval;
}
}