/*******************************************************************************
* 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.phpdoc;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.dltk.core.*;
import org.eclipse.dltk.ti.GoalState;
import org.eclipse.dltk.ti.goals.IGoal;
import org.eclipse.dltk.ti.types.IEvaluatedType;
import org.eclipse.php.internal.core.Constants;
import org.eclipse.php.internal.core.Logger;
import org.eclipse.php.internal.core.typeinference.IModelAccessCache;
import org.eclipse.php.internal.core.typeinference.PHPModelUtils;
import org.eclipse.php.internal.core.typeinference.PHPTypeInferenceUtils;
import org.eclipse.php.internal.core.typeinference.context.TypeContext;
import org.eclipse.php.internal.core.typeinference.evaluators.AbstractPHPGoalEvaluator;
import org.eclipse.php.internal.core.typeinference.evaluators.PHPEvaluationUtils;
import org.eclipse.php.internal.core.typeinference.goals.phpdoc.PHPDocClassVariableGoal;
/**
* This evaluator finds class field declaration either using "var" or in method
* body using field access.
*/
public class PHPDocClassVariableEvaluator extends AbstractPHPGoalEvaluator {
private List<IEvaluatedType> evaluated = new LinkedList<IEvaluatedType>();
public PHPDocClassVariableEvaluator(IGoal goal) {
super(goal);
}
@Override
public IGoal[] init() {
PHPDocClassVariableGoal typedGoal = (PHPDocClassVariableGoal) goal;
TypeContext context = (TypeContext) typedGoal.getContext();
String variableName = typedGoal.getVariableName();
int offset = typedGoal.getOffset();
IModelAccessCache cache = context.getCache();
IType[] types = PHPTypeInferenceUtils.getModelElements(context.getInstanceType(), context, offset, cache);
// remove array index from field name
if (variableName.endsWith("]")) { //$NON-NLS-1$
int index = variableName.indexOf("["); //$NON-NLS-1$
if (index != -1) {
variableName = variableName.substring(0, index);
}
}
if (types == null) {
return IGoal.NO_GOALS;
}
for (IType type : types) {
try {
// we look in whole hiearchy
ITypeHierarchy superHierarchy;
if (cache != null) {
superHierarchy = cache.getSuperTypeHierarchy(type, null);
} else {
superHierarchy = type.newSupertypeHierarchy(null);
}
IType[] superTypes = superHierarchy.getAllTypes();
for (IType superType : superTypes) {
IField[] typeField = PHPModelUtils.getTypeField(superType, variableName, true);
if (typeField.length > 0 && typeField[0].exists()) {
addFieldType(typeField[0]);
}
}
} catch (ModelException e) {
Logger.logException(e);
}
}
return IGoal.NO_GOALS;
}
private void addFieldType(IField typeField) throws ModelException {
String fieldType = typeField.getType();
if (fieldType == null) {
return;
}
String[] typeNames = StringUtils.split(fieldType, Constants.TYPE_SEPARATOR_CHAR);
IType currentNamespace = PHPModelUtils.getCurrentNamespace(typeField);
IModelElement space = currentNamespace != null ? currentNamespace : typeField.getSourceModule();
evaluated.addAll(Arrays.asList(
PHPEvaluationUtils.evaluatePHPDocType(typeNames, space, typeField.getSourceRange().getOffset(), null)));
}
@Override
public Object produceResult() {
return PHPTypeInferenceUtils.combineTypes(evaluated);
}
@Override
public IGoal[] subGoalDone(IGoal subgoal, Object result, GoalState state) {
if (state != GoalState.RECURSIVE && result != null) {
evaluated.add((IEvaluatedType) result);
}
return IGoal.NO_GOALS;
}
}