/******************************************************************************* * Copyright (c) 2009 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 java.util.*; import java.util.Map.Entry; import org.eclipse.dltk.ast.ASTNode; import org.eclipse.dltk.ast.Modifiers; import org.eclipse.dltk.ast.declarations.ModuleDeclaration; import org.eclipse.dltk.ast.expressions.Expression; import org.eclipse.dltk.ast.references.VariableReference; import org.eclipse.dltk.core.*; import org.eclipse.dltk.core.index2.search.ISearchEngine.MatchRule; import org.eclipse.dltk.core.search.IDLTKSearchScope; import org.eclipse.dltk.core.search.SearchEngine; import org.eclipse.dltk.internal.core.SourceField; import org.eclipse.dltk.ti.GoalState; import org.eclipse.dltk.ti.IContext; import org.eclipse.dltk.ti.ISourceModuleContext; 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.Assignment; import org.eclipse.php.internal.core.model.PHPModelAccess; import org.eclipse.php.internal.core.typeinference.Declaration; import org.eclipse.php.internal.core.typeinference.DeclarationScope; import org.eclipse.php.internal.core.typeinference.PHPTypeInferenceUtils; import org.eclipse.php.internal.core.typeinference.VariableDeclarationSearcher; import org.eclipse.php.internal.core.typeinference.context.IModelCacheContext; import org.eclipse.php.internal.core.typeinference.goals.GlobalVariableReferencesGoal; /** * This evaluator finds all global declarations of the variable and produces * {@link VariableDeclarationGoal} as a subgoal. */ public class GlobalVariableReferencesEvaluator extends GoalEvaluator { private List<IEvaluatedType> evaluated = new LinkedList<IEvaluatedType>(); public GlobalVariableReferencesEvaluator(IGoal goal) { super(goal); } public IGoal[] init() { GlobalVariableReferencesGoal typedGoal = (GlobalVariableReferencesGoal) goal; IContext context = goal.getContext(); ISourceModuleContext sourceModuleContext = null; IScriptProject scriptProject = null; if (context instanceof ISourceModuleContext) { sourceModuleContext = (ISourceModuleContext) context; scriptProject = sourceModuleContext.getSourceModule().getScriptProject(); } String variableName = typedGoal.getVariableName(); boolean exploreOtherFiles = true; // Find all global variables from mixin IDLTKSearchScope scope = SearchEngine.createSearchScope(scriptProject); IField[] elements = PHPModelAccess.getDefault().findFileFields(variableName, MatchRule.EXACT, Modifiers.AccGlobal, Modifiers.AccConstant, scope, null); // if no element found, return empty array. if (elements == null) { return new IGoal[] {}; } Map<ISourceModule, SortedSet<ISourceRange>> offsets = new HashMap<ISourceModule, SortedSet<ISourceRange>>(); Comparator<ISourceRange> sourceRangeComparator = new Comparator<ISourceRange>() { public int compare(ISourceRange o1, ISourceRange o2) { return o1.getOffset() - o2.getOffset(); } }; for (IModelElement element : elements) { if (element instanceof SourceField) { SourceField sourceField = (SourceField) element; ISourceModule sourceModule = sourceField.getSourceModule(); if (!offsets.containsKey(sourceModule)) { offsets.put(sourceModule, new TreeSet<ISourceRange>(sourceRangeComparator)); } try { offsets.get(sourceModule).add(sourceField.getSourceRange()); } catch (ModelException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } } } List<IGoal> subGoals = new LinkedList<IGoal>(); for (Entry<ISourceModule, SortedSet<ISourceRange>> entry : offsets.entrySet()) { ISourceModule sourceModule = entry.getKey(); if (exploreOtherFiles || (sourceModuleContext != null && sourceModuleContext.getSourceModule().equals(sourceModule))) { ModuleDeclaration moduleDeclaration = SourceParserUtil.getModuleDeclaration(sourceModule); SortedSet<ISourceRange> fileOffsets = entry.getValue(); if (!fileOffsets.isEmpty()) { GlobalReferenceDeclSearcher varSearcher = new GlobalReferenceDeclSearcher(sourceModule, fileOffsets, variableName); try { moduleDeclaration.traverse(varSearcher); DeclarationScope[] scopes = varSearcher.getScopes(); for (DeclarationScope s : scopes) { for (Declaration decl : s.getDeclarations(variableName)) { IContext context2 = s.getContext(); if (context2 instanceof IModelCacheContext && this.goal.getContext() instanceof IModelCacheContext) { ((IModelCacheContext) context2) .setCache(((IModelCacheContext) this.goal.getContext()).getCache()); } subGoals.add(new ExpressionTypeGoal(context2, decl.getNode())); } } } catch (Exception e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } } } } return subGoals.toArray(new IGoal[subGoals.size()]); } public Object produceResult() { return PHPTypeInferenceUtils.combineTypes(evaluated); } public IGoal[] subGoalDone(IGoal subgoal, Object result, GoalState state) { if (state != GoalState.RECURSIVE && result != null) { evaluated.add((IEvaluatedType) result); } return IGoal.NO_GOALS; } class GlobalReferenceDeclSearcher extends VariableDeclarationSearcher { private final String variableName; private Iterator<ISourceRange> offsetsIt; private int currentStart; private int currentEnd; private boolean stopProcessing; public GlobalReferenceDeclSearcher(ISourceModule sourceModule, SortedSet<ISourceRange> offsets, String variableName) { super(sourceModule); this.variableName = variableName; offsetsIt = offsets.iterator(); setNextRange(); } private void setNextRange() { if (offsetsIt.hasNext()) { ISourceRange range = offsetsIt.next(); currentStart = range.getOffset(); currentEnd = currentStart + range.getLength(); } else { stopProcessing = true; } } protected void postProcess(Expression node) { if (node instanceof Assignment) { Expression variable = ((Assignment) node).getVariable(); if (variable instanceof VariableReference) { VariableReference variableReference = (VariableReference) variable; if (variableName.equals(variableReference.getName())) { setNextRange(); } } } } protected boolean isInteresting(ASTNode node) { return !stopProcessing && node.sourceStart() <= currentStart && node.sourceEnd() >= currentEnd; } } }