/*******************************************************************************
* Copyright (c) 2009, 2015, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.core.typeinference.evaluators;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.dltk.ast.references.SimpleReference;
import org.eclipse.dltk.ast.references.TypeReference;
import org.eclipse.dltk.core.IMethod;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.evaluation.types.MultiTypeType;
import org.eclipse.dltk.ti.GoalState;
import org.eclipse.dltk.ti.IContext;
import org.eclipse.dltk.ti.goals.ExpressionTypeGoal;
import org.eclipse.dltk.ti.goals.GoalEvaluator;
import org.eclipse.dltk.ti.goals.IGoal;
import org.eclipse.dltk.ti.types.IEvaluatedType;
import org.eclipse.php.core.compiler.ast.nodes.*;
import org.eclipse.php.core.compiler.ast.nodes.PHPDocTag.TagKind;
import org.eclipse.php.internal.core.typeinference.PHPClassType;
import org.eclipse.php.internal.core.typeinference.PHPModelUtils;
import org.eclipse.php.internal.core.typeinference.PHPSimpleTypes;
import org.eclipse.php.internal.core.typeinference.context.MethodContext;
public class FormalParameterEvaluator extends GoalEvaluator {
public static final String ELLIPSIS = "..."; //$NON-NLS-1$
private IEvaluatedType result;
public FormalParameterEvaluator(IGoal goal) {
super(goal);
}
public IGoal[] init() {
ExpressionTypeGoal typedGoal = (ExpressionTypeGoal) goal;
FormalParameter parameter = (FormalParameter) typedGoal.getExpression();
SimpleReference type = parameter.getParameterType();
IContext context = typedGoal.getContext();
if (type != null && "array".equals(type.getName()) == false) { //$NON-NLS-1$
if (context instanceof MethodContext) {
MethodContext methodContext = (MethodContext) context;
String typeName = type.getName();
String namespace = null;
if (type instanceof FullyQualifiedReference) {
FullyQualifiedReference fqn = (FullyQualifiedReference) type;
if (fqn.getNamespace() != null) {
namespace = fqn.getNamespace().getName();
}
}
if (namespace == null) {
String fullName = PHPModelUtils.getFullName(typeName, methodContext.getSourceModule(),
parameter.start());
typeName = PHPModelUtils.extractElementName(fullName);
namespace = PHPModelUtils.extractNameSpaceName(fullName);
}
if (namespace != null) {
result = new PHPClassType(namespace, typeName);
} else {
result = new PHPClassType(typeName);
}
if (parameter.isVariadic()) {
// a variadic parameter is an array of a single type of data
MultiTypeType multiType = new MultiTypeType();
multiType.addType(result);
result = multiType;
}
} else {
result = PHPClassType.fromSimpleReference(type);
}
} else {
if (context instanceof MethodContext) {
MethodContext methodContext = (MethodContext) context;
PHPMethodDeclaration methodDeclaration = (PHPMethodDeclaration) methodContext.getMethodNode();
ISourceModule sourceModule = methodContext.getSourceModule();
PHPDocBlock[] docBlocks = new PHPDocBlock[0];
try {
IModelElement element = sourceModule.getElementAt(methodDeclaration.getNameStart());
if (element instanceof IMethod) {
IMethod method = (IMethod) element;
if (method.getDeclaringType() != null) {
docBlocks = PHPModelUtils.getTypeHierarchyMethodDoc(method.getDeclaringType(),
methodContext.getCache() != null ? methodContext.getCache()
.getSuperTypeHierarchy(method.getDeclaringType(), null) : null,
method.getElementName(), true, null);
} else {
docBlocks = new PHPDocBlock[] { methodDeclaration.getPHPDoc() };
}
} else {
docBlocks = new PHPDocBlock[] { methodDeclaration.getPHPDoc() };
}
} catch (CoreException e) {
}
for (PHPDocBlock docBlock : docBlocks) {
if (result != null) {
break;
}
if (docBlock != null) {
for (PHPDocTag tag : docBlock.getTags(TagKind.PARAM)) {
if (!tag.isValidParamTag()) {
continue;
}
String parameterName = parameter.getName();
if (parameter.isVariadic()) {
parameterName = ELLIPSIS + parameterName;
}
if (tag.getVariableReference().getName().equals(parameterName)) {
MultiTypeType multiType = new MultiTypeType();
for (TypeReference paramType : tag.getTypeReferences()) {
String typeName = paramType.getName();
typeName = PHPEvaluationUtils.extractArrayType(typeName);
multiType.addType(
PHPClassType.fromTypeName(typeName, sourceModule, paramType.sourceStart()));
}
// when it is not true multi type
if (multiType.size() == 1) {
result = multiType.get(0);
} else if (multiType.size() > 1) {
result = multiType;
}
break;
}
}
}
}
if (result == null && parameter.getInitialization() instanceof Scalar) {
Scalar scalar = (Scalar) parameter.getInitialization();
result = PHPSimpleTypes.fromString(scalar.getType());
if (result == null) {
result = new PHPClassType(scalar.getType());
}
}
}
}
return IGoal.NO_GOALS;
}
public Object produceResult() {
return result;
}
public IGoal[] subGoalDone(IGoal subgoal, Object result, GoalState state) {
return IGoal.NO_GOALS;
}
}