/***** 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.ArrayList; import java.util.Collection; import java.util.HashSet; import org.jruby.ast.AssignableNode; import org.jruby.ast.ListNode; import org.jruby.ast.MultipleAsgnNode; import org.jruby.ast.types.INameNode; import org.jruby.parser.StaticScope; import org.rubypeople.rdt.refactoring.classnodeprovider.IncludedClassesProvider; import org.rubypeople.rdt.refactoring.core.IRefactoringConfig; import org.rubypeople.rdt.refactoring.core.NodeProvider; import org.rubypeople.rdt.refactoring.core.RefactoringConditionChecker; import org.rubypeople.rdt.refactoring.core.SelectionNodeProvider; import org.rubypeople.rdt.refactoring.documentprovider.IDocumentProvider; import org.rubypeople.rdt.refactoring.documentprovider.StringDocumentProvider; import org.rubypeople.rdt.refactoring.util.NodeUtil; public class InlineMethodConditionChecker extends RefactoringConditionChecker { private InlineMethodConfig config; public InlineMethodConditionChecker(InlineMethodConfig config) { super(config); } public void init(IRefactoringConfig configObj) { this.config = (InlineMethodConfig) configObj; if(!(findSelectedCall(config.getPos()) && findTargetClass(config.getTargetClassFinder()) && findMethodDefinition())) { return; } config.setCallParent(NodeProvider.findParentNode(config.getDocumentProvider().getActiveFileRootNode(), config.getSelectedCall().getWrappedNode())); replaceParameters(); if(resultIsAssigned()) { replaceReturnStatements(); } createInlinedMethodBody(config.getDocumentProvider()); renameDuplicates(config.getDocumentProvider()); } private void renameDuplicates(IDocumentProvider doc) { StaticScope parent = NodeUtil.getScope(SelectionNodeProvider.getEnclosingScope(doc.getActiveFileRootNode(), config.getSelectedCall().getWrappedNode())); ArrayList<String> localNames = new ArrayList<String>(); if(parent.getVariables() != null) { for(String name : parent.getVariables()) { localNames.add(name); } } if(resultIsAssigned()) { AssignableNode callParent = (AssignableNode) config.getCallParent(); String name; if(callParent instanceof INameNode) { name = ((INameNode) callParent).getName(); localNames.remove(name); } else { ListNode head = ((MultipleAsgnNode) callParent).getHeadNode(); localNames.removeAll(head.childNodes()); } } config.setMethodDefDoc(new RenameDuplicatedVariables().rename(new StringDocumentProvider(config.getMethodDefDoc()), localNames.toArray(new String[localNames.size()]))); } private boolean findSelectedCall(int pos) { config.setSelectedCall(new SelectedCallFinder().findSelectedCall(pos, config.getDocumentProvider())); return config.getSelectedCall() != null; } private boolean findTargetClass(ITargetClassFinder targetClassFinder) { config.setClassName(targetClassFinder.findTargetClass(config.getSelectedCall(), config.getDocumentProvider())); return config.getClassName() != null && !"".equals(config.getClassName()); //$NON-NLS-1$ } private boolean findMethodDefinition() { config.setMethodDefinitionNode(new MethodFinder().find(config.getClassName(), config.getSelectedCall().getName(), config.getDocumentProvider())); return config.getMethodDefinitionNode() != null; } private void replaceParameters() { config.setMethodDefDoc(new ParameterReplacer().replace(config.getDocumentProvider(), config.getSelectedCall(), config.getMethodDefinitionNode())); } private void createInlinedMethodBody(IDocumentProvider doc) { MethodBodyStatementReplacer bodyReplacer = new MethodBodyStatementReplacer(); if(config.getSelectedCall().getReceiverNode() != null) { final String name = ((INameNode)config.getSelectedCall().getReceiverNode()).getName(); config.setMethodDefDoc(bodyReplacer.replaceSelfWithObject(config.getMethodDefDoc(), name)); config.setMethodDefDoc(bodyReplacer.prefixCallsWithObject(config.getMethodDefDoc(), new IncludedClassesProvider(doc), config.getClassName(), name)); Collection<String> usedMembers = new HashSet<String>(); config.setMethodDefDoc(bodyReplacer.replaceVarsWithAccessor(config.getMethodDefDoc(), name, usedMembers)); config.setUsedMembers(usedMembers); } config.setMethodDefDoc(bodyReplacer.removeReturnStatements(config.getMethodDefDoc())); } private void replaceReturnStatements() { IReturnStatementReplacer returnReplacer = new ReturnStatementReplacer(); config.setSingleReturnStatement(Boolean.valueOf((returnReplacer.singleReturnOnLastLine(config.getMethodDefDoc())))); if(returnReplacer.singleReturnOnLastLine(config.getMethodDefDoc()) ) { config.setMethodDefDoc(returnReplacer.replaceReturn(config.getMethodDefDoc(), (AssignableNode) config.getCallParent())); } } private boolean resultIsAssigned() { return config.getCallParent() instanceof AssignableNode; } @Override protected void checkInitialConditions() { if(config.getSelectedCall() == null) { addError(Messages.InlineMethodConditionChecker_NoMethodCall); } else if (config.getClassName() == null || "".equals(config.getClassName())) { //$NON-NLS-1$ addError(Messages.InlineMethodConditionChecker_CannotGuessType); } else if (config.getMethodDefinitionNode() == null) { addError(Messages.InlineMethodConditionChecker_CannotFindDefinition); } else if (config.isSingleReturnStatement() != null && config.isSingleReturnStatement().booleanValue() == false) { addError(Messages.InlineMethodConditionChecker_ToManyReturns); } } @Override protected void checkFinalConditions() { } }