| /******************************************************************************* |
| * Copyright (c) 2010 xored software, Inc. |
| * |
| * 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: |
| * xored software, Inc. - initial API and Implementation (Alex Panchenko) |
| *******************************************************************************/ |
| package org.eclipse.dltk.javascript.internal.core.codeassist; |
| |
| import java.util.List; |
| |
| import org.eclipse.dltk.ast.ASTNode; |
| import org.eclipse.dltk.internal.javascript.ti.ITypeInferenceContext; |
| import org.eclipse.dltk.internal.javascript.ti.PositionReachedException; |
| import org.eclipse.dltk.internal.javascript.ti.TypeInferencerVisitor; |
| import org.eclipse.dltk.javascript.ast.Argument; |
| import org.eclipse.dltk.javascript.ast.CallExpression; |
| import org.eclipse.dltk.javascript.ast.Expression; |
| import org.eclipse.dltk.javascript.ast.FunctionStatement; |
| import org.eclipse.dltk.javascript.ast.Identifier; |
| import org.eclipse.dltk.javascript.ast.VariableDeclaration; |
| import org.eclipse.dltk.javascript.typeinference.IValueCollection; |
| import org.eclipse.dltk.javascript.typeinference.IValueReference; |
| import org.eclipse.dltk.javascript.typeinference.ReferenceKind; |
| |
| public class SelectionVisitor extends TypeInferencerVisitor { |
| |
| private final ASTNode target; |
| private IValueReference value; |
| private IValueReference[] arguments; |
| |
| public SelectionVisitor(ITypeInferenceContext context, ASTNode target) { |
| super(context); |
| this.target = target; |
| } |
| |
| public IValueReference getValue() { |
| return value; |
| } |
| |
| public IValueReference[] getArguments() { |
| return arguments; |
| } |
| |
| @Override |
| public IValueReference visit(ASTNode node) { |
| final IValueReference result = super.visit(node); |
| if (node == target) { |
| value = result; |
| earlyExit(); |
| } |
| return result; |
| } |
| |
| @Override |
| public IValueReference visitCallExpression(CallExpression node) { |
| final IValueReference reference; |
| boolean nullValue = value == null; |
| try { |
| reference = visit(node.getExpression()); |
| } finally { |
| boolean valueHit = value != null && nullValue; |
| final List<ASTNode> callArgs = node.getArguments(); |
| final IValueReference[] arguments = new IValueReference[callArgs |
| .size()]; |
| for (int i = 0, size = callArgs.size(); i < size; ++i) { |
| arguments[i] = visit(callArgs.get(i)); |
| } |
| if (valueHit) { |
| this.arguments = arguments; |
| } |
| } |
| if (reference != null) { |
| return reference.getChild(IValueReference.FUNCTION_OP); |
| } else { |
| return null; |
| } |
| } |
| |
| @Override |
| protected IValueReference extractNamedChild(IValueReference parent, |
| Expression name) { |
| final IValueReference result = super.extractNamedChild(parent, name); |
| if (name == target) { |
| value = result; |
| earlyExit(); |
| } |
| return result; |
| } |
| |
| private IValueReference check(Identifier node, IValueReference reference) { |
| if (node == target) { |
| value = reference; |
| earlyExit(); |
| } |
| return reference; |
| } |
| |
| @Override |
| public void visitFunctionBody(FunctionStatement node) { |
| for (Argument argument : node.getArguments()) { |
| check(argument.getIdentifier(), |
| peekContext().getChild(argument.getArgumentName())); |
| } |
| super.visitFunctionBody(node); |
| } |
| |
| @Override |
| protected IValueReference createVariable( |
| IValueCollection context, VariableDeclaration declaration) { |
| return check(declaration.getIdentifier(), |
| super.createVariable(context, declaration)); |
| } |
| |
| @Override |
| public IValueReference visitFunctionStatement(FunctionStatement node) { |
| IValueReference fs = super.visitFunctionStatement(node); |
| if (node.getName() != null) |
| visit(node.getName()); |
| return fs; |
| |
| } |
| |
| private void earlyExit() { |
| if (value == null || value.getKind() != ReferenceKind.UNKNOWN) { |
| throw new PositionReachedException(target, value); |
| } |
| } |
| |
| } |