blob: d8d9e4b912a34c3937b2826ff3c3ffe0727834ad [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2018 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.corext.refactoring.structure;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.resources.IFile;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.text.edits.TextEditCopier;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.GroupCategory;
import org.eclipse.ltk.core.refactoring.GroupCategorySet;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextChange;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeParameter;
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.ASTParser;
import org.eclipse.jdt.core.dom.ASTRequestor;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
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.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.TypeParameter;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.jdt.core.manipulation.CodeGeneration;
import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
import org.eclipse.jdt.core.refactoring.descriptors.ExtractSuperclassDescriptor;
import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
import org.eclipse.jdt.internal.core.manipulation.StubUtility;
import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory;
import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2;
import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2Core;
import org.eclipse.jdt.internal.corext.dom.IASTSharedValues;
import org.eclipse.jdt.internal.corext.refactoring.Checks;
import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
import org.eclipse.jdt.internal.corext.refactoring.changes.CreateCompilationUnitChange;
import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
import org.eclipse.jdt.internal.corext.refactoring.changes.MultiStateCompilationUnitChange;
import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
import org.eclipse.jdt.internal.corext.refactoring.util.TextEditBasedChangeManager;
import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.JdtFlags;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
import org.eclipse.jdt.internal.ui.preferences.formatter.FormatterProfileManager;
/**
* Refactoring processor for the extract supertype refactoring.
*
* @since 3.2
*/
public final class ExtractSupertypeProcessor extends PullUpRefactoringProcessor {
/** The extract attribute */
private static final String ATTRIBUTE_EXTRACT= "extract"; //$NON-NLS-1$
/** The types attribute */
private static final String ATTRIBUTE_TYPES= "types"; //$NON-NLS-1$
/** The extract supertype group category set */
private static final GroupCategorySet SET_EXTRACT_SUPERTYPE= new GroupCategorySet(new GroupCategory("org.eclipse.jdt.internal.corext.extractSupertype", //$NON-NLS-1$
RefactoringCoreMessages.ExtractSupertypeProcessor_category_name, RefactoringCoreMessages.ExtractSupertypeProcessor_category_description));
/**
* The changes of the working copy layer (element type:
* <ICompilationUnit, TextEditBasedChange>)
* <p>
* The compilation units are all primary working copies or normal
* compilation units.
* </p>
*/
private final Map<ICompilationUnit, CompilationUnitChange> fLayerChanges= new HashMap<>();
/** The possible extract supertype candidates, or the empty array */
private IType[] fPossibleCandidates= {};
/** The source of the supertype */
private String fSuperSource;
/** The name of the extracted type */
private String fTypeName= ""; //$NON-NLS-1$
/** The types where to extract the supertype */
private IType[] fTypesToExtract= {};
/**
* Creates a new extract supertype refactoring processor.
*
* @param members
* the members to extract, or <code>null</code> if invoked by
* scripting
* @param settings
* the code generation settings, or <code>null</code> if
* invoked by scripting
*/
public ExtractSupertypeProcessor(final IMember[] members, final CodeGenerationSettings settings) {
super(members, settings, true);
if (members != null) {
final IType declaring= getDeclaringType();
if (declaring != null)
fTypesToExtract= new IType[] { declaring};
}
}
/**
* Creates a new extract supertype refactoring processor from refactoring arguments.
*
* @param arguments
* the refactoring arguments
* @param status
* the resulting status
*/
public ExtractSupertypeProcessor(JavaRefactoringArguments arguments, RefactoringStatus status) {
super(null, null, true);
RefactoringStatus initializeStatus= initialize(arguments);
status.merge(initializeStatus);
}
@Override
public String getProcessorName() {
return RefactoringCoreMessages.ExtractSupertypeProcessor_extract_supertype;
}
@Override
protected RefactoringStatus checkDeclaringSuperTypes(final IProgressMonitor monitor) throws JavaModelException {
return new RefactoringStatus();
}
@Override
protected CompilationUnitRewrite getCompilationUnitRewrite(final Map<ICompilationUnit, CompilationUnitRewrite> rewrites, final ICompilationUnit unit) {
Assert.isNotNull(rewrites);
Assert.isNotNull(unit);
CompilationUnitRewrite rewrite= rewrites.get(unit);
if (rewrite == null) {
rewrite= new CompilationUnitRewrite(fOwner, unit);
rewrite.rememberContent();
rewrites.put(unit, rewrite);
}
return rewrite;
}
/**
* Checks whether the compilation unit to be extracted is valid.
*
* @return a status describing the outcome of the
*/
public RefactoringStatus checkExtractedCompilationUnit() {
final RefactoringStatus status= new RefactoringStatus();
final ICompilationUnit cu= getDeclaringType().getCompilationUnit();
if (fTypeName == null || "".equals(fTypeName)) //$NON-NLS-1$
return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.Checks_Choose_name);
status.merge(Checks.checkTypeName(fTypeName, cu));
if (status.hasFatalError())
return status;
status.merge(Checks.checkCompilationUnitName(JavaModelUtil.getRenamedCUName(cu, fTypeName), cu));
if (status.hasFatalError())
return status;
status.merge(Checks.checkCompilationUnitNewName(cu, fTypeName));
return status;
}
@Override
public RefactoringStatus checkFinalConditions(final IProgressMonitor monitor, final CheckConditionsContext context) throws CoreException, OperationCanceledException {
final RefactoringStatus status= new RefactoringStatus();
try {
monitor.beginTask("", 1); //$NON-NLS-1$
monitor.setTaskName(RefactoringCoreMessages.ExtractSupertypeProcessor_checking);
status.merge(checkExtractedCompilationUnit());
if (status.hasFatalError())
return status;
return super.checkFinalConditions(new SubProgressMonitor(monitor, 1), context);
} finally {
monitor.done();
}
}
/**
* Computes the destination type based on the new name.
*
* @param name the new name
* @return the destination type
*/
public IType computeExtractedType(final String name) {
if (name != null && !name.isEmpty()) {
final IType declaring= getDeclaringType();
try {
final String newName= JavaModelUtil.getRenamedCUName(declaring.getCompilationUnit(), name);
ICompilationUnit result= null;
for (ICompilationUnit unit : declaring.getPackageFragment().getCompilationUnits(fOwner)) {
if (unit.getElementName().equals(newName)) {
result= unit;
}
}
if (result != null) {
final IType type= result.getType(name);
setDestinationType(type);
return type;
}
} catch (JavaModelException exception) {
JavaPlugin.log(exception);
}
}
return null;
}
@Override
public Change createChange(final IProgressMonitor monitor) throws CoreException, OperationCanceledException {
try {
final Map<String, String> arguments= new HashMap<>();
String project= null;
final IType declaring= getDeclaringType();
final IJavaProject javaProject= declaring.getJavaProject();
if (javaProject != null)
project= javaProject.getElementName();
int flags= JavaRefactoringDescriptor.JAR_MIGRATION | JavaRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE;
try {
if (declaring.isLocal() || declaring.isAnonymous())
flags|= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
} catch (JavaModelException exception) {
JavaPlugin.log(exception);
}
final String description= Messages.format(RefactoringCoreMessages.ExtractSupertypeProcessor_descriptor_description_short, BasicElementLabels.getJavaElementName(fTypeName));
final String header= Messages.format(RefactoringCoreMessages.ExtractSupertypeProcessor_descriptor_description, new String[] { JavaElementLabels.getElementLabel(fDestinationType, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getElementLabel(fCachedDeclaringType, JavaElementLabels.ALL_FULLY_QUALIFIED)});
final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
final IType[] types= getTypesToExtract();
String[] settings= new String[types.length];
for (int index= 0; index < settings.length; index++)
settings[index]= JavaElementLabels.getElementLabel(types[index], JavaElementLabels.ALL_FULLY_QUALIFIED);
comment.addSetting(JDTRefactoringDescriptorComment.createCompositeSetting(RefactoringCoreMessages.ExtractSupertypeProcessor_subtypes_pattern, settings));
comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractSupertypeProcessor_refactored_element_pattern, JavaElementLabels.getElementLabel(fDestinationType, JavaElementLabels.ALL_FULLY_QUALIFIED)));
settings= new String[fMembersToMove.length];
for (int index= 0; index < settings.length; index++)
settings[index]= JavaElementLabels.getElementLabel(fMembersToMove[index], JavaElementLabels.ALL_FULLY_QUALIFIED);
comment.addSetting(JDTRefactoringDescriptorComment.createCompositeSetting(RefactoringCoreMessages.ExtractInterfaceProcessor_extracted_members_pattern, settings));
addSuperTypeSettings(comment, true);
final ExtractSuperclassDescriptor descriptor= RefactoringSignatureDescriptorFactory.createExtractSuperclassDescriptor(project, description, comment.asString(), arguments, flags);
arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME, fTypeName);
arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT, JavaRefactoringDescriptorUtil.elementToHandle(project, getDeclaringType()));
arguments.put(ATTRIBUTE_REPLACE, Boolean.toString(fReplace));
arguments.put(ATTRIBUTE_INSTANCEOF, Boolean.toString(fInstanceOf));
arguments.put(ATTRIBUTE_STUBS, Boolean.toString(fCreateMethodStubs));
arguments.put(ATTRIBUTE_EXTRACT, Integer.toString(fMembersToMove.length));
for (int offset= 0; offset < fMembersToMove.length; offset++)
arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + (offset + 1), JavaRefactoringDescriptorUtil.elementToHandle(project, fMembersToMove[offset]));
arguments.put(ATTRIBUTE_DELETE, Integer.toString(fDeletedMethods.length));
for (int offset= 0; offset < fDeletedMethods.length; offset++)
arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + (offset + fMembersToMove.length + 1), JavaRefactoringDescriptorUtil.elementToHandle(project, fDeletedMethods[offset]));
arguments.put(ATTRIBUTE_ABSTRACT, Integer.toString(fAbstractMethods.length));
for (int offset= 0; offset < fAbstractMethods.length; offset++)
arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + (offset + fMembersToMove.length + fDeletedMethods.length + 1), JavaRefactoringDescriptorUtil.elementToHandle(project, fAbstractMethods[offset]));
arguments.put(ATTRIBUTE_TYPES, Integer.toString(fTypesToExtract.length));
for (int offset= 0; offset < fTypesToExtract.length; offset++)
arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + (offset + fMembersToMove.length + fDeletedMethods.length + fAbstractMethods.length + 1), JavaRefactoringDescriptorUtil.elementToHandle(project, fTypesToExtract[offset]));
final DynamicValidationRefactoringChange change= new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.ExtractSupertypeProcessor_extract_supertype, fChangeManager.getAllChanges());
final IFile file= ResourceUtil.getFile(declaring.getCompilationUnit());
if (fSuperSource != null && fSuperSource.length() > 0)
change.add(new CreateCompilationUnitChange(declaring.getPackageFragment().getCompilationUnit(JavaModelUtil.getRenamedCUName(declaring.getCompilationUnit(), fTypeName)), fSuperSource, file.getCharset(false)));
return change;
} finally {
monitor.done();
clearCaches();
}
}
/**
* Creates the new extracted supertype.
*
* @param superType
* the super type, or <code>null</code> if no super type (ie.
* <code>java.lang.Object</code>) is available
* @param monitor
* the progress monitor
* @return a status describing the outcome of the operation
* @throws CoreException
* if an error occurs
*/
protected RefactoringStatus createExtractedSuperType(final IType superType, final IProgressMonitor monitor) throws CoreException {
Assert.isNotNull(monitor);
fSuperSource= null;
final RefactoringStatus status= new RefactoringStatus();
try {
monitor.beginTask(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing, 20);
final IType declaring= getDeclaringType();
final CompilationUnitRewrite declaringRewrite= new CompilationUnitRewrite(fOwner, declaring.getCompilationUnit());
final AbstractTypeDeclaration declaringDeclaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(declaring, declaringRewrite.getRoot());
if (declaringDeclaration != null) {
final String name= JavaModelUtil.getRenamedCUName(declaring.getCompilationUnit(), fTypeName);
final ICompilationUnit original= declaring.getPackageFragment().getCompilationUnit(name);
final ICompilationUnit copy= getSharedWorkingCopy(original.getPrimary(), new SubProgressMonitor(monitor, 10));
fSuperSource= createSuperTypeSource(copy, superType, declaringDeclaration, status, new SubProgressMonitor(monitor, 10));
if (fSuperSource != null) {
copy.getBuffer().setContents(fSuperSource);
JavaModelUtil.reconcile(copy);
}
}
} finally {
monitor.done();
}
return status;
}
/**
* Creates a working copy for the modified subtype.
*
* @param unit
* the compilation unit
* @param root
* the compilation unit node
* @param subDeclaration
* the declaration of the subtype to modify
* @param extractedType
* the extracted super type
* @param extractedBinding
* the binding of the extracted super type
* @param status
* the refactoring status
*/
protected void createModifiedSubType(final ICompilationUnit unit, final CompilationUnit root, final IType extractedType, final ITypeBinding extractedBinding, final AbstractTypeDeclaration subDeclaration, final RefactoringStatus status) {
Assert.isNotNull(unit);
Assert.isNotNull(subDeclaration);
Assert.isNotNull(extractedType);
try {
final CompilationUnitRewrite rewrite= new CompilationUnitRewrite(fOwner, unit, root);
createTypeSignature(rewrite, subDeclaration, extractedType, extractedBinding, new NullProgressMonitor());
final Document document= new Document(unit.getBuffer().getContents());
final CompilationUnitChange change= rewrite.createChange(true);
if (change != null) {
fLayerChanges.put(unit.getPrimary(), change);
final TextEdit edit= change.getEdit();
if (edit != null) {
final TextEditCopier copier= new TextEditCopier(edit);
final TextEdit copy= copier.perform();
copy.apply(document, TextEdit.NONE);
}
}
final ICompilationUnit copy= getSharedWorkingCopy(unit, new NullProgressMonitor());
copy.getBuffer().setContents(document.get());
JavaModelUtil.reconcile(copy);
} catch (CoreException | MalformedTreeException | BadLocationException exception) {
JavaPlugin.log(exception);
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
}
}
/**
* Creates the necessary constructors for the extracted supertype.
*
* @param targetRewrite
* the target compilation unit rewrite
* @param superType
* the super type, or <code>null</code> if no super type (ie.
* <code>java.lang.Object</code>) is available
* @param targetDeclaration
* the type declaration of the target type
* @param status
* the refactoring status
*/
protected void createNecessaryConstructors(final CompilationUnitRewrite targetRewrite, final IType superType, final AbstractTypeDeclaration targetDeclaration, final RefactoringStatus status) {
Assert.isNotNull(targetRewrite);
Assert.isNotNull(targetDeclaration);
if (superType != null) {
final ITypeBinding binding= targetDeclaration.resolveBinding();
if (binding != null && binding.isClass()) {
final IMethodBinding[] bindings= StubUtility2Core.getVisibleConstructors(binding, true, true);
int deprecationCount= 0;
for (IMethodBinding b : bindings) {
if (b.isDeprecated()) {
deprecationCount++;
}
}
final ListRewrite rewrite= targetRewrite.getASTRewrite().getListRewrite(targetDeclaration, TypeDeclaration.BODY_DECLARATIONS_PROPERTY);
if (rewrite != null) {
boolean createDeprecated= deprecationCount == bindings.length;
for (IMethodBinding curr : bindings) {
if (!curr.isDeprecated() || createDeprecated) {
MethodDeclaration stub;
try {
ImportRewriteContext context= new ContextSensitiveImportRewriteContext(targetDeclaration, targetRewrite.getImportRewrite());
stub= StubUtility2.createConstructorStub(targetRewrite.getCu(), targetRewrite.getASTRewrite(), targetRewrite.getImportRewrite(), context, curr, binding.getName(),
Modifier.PUBLIC, false, false, fSettings);
if (stub != null)
rewrite.insertLast(stub, null);
} catch (CoreException exception) {
JavaPlugin.log(exception);
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
}
}
}
}
}
}
}
/**
* Creates the source for the new compilation unit containing the supertype.
*
* @param extractedWorkingCopy
* the working copy of the new extracted supertype
* @param superType
* the super type, or <code>null</code> if no super type (ie.
* <code>java.lang.Object</code>) is available
* @param declaringDeclaration
* the declaration of the declaring type
* @param status
* the refactoring status
* @param monitor
* the progress monitor to display progress
* @return the source of the new compilation unit, or <code>null</code>
* @throws CoreException
* if an error occurs
*/
protected String createSuperTypeSource(final ICompilationUnit extractedWorkingCopy, final IType superType, final AbstractTypeDeclaration declaringDeclaration, final RefactoringStatus status, final IProgressMonitor monitor) throws CoreException {
Assert.isNotNull(extractedWorkingCopy);
Assert.isNotNull(declaringDeclaration);
Assert.isNotNull(status);
Assert.isNotNull(monitor);
String source= null;
try {
monitor.beginTask("", 2); //$NON-NLS-1$
monitor.setTaskName(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing);
final IType declaring= getDeclaringType();
final String delimiter= StubUtility.getLineDelimiterUsed(extractedWorkingCopy.getJavaProject());
String typeComment= null;
String fileComment= null;
if (fSettings.createComments) {
final ITypeParameter[] parameters= declaring.getTypeParameters();
final String[] names= new String[parameters.length];
for (int index= 0; index < parameters.length; index++)
names[index]= parameters[index].getElementName();
typeComment= CodeGeneration.getTypeComment(extractedWorkingCopy, fTypeName, names, delimiter);
fileComment= CodeGeneration.getFileComment(extractedWorkingCopy, delimiter);
}
final StringBuffer buffer= new StringBuffer(64);
final ITypeBinding binding= declaringDeclaration.resolveBinding();
if (binding != null) {
final ITypeBinding superBinding= binding.getSuperclass();
if (superBinding != null)
fTypeBindings.add(superBinding);
ITypeBinding[] typeParameters= binding.getTypeParameters();
Collections.addAll(fTypeBindings, typeParameters);
final ITypeBinding[] bindings= binding.getInterfaces();
Collections.addAll(fTypeBindings, bindings);
}
final String imports= createTypeImports(extractedWorkingCopy, monitor);
if (imports != null && !"".equals(imports)) { //$NON-NLS-1$
buffer.append(imports);
}
createTypeDeclaration(extractedWorkingCopy, superType, declaringDeclaration, typeComment, buffer, status, new SubProgressMonitor(monitor, 1));
source= createTypeTemplate(extractedWorkingCopy, "", fileComment, "", buffer.toString()); //$NON-NLS-1$ //$NON-NLS-2$
if (source == null) {
if (!declaring.getPackageFragment().isDefaultPackage()) {
if (imports != null && imports.length() > 0)
buffer.insert(0, imports);
buffer.insert(0, "package " + declaring.getPackageFragment().getElementName() + ";"); //$NON-NLS-1$//$NON-NLS-2$
}
source= buffer.toString();
}
final IDocument document= new Document(source);
final TextEdit edit= CodeFormatterUtil.format2(CodeFormatter.K_COMPILATION_UNIT, source, 0, delimiter, FormatterProfileManager.getProjectSettings(extractedWorkingCopy.getJavaProject()));
if (edit != null) {
try {
edit.apply(document, TextEdit.UPDATE_REGIONS);
} catch (MalformedTreeException | BadLocationException exception) {
JavaPlugin.log(exception);
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
}
source= document.get();
}
} finally {
monitor.done();
}
return source;
}
/**
* Creates the declaration of the new supertype, excluding any comments or
* package declaration.
*
* @param extractedWorkingCopy
* the working copy of the new extracted supertype
* @param superType
* the super type, or <code>null</code> if no super type (ie.
* <code>java.lang.Object</code>) is available
* @param declaringDeclaration
* the declaration of the declaring type
* @param comment
* the comment of the new type declaration
* @param buffer
* the string buffer containing the declaration
* @param status
* the refactoring status
* @param monitor
* the progress monitor to use
* @throws CoreException
* if an error occurs
*/
protected void createTypeDeclaration(final ICompilationUnit extractedWorkingCopy, final IType superType, final AbstractTypeDeclaration declaringDeclaration, final String comment, final StringBuffer buffer, final RefactoringStatus status, final IProgressMonitor monitor) throws CoreException {
Assert.isNotNull(extractedWorkingCopy);
Assert.isNotNull(declaringDeclaration);
Assert.isNotNull(buffer);
Assert.isNotNull(status);
Assert.isNotNull(monitor);
try {
monitor.beginTask("", 1); //$NON-NLS-1$
monitor.setTaskName(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing);
final IJavaProject project= extractedWorkingCopy.getJavaProject();
final String delimiter= StubUtility.getLineDelimiterUsed(project);
if (comment != null && !"".equals(comment)) { //$NON-NLS-1$
buffer.append(comment);
buffer.append(delimiter);
}
buffer.append(JdtFlags.VISIBILITY_STRING_PUBLIC);
if (superType != null && Flags.isAbstract(superType.getFlags())) {
buffer.append(' ');
buffer.append("abstract "); //$NON-NLS-1$
}
buffer.append(' ');
buffer.append("class "); //$NON-NLS-1$
buffer.append(fTypeName);
if (superType != null && !"java.lang.Object".equals(superType.getFullyQualifiedName())) { //$NON-NLS-1$
buffer.append(' ');
if (superType.isInterface())
buffer.append("implements "); //$NON-NLS-1$
else
buffer.append("extends "); //$NON-NLS-1$
buffer.append(superType.getElementName());
}
buffer.append(" {"); //$NON-NLS-1$
buffer.append(delimiter);
buffer.append(delimiter);
buffer.append('}');
final String string= buffer.toString();
extractedWorkingCopy.getBuffer().setContents(string);
final IDocument document= new Document(string);
final CompilationUnitRewrite targetRewrite= new CompilationUnitRewrite(fOwner, extractedWorkingCopy);
final AbstractTypeDeclaration targetDeclaration= (AbstractTypeDeclaration) targetRewrite.getRoot().types().get(0);
createTypeParameters(targetRewrite, superType, declaringDeclaration, targetDeclaration);
createTypeSignature(targetRewrite, superType, declaringDeclaration, targetDeclaration);
createNecessaryConstructors(targetRewrite, superType, targetDeclaration, status);
final TextEdit edit= targetRewrite.createChange(true).getEdit();
try {
edit.apply(document, TextEdit.UPDATE_REGIONS);
} catch (MalformedTreeException | BadLocationException exception) {
JavaPlugin.log(exception);
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
}
buffer.setLength(0);
buffer.append(document.get());
} finally {
monitor.done();
}
}
/**
* Creates the type parameters of the new supertype.
*
* @param targetRewrite
* the target compilation unit rewrite
* @param subType
* the subtype
* @param sourceDeclaration
* the type declaration of the source type
* @param targetDeclaration
* the type declaration of the target type
*/
protected void createTypeParameters(final CompilationUnitRewrite targetRewrite, final IType subType, final AbstractTypeDeclaration sourceDeclaration, final AbstractTypeDeclaration targetDeclaration) {
Assert.isNotNull(targetRewrite);
Assert.isNotNull(sourceDeclaration);
Assert.isNotNull(targetDeclaration);
if (sourceDeclaration instanceof TypeDeclaration) {
TypeParameter parameter= null;
final ListRewrite rewrite= targetRewrite.getASTRewrite().getListRewrite(targetDeclaration, TypeDeclaration.TYPE_PARAMETERS_PROPERTY);
for (final Iterator<TypeParameter> iterator= ((TypeDeclaration) sourceDeclaration).typeParameters().iterator(); iterator.hasNext();) {
parameter= iterator.next();
final ASTNode node= ASTNode.copySubtree(targetRewrite.getAST(), parameter);
rewrite.insertLast(node, null);
}
}
}
/**
* Creates a new type signature of a subtype.
*
* @param subRewrite
* the compilation unit rewrite of a subtype
* @param declaration
* the type declaration of a subtype
* @param extractedType
* the extracted super type
* @param extractedBinding
* the binding of the extracted super type
* @param monitor
* the progress monitor to use
* @throws JavaModelException
* if the type parameters cannot be retrieved
*/
protected void createTypeSignature(final CompilationUnitRewrite subRewrite, final AbstractTypeDeclaration declaration, final IType extractedType, final ITypeBinding extractedBinding, final IProgressMonitor monitor) throws JavaModelException {
Assert.isNotNull(subRewrite);
Assert.isNotNull(declaration);
Assert.isNotNull(extractedType);
Assert.isNotNull(monitor);
try {
monitor.beginTask(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing, 10);
final AST ast= subRewrite.getAST();
Type type= null;
if (extractedBinding != null) {
type= subRewrite.getImportRewrite().addImport(extractedBinding, ast);
} else {
subRewrite.getImportRewrite().addImport(extractedType.getFullyQualifiedName('.'));
type= ast.newSimpleType(ast.newSimpleName(extractedType.getElementName()));
}
subRewrite.getImportRemover().registerAddedImport(extractedType.getFullyQualifiedName('.'));
if (type != null) {
final ITypeParameter[] parameters= extractedType.getTypeParameters();
if (parameters.length > 0) {
final ParameterizedType parameterized= ast.newParameterizedType(type);
for (ITypeParameter parameter : parameters) {
parameterized.typeArguments().add(ast.newSimpleType(ast.newSimpleName(parameter.getElementName())));
}
type= parameterized;
}
}
final ASTRewrite rewriter= subRewrite.getASTRewrite();
if (type != null && declaration instanceof TypeDeclaration) {
final TypeDeclaration extended= (TypeDeclaration) declaration;
final Type superClass= extended.getSuperclassType();
if (superClass != null) {
rewriter.replace(superClass, type, subRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractSupertypeProcessor_add_supertype, SET_EXTRACT_SUPERTYPE));
subRewrite.getImportRemover().registerRemovedNode(superClass);
} else
rewriter.set(extended, TypeDeclaration.SUPERCLASS_TYPE_PROPERTY, type, subRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractSupertypeProcessor_add_supertype, SET_EXTRACT_SUPERTYPE));
}
} finally {
monitor.done();
}
}
/**
* Creates the type signature of the extracted supertype.
*
* @param targetRewrite
* the target compilation unit rewrite
* @param superType
* the super type, or <code>null</code> if no super type (ie.
* <code>java.lang.Object</code>) is available
* @param declaringDeclaration
* the declaration of the declaring type
* @param targetDeclaration
* the type declaration of the target type
*/
protected void createTypeSignature(final CompilationUnitRewrite targetRewrite, final IType superType, final AbstractTypeDeclaration declaringDeclaration, final AbstractTypeDeclaration targetDeclaration) {
Assert.isNotNull(targetRewrite);
Assert.isNotNull(declaringDeclaration);
Assert.isNotNull(targetDeclaration);
if (declaringDeclaration instanceof TypeDeclaration) {
final TypeDeclaration declaration= (TypeDeclaration) declaringDeclaration;
final Type superclassType= declaration.getSuperclassType();
if (superclassType != null) {
Type type= null;
final ITypeBinding binding= superclassType.resolveBinding();
if (binding != null) {
type= targetRewrite.getImportRewrite().addImport(binding, targetRewrite.getAST());
targetRewrite.getImportRemover().registerAddedImports(type);
}
if (type != null && targetDeclaration instanceof TypeDeclaration) {
final TypeDeclaration extended= (TypeDeclaration) targetDeclaration;
final Type targetSuperType= extended.getSuperclassType();
if (targetSuperType != null) {
targetRewrite.getASTRewrite().replace(targetSuperType, type, null);
} else {
targetRewrite.getASTRewrite().set(extended, TypeDeclaration.SUPERCLASS_TYPE_PROPERTY, type, null);
}
}
}
}
}
@Override
public RefactoringStatus createWorkingCopyLayer(final IProgressMonitor monitor) {
Assert.isNotNull(monitor);
final RefactoringStatus status= new RefactoringStatus();
try {
monitor.beginTask(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing, 70);
status.merge(super.createWorkingCopyLayer(new SubProgressMonitor(monitor, 10)));
final IType declaring= getDeclaringType();
status.merge(createExtractedSuperType(getDeclaringSuperTypeHierarchy(new SubProgressMonitor(monitor, 10)).getSuperclass(declaring), new SubProgressMonitor(monitor, 10)));
if (status.hasFatalError())
return status;
final IType extractedType= computeExtractedType(fTypeName);
setDestinationType(extractedType);
final List<IType> subTypes= new ArrayList<>(Arrays.asList(fTypesToExtract));
if (!subTypes.contains(declaring))
subTypes.add(declaring);
final Map<ICompilationUnit, Collection<IType>> unitToTypes= new HashMap<>(subTypes.size());
final Set<ICompilationUnit> units= new HashSet<>(subTypes.size());
for (final IType type : subTypes) {
final ICompilationUnit unit= type.getCompilationUnit();
units.add(unit);
Collection<IType> collection= unitToTypes.get(unit);
if (collection == null) {
collection= new ArrayList<>(2);
unitToTypes.put(unit, collection);
}
collection.add(type);
}
final Map<IJavaProject, Collection<ICompilationUnit>> projectToUnits= new HashMap<>();
Collection<ICompilationUnit> collection= null;
IJavaProject project= null;
ICompilationUnit current= null;
for (final Iterator<ICompilationUnit> iterator= units.iterator(); iterator.hasNext();) {
current= iterator.next();
project= current.getJavaProject();
collection= projectToUnits.get(project);
if (collection == null) {
collection= new ArrayList<>();
projectToUnits.put(project, collection);
}
collection.add(current);
}
final ITypeBinding[] extractBindings= { null};
final ASTParser extractParser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL);
extractParser.setWorkingCopyOwner(fOwner);
extractParser.setResolveBindings(true);
extractParser.setProject(project);
extractParser.setSource(extractedType.getCompilationUnit());
final CompilationUnit extractUnit= (CompilationUnit) extractParser.createAST(new SubProgressMonitor(monitor, 10));
if (extractUnit != null) {
final AbstractTypeDeclaration extractDeclaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(extractedType, extractUnit);
if (extractDeclaration != null)
extractBindings[0]= extractDeclaration.resolveBinding();
}
final ASTParser parser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL);
final IProgressMonitor subMonitor= new SubProgressMonitor(monitor, 30);
try {
final Set<IJavaProject> keySet= projectToUnits.keySet();
subMonitor.beginTask("", keySet.size()); //$NON-NLS-1$
subMonitor.setTaskName(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing);
for (final Iterator<IJavaProject> iterator= keySet.iterator(); iterator.hasNext();) {
project= iterator.next();
collection= projectToUnits.get(project);
parser.setWorkingCopyOwner(fOwner);
parser.setResolveBindings(true);
parser.setProject(project);
parser.setCompilerOptions(RefactoringASTParser.getCompilerOptions(project));
final IProgressMonitor subsubMonitor= new SubProgressMonitor(subMonitor, 1);
try {
subsubMonitor.beginTask("", collection.size()); //$NON-NLS-1$
subsubMonitor.setTaskName(RefactoringCoreMessages.ExtractSupertypeProcessor_preparing);
parser.createASTs(collection.toArray(new ICompilationUnit[collection.size()]), new String[0], new ASTRequestor() {
@Override
public final void acceptAST(final ICompilationUnit unit, final CompilationUnit node) {
try {
final Collection<IType> types= unitToTypes.get(unit);
if (types != null) {
for (IType currentType : types) {
final AbstractTypeDeclaration currentDeclaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(currentType, node);
if (currentDeclaration != null)
createModifiedSubType(unit, node, extractedType, extractBindings[0], currentDeclaration, status);
}
}
} catch (CoreException exception) {
JavaPlugin.log(exception);
status.merge(RefactoringStatus.createFatalErrorStatus(exception.getLocalizedMessage()));
} finally {
subsubMonitor.worked(1);
}
}
@Override
public final void acceptBinding(final String key, final IBinding binding) {
// Do nothing
}
}, subsubMonitor);
} finally {
subsubMonitor.done();
}
}
} finally {
subMonitor.done();
}
} catch (CoreException exception) {
JavaPlugin.log(exception);
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractSupertypeProcessor_unexpected_exception_on_layer));
} finally {
monitor.done();
}
return status;
}
@Override
public IType[] getCandidateTypes(final RefactoringStatus status, final IProgressMonitor monitor) {
Assert.isNotNull(monitor);
if (fPossibleCandidates == null || fPossibleCandidates.length == 0) {
final IType declaring= getDeclaringType();
if (declaring != null) {
try {
monitor.beginTask(RefactoringCoreMessages.ExtractSupertypeProcessor_computing_possible_types, 10);
final IType superType= getDeclaringSuperTypeHierarchy(new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)).getSuperclass(declaring);
if (superType != null) {
fPossibleCandidates= superType.newTypeHierarchy(fOwner, new SubProgressMonitor(monitor, 9, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)).getSubtypes(superType);
final LinkedList<IType> list= new LinkedList<>(Arrays.asList(fPossibleCandidates));
final Set<String> names= new HashSet<>();
for (final Iterator<IType> iterator= list.iterator(); iterator.hasNext();) {
final IType type= iterator.next();
if (type.isReadOnly() || type.isBinary() || type.isAnonymous() || !type.isClass() || names.contains(type.getFullyQualifiedName()))
iterator.remove();
else
names.add(type.getFullyQualifiedName());
}
fPossibleCandidates= list.toArray(new IType[list.size()]);
}
} catch (JavaModelException exception) {
JavaPlugin.log(exception);
} finally {
monitor.done();
}
}
}
return fPossibleCandidates;
}
@Override
public Object[] getElements() {
return new Object[] { getDeclaringType()};
}
/**
* Returns the extracted type.
*
* @return the extracted type, or <code>null</code>
*/
public IType getExtractedType() {
return getDestinationType();
}
/**
* Returns the type name.
*
* @return the type name
*/
public String getTypeName() {
return fTypeName;
}
/**
* Returns the types to extract. The declaring type may or may not be
* contained in the result.
*
* @return the types to extract
*/
public IType[] getTypesToExtract() {
return fTypesToExtract;
}
private RefactoringStatus initialize(JavaRefactoringArguments extended) {
final String name= extended.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME);
if (name != null && !"".equals(name)) //$NON-NLS-1$
fTypeName= name;
else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME));
String handle= extended.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
if (handle != null) {
final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(extended.getProject(), handle, false);
if (element == null || element.getElementType() != IJavaElement.TYPE)
return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getProcessorName(), IJavaRefactorings.EXTRACT_SUPERCLASS);
IType type= null;
final ICompilationUnit unit= ((IType) element).getCompilationUnit();
if (unit != null && unit.exists()) {
try {
final ICompilationUnit copy= getSharedWorkingCopy(unit, new NullProgressMonitor());
final IJavaElement[] elements= copy.findElements(element);
if (elements != null && elements.length == 1 && elements[0] instanceof IType && elements[0].exists())
type= (IType) elements[0];
} catch (JavaModelException exception) {
// TODO: log exception
}
}
if (type != null)
fCachedDeclaringType= type;
else
return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getProcessorName(), IJavaRefactorings.EXTRACT_SUPERCLASS);
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
final String stubs= extended.getAttribute(ATTRIBUTE_STUBS);
if (stubs != null) {
fCreateMethodStubs= Boolean.parseBoolean(stubs);
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_STUBS));
final String instance= extended.getAttribute(ATTRIBUTE_INSTANCEOF);
if (instance != null) {
fInstanceOf= Boolean.parseBoolean(instance);
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_INSTANCEOF));
final String replace= extended.getAttribute(ATTRIBUTE_REPLACE);
if (replace != null) {
fReplace= Boolean.parseBoolean(replace);
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_REPLACE));
int extractCount= 0;
int abstractCount= 0;
int deleteCount= 0;
int typeCount= 0;
String value= extended.getAttribute(ATTRIBUTE_ABSTRACT);
if (value != null && !"".equals(value)) {//$NON-NLS-1$
try {
abstractCount= Integer.parseInt(value);
} catch (NumberFormatException exception) {
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_ABSTRACT));
}
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_ABSTRACT));
value= extended.getAttribute(ATTRIBUTE_DELETE);
if (value != null && !"".equals(value)) {//$NON-NLS-1$
try {
deleteCount= Integer.parseInt(value);
} catch (NumberFormatException exception) {
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_DELETE));
}
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_DELETE));
value= extended.getAttribute(ATTRIBUTE_EXTRACT);
if (value != null && !"".equals(value)) {//$NON-NLS-1$
try {
extractCount= Integer.parseInt(value);
} catch (NumberFormatException exception) {
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_EXTRACT));
}
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_EXTRACT));
value= extended.getAttribute(ATTRIBUTE_TYPES);
if (value != null && !"".equals(value)) {//$NON-NLS-1$
try {
typeCount= Integer.parseInt(value);
} catch (NumberFormatException exception) {
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_TYPES));
}
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_TYPES));
final RefactoringStatus status= new RefactoringStatus();
List<IJavaElement> elements= new ArrayList<>();
for (int index= 0; index < extractCount; index++) {
final String attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + (index + 1);
handle= extended.getAttribute(attribute);
if (handle != null && !"".equals(handle)) { //$NON-NLS-1$
final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(fOwner, extended.getProject(), handle, false);
if (element == null || !element.exists())
status.merge(JavaRefactoringDescriptorUtil.createInputWarningStatus(element, getProcessorName(), IJavaRefactorings.EXTRACT_SUPERCLASS));
else
elements.add(element);
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, attribute));
}
fMembersToMove= elements.toArray(new IMember[elements.size()]);
elements= new ArrayList<>();
for (int index= 0; index < deleteCount; index++) {
final String attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + (extractCount + index + 1);
handle= extended.getAttribute(attribute);
if (handle != null && !"".equals(handle)) { //$NON-NLS-1$
final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(fOwner, extended.getProject(), handle, false);
if (element == null || !element.exists())
status.merge(JavaRefactoringDescriptorUtil.createInputWarningStatus(element, getProcessorName(), IJavaRefactorings.EXTRACT_SUPERCLASS));
else
elements.add(element);
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, attribute));
}
fDeletedMethods= elements.toArray(new IMethod[elements.size()]);
elements= new ArrayList<>();
for (int index= 0; index < abstractCount; index++) {
final String attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + (extractCount + abstractCount + index + 1);
handle= extended.getAttribute(attribute);
if (handle != null && !"".equals(handle)) { //$NON-NLS-1$
final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(fOwner, extended.getProject(), handle, false);
if (element == null || !element.exists())
status.merge(JavaRefactoringDescriptorUtil.createInputWarningStatus(element, getProcessorName(), IJavaRefactorings.EXTRACT_SUPERCLASS));
else
elements.add(element);
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, attribute));
}
fAbstractMethods= elements.toArray(new IMethod[elements.size()]);
elements= new ArrayList<>();
for (int index= 0; index < typeCount; index++) {
final String attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + (extractCount + abstractCount + deleteCount + index + 1);
handle= extended.getAttribute(attribute);
if (handle != null && !"".equals(handle)) { //$NON-NLS-1$
final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(fOwner, extended.getProject(), handle, false);
if (element == null || !element.exists())
status.merge(JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getProcessorName(), IJavaRefactorings.EXTRACT_SUPERCLASS));
else
elements.add(element);
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, attribute));
}
fTypesToExtract= elements.toArray(new IType[elements.size()]);
IJavaProject project= null;
if (fMembersToMove.length > 0)
project= fMembersToMove[0].getJavaProject();
fSettings= JavaPreferencesSettings.getCodeGenerationSettings(project);
if (!status.isOK())
return status;
return new RefactoringStatus();
}
@Override
protected void registerChanges(final TextEditBasedChangeManager manager) throws CoreException {
try {
final ICompilationUnit extractedUnit= getExtractedType().getCompilationUnit();
ICompilationUnit unit= null;
CompilationUnitRewrite rewrite= null;
for (final Iterator<ICompilationUnit> iterator= fCompilationUnitRewrites.keySet().iterator(); iterator.hasNext();) {
unit= iterator.next();
if (unit.equals(extractedUnit)) {
rewrite= fCompilationUnitRewrites.get(unit);
if (rewrite != null) {
CompilationUnitChange change= rewrite.createChange(true);
if (change != null) {
final TextEdit edit= ((TextChange) change).getEdit();
if (edit != null) {
final IDocument document= new Document(fSuperSource);
try {
edit.apply(document, TextEdit.UPDATE_REGIONS);
} catch (MalformedTreeException | BadLocationException exception) {
JavaPlugin.log(exception);
}
fSuperSource= document.get();
manager.remove(extractedUnit);
}
}
}
} else {
rewrite= fCompilationUnitRewrites.get(unit);
if (rewrite != null) {
final CompilationUnitChange layerChange= fLayerChanges.get(unit.getPrimary());
final CompilationUnitChange rewriteChange= rewrite.createChange(true);
if (rewriteChange != null && layerChange != null) {
final MultiStateCompilationUnitChange change= new MultiStateCompilationUnitChange(rewriteChange.getName(), unit);
change.addChange(layerChange);
change.addChange(rewriteChange);
fLayerChanges.remove(unit.getPrimary());
manager.manage(unit, change);
} else if (layerChange != null) {
manager.manage(unit, layerChange);
fLayerChanges.remove(unit.getPrimary());
} else if (rewriteChange != null) {
manager.manage(unit, rewriteChange);
}
}
}
}
for (Entry<ICompilationUnit, CompilationUnitChange> entry : fLayerChanges.entrySet()) {
manager.manage(entry.getKey(), entry.getValue());
}
for (ICompilationUnit cu : manager.getAllCompilationUnits()) {
if (cu.getPath().equals(extractedUnit.getPath())) {
manager.remove(cu);
}
}
} finally {
fLayerChanges.clear();
}
}
/**
* Resets the changes necessary for the working copy layer.
*/
public void resetChanges() {
fLayerChanges.clear();
}
/**
* Sets the type name.
*
* @param name
* the type name
*/
public void setTypeName(final String name) {
Assert.isNotNull(name);
fTypeName= name;
}
/**
* Sets the types to extract. Must be a subset of
* <code>getPossibleCandidates()</code>. If the declaring type is not
* contained, it will automatically be added.
*
* @param types
* the types to extract
*/
public void setTypesToExtract(final IType[] types) {
Assert.isNotNull(types);
fTypesToExtract= types;
}
}