blob: 9b291ff5464fa0bd03d41d4e73d6a063a46d5e9f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2007 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.corext.refactoring.structure;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.NamingConventions;
import org.eclipse.jdt.core.ToolFactory;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.compiler.IScanner;
import org.eclipse.jdt.core.compiler.ITerminalSymbols;
import org.eclipse.jdt.core.compiler.InvalidInputException;
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.ArrayCreation;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
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.IMethodBinding;
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.Message;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NullLiteral;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.SuperFieldAccess;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.dom.NodeFinder;
import org.eclipse.jdt.internal.corext.dom.TokenScanner;
import org.eclipse.jdt.internal.corext.dom.TypeBindingVisitor;
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.TypeContextChecker.IProblemVerifier;
import org.eclipse.jdt.internal.corext.refactoring.changes.CreateCompilationUnitChange;
import org.eclipse.jdt.internal.corext.refactoring.changes.CreatePackageChange;
import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.CodeGeneration;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
public class IntroduceParameterObjectRefactoring extends ChangeSignatureRefactoring {
private final class ParameterObjectCreator implements IDefaultValueAdvisor {
public Expression createDefaultExpression(List invocationArguments, ParameterInfo addedInfo, List parameterInfos,
MethodDeclaration enclosingMethod, boolean isRecursive, CompilationUnitRewrite cuRewrite) {
final AST ast= cuRewrite.getAST();
final ASTRewrite rewrite= cuRewrite.getASTRewrite();
if (isRecursive && canReuseParameterObject(invocationArguments, addedInfo, parameterInfos, enclosingMethod)) {
return ast.newSimpleName(addedInfo.getNewName());
}
ClassInstanceCreation classCreation= ast.newClassInstanceCreation();
int startPosition= enclosingMethod != null ? enclosingMethod.getStartPosition() : cuRewrite.getRoot().getStartPosition();
classCreation.setType(fParameterObjectFactory.createType(fCreateAsTopLevel, cuRewrite, startPosition));
List constructorArguments= classCreation.arguments();
for (Iterator iter= parameterInfos.iterator(); iter.hasNext();) {
ParameterInfo pi= (ParameterInfo) iter.next();
if (isValidField(pi)) {
if (pi.isOldVarargs()) {
boolean isLastParameter= !iter.hasNext();
constructorArguments.addAll(computeVarargs(invocationArguments, pi, isLastParameter, cuRewrite));
} else {
Expression exp= (Expression) invocationArguments.get(pi.getOldIndex());
importNodeTypes(exp, cuRewrite);
constructorArguments.add(moveNode(exp, rewrite));
}
}
}
return classCreation;
}
public Type createType(String newTypeName, int startPosition, CompilationUnitRewrite cuRewrite) {
return fParameterObjectFactory.createType(fCreateAsTopLevel, cuRewrite, startPosition);
}
private boolean canReuseParameterObject(List invocationArguments, ParameterInfo addedInfo, List parameterInfos,
MethodDeclaration enclosingMethod) {
Assert.isNotNull(enclosingMethod);
List parameters= enclosingMethod.parameters();
for (Iterator iter= parameterInfos.iterator(); iter.hasNext();) {
ParameterInfo pi= (ParameterInfo) iter.next();
if (isValidField(pi)) {
if (!pi.isInlined())
return false;
ASTNode node= (ASTNode) invocationArguments.get(pi.getOldIndex());
if (!isParameter(pi, node, parameters, addedInfo.getNewName())) {
return false;
}
}
}
return true;
}
private List computeVarargs(List invocationArguments, ParameterInfo varArgPI, boolean isLastParameter, CompilationUnitRewrite cuRewrite) {
boolean isEmptyVarArg= varArgPI.getOldIndex() >= invocationArguments.size();
ASTRewrite rewrite= cuRewrite.getASTRewrite();
AST ast= cuRewrite.getAST();
ASTNode lastNode= isEmptyVarArg ? null : (ASTNode) invocationArguments.get(varArgPI.getOldIndex());
List constructorArguments= new ArrayList();
if (lastNode instanceof ArrayCreation) {
ArrayCreation creation= (ArrayCreation) lastNode;
ITypeBinding arrayType= creation.resolveTypeBinding();
if (arrayType != null && arrayType.isAssignmentCompatible(varArgPI.getNewTypeBinding())) {
constructorArguments.add(moveNode(creation, rewrite));
return constructorArguments;
}
}
if (isLastParameter) {
// copy all varargs
for (int i= varArgPI.getOldIndex(); i < invocationArguments.size(); i++) {
ASTNode node= (ASTNode) invocationArguments.get(i);
importNodeTypes(node, cuRewrite);
constructorArguments.add(moveNode(node, rewrite));
}
} else { // new signature would be String...args, int
if (lastNode instanceof NullLiteral) {
NullLiteral nullLiteral= (NullLiteral) lastNode;
constructorArguments.add(moveNode(nullLiteral, rewrite));
} else {
ArrayCreation creation= ast.newArrayCreation();
creation.setType((ArrayType) importBinding(varArgPI.getNewTypeBinding(), cuRewrite));
ArrayInitializer initializer= ast.newArrayInitializer();
List expressions= initializer.expressions();
for (int i= varArgPI.getOldIndex(); i < invocationArguments.size(); i++) {
ASTNode node= (ASTNode) invocationArguments.get(i);
importNodeTypes(node, cuRewrite);
expressions.add(moveNode(node, rewrite));
}
if (expressions.isEmpty())
creation.dimensions().add(ast.newNumberLiteral("0")); //$NON-NLS-1$
else
creation.setInitializer(initializer);
constructorArguments.add(creation);
}
}
return constructorArguments;
}
public Type importBinding(ITypeBinding newTypeBinding, CompilationUnitRewrite cuRewrite) {
Type type= cuRewrite.getImportRewrite().addImport(newTypeBinding, cuRewrite.getAST());
cuRewrite.getImportRemover().registerAddedImports(type);
return type;
}
private void importNodeTypes(ASTNode node, final CompilationUnitRewrite cuRewrite) {
ASTResolving.visitAllBindings(node, new TypeBindingVisitor() {
public boolean visit(ITypeBinding nodeBinding) {
importBinding(nodeBinding, cuRewrite);
return false;
}
});
}
}
private boolean isParameter(ParameterInfo pi, ASTNode node, List enclosingMethodParameters, String qualifier) {
if (node instanceof Name) {
Name name= (Name) node;
IVariableBinding binding= ASTNodes.getVariableBinding(name);
if (binding != null && binding.isParameter()) {
return binding.getName().equals(getNameInScope(pi, enclosingMethodParameters));
} else {
if (node instanceof QualifiedName) {
QualifiedName qn= (QualifiedName) node;
return qn.getFullyQualifiedName().equals(JavaModelUtil.concatenateName(qualifier, getNameInScope(pi, enclosingMethodParameters)));
}
}
}
return false;
}
private final class RewriteParameterBody extends BodyUpdater {
private boolean fParameterClassCreated= false;
public void updateBody(MethodDeclaration methodDeclaration, CompilationUnitRewrite cuRewrite, RefactoringStatus result) throws CoreException {
// ensure that the parameterObject is imported
fParameterObjectFactory.createType(fCreateAsTopLevel, cuRewrite, methodDeclaration.getStartPosition());
if (cuRewrite.getCu().equals(fCompilationUnit) && !fParameterClassCreated) {
createParameterClass(methodDeclaration, cuRewrite);
fParameterClassCreated= true;
}
Block body= methodDeclaration.getBody();
final List parameters= methodDeclaration.parameters();
if (body != null) { // abstract methods don't have bodies
final ASTRewrite rewriter= cuRewrite.getASTRewrite();
ListRewrite bodyStatements= rewriter.getListRewrite(body, Block.STATEMENTS_PROPERTY);
List managedParams= getParameterInfos();
for (Iterator iter= managedParams.iterator(); iter.hasNext();) {
final ParameterInfo pi= (ParameterInfo) iter.next();
if (isValidField(pi)) {
if (isReadOnly(pi, body, parameters, null)) {
body.accept(new ASTVisitor(false) {
public boolean visit(SimpleName node) {
updateSimpleName(rewriter, pi, node, parameters);
return false;
}
});
pi.setInlined(true);
} else {
ExpressionStatement initializer= fParameterObjectFactory.createInitializer(pi, getParameterName(), cuRewrite);
bodyStatements.insertFirst(initializer, null);
}
}
}
}
}
private void updateSimpleName(ASTRewrite rewriter, ParameterInfo pi, SimpleName node, List enclosingParameters) {
AST ast= rewriter.getAST();
IBinding binding= node.resolveBinding();
Expression replacementNode= fParameterObjectFactory.createFieldReadAccess(pi, getParameterName(), ast);
if (binding instanceof IVariableBinding) {
IVariableBinding variable= (IVariableBinding) binding;
if (variable.isParameter() && variable.getName().equals(getNameInScope(pi, enclosingParameters))) {
rewriter.replace(node, replacementNode, null);
}
} else {
ASTNode parent= node.getParent();
if (! (parent instanceof QualifiedName || parent instanceof FieldAccess || parent instanceof SuperFieldAccess)) {
if (node.getIdentifier().equals(getNameInScope(pi, enclosingParameters))) {
rewriter.replace(node, replacementNode, null);
}
}
}
}
private boolean isReadOnly(final ParameterInfo pi, Block block, final List enclosingMethodParameters, final String qualifier) {
class NotWrittenDetector extends ASTVisitor {
boolean notWritten= true;
public boolean visit(SimpleName node) {
if (isParameter(pi, node, enclosingMethodParameters, qualifier) && ASTResolving.isWriteAccess(node))
notWritten= false;
return false;
}
public boolean visit(SuperFieldAccess node) {
return false;
}
}
NotWrittenDetector visitor= new NotWrittenDetector();
block.accept(visitor);
return visitor.notWritten;
}
public boolean needsParameterUsedCheck() {
return false;
}
}
private static final String PARAMETER_CLASS_APPENDIX= "Parameter"; //$NON-NLS-1$
private static final String DEFAULT_PARAMETER_OBJECT_NAME= "parameterObject"; //$NON-NLS-1$
private MethodDeclaration fMethodDeclaration;
private ICompilationUnit fCompilationUnit;
private int fOffset;
private int fLength;
private ParameterObjectFactory fParameterObjectFactory;
private boolean fCreateAsTopLevel= true;
private ParameterInfo fParameterObjectReference;
public IntroduceParameterObjectRefactoring(IMethod method) throws JavaModelException {
super(method);
Assert.isNotNull(method);
initializeFields(method);
setBodyUpdater(new RewriteParameterBody());
setDefaultValueAdvisor(new ParameterObjectCreator());
List parameterInfos= getParameterInfos();
for (Iterator iter= parameterInfos.iterator(); iter.hasNext();) {
ParameterInfo pi= (ParameterInfo) iter.next();
if (!pi.isAdded()) {
pi.setCreateField(true);
pi.setNewName(getFieldName(pi));
}
}
}
private void initializeFields(IMethod method) throws JavaModelException {
fCompilationUnit= method.getCompilationUnit();
Assert.isNotNull(fCompilationUnit);
fOffset= method.getNameRange().getOffset();
fLength= method.getNameRange().getLength();
fParameterObjectFactory= new ParameterObjectFactory(fCompilationUnit);
String methodName= method.getElementName();
String className= String.valueOf(Character.toUpperCase(methodName.charAt(0)));
if (methodName.length() > 1)
className+= methodName.substring(1);
className+= PARAMETER_CLASS_APPENDIX;
fParameterObjectReference= ParameterInfo.createInfoForAddedParameter(className, DEFAULT_PARAMETER_OBJECT_NAME);
fParameterObjectFactory.setClassName(className);
fParameterObjectFactory.setPackage(method.getDeclaringType().getPackageFragment().getElementName());
updateReferenceType();
}
public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
RefactoringStatus status= new RefactoringStatus();
status.merge(fParameterObjectFactory.checkConditions());
status.merge(Checks.checkIdentifier(getParameterName()));
if (status.hasFatalError())
return status;
status.merge(super.checkFinalConditions(pm));
return status;
}
public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
RefactoringStatus status= new RefactoringStatus();
status.merge(super.checkInitialConditions(pm));
status.merge(Checks.checkAvailability(fCompilationUnit));
if (status.hasFatalError())
return status;
CompilationUnit astRoot= getBaseCuRewrite().getRoot();
ASTNode selectedNode= NodeFinder.perform(astRoot, fOffset, fLength);
if (selectedNode == null) {
return mappingErrorFound(status, selectedNode);
}
fMethodDeclaration= (MethodDeclaration) ASTNodes.getParent(selectedNode, MethodDeclaration.class);
if (fMethodDeclaration == null) {
return mappingErrorFound(status, selectedNode);
}
IMethodBinding resolveBinding= fMethodDeclaration.resolveBinding();
if (resolveBinding == null) {
if (!processCompilerError(status, selectedNode))
status.addFatalError(RefactoringCoreMessages.SelfEncapsulateField_type_not_resolveable);
return status;
}
ITypeBinding declaringClass= resolveBinding.getDeclaringClass();
if (fParameterObjectFactory.getPackage() == null)
fParameterObjectFactory.setPackage(declaringClass.getPackage().getName());
if (fParameterObjectFactory.getEnclosingType() == null)
fParameterObjectFactory.setEnclosingType(declaringClass.getQualifiedName());
List parameterInfos= super.getParameterInfos();
if (!parameterInfos.contains(fParameterObjectReference)) {
parameterInfos.add(0, fParameterObjectReference);
}
Map bindingMap= new HashMap();
for (Iterator iter= fMethodDeclaration.parameters().iterator(); iter.hasNext();) {
SingleVariableDeclaration sdv= (SingleVariableDeclaration) iter.next();
bindingMap.put(sdv.getName().getIdentifier(), sdv.resolveBinding());
}
for (Iterator iter= parameterInfos.iterator(); iter.hasNext();) {
ParameterInfo pi= (ParameterInfo) iter.next();
if (pi != fParameterObjectReference)
pi.setOldBinding((IVariableBinding) bindingMap.get(pi.getOldName()));
}
fParameterObjectFactory.setVariables(parameterInfos);
return status;
}
protected IProblemVerifier doGetProblemVerifier() {
return new IProblemVerifier() {
public boolean isError(IProblem problem, ASTNode node) {
if (node instanceof Type) {
Type type= (Type) node;
if (problem.getID() == IProblem.UndefinedType && getClassName().equals(ASTNodes.getTypeName(type))) {
return false;
}
}
if (node instanceof Name) {
Name name= (Name) node;
if (problem.getID() == IProblem.ImportNotFound && getPackage().indexOf(name.getFullyQualifiedName()) != -1)
return false;
}
return true;
}
};
}
public String getClassName() {
return fParameterObjectFactory.getClassName();
}
public ITypeBinding getContainingClass() {
return fMethodDeclaration.resolveBinding().getDeclaringClass();
}
private String getMappingErrorMessage() {
return Messages.format(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_cannotalanyzemethod_mappingerror, new String[] {});
}
public String getFieldName(ParameterInfo element) {
String paramName= element.getOldName();
IJavaProject javaProject= fCompilationUnit.getJavaProject();
String stripped= NamingConventions.removePrefixAndSuffixForArgumentName(javaProject, paramName);
int dim= element.getNewTypeBinding() != null ? element.getNewTypeBinding().getDimensions() : 0;
return StubUtility.getVariableNameSuggestions(StubUtility.INSTANCE_FIELD, javaProject, stripped, dim, null, true)[0];
}
public String getName() {
return RefactoringCoreMessages.IntroduceParameterObjectRefactoring_refactoring_name;
}
protected String doGetRefactoringChangeName() {
return getName();
}
public String getParameterName() {
return fParameterObjectReference.getNewName();
}
public RefactoringStatus initialize(RefactoringArguments arguments) {
RefactoringStatus refactoringStatus= new RefactoringStatus();
refactoringStatus.merge(super.initialize(arguments));
return refactoringStatus;
}
public boolean isCreateGetter() {
return fParameterObjectFactory.isCreateGetter();
}
public boolean isCreateSetter() {
return fParameterObjectFactory.isCreateSetter();
}
public boolean isCreateAsTopLevel() {
return fCreateAsTopLevel;
}
/**
* Checks if the given parameter info has been selected for field creation
*
* @param pi parameter info
* @return true if the given parameter info has been selected for field creation
*/
private boolean isValidField(ParameterInfo pi) {
return pi.isCreateField() & !pi.isAdded();
}
private RefactoringStatus mappingErrorFound(RefactoringStatus result, ASTNode node) {
if (node != null && (node.getFlags() & ASTNode.MALFORMED) != 0 && processCompilerError(result, node))
return result;
result.addFatalError(getMappingErrorMessage());
return result;
}
public void moveFieldDown(ParameterInfo selected) {
fParameterObjectFactory.moveDown(selected);
}
public void moveFieldUp(ParameterInfo selected) {
fParameterObjectFactory.moveUp(selected);
}
private boolean processCompilerError(RefactoringStatus result, ASTNode node) {
Message[] messages= ASTNodes.getMessages(node, ASTNodes.INCLUDE_ALL_PARENTS);
if (messages.length == 0)
return false;
result.addFatalError(Messages.format(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_cannotanalysemethod_compilererror,
new String[] { messages[0].getMessage() }));
return true;
}
public void setClassName(String className) {
fParameterObjectFactory.setClassName(className);
updateReferenceType();
}
private void updateReferenceType() {
if (fCreateAsTopLevel)
fParameterObjectReference.setNewTypeName(JavaModelUtil.concatenateName(fParameterObjectFactory.getPackage(), fParameterObjectFactory
.getClassName()));
else
fParameterObjectReference.setNewTypeName(JavaModelUtil.concatenateName(fParameterObjectFactory.getEnclosingType(),
fParameterObjectFactory.getClassName()));
}
public void setCreateComments(boolean selection) {
fParameterObjectFactory.setCreateComments(selection);
}
public void setCreateGetter(boolean createGetter) {
fParameterObjectFactory.setCreateGetter(createGetter);
}
public void setCreateSetter(boolean createSetter) {
fParameterObjectFactory.setCreateSetter(createSetter);
}
public void setPackageName(String packageName) {
fParameterObjectFactory.setPackage(packageName);
updateReferenceType();
}
public void setParameterName(String paramName) {
this.fParameterObjectReference.setNewName(paramName);
}
public void setCreateAsTopLevel(boolean topLevel) {
this.fCreateAsTopLevel= topLevel;
updateReferenceType();
}
public void updateParameterPosition() {
fParameterObjectFactory.updateParameterPosition(fParameterObjectReference);
}
private void createParameterClass(MethodDeclaration methodDeclaration, CompilationUnitRewrite cuRewrite) throws CoreException {
if (fCreateAsTopLevel) {
IJavaProject javaProject= fCompilationUnit.getJavaProject();
IPackageFragment packageFragment= getPackageFragmentRoot().getPackageFragment(fParameterObjectFactory.getPackage());
if (!packageFragment.exists()) {
fOtherChanges.add(new CreatePackageChange(packageFragment));
}
ICompilationUnit unit= packageFragment.getCompilationUnit(fParameterObjectFactory.getClassName() + ".java"); //$NON-NLS-1$
Assert.isTrue(!unit.exists());
createTopLevelParameterObject(javaProject, unit);
} else {
ASTRewrite rewriter= cuRewrite.getASTRewrite();
TypeDeclaration enclosingType= (TypeDeclaration) methodDeclaration.getParent();
ListRewrite bodyRewrite= rewriter.getListRewrite(enclosingType, TypeDeclaration.BODY_DECLARATIONS_PROPERTY);
TypeDeclaration classDeclaration= fParameterObjectFactory.createClassDeclaration(fCompilationUnit, enclosingType.getName()
.getFullyQualifiedName(), cuRewrite);
classDeclaration.modifiers().add(rewriter.getAST().newModifier(ModifierKeyword.PUBLIC_KEYWORD));
classDeclaration.modifiers().add(rewriter.getAST().newModifier(ModifierKeyword.STATIC_KEYWORD));
bodyRewrite.insertBefore(classDeclaration, methodDeclaration, null);
}
}
private void createTopLevelParameterObject(IJavaProject javaProject, ICompilationUnit unit) throws JavaModelException, CoreException {
ICompilationUnit workingCopy= unit.getWorkingCopy(null);
try {
// create stub with comments and dummy type
String lineDelimiter= StubUtility.getLineDelimiterUsed(javaProject);
String fileComment= getFileComment(workingCopy, lineDelimiter);
String typeComment= getTypeComment(workingCopy, lineDelimiter);
String content= CodeGeneration.getCompilationUnitContent(workingCopy, fileComment, typeComment,
"class " + getClassName() + "{}", lineDelimiter); //$NON-NLS-1$ //$NON-NLS-2$
workingCopy.getBuffer().setContents(content);
CompilationUnitRewrite cuRewrite= new CompilationUnitRewrite(workingCopy);
ASTRewrite rewriter= cuRewrite.getASTRewrite();
CompilationUnit root= cuRewrite.getRoot();
AST ast= cuRewrite.getAST();
ImportRewrite importRewrite= cuRewrite.getImportRewrite();
// retrieve&replace dummy type with real class
ListRewrite types= rewriter.getListRewrite(root, CompilationUnit.TYPES_PROPERTY);
ASTNode dummyType= (ASTNode) types.getOriginalList().get(0);
String newTypeName= JavaModelUtil.concatenateName(fParameterObjectFactory.getPackage(), fParameterObjectFactory.getClassName());
TypeDeclaration classDeclaration= fParameterObjectFactory.createClassDeclaration(workingCopy, newTypeName, cuRewrite);
classDeclaration.modifiers().add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD));
Javadoc javadoc= (Javadoc) dummyType.getStructuralProperty(TypeDeclaration.JAVADOC_PROPERTY);
rewriter.set(classDeclaration, TypeDeclaration.JAVADOC_PROPERTY, javadoc, null);
types.replace(dummyType, classDeclaration, null);
// Apply rewrites and discard workingcopy
// Using CompilationUnitRewrite.createChange() leads to strange
// results
String charset= ResourceUtil.getFile(fCompilationUnit).getCharset(false);
Document document= new Document(content);
try {
rewriter.rewriteAST().apply(document);
TextEdit rewriteImports= importRewrite.rewriteImports(null);
rewriteImports.apply(document);
} catch (BadLocationException e) {
throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(),
RefactoringCoreMessages.IntroduceParameterObjectRefactoring_parameter_object_creation_error, e));
}
String docContent= document.get();
CreateCompilationUnitChange compilationUnitChange= new CreateCompilationUnitChange(unit, docContent, charset);
fOtherChanges.add(compilationUnitChange);
} finally {
workingCopy.discardWorkingCopy();
}
}
public IPackageFragmentRoot getPackageFragmentRoot() {
return (IPackageFragmentRoot) fCompilationUnit.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
}
protected String getFileComment(ICompilationUnit parentCU, String lineDelimiter) throws CoreException {
if (fParameterObjectFactory.isCreateComments()) {
return CodeGeneration.getFileComment(parentCU, lineDelimiter);
}
return null;
}
protected String getTypeComment(ICompilationUnit parentCU, String lineDelimiter) throws CoreException {
if (fParameterObjectFactory.isCreateComments()) {
StringBuffer typeName= new StringBuffer();
typeName.append(fParameterObjectFactory.getClassName());
String[] typeParamNames= new String[0];
String comment= CodeGeneration.getTypeComment(parentCU, typeName.toString(), typeParamNames, lineDelimiter);
if (comment != null && isValidComment(comment)) {
return comment;
}
}
return null;
}
private boolean isValidComment(String template) {
IScanner scanner= ToolFactory.createScanner(true, false, false, false);
scanner.setSource(template.toCharArray());
try {
int next= scanner.getNextToken();
while (TokenScanner.isComment(next)) {
next= scanner.getNextToken();
}
return next == ITerminalSymbols.TokenNameEOF;
} catch (InvalidInputException e) {
}
return false;
}
public String getPackage() {
return fParameterObjectFactory.getPackage();
}
public void setPackage(String typeQualifier) {
fParameterObjectFactory.setPackage(typeQualifier);
}
public ICompilationUnit getCompilationUnit() {
return fCompilationUnit;
}
private String getNameInScope(ParameterInfo pi, List enclosingMethodParameters) {
Assert.isNotNull(enclosingMethodParameters);
boolean emptyVararg= pi.getOldIndex() >= enclosingMethodParameters.size();
if (!emptyVararg) {
SingleVariableDeclaration svd= (SingleVariableDeclaration) enclosingMethodParameters.get(pi.getOldIndex());
return svd.getName().getIdentifier();
}
return null;
}
public String getNewTypeName() {
return fParameterObjectReference.getNewTypeName();
}
}