blob: 1c5ebf81854d10c3b9d38b9b83134ea14615541b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.corext.refactoring.code;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.resources.IFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
import org.eclipse.jdt.ui.CodeGeneration;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.jdt.internal.corext.Assert;
import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
import org.eclipse.jdt.internal.corext.codemanipulation.ImportRewrite;
import org.eclipse.jdt.internal.corext.dom.ASTFlattener;
import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.dom.ASTRewrite;
import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder;
import org.eclipse.jdt.internal.corext.dom.Selection;
import org.eclipse.jdt.internal.corext.refactoring.Checks;
import org.eclipse.jdt.internal.corext.refactoring.ParameterInfo;
import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
import org.eclipse.jdt.internal.corext.refactoring.base.IChange;
import org.eclipse.jdt.internal.corext.refactoring.base.Refactoring;
import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatus;
import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange;
import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
import org.eclipse.jdt.internal.corext.textmanipulation.GroupDescription;
import org.eclipse.jdt.internal.corext.textmanipulation.TextBuffer;
import org.eclipse.jdt.internal.corext.util.WorkingCopyUtil;
/**
* Extracts a method in a compilation unit based on a text selection range.
* <p>
* <bf>NOTE:<bf> This class/interface is part of an interim API that is still under development
* and expected to change significantly before reaching stability. It is being made available at
* this early stage to solicit feedback from pioneering adopters on the understanding that any
* code that uses this API will almost certainly be broken (repeatedly) as the API evolves.</p>
*/
public class ExtractMethodRefactoring extends Refactoring {
private ICompilationUnit fCUnit;
private ImportRewrite fImportRewriter;
private int fSelectionStart;
private int fSelectionLength;
private CodeGenerationSettings fSettings;
private AST fAST;
private ASTRewrite fRewriter;
private ExtractMethodAnalyzer fAnalyzer;
private int fVisibility;
private String fMethodName;
private boolean fThrowRuntimeExceptions;
private List fParameterInfos;
private Set fUsedNames;
private boolean fGenerateJavadoc;
private boolean fReplaceDuplicates;
private SnippetFinder.Match[] fDuplicates;
private static final String EMPTY= ""; //$NON-NLS-1$
private static class UsedNamesCollector extends ASTVisitor {
private Set result= new HashSet();
private Set fIgnore= new HashSet();
public static Set perform(ASTNode[] nodes) {
UsedNamesCollector collector= new UsedNamesCollector();
for (int i= 0; i < nodes.length; i++) {
nodes[i].accept(collector);
}
return collector.result;
}
public boolean visit(FieldAccess node) {
Expression exp= node.getExpression();
if (exp != null)
fIgnore.add(node.getName());
return true;
}
public void endVisit(FieldAccess node) {
fIgnore.remove(node.getName());
}
public boolean visit(MethodInvocation node) {
Expression exp= node.getExpression();
if (exp != null)
fIgnore.add(node.getName());
return true;
}
public void endVisit(MethodInvocation node) {
fIgnore.remove(node.getName());
}
public boolean visit(QualifiedName node) {
fIgnore.add(node.getName());
return true;
}
public void endVisit(QualifiedName node) {
fIgnore.remove(node.getName());
}
public boolean visit(SimpleName node) {
if (!fIgnore.contains(node))
result.add(node.getIdentifier());
return true;
}
public boolean visit(TypeDeclaration node) {
result.add(node.getName().getIdentifier());
// don't dive into type declaration since they open a new
// context.
return false;
}
}
/**
* Creates a new extract method refactoring.
*
* @param cu the compilation unit which is going to be modified.
* @param accessor a callback object to access the source this refactoring is working on.
*/
private ExtractMethodRefactoring(ICompilationUnit cu, int selectionStart, int selectionLength, CodeGenerationSettings settings) throws CoreException {
Assert.isNotNull(cu);
Assert.isNotNull(settings);
fCUnit= cu;
fImportRewriter= new ImportRewrite(cu, settings);
fMethodName= "extracted"; //$NON-NLS-1$
fSelectionStart= selectionStart;
fSelectionLength= selectionLength;
fSettings= settings;
fVisibility= -1;
}
public static boolean isAvailable(ASTNode[] selectedNodes) {
if (selectedNodes == null || selectedNodes.length == 0)
return false;
if (selectedNodes.length == 1) {
return selectedNodes[0] instanceof Statement || Checks.isExtractableExpression(selectedNodes[0]);
} else {
for (int i= 0; i < selectedNodes.length; i++) {
if (!(selectedNodes[i] instanceof Statement))
return false;
}
}
return true;
}
public static ExtractMethodRefactoring create(ICompilationUnit cu, int selectionStart, int selectionLength, CodeGenerationSettings settings) throws CoreException {
return new ExtractMethodRefactoring(cu, selectionStart, selectionLength, settings);
}
/* (non-Javadoc)
* Method declared in IRefactoring
*/
public String getName() {
return RefactoringCoreMessages.getFormattedString("ExtractMethodRefactoring.name", new String[]{fMethodName, fCUnit.getElementName()}); //$NON-NLS-1$
}
/**
* Checks if the refactoring can be activated. Activation typically means, if a
* corresponding menu entry can be added to the UI.
*
* @param pm a progress monitor to report progress during activation checking.
* @return the refactoring status describing the result of the activation check.
*/
public RefactoringStatus checkActivation(IProgressMonitor pm) throws JavaModelException {
try{
pm.beginTask(RefactoringCoreMessages.getString("ExtractMethodRefactoring.checking_selection"), 1); //$NON-NLS-1$
RefactoringStatus result= new RefactoringStatus();
if (fSelectionStart < 0 || fSelectionLength == 0)
return mergeTextSelectionStatus(result);
result.merge(Checks.validateModifiesFiles(ResourceUtil.getFiles(new ICompilationUnit[]{fCUnit})));
if (result.hasFatalError())
return result;
CompilationUnit root= AST.parseCompilationUnit(fCUnit, true);
fAST= root.getAST();
root.accept(createVisitor());
result.merge(fAnalyzer.checkActivation());
if (result.hasFatalError())
return result;
if (fVisibility == -1) {
setVisibility(Modifier.PRIVATE);
}
initializeParameterInfos();
initializeUsedNames();
initializeDuplicates();
return result;
} finally {
pm.worked(1);
pm.done();
}
}
private ASTVisitor createVisitor() throws JavaModelException {
fAnalyzer= new ExtractMethodAnalyzer(fCUnit, Selection.createFromStartLength(fSelectionStart, fSelectionLength));
return fAnalyzer;
}
/**
* Sets the method name to be used for the extracted method.
*
* @param name the new method name.
*/
public void setMethodName(String name) {
fMethodName= name;
}
/**
* Returns the method name to be used for the extracted method.
* @return the method name to be used for the extracted method.
*/
public String getMethodName() {
return fMethodName;
}
/**
* Sets the visibility of the new method.
*
* @param visibility the visibility of the new method. Valid values are
* "public", "protected", "", and "private"
*/
public void setVisibility(int visibility) {
fVisibility= visibility;
}
/**
* Returns the visibility of the new method.
*
* @return the visibility of the new method
*/
public int getVisibility() {
return fVisibility;
}
/**
* Returns the parameter infos.
* @return a list of parameter infos.
*/
public List getParameterInfos() {
return fParameterInfos;
}
/**
* Sets whether the new method signature throws runtime exceptions.
*
* @param throwsRuntimeExceptions flag indicating if the new method
* throws runtime exceptions
*/
public void setThrowRuntimeExceptions(boolean throwRuntimeExceptions) {
fThrowRuntimeExceptions= throwRuntimeExceptions;
}
/**
* Checks if the new method name is a valid method name. This method doesn't
* check if a method with the same name already exists in the hierarchy. This
* check is done in <code>checkInput</code> since it is expensive.
*/
public RefactoringStatus checkMethodName() {
return Checks.checkMethodName(fMethodName);
}
/**
* Checks if the parameter names are valid.
*/
public RefactoringStatus checkParameterNames() {
RefactoringStatus result= new RefactoringStatus();
for (Iterator iter= fParameterInfos.iterator(); iter.hasNext();) {
ParameterInfo parameter= (ParameterInfo)iter.next();
result.merge(Checks.checkIdentifier(parameter.getNewName()));
for (Iterator others= fParameterInfos.iterator(); others.hasNext();) {
ParameterInfo other= (ParameterInfo) others.next();
if (parameter != other && other.getNewName().equals(parameter.getNewName())) {
result.addError(RefactoringCoreMessages.getFormattedString(
"ExtractMethodRefactoring.error.sameParameter", //$NON-NLS-1$
other.getNewName()));
return result;
}
}
if (parameter.isRenamed() && fUsedNames.contains(parameter.getNewName())) {
result.addError(RefactoringCoreMessages.getFormattedString(
"ExtractMethodRefactoring.error.nameInUse", //$NON-NLS-1$
parameter.getNewName()));
return result;
}
}
return result;
}
/**
* Returns the names already in use in the selected statements/expressions.
*
* @return names already in use.
*/
public Set getUsedNames() {
return fUsedNames;
}
/* (non-Javadoc)
* Method declared in Refactoring
*/
public RefactoringStatus checkInput(IProgressMonitor pm) {
pm.beginTask(RefactoringCoreMessages.getString("ExtractMethodRefactoring.checking_new_name"), 2); //$NON-NLS-1$
pm.subTask(EMPTY);
RefactoringStatus result= checkMethodName();
result.merge(checkParameterNames());
pm.worked(1);
BodyDeclaration node= fAnalyzer.getEnclosingBodyDeclaration();
if (node != null) {
fAnalyzer.checkInput(result, fMethodName, fCUnit.getJavaProject(), fAST);
pm.worked(1);
}
pm.done();
return result;
}
/* (non-Javadoc)
* Method declared in IRefactoring
*/
public IChange createChange(IProgressMonitor pm) throws JavaModelException {
if (fMethodName == null)
return null;
fAnalyzer.aboutToCreateChange();
BodyDeclaration declaration= fAnalyzer.getEnclosingBodyDeclaration();
TypeDeclaration type= (TypeDeclaration)ASTNodes.getParent(declaration, TypeDeclaration.class);
fRewriter= new ASTRewrite(type);
String sourceMethodName= declaration.getNodeType() == ASTNode.METHOD_DECLARATION
? ((MethodDeclaration)declaration).getName().getIdentifier()
: "";
CompilationUnitChange result= null;
try {
result= new CompilationUnitChange(
RefactoringCoreMessages.getFormattedString("ExtractMethodRefactoring.change_name", new String[]{fMethodName, sourceMethodName}), //$NON-NLS-1$
fCUnit);
MultiTextEdit root= new MultiTextEdit();
result.setEdit(root);
TextBuffer buffer= null;
try {
// This is cheap since the compilation unit is already open in a editor.
buffer= TextBuffer.acquire((IFile)WorkingCopyUtil.getOriginal(fCUnit).getResource());
ASTNode[] selectedNodes= fAnalyzer.getSelectedNodes();
ASTNodes.expandRange(selectedNodes, buffer, fSelectionStart, fSelectionLength);
ASTNode target= getTargetNode(selectedNodes);
MethodDeclaration mm= createNewMethod(fMethodName, true, target, buffer.getLineDelimiter());
GroupDescription insertDesc= new GroupDescription(RefactoringCoreMessages.getFormattedString("ExtractMethodRefactoring.add_method", fMethodName)); //$NON-NLS-1$
result.addGroupDescription(insertDesc);
fRewriter.markAsInserted(mm, insertDesc);
List container= ASTNodes.getContainingList(declaration);
container.add(container.indexOf(declaration) + 1, mm);
GroupDescription description= new GroupDescription(RefactoringCoreMessages.getFormattedString("ExtractMethodRefactoring.substitute_with_call", fMethodName)); //$NON-NLS-1$
result.addGroupDescription(description);
ASTNode[] callNodes= createCallNodes(null);
fRewriter.markAsReplaced(target, callNodes[0], description);
if (callNodes.length > 1) {
container= ASTNodes.getContainingList(target);
int index= container.indexOf(target);
for (int i= 1; i < callNodes.length; i++) {
ASTNode node= callNodes[i];
container.add(index + i, node);
fRewriter.markAsInserted(node, description);
}
}
replaceDuplicates(result);
if (!fImportRewriter.isEmpty()) {
TextEdit edit= fImportRewriter.createEdit(buffer);
root.addChild(edit);
result.addGroupDescription(new GroupDescription(
RefactoringCoreMessages.getString("ExtractMethodRefactoring.organize_imports"), //$NON-NLS-1$
new TextEdit[] {edit}
));
}
MultiTextEdit changes= new MultiTextEdit();
fRewriter.rewriteNode(buffer, changes);
root.addChild(changes);
fRewriter.removeModifications();
} finally {
TextBuffer.release(buffer);
}
} catch (JavaModelException e){
throw e;
} catch (CoreException e) {
throw new JavaModelException(e);
}
return result;
}
/**
* Returns the signature of the new method.
*
* @return the signature of the extracted method
*/
public String getSignature() {
return getSignature(fMethodName);
}
/**
* Returns the signature of the new method.
*
* @param methodName the method name used for the new method
* @return the signature of the extracted method
*/
public String getSignature(String methodName) {
MethodDeclaration method= null;
try {
method= createNewMethod(methodName, false, null, String.valueOf('\n'));
} catch (CoreException cannotHappen) {
// we don't generate a code block and java comments.
Assert.isTrue(false);
}
method.setBody(fAST.newBlock());
ASTFlattener flattener= new ASTFlattener() {
public boolean visit(Block node) {
return false;
}
};
method.accept(flattener);
return flattener.getResult();
}
/**
* Returns the number of duplicate code snippets found.
*
* @return the number of duplicate code fragments
*/
public int getNumberOfDuplicates() {
if (fDuplicates == null)
return 0;
int result=0;
for (int i= 0; i < fDuplicates.length; i++) {
if (!fDuplicates[i].isMethodBody())
result++;
}
return result;
}
public void setReplaceDuplicates(boolean replace) {
fReplaceDuplicates= replace;
}
public void setGenerateJavadoc(boolean generate) {
fGenerateJavadoc= generate;
}
public boolean getGenerateJavadoc() {
return fGenerateJavadoc;
}
//---- Helper methods ------------------------------------------------------------------------
private void initializeParameterInfos() {
IVariableBinding[] arguments= fAnalyzer.getArguments();
fParameterInfos= new ArrayList(arguments.length);
ASTNode root= fAnalyzer.getEnclosingBodyDeclaration();
for (int i= 0; i < arguments.length; i++) {
IVariableBinding argument= arguments[i];
if (argument == null)
continue;
VariableDeclaration declaration= ASTNodes.findVariableDeclaration(argument, root);
ParameterInfo info= new ParameterInfo(argument, getType(declaration), argument.getName(), i);
info.setData(argument);
fParameterInfos.add(info);
}
}
private void initializeUsedNames() {
fUsedNames= UsedNamesCollector.perform(fAnalyzer.getSelectedNodes());
for (Iterator iter= fParameterInfos.iterator(); iter.hasNext();) {
ParameterInfo parameter= (ParameterInfo)iter.next();
fUsedNames.remove(parameter.getOldName());
}
}
private void initializeDuplicates() {
fDuplicates= SnippetFinder.perform(
(TypeDeclaration)ASTNodes.getParent(fAnalyzer.getEnclosingBodyDeclaration(), TypeDeclaration.class),
fAnalyzer.getSelectedNodes());
fReplaceDuplicates= fDuplicates.length > 0;
}
private RefactoringStatus mergeTextSelectionStatus(RefactoringStatus status) {
status.addFatalError(RefactoringCoreMessages.getString("ExtractMethodRefactoring.no_set_of_statements")); //$NON-NLS-1$
return status;
}
private String getType(VariableDeclaration declaration) {
return ASTNodes.asString(ASTNodes.getType(declaration.getAST(), declaration));
}
//---- Code generation -----------------------------------------------------------------------
private ASTNode getTargetNode(ASTNode[] nodes) {
ASTNode result;
if (nodes.length == 1) {
return nodes[0];
} else {
ASTNode first= nodes[0];
List container= ASTNodes.getContainingList(first);
result= fRewriter.collapseNodes(container, container.indexOf(first), nodes.length);
}
return result;
}
private ASTNode[] createCallNodes(SnippetFinder.Match duplicate) {
List result= new ArrayList(2);
IVariableBinding[] locals= fAnalyzer.getCallerLocals();
for (int i= 0; i < locals.length; i++) {
result.add(createDeclaration(locals[i], null));
}
MethodInvocation invocation= fAST.newMethodInvocation();
invocation.setName(fAST.newSimpleName(fMethodName));
List arguments= invocation.arguments();
for (int i= 0; i < fParameterInfos.size(); i++) {
ParameterInfo parameter= ((ParameterInfo)fParameterInfos.get(i));
if (duplicate == null) {
arguments.add(ASTNodeFactory.newName(fAST, parameter.getOldName()));
} else {
arguments.add(ASTNodeFactory.newName(fAST, duplicate.getMappedName(parameter.getOldBinding()).getIdentifier()));
}
}
ASTNode call;
int returnKind= fAnalyzer.getReturnKind();
switch (returnKind) {
case ExtractMethodAnalyzer.ACCESS_TO_LOCAL:
IVariableBinding binding= fAnalyzer.getReturnLocal();
if (binding != null) {
VariableDeclarationStatement decl= createDeclaration(binding, invocation);
call= decl;
} else {
Assignment assignment= fAST.newAssignment();
assignment.setLeftHandSide(ASTNodeFactory.newName(fAST, fAnalyzer.getReturnValue().getName()));
assignment.setRightHandSide(invocation);
call= assignment;
}
break;
case ExtractMethodAnalyzer.RETURN_STATEMENT_VALUE:
ReturnStatement rs= fAST.newReturnStatement();
rs.setExpression(invocation);
call= rs;
break;
default:
call= invocation;
}
if (call instanceof Expression && !fAnalyzer.isExpressionSelected()) {
call= fAST.newExpressionStatement((Expression)call);
}
result.add(call);
// We have a void return statement. The code looks like
// extracted();
// return;
if (returnKind == ExtractMethodAnalyzer.RETURN_STATEMENT_VOID && !fAnalyzer.isLastStatementSelected()) {
result.add(fAST.newReturnStatement());
}
return (ASTNode[])result.toArray(new ASTNode[result.size()]);
}
private void replaceDuplicates(CompilationUnitChange result) {
int numberOf= getNumberOfDuplicates();
if (numberOf == 0 || !fReplaceDuplicates)
return;
String label= null;
if (numberOf == 1)
label= RefactoringCoreMessages.getFormattedString("ExtractMethodRefactoring.duplicates.single", fMethodName); //$NON-NLS-1$
else
label= RefactoringCoreMessages.getFormattedString("ExtractMethodRefactoring.duplicates.multi", fMethodName); //$NON-NLS-1$
GroupDescription description= new GroupDescription(label);
result.addGroupDescription(description);
for (int d= 0; d < fDuplicates.length; d++) {
SnippetFinder.Match duplicate= fDuplicates[d];
if (!duplicate.isMethodBody()) {
ASTNode target= getTargetNode(duplicate.getNodes());
ASTNode[] callNodes= createCallNodes(duplicate);
fRewriter.markAsReplaced(target, callNodes[0], description);
if (callNodes.length > 1) {
List container= ASTNodes.getContainingList(target);
int index= container.indexOf(target);
for (int n= 1; n < callNodes.length; n++) {
ASTNode node= callNodes[n];
container.add(index + n, node);
fRewriter.markAsInserted(node, description);
}
}
}
}
}
private MethodDeclaration createNewMethod(String name, boolean code, ASTNode selection, String lineDelimiter) throws CoreException {
MethodDeclaration result= fAST.newMethodDeclaration();
int modifiers= fVisibility;
if (Modifier.isStatic(fAnalyzer.getEnclosingBodyDeclaration().getModifiers()) || fAnalyzer.getForceStatic()) {
modifiers= modifiers | Modifier.STATIC;
}
result.setModifiers(modifiers);
if (fAnalyzer.isExpressionSelected()) {
String type= fImportRewriter.addImport(ASTNodes.asString(fAnalyzer.getReturnType()));
result.setReturnType(ASTNodeFactory.newType(fAST, type));
} else {
result.setReturnType((Type)ASTNode.copySubtree(fAST, fAnalyzer.getReturnType()));
}
result.setName(fAST.newSimpleName(name));
List parameters= result.parameters();
for (int i= 0; i < fParameterInfos.size(); i++) {
ParameterInfo info= (ParameterInfo)fParameterInfos.get(i);
VariableDeclaration infoDecl= getVariableDeclaration(info);
SingleVariableDeclaration parameter= fAST.newSingleVariableDeclaration();
parameter.setModifiers(ASTNodes.getModifiers(infoDecl));
parameter.setType(ASTNodes.getType(fAST, infoDecl));
parameter.setName(fAST.newSimpleName(info.getNewName()));
parameters.add(parameter);
}
List exceptions= result.thrownExceptions();
ITypeBinding[] exceptionTypes= fAnalyzer.getExceptions(fThrowRuntimeExceptions, fAST);
for (int i= 0; i < exceptionTypes.length; i++) {
ITypeBinding exceptionType= exceptionTypes[i];
exceptions.add(ASTNodeFactory.newName(fAST, fImportRewriter.addImport(exceptionType)));
}
if (code) {
result.setBody(createMethodBody(selection));
if (fGenerateJavadoc) {
TypeDeclaration enclosingType=
(TypeDeclaration)ASTNodes.getParent(fAnalyzer.getEnclosingBodyDeclaration(), TypeDeclaration.class);
String string= CodeGeneration.getMethodComment(fCUnit, enclosingType.getName().getIdentifier(), result, null, lineDelimiter);
if (string != null) {
Javadoc javadoc= (Javadoc)fRewriter.createPlaceholder(string, ASTRewrite.JAVADOC);
result.setJavadoc(javadoc);
}
}
}
return result;
}
private Block createMethodBody(ASTNode selection) {
Block result= fAST.newBlock();
List statements= result.statements();
// Locals that are not passed as an arguments since the extracted method only
// writes to them
IVariableBinding[] methodLocals= fAnalyzer.getMethodLocals();
for (int i= 0; i < methodLocals.length; i++) {
if (methodLocals[i] != null) {
result.statements().add(createDeclaration(methodLocals[i], null));
}
}
// Rewrite local names
ASTNode[] selected= fAnalyzer.getSelectedNodes();
for (Iterator iter= fParameterInfos.iterator(); iter.hasNext();) {
ParameterInfo parameter= (ParameterInfo)iter.next();
if (parameter.isRenamed()) {
for (int n= 0; n < selected.length; n++) {
SimpleName[] oldNames= LinkedNodeFinder.findByBinding(selected[n], (IBinding) parameter.getData());
for (int i= 0; i < oldNames.length; i++) {
fRewriter.markAsReplaced(oldNames[i], fAST.newSimpleName(parameter.getNewName()));
}
}
}
}
boolean extractsExpression= fAnalyzer.isExpressionSelected();
if (extractsExpression) {
ITypeBinding binding= fAnalyzer.getExpressionBinding();
if (binding != null && (!binding.isPrimitive() || !"void".equals(binding.getName()))) { //$NON-NLS-1$
ReturnStatement rs= fAST.newReturnStatement();
rs.setExpression((Expression)fRewriter.createCopy(selection));
fRewriter.markAsInserted(rs);
statements.add(rs);
} else {
ExpressionStatement st= fAST.newExpressionStatement((Expression)fRewriter.createCopy(selection));
fRewriter.markAsInserted(st);
statements.add(st);
}
} else {
statements.add(fRewriter.createCopy(selection));
IVariableBinding returnValue= fAnalyzer.getReturnValue();
if (returnValue != null) {
ReturnStatement rs= fAST.newReturnStatement();
rs.setExpression(fAST.newSimpleName(returnValue.getName()));
statements.add(rs);
}
}
return result;
}
private VariableDeclaration getVariableDeclaration(ParameterInfo parameter) {
return ASTNodes.findVariableDeclaration((IVariableBinding)parameter.getData(), fAnalyzer.getEnclosingBodyDeclaration());
}
private VariableDeclarationStatement createDeclaration(IVariableBinding binding, Expression intilizer) {
VariableDeclaration original= ASTNodes.findVariableDeclaration(binding, fAnalyzer.getEnclosingBodyDeclaration());
VariableDeclarationFragment fragment= fAST.newVariableDeclarationFragment();
fragment.setName((SimpleName)ASTNode.copySubtree(fAST, original.getName()));
fragment.setInitializer(intilizer);
VariableDeclarationStatement result= fAST.newVariableDeclarationStatement(fragment);
result.setModifiers(ASTNodes.getModifiers(original));
result.setType(ASTNodes.getType(fAST, original));
return result;
}
}