/******************************************************************************* * Copyright (c) 2005, 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 * *******************************************************************************/ package org.eclipse.dltk.ruby.typeinference.evaluators; import java.util.ArrayList; import java.util.List; import org.eclipse.dltk.ast.declarations.ModuleDeclaration; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.ruby.ast.RubyAssignment; import org.eclipse.dltk.ruby.internal.parsers.jruby.ASTUtils; import org.eclipse.dltk.ruby.typeinference.RubyFieldReference; import org.eclipse.dltk.ruby.typeinference.RubyTypeInferencingUtils; import org.eclipse.dltk.ruby.typeinference.VariableTypeGoal; import org.eclipse.dltk.ti.BasicContext; import org.eclipse.dltk.ti.GoalState; import org.eclipse.dltk.ti.goals.ExpressionTypeGoal; import org.eclipse.dltk.ti.goals.FieldReferencesGoal; import org.eclipse.dltk.ti.goals.GoalEvaluator; import org.eclipse.dltk.ti.goals.IGoal; import org.eclipse.dltk.ti.goals.ItemReference; import org.eclipse.dltk.ti.types.IEvaluatedType; public class RubyVariableTypeEvaluator extends GoalEvaluator { private List<IGoal> possibilities = new ArrayList<IGoal>(); private List results = new ArrayList(); private boolean init = false; public RubyVariableTypeEvaluator(IGoal goal) { super(goal); } @Override public IGoal[] init() { init = true; VariableTypeGoal goal = (VariableTypeGoal) this.goal; String name = goal.getName(); String parent = goal.getParentKey(); return new IGoal[] { new FieldReferencesGoal(goal.getContext(), name, parent) }; } @Override public Object produceResult() { IEvaluatedType type = RubyTypeInferencingUtils.combineTypes(results); return type; } private BasicContext buildContext(RubyFieldReference ref) { IModelElement element = DLTKCore .create(ref.getPosition().getResource()); if (element instanceof ISourceModule) { ISourceModule sourceModule = (ISourceModule) element; ModuleDeclaration module = ASTUtils.getAST(sourceModule); return new BasicContext(sourceModule, module); /* XXX: don't forget about options transfer */ } return (BasicContext) this.goal.getContext(); } @Override public IGoal[] subGoalDone(IGoal subgoal, Object result, GoalState state) { if (init) { init = false; if (result instanceof ItemReference[]) { ItemReference[] references = (ItemReference[]) result; for (int i = 0; i < references.length; i++) { if (references[i] instanceof RubyFieldReference) { RubyFieldReference ref = (RubyFieldReference) references[i]; if (ref.getNode() instanceof RubyAssignment) { RubyAssignment assignment = (RubyAssignment) ref .getNode(); ExpressionTypeGoal s = new ExpressionTypeGoal( buildContext(ref), assignment.getRight()); possibilities.add(s); } } } } return possibilities.toArray(new IGoal[possibilities.size()]); } else { if (result != null) results.add(result); } return null; } }