blob: 1b441f06763520806509aabb5dc9de8502fad7da [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.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.netbeans.modules.parsing.spi.indexing.support.IndexResult;
import org.netbeans.modules.php.api.PhpVersion;
import org.netbeans.modules.php.editor.CodeUtils;
import org.netbeans.modules.php.editor.api.ElementQuery;
import org.netbeans.modules.php.editor.api.NameKind;
import org.netbeans.modules.php.editor.api.PhpElementKind;
import org.netbeans.modules.php.editor.api.QualifiedName;
import org.netbeans.modules.php.editor.api.elements.BaseFunctionElement.PrintAs;
import org.netbeans.modules.php.editor.api.elements.FunctionElement;
import org.netbeans.modules.php.editor.api.elements.NamespaceElement;
import org.netbeans.modules.php.editor.api.elements.ParameterElement;
import org.netbeans.modules.php.editor.api.elements.TypeNameResolver;
import org.netbeans.modules.php.editor.api.elements.TypeResolver;
import org.netbeans.modules.php.editor.index.PHPIndexer;
import org.netbeans.modules.php.editor.index.Signature;
import org.netbeans.modules.php.editor.model.impl.VariousUtils;
import org.netbeans.modules.php.editor.model.nodes.FunctionDeclarationInfo;
import org.netbeans.modules.php.editor.parser.astnodes.FunctionDeclaration;
import org.openide.util.Parameters;
/**
* @author Radek Matous
*/
public final class FunctionElementImpl extends FullyQualifiedElementImpl implements FunctionElement {
public static final String IDX_FIELD = PHPIndexer.FIELD_BASE;
private final BaseFunctionElementSupport functionSupport;
private FunctionElementImpl(
final QualifiedName qualifiedName,
final int offset,
final String fileUrl,
final ElementQuery elementQuery,
final BaseFunctionElementSupport.Parameters parameters,
final BaseFunctionElementSupport.ReturnTypes returnTypes,
final boolean isDeprecated) {
super(qualifiedName.toName().toString(), qualifiedName.toNamespaceName().toString(),
fileUrl, offset, elementQuery, isDeprecated);
this.functionSupport = new BaseFunctionElementSupport(parameters, returnTypes);
}
public static Set<FunctionElement> fromSignature(final IndexQueryImpl indexQuery, final IndexResult indexResult) {
return fromSignature(NameKind.empty(), indexQuery, indexResult);
}
public static Set<FunctionElement> fromSignature(
final NameKind query, final IndexQueryImpl indexQuery, final IndexResult indexResult) {
String[] values = indexResult.getValues(IDX_FIELD);
Set<FunctionElement> retval = values.length > 0 ? new HashSet<FunctionElement>() : Collections.<FunctionElement>emptySet();
for (String val : values) {
final FunctionElement fnc = fromSignature(query, indexQuery, Signature.get(val));
if (fnc != null) {
retval.add(fnc);
}
}
return retval;
}
public static FunctionElement fromSignature(final NameKind query, IndexQueryImpl indexScopeQuery, Signature sig) {
Parameters.notNull("NameKind query: can't be null", query);
FunctionSignatureParser signParser = new FunctionSignatureParser(sig);
FunctionElement retval = null;
if (matchesQuery(query, signParser)) {
retval = new FunctionElementImpl(signParser.getQualifiedName(),
signParser.getOffset(), signParser.getFileUrl(),
indexScopeQuery, new ParametersFromSignature(signParser), new ReturnTypesFromSignature(signParser),
signParser.isDeprecated());
}
return retval;
}
public static FunctionElement fromNode(final NamespaceElement namespace, final FunctionDeclaration node, final ElementQuery.File fileQuery) {
Parameters.notNull("node", node);
Parameters.notNull("fileQuery", fileQuery);
FunctionDeclarationInfo info = FunctionDeclarationInfo.create(node);
final QualifiedName fullyQualifiedName = namespace != null ? namespace.getFullyQualifiedName() : QualifiedName.createForDefaultNamespaceName();
return new FunctionElementImpl(
fullyQualifiedName.append(info.getName()), info.getRange().getStart(),
fileQuery.getURL().toExternalForm(), fileQuery, BaseFunctionElementSupport.ParametersImpl.create(info.getParameters()),
BaseFunctionElementSupport.ReturnTypesImpl.create(TypeResolverImpl.parseTypes(VariousUtils.getReturnType(fileQuery.getResult().getProgram(), node))),
VariousUtils.isDeprecatedFromPHPDoc(fileQuery.getResult().getProgram(), node));
}
private static boolean matchesQuery(final NameKind query, FunctionSignatureParser signParser) {
Parameters.notNull("NameKind query: can't be null", query);
return (query instanceof NameKind.Empty) || query.matchesName(FunctionElement.KIND, signParser.getQualifiedName());
}
@Override
public PhpElementKind getPhpElementKind() {
return FunctionElement.KIND;
}
@Override
public String getSignature() {
StringBuilder sb = new StringBuilder();
sb.append(getName().toLowerCase()).append(Separator.SEMICOLON); //NOI18N
sb.append(getName()).append(Separator.SEMICOLON); //NOI18N
sb.append(getSignatureLastPart());
checkFunctionSignature(sb);
return sb.toString();
}
private String getSignatureLastPart() {
StringBuilder sb = new StringBuilder();
sb.append(getOffset()).append(Separator.SEMICOLON); //NOI18N
List<ParameterElement> parameterList = getParameters();
for (int idx = 0; idx < parameterList.size(); idx++) {
ParameterElementImpl parameter = (ParameterElementImpl) parameterList.get(idx);
if (idx > 0) {
sb.append(Separator.COMMA); //NOI18N
}
sb.append(parameter.getSignature());
}
sb.append(Separator.SEMICOLON); //NOI18N
for (TypeResolver typeResolver : getReturnTypes()) {
TypeResolverImpl resolverImpl = (TypeResolverImpl) typeResolver;
sb.append(resolverImpl.getSignature());
}
sb.append(Separator.SEMICOLON); //NOI18N
sb.append(getPhpModifiers().toFlags()).append(Separator.SEMICOLON);
sb.append(isDeprecated() ? 1 : 0).append(Separator.SEMICOLON);
sb.append(getFilenameUrl()).append(Separator.SEMICOLON);
return sb.toString();
}
private void checkFunctionSignature(StringBuilder sb) {
boolean checkEnabled = false;
assert checkEnabled = true;
if (checkEnabled) {
String retval = sb.toString();
FunctionSignatureParser parser = new FunctionSignatureParser(Signature.get(retval));
assert getName().equals(parser.getQualifiedName().toName().toString());
assert getNamespaceName().equals(parser.getQualifiedName().toNamespaceName());
assert getOffset() == parser.getOffset();
assert getParameters().size() == parser.getParameters().size();
assert getReturnTypes().size() == parser.getReturnTypes().size();
}
}
@Override
public List<ParameterElement> getParameters() {
return this.functionSupport.getParameters();
}
@Override
public Collection<TypeResolver> getReturnTypes() {
return this.functionSupport.getReturnTypes();
}
@Override
public boolean isAnonymous() {
return CodeUtils.isSyntheticFunctionName(getName());
}
@Override
public String asString(PrintAs as) {
return asString(as, TypeNameResolverImpl.forNull());
}
@Override
public String asString(PrintAs as, TypeNameResolver typeNameResolver) {
return this.functionSupport.asString(as, this, typeNameResolver);
}
@Override
public String asString(PrintAs as, TypeNameResolver typeNameResolver, PhpVersion phpVersion) {
return this.functionSupport.asString(as, this, typeNameResolver, phpVersion);
}
//~ Inner classes
private static class FunctionSignatureParser {
private final Signature signature;
FunctionSignatureParser(Signature signature) {
this.signature = signature;
}
QualifiedName getQualifiedName() {
return composeQualifiedName(signature.string(5), signature.string(1));
}
int getOffset() {
return signature.integer(2);
}
List<ParameterElement> getParameters() {
return ParameterElementImpl.parseParameters(signature.string(3));
}
Set<TypeResolver> getReturnTypes() {
return TypeResolverImpl.parseTypes(signature.string(4));
}
boolean isDeprecated() {
return signature.integer(6) == 1;
}
String getFileUrl() {
return signature.string(7);
}
}
private static final class ParametersFromSignature implements BaseFunctionElementSupport.Parameters {
private final FunctionSignatureParser functionSignatureParser;
//@GuardedBy("this")
private List<ParameterElement> retrievedParameters = null;
public ParametersFromSignature(FunctionSignatureParser functionSignatureParser) {
this.functionSignatureParser = functionSignatureParser;
}
@Override
public synchronized List<ParameterElement> getParameters() {
if (retrievedParameters == null) {
retrievedParameters = functionSignatureParser.getParameters();
}
return retrievedParameters;
}
}
private static final class ReturnTypesFromSignature implements BaseFunctionElementSupport.ReturnTypes {
private final FunctionSignatureParser functionSignatureParser;
//@GuardedBy("this")
private Set<TypeResolver> retrievedReturnTypes = null;
public ReturnTypesFromSignature(FunctionSignatureParser functionSignatureParser) {
this.functionSignatureParser = functionSignatureParser;
}
@Override
public synchronized Set<TypeResolver> getReturnTypes() {
if (retrievedReturnTypes == null) {
retrievedReturnTypes = functionSignatureParser.getReturnTypes();
}
return retrievedReturnTypes;
}
}
}