/******************************************************************************* * 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.Collections; import java.util.LinkedList; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.eclipse.dltk.core.IMethod; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.IType; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.ti.GoalState; import org.eclipse.dltk.ti.IContext; import org.eclipse.dltk.ti.goals.IGoal; import org.eclipse.dltk.ti.types.IEvaluatedType; import org.eclipse.php.core.compiler.PHPFlags; import org.eclipse.php.internal.core.Constants; import org.eclipse.php.internal.core.Logger; import org.eclipse.php.internal.core.index.IPHPDocAwareElement; 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.IModelCacheContext; import org.eclipse.php.internal.core.typeinference.evaluators.AbstractMethodReturnTypeEvaluator; import org.eclipse.php.internal.core.typeinference.evaluators.PHPEvaluationUtils; import org.eclipse.php.internal.core.typeinference.goals.AbstractMethodReturnTypeGoal; /** * This Evaluator process the phpdoc of a method to determine its returned * type(s) * * @see the PHPCodumentor spec at {@link http * ://manual.phpdoc.org/HTMLSmartyConverter * /HandS/phpDocumentor/tutorial_tags.return.pkg.html} */ public class PHPDocMethodReturnTypeEvaluator extends AbstractMethodReturnTypeEvaluator { /** * Holds the result of evaluated types that this evaluator resolved */ private final List<IEvaluatedType> evaluated = new LinkedList<IEvaluatedType>(); public PHPDocMethodReturnTypeEvaluator(IGoal goal) { super(goal); } public IGoal[] init() { for (IMethod method : getMethods()) { if (!method.exists()) { continue; } String[] typeNames = null; if (method instanceof IPHPDocAwareElement) { typeNames = ((IPHPDocAwareElement) method).getReturnTypes(); } else { try { String returnType = method.getType(); if (returnType != null) { typeNames = StringUtils.split(returnType, Constants.TYPE_SEPARATOR_CHAR); } else { List<String> returnTypeList = new LinkedList<String>(); evaluateReturnType(returnTypeList, method); typeNames = returnTypeList.toArray(new String[returnTypeList.size()]); } } catch (ModelException e) { Logger.logException(e); } } if (typeNames != null) { AbstractMethodReturnTypeGoal goal = (AbstractMethodReturnTypeGoal) getGoal(); IType currentNamespace = PHPModelUtils.getCurrentNamespace(method); IModelElement space = currentNamespace != null ? currentNamespace : method.getSourceModule(); try { evaluated.addAll(Arrays.asList(PHPEvaluationUtils.evaluatePHPDocType(typeNames, space, method.getSourceRange().getOffset(), goal.getTypes()))); } catch (ModelException e) { Logger.logException(e); } } } return IGoal.NO_GOALS; } private void evaluateReturnType(List<String> returnTypeList, IMethod method) throws ModelException { if (!PHPFlags.isInheritdoc(method.getFlags())) { return; } IType type = method.getDeclaringType(); if (type == null) { return; } IContext context = goal.getContext(); IModelAccessCache cache = null; if (context instanceof IModelCacheContext) { cache = ((IModelCacheContext) context).getCache(); } IType[] superClasses = PHPModelUtils.getSuperClasses(type, cache == null ? null : cache.getSuperTypeHierarchy(type, null)); for (IType superClass : superClasses) { IMethod superClassMethod = superClass.getMethod(method.getElementName()); if (superClassMethod != null && superClassMethod.exists()) { String returnType = superClassMethod.getType(); if (returnType != null) { Collections.addAll(returnTypeList, StringUtils.split(returnType, Constants.TYPE_SEPARATOR_CHAR)); } evaluateReturnType(returnTypeList, superClassMethod); } } } public Object produceResult() { return PHPTypeInferenceUtils.combineTypes(evaluated); } public IGoal[] subGoalDone(IGoal subgoal, Object result, GoalState state) { return IGoal.NO_GOALS; } }