/***** BEGIN LICENSE BLOCK *****
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Common Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/cpl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2006 Mirko Stocker <me@misto.ch>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the CPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the CPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/
package org.rubypeople.rdt.refactoring.core.inlinemethod;
import java.util.Collection;
import org.jruby.ast.AssignableNode;
import org.jruby.ast.CallNode;
import org.jruby.ast.ClassNode;
import org.jruby.ast.InstAsgnNode;
import org.jruby.ast.InstVarNode;
import org.jruby.ast.LocalAsgnNode;
import org.jruby.ast.LocalVarNode;
import org.jruby.ast.MethodDefNode;
import org.jruby.ast.Node;
import org.jruby.ast.RootNode;
import org.rubypeople.rdt.refactoring.classnodeprovider.ClassNodeProvider;
import org.rubypeople.rdt.refactoring.core.NodeProvider;
import org.rubypeople.rdt.refactoring.core.SelectionNodeProvider;
import org.rubypeople.rdt.refactoring.documentprovider.IDocumentProvider;
import org.rubypeople.rdt.refactoring.exception.NoClassNodeException;
import org.rubypeople.rdt.refactoring.nodewrapper.ClassNodeWrapper;
import org.rubypeople.rdt.refactoring.nodewrapper.FieldNodeWrapper;
import org.rubypeople.rdt.refactoring.nodewrapper.MethodCallNodeWrapper;
import org.rubypeople.rdt.refactoring.util.NameHelper;
import org.rubypeople.rdt.refactoring.util.NodeUtil;
public class TargetClassFinder implements ITargetClassFinder {
public String findTargetClass(final MethodCallNodeWrapper call, final IDocumentProvider doc) {
String name = ""; //$NON-NLS-1$
if(call.getReceiverNode() == null) {
name = getSurroundingClass(call, doc);
}
final AssignableNode type = getAssignableNode(call, doc);
if(createsNewInstance(type)) {
Node receiver = ((CallNode) type.getValueNode()).getReceiverNode();
name = NameHelper.getFullyQualifiedName(receiver);
}
return name;
}
private String getSurroundingClass(final MethodCallNodeWrapper call, final IDocumentProvider doc) {
ClassNode classNode = ((ClassNode) NodeProvider.getEnclosingNodeOfType(doc.getActiveFileRootNode(), call.getWrappedNode(), ClassNode.class));
if(classNode != null) {
return classNode.getCPath().getName();
}
return ""; //$NON-NLS-1$
}
private AssignableNode getAssignableNode(final MethodCallNodeWrapper call, final IDocumentProvider doc) {
AssignableNode receiverType = null;
if(call.getReceiverNode() instanceof LocalVarNode) {
receiverType = localAsgnFromLocalVar((LocalVarNode) call.getReceiverNode(), doc);
} else if(call.getReceiverNode() instanceof InstVarNode) {
receiverType = instVarFromCall((InstVarNode) call.getReceiverNode(), doc);
}
return receiverType;
}
private boolean createsNewInstance(final AssignableNode receiverType) {
return receiverType != null
&& receiverType.getValueNode() instanceof CallNode
&& "new".equals(((CallNode) receiverType.getValueNode()).getName()); //$NON-NLS-1$
}
/**
* Finds the corresponding InstAsgnNode node to the supplied InstVarNode
*/
public InstAsgnNode instVarFromCall(final InstVarNode node, final IDocumentProvider doc) {
InstAsgnNode decoratedNode = null;
try {
final ClassNodeWrapper selectedClassNode = SelectionNodeProvider.getSelectedClassNode(doc.getActiveFileRootNode(), node.getPosition().getStartOffset());
final ClassNodeWrapper allClassNodes = new ClassNodeProvider(doc).getClassNode((selectedClassNode.getName()));
if(allClassNodes == null) {
throw new NoClassNodeException();
}
for (FieldNodeWrapper field : allClassNodes.getFields()) {
if (field.getName().equals(node.getName()) && field.getNodeType() == FieldNodeWrapper.INST_ASGN_NODE) {
decoratedNode = (InstAsgnNode) field.getWrappedNode();
}
}
} catch (NoClassNodeException e) {
decoratedNode = findInstVarInScope(node, doc, null);
}
return decoratedNode;
}
private InstAsgnNode findInstVarInScope(final InstVarNode node, final IDocumentProvider doc, InstAsgnNode decoratedNode) {
Collection<Node> assignments = NodeProvider.getSubNodes(doc.getActiveFileRootNode(), InstAsgnNode.class);
for (Node assignment : assignments) {
if(((InstAsgnNode) assignment).getName().equals(node.getName()) && assignment.getPosition().getStartOffset() < node.getPosition().getStartOffset()) {
decoratedNode = (InstAsgnNode) assignment;
}
}
return decoratedNode;
}
/**
* Finds the corresponding LocalAsgnNode node to the supplied LocalVarNode
*/
public LocalAsgnNode localAsgnFromLocalVar(final LocalVarNode node, final IDocumentProvider doc) {
Node enclosingScope = SelectionNodeProvider.getEnclosingScope(doc.getActiveFileRootNode(), node);
LocalAsgnNode asgnNode = findLastAssignmentToVar(node, NodeUtil.getBody(enclosingScope));
if(asgnNode != null) {
return asgnNode;
}
do {
enclosingScope = SelectionNodeProvider.getEnclosingScope(doc.getActiveFileRootNode(), NodeProvider.findParentNode(doc.getActiveFileRootNode(), enclosingScope));
asgnNode = findLastAssignmentToVar(node, NodeUtil.getBody(enclosingScope));
} while(!(enclosingScope instanceof RootNode || enclosingScope instanceof MethodDefNode) && asgnNode == null);
return asgnNode;
}
private LocalAsgnNode findLastAssignmentToVar(final LocalVarNode node, final Node enclosingScope) {
LocalAsgnNode localAsgnNode = null;
for (LocalAsgnNode asgnNode : NodeProvider.gatherLocalAsgnNodes(enclosingScope)) {
if(asgnNode.getIndex() == node.getIndex() && asgnNode.getName().equals(node.getName()) && asgnNode.getPosition().getStartOffset() < node.getPosition().getStartOffset()) {
localAsgnNode = asgnNode;
}
}
return localAsgnNode;
}
}