blob: c1d0ab0bc2d3a18cff38374be365e1d607d9043a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 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
* Jerome Cambon <jerome.cambon@oracle.com> - [code style] don't generate redundant modifiers "public static final abstract" for interface members - https://bugs.eclipse.org/71627
*******************************************************************************/
package org.eclipse.jdt.internal.corext.refactoring.structure;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
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.core.filebuffers.ITextFileBuffer;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.TextEdit;
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.TextEditBasedChange;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
import org.eclipse.ltk.core.refactoring.participants.SharableParticipants;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
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.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeParameter;
import org.eclipse.jdt.core.JavaCore;
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.Annotation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.EnumDeclaration;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IExtendedModifier;
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.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jdt.core.manipulation.CodeGeneration;
import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
import org.eclipse.jdt.core.refactoring.descriptors.ExtractInterfaceDescriptor;
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.manipulation.util.Strings;
import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory;
import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2Core;
import org.eclipse.jdt.internal.corext.dom.Bindings;
import org.eclipse.jdt.internal.corext.dom.IASTSharedValues;
import org.eclipse.jdt.internal.corext.dom.ModifierRewrite;
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.reorg.ASTNodeDeleteUtil;
import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsModel;
import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsSolver;
import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeRefactoringProcessor;
import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompilationUnitRange;
import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeConstraintVariable;
import org.eclipse.jdt.internal.corext.refactoring.util.JavaStatusContext;
import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringFileBuffers;
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.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;
/**
* Refactoring processor to extract interfaces.
*/
public final class ExtractInterfaceProcessor extends SuperTypeRefactoringProcessor {
private static final String ATTRIBUTE_COMMENTS= "comments"; //$NON-NLS-1$
/** The identifier of this processor */
public static final String IDENTIFIER= "org.eclipse.jdt.ui.extractInterfaceProcessor"; //$NON-NLS-1$
/** The extract interface group category set */
private static final GroupCategorySet SET_EXTRACT_INTERFACE= new GroupCategorySet(new GroupCategory("org.eclipse.jdt.internal.corext.extractInterface", //$NON-NLS-1$
RefactoringCoreMessages.ExtractInterfaceProcessor_category_name, RefactoringCoreMessages.ExtractInterfaceProcessor_category_description));
/**
* Is the specified member extractable from the type?
*
* @param member
* the member to test
* @return <code>true</code> if the member is extractable,
* <code>false</code> otherwise
* @throws JavaModelException
* if an error occurs
*/
protected static boolean isExtractableMember(final IMember member) throws JavaModelException {
Assert.isNotNull(member);
switch (member.getElementType()) {
case IJavaElement.METHOD:
return JdtFlags.isPublic(member) && !JdtFlags.isStatic(member) && !((IMethod) member).isConstructor();
case IJavaElement.FIELD:
return JdtFlags.isPublic(member) && JdtFlags.isStatic(member) && JdtFlags.isFinal(member) && !JdtFlags.isEnum(member);
default:
return false;
}
}
/** Should override annotations be generated? */
private boolean fAnnotations= false;
/** The text edit based change manager */
private TextEditBasedChangeManager fChangeManager= null;
/** Should comments be generated? */
private boolean fComments= true;
/** The members to extract */
private IMember[] fMembers= null;
/** The subtype where to extract the supertype */
private IType fSubType;
/** The supertype name */
private String fSuperName;
/** The source of the new supertype */
private String fSuperSource= null;
/**
* Creates a new extract interface processor.
*
* @param type
* the type where to extract the supertype, or <code>null</code>
* if invoked by scripting
* @param settings
* the code generation settings, or <code>null</code> if
* invoked by scripting
*/
public ExtractInterfaceProcessor(final IType type, final CodeGenerationSettings settings) {
super(settings);
fSubType= type;
if (fSubType != null)
fSuperName= fSubType.getElementName();
}
/**
* Creates a new extract interface processor from refactoring arguments.
*
* @param arguments
* the refactoring arguments
* @param status
* the resulting status
*/
public ExtractInterfaceProcessor(JavaRefactoringArguments arguments, RefactoringStatus status) {
super(null);
RefactoringStatus initializeStatus= initialize(arguments);
status.merge(initializeStatus);
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#checkFinalConditions(org.eclipse.core.runtime.IProgressMonitor,org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext)
*/
@Override
public final RefactoringStatus checkFinalConditions(final IProgressMonitor monitor, final CheckConditionsContext context) throws CoreException, OperationCanceledException {
Assert.isNotNull(monitor);
Assert.isNotNull(context);
final RefactoringStatus status= new RefactoringStatus();
fChangeManager= new TextEditBasedChangeManager();
try {
monitor.beginTask("", 1); //$NON-NLS-1$
monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_checking);
status.merge(Checks.checkIfCuBroken(fSubType));
if (!status.hasError()) {
if (fSubType.isBinary() || fSubType.isReadOnly() || !fSubType.exists())
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_no_binary, JavaStatusContext.create(fSubType)));
else if (fSubType.isAnonymous())
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_no_anonymous, JavaStatusContext.create(fSubType)));
else if (fSubType.isAnnotation())
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_no_annotation, JavaStatusContext.create(fSubType)));
else {
status.merge(checkSuperType());
if (!status.hasFatalError()) {
if (!status.hasFatalError()) {
fChangeManager= createChangeManager(new SubProgressMonitor(monitor, 1), status);
if (!status.hasFatalError()) {
Checks.addModifiedFilesToChecker(ResourceUtil.getFiles(fChangeManager.getAllCompilationUnits()), context);
}
}
}
}
}
} finally {
monitor.done();
}
return status;
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public final RefactoringStatus checkInitialConditions(final IProgressMonitor monitor) throws CoreException, OperationCanceledException {
Assert.isNotNull(monitor);
final RefactoringStatus status= new RefactoringStatus();
try {
monitor.beginTask("", 1); //$NON-NLS-1$
monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_checking);
status.merge(Checks.checkIfCuBroken(fSubType));
monitor.worked(1);
} finally {
monitor.done();
}
return status;
}
/**
* Checks whether the supertype clashes with existing types.
*
* @return the status of the condition checking
* @throws JavaModelException
* if an error occurs
*/
protected final RefactoringStatus checkSuperType() throws JavaModelException {
final IPackageFragment fragment= fSubType.getPackageFragment();
final IType type= Checks.findTypeInPackage(fragment, fSuperName);
if (type != null && type.exists()) {
if (fragment.isDefaultPackage())
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_existing_default_type, BasicElementLabels.getJavaElementName(fSuperName)));
else {
String packageLabel= JavaElementLabels.getElementLabel(fragment, JavaElementLabels.ALL_DEFAULT);
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_existing_type, new String[] { BasicElementLabels.getJavaElementName(fSuperName), packageLabel }));
}
}
return new RefactoringStatus();
}
/**
* Checks whether the type name is valid.
*
* @param name
* the name to check
* @return the status of the condition checking
*/
public final RefactoringStatus checkTypeName(final String name) {
Assert.isNotNull(name);
try {
final RefactoringStatus result= Checks.checkTypeName(name, fSubType);
if (result.hasFatalError())
return result;
final String unitName= JavaModelUtil.getRenamedCUName(fSubType.getCompilationUnit(), name);
result.merge(Checks.checkCompilationUnitName(unitName, fSubType));
if (result.hasFatalError())
return result;
final IPackageFragment fragment= fSubType.getPackageFragment();
if (fragment.getCompilationUnit(unitName).exists()) {
result.addFatalError(Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_existing_compilation_unit, new String[] { BasicElementLabels.getResourceName(unitName), JavaElementLabels.getElementLabel(fragment, JavaElementLabels.ALL_DEFAULT) }));
return result;
}
result.merge(checkSuperType());
return result;
} catch (JavaModelException exception) {
return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error);
}
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#createChange(org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public final Change createChange(final IProgressMonitor monitor) throws CoreException, OperationCanceledException {
Assert.isNotNull(monitor);
try {
monitor.beginTask("", 1); //$NON-NLS-1$
monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
final Map<String, String> arguments= new HashMap<>();
String project= null;
final IJavaProject javaProject= fSubType.getJavaProject();
if (javaProject != null)
project= javaProject.getElementName();
int flags= JavaRefactoringDescriptor.JAR_MIGRATION | JavaRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE;
try {
if (fSubType.isLocal() || fSubType.isAnonymous())
flags|= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
} catch (JavaModelException exception) {
JavaPlugin.log(exception);
}
final IPackageFragment fragment= fSubType.getPackageFragment();
final ICompilationUnit cu= fragment.getCompilationUnit(JavaModelUtil.getRenamedCUName(fSubType.getCompilationUnit(), fSuperName));
final IType type= cu.getType(fSuperName);
final String description= Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_description_descriptor_short, BasicElementLabels.getJavaElementName(fSuperName));
final String header= Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_descriptor_description, new String[] { JavaElementLabels.getElementLabel(type, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getElementLabel(fSubType, JavaElementLabels.ALL_FULLY_QUALIFIED) });
final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_refactored_element_pattern, JavaElementLabels.getElementLabel(type, JavaElementLabels.ALL_FULLY_QUALIFIED)));
final String[] settings= new String[fMembers.length];
for (int index= 0; index < settings.length; index++)
settings[index]= JavaElementLabels.getElementLabel(fMembers[index], JavaElementLabels.ALL_FULLY_QUALIFIED);
comment.addSetting(JDTRefactoringDescriptorComment.createCompositeSetting(RefactoringCoreMessages.ExtractInterfaceProcessor_extracted_members_pattern, settings));
addSuperTypeSettings(comment, true);
final ExtractInterfaceDescriptor descriptor= RefactoringSignatureDescriptorFactory.createExtractInterfaceDescriptor(project, description, comment.asString(), arguments, flags);
arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT, JavaRefactoringDescriptorUtil.elementToHandle(project, fSubType));
arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME, fSuperName);
for (int index= 0; index < fMembers.length; index++)
arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + (index + 1), JavaRefactoringDescriptorUtil.elementToHandle(project, fMembers[index]));
arguments.put(ATTRIBUTE_COMMENTS, Boolean.valueOf(fComments).toString());
arguments.put(ATTRIBUTE_REPLACE, Boolean.valueOf(fReplace).toString());
arguments.put(ATTRIBUTE_INSTANCEOF, Boolean.valueOf(fInstanceOf).toString());
final DynamicValidationRefactoringChange change= new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.ExtractInterfaceRefactoring_name, fChangeManager.getAllChanges());
final IFile file= ResourceUtil.getFile(fSubType.getCompilationUnit());
if (fSuperSource != null && fSuperSource.length() > 0)
change.add(new CreateCompilationUnitChange(fSubType.getPackageFragment().getCompilationUnit(JavaModelUtil.getRenamedCUName(fSubType.getCompilationUnit(), fSuperName)), fSuperSource, file.getCharset(false)));
monitor.worked(1);
return change;
} finally {
monitor.done();
}
}
/**
* Creates the text change manager for this processor.
*
* @param monitor
* the progress monitor to display progress
* @param status
* the refactoring status
* @return the created text change manager
* @throws JavaModelException
* if the method declaration could not be found
* @throws CoreException
* if the changes could not be generated
*/
protected final TextEditBasedChangeManager createChangeManager(final IProgressMonitor monitor, final RefactoringStatus status) throws JavaModelException, CoreException {
Assert.isNotNull(status);
Assert.isNotNull(monitor);
try {
monitor.beginTask("", 300); //$NON-NLS-1$
monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
resetEnvironment();
final TextEditBasedChangeManager manager= new TextEditBasedChangeManager();
final CompilationUnitRewrite sourceRewrite= new CompilationUnitRewrite(fSubType.getCompilationUnit());
final AbstractTypeDeclaration declaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(fSubType, sourceRewrite.getRoot());
if (declaration != null) {
createTypeSignature(sourceRewrite, declaration, status, new SubProgressMonitor(monitor, 20));
final IField[] fields= getExtractedFields(fSubType.getCompilationUnit());
if (fields.length > 0)
ASTNodeDeleteUtil.markAsDeleted(fields, sourceRewrite, sourceRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_remove_field_label, SET_EXTRACT_INTERFACE));
if (fSubType.isInterface()) {
final IMethod[] methods= getExtractedMethods(fSubType.getCompilationUnit());
if (methods.length > 0)
ASTNodeDeleteUtil.markAsDeleted(methods, sourceRewrite, sourceRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_remove_method_label, SET_EXTRACT_INTERFACE));
}
final String name= JavaModelUtil.getRenamedCUName(fSubType.getCompilationUnit(), fSuperName);
final ICompilationUnit original= fSubType.getPackageFragment().getCompilationUnit(name);
final ICompilationUnit copy= getSharedWorkingCopy(original.getPrimary(), new SubProgressMonitor(monitor, 20));
fSuperSource= createTypeSource(copy, fSubType, fSuperName, sourceRewrite, declaration, status, new SubProgressMonitor(monitor, 40));
if (fSuperSource != null) {
copy.getBuffer().setContents(fSuperSource);
JavaModelUtil.reconcile(copy);
}
final Set<String> replacements= new HashSet<>();
if (fReplace)
rewriteTypeOccurrences(manager, sourceRewrite, copy, replacements, status, new SubProgressMonitor(monitor, 220));
rewriteSourceMethods(sourceRewrite, replacements);
manager.manage(fSubType.getCompilationUnit(), sourceRewrite.createChange(true));
}
return manager;
} finally {
monitor.done();
}
}
/*
* @see org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeRefactoringProcessor#createContraintSolver(org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsModel)
*/
@Override
protected final SuperTypeConstraintsSolver createContraintSolver(final SuperTypeConstraintsModel model) {
return new ExtractInterfaceConstraintsSolver(model, fSuperName);
}
/**
* Creates a target field declaration.
*
* @param sourceRewrite
* the source compilation unit rewrite
* @param targetRewrite
* the target rewrite
* @param targetDeclaration
* the target type declaration
* @param fragment
* the source variable declaration fragment
* @throws CoreException
* if a buffer could not be retrieved
*/
protected final void createFieldDeclaration(final CompilationUnitRewrite sourceRewrite, final ASTRewrite targetRewrite, final AbstractTypeDeclaration targetDeclaration, final VariableDeclarationFragment fragment) throws CoreException {
Assert.isNotNull(targetDeclaration);
Assert.isNotNull(sourceRewrite);
Assert.isNotNull(targetRewrite);
Assert.isNotNull(fragment);
final FieldDeclaration field= (FieldDeclaration) fragment.getParent();
ImportRewriteUtil.collectImports(fSubType.getJavaProject(), field, fTypeBindings, fStaticBindings, false);
final ASTRewrite rewrite= ASTRewrite.create(field.getAST());
final ITrackedNodePosition position= rewrite.track(field);
final ListRewrite rewriter= rewrite.getListRewrite(field, FieldDeclaration.FRAGMENTS_PROPERTY);
VariableDeclarationFragment current= null;
for (final Iterator<VariableDeclarationFragment> iterator= field.fragments().iterator(); iterator.hasNext();) {
current= iterator.next();
if (!current.getName().getIdentifier().equals(fragment.getName().getIdentifier()))
rewriter.remove(current, null);
}
int modifiers= field.getModifiers();
modifiers= JdtFlags.clearAccessModifiers(modifiers);
modifiers= JdtFlags.clearFlag(Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL, modifiers);
ModifierRewrite.create(rewrite, field).setModifiers(modifiers, null);
final ICompilationUnit unit= sourceRewrite.getCu();
final ITextFileBuffer buffer= RefactoringFileBuffers.acquire(unit);
try {
final IDocument document= new Document(buffer.getDocument().get());
try {
rewrite.rewriteAST(document, unit.getJavaProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
targetRewrite.getListRewrite(targetDeclaration, targetDeclaration.getBodyDeclarationsProperty()).insertFirst(targetRewrite.createStringPlaceholder(normalizeText(document.get(position.getStartPosition(), position.getLength())), ASTNode.FIELD_DECLARATION), null);
} catch (MalformedTreeException exception) {
JavaPlugin.log(exception);
} catch (BadLocationException exception) {
JavaPlugin.log(exception);
}
} finally {
RefactoringFileBuffers.release(unit);
}
}
@Override
protected final void createMemberDeclarations(final CompilationUnitRewrite sourceRewrite, final ASTRewrite targetRewrite, final AbstractTypeDeclaration targetDeclaration) throws CoreException {
Assert.isNotNull(sourceRewrite);
Assert.isNotNull(targetRewrite);
Assert.isNotNull(targetDeclaration);
Arrays.sort(fMembers, new Comparator<IMember>() {
@Override
public final int compare(final IMember first, final IMember second) {
try {
return first.getSourceRange().getOffset() - second.getSourceRange().getOffset();
} catch (JavaModelException exception) {
return first.hashCode() - second.hashCode();
}
}
});
fTypeBindings.clear();
fStaticBindings.clear();
if (fMembers.length > 0) {
IMember member= null;
for (int index= fMembers.length - 1; index >= 0; index--) {
member= fMembers[index];
if (member instanceof IField) {
createFieldDeclaration(sourceRewrite, targetRewrite, targetDeclaration, ASTNodeSearchUtil.getFieldDeclarationFragmentNode((IField) member, sourceRewrite.getRoot()));
} else if (member instanceof IMethod) {
createMethodDeclaration(sourceRewrite, targetRewrite, targetDeclaration, ASTNodeSearchUtil.getMethodDeclarationNode((IMethod) member, sourceRewrite.getRoot()));
}
}
}
}
/**
* Creates the method comment for the specified declaration.
*
* @param sourceRewrite
* the compilation unit rewrite
* @param declaration
* the method declaration
* @param replacements
* the set of variable binding keys of formal parameters which
* must be replaced
* @param javadoc
* <code>true</code> if javadoc comments are processed,
* <code>false</code> otherwise
* @throws CoreException
* if an error occurs
*/
protected final void createMethodComment(final CompilationUnitRewrite sourceRewrite, final MethodDeclaration declaration, final Set<String> replacements, final boolean javadoc) throws CoreException {
Assert.isNotNull(sourceRewrite);
Assert.isNotNull(declaration);
Assert.isNotNull(replacements);
final IMethodBinding binding= declaration.resolveBinding();
if (binding != null) {
IVariableBinding variable= null;
SingleVariableDeclaration argument= null;
final IPackageFragment fragment= fSubType.getPackageFragment();
final String string= fragment.isDefaultPackage() ? fSuperName : fragment.getElementName() + "." + fSuperName; //$NON-NLS-1$
final ITypeBinding[] bindings= binding.getParameterTypes();
final String[] names= new String[bindings.length];
for (int offset= 0; offset < names.length; offset++) {
argument= (SingleVariableDeclaration) declaration.parameters().get(offset);
variable= argument.resolveBinding();
if (variable != null) {
if (replacements.contains(variable.getKey()))
names[offset]= string;
else {
if (binding.isVarargs() && bindings[offset].isArray() && offset == names.length - 1)
names[offset]= Bindings.getFullyQualifiedName(bindings[offset].getElementType());
else
names[offset]= Bindings.getFullyQualifiedName(bindings[offset]);
}
}
}
final String comment= CodeGeneration.getMethodComment(fSubType.getCompilationUnit(), fSubType.getElementName(), declaration, false, binding.getName(), string, names, StubUtility.getLineDelimiterUsed(fSubType.getJavaProject()));
if (comment != null) {
final ASTRewrite rewrite= sourceRewrite.getASTRewrite();
if (declaration.getJavadoc() != null) {
rewrite.replace(declaration.getJavadoc(), rewrite.createStringPlaceholder(comment, ASTNode.JAVADOC), sourceRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_rewrite_comment, SET_EXTRACT_INTERFACE));
} else if (javadoc) {
rewrite.set(declaration, MethodDeclaration.JAVADOC_PROPERTY, rewrite.createStringPlaceholder(comment, ASTNode.JAVADOC), sourceRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_add_comment, SET_EXTRACT_INTERFACE));
}
}
}
}
/**
* Rewrites the extracted methods in the source type.
* Adds/removes method annotations and adds method comments.
*
* @param sourceRewrite
* the source compilation unit rewrite
* @param replacements
* the set of variable binding keys of formal parameters which
* must be replaced
* @throws CoreException
* if an error occurs
*/
private void rewriteSourceMethods(final CompilationUnitRewrite sourceRewrite, final Set<String> replacements) throws CoreException {
Assert.isNotNull(sourceRewrite);
Assert.isNotNull(replacements);
if (fMembers.length > 0) {
IJavaProject project= fSubType.getJavaProject();
boolean annotations= fAnnotations && !JavaModelUtil.isVersionLessThan(project.getOption(JavaCore.COMPILER_SOURCE, true), JavaCore.VERSION_1_6);
boolean inheritNullAnnotations= JavaCore.ENABLED.equals(project.getOption(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, true));
boolean javadoc= project.getOption(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, true).equals(JavaCore.ENABLED);
for (IMember member : fMembers) {
if (member instanceof IMethod) {
MethodDeclaration declaration= ASTNodeSearchUtil.getMethodDeclarationNode((IMethod) member, sourceRewrite.getRoot());
if (inheritNullAnnotations) {
for (IExtendedModifier extended : (List<IExtendedModifier>) declaration.modifiers()) {
if (extended.isAnnotation()) {
Annotation annotation= (Annotation) extended;
ITypeBinding binding= annotation.resolveTypeBinding();
if (binding != null && Bindings.isAnyNullAnnotation(binding, project)) {
ASTRewrite rewrite= sourceRewrite.getASTRewrite();
rewrite.getListRewrite(declaration, MethodDeclaration.MODIFIERS2_PROPERTY).remove(annotation, null);
}
}
}
for (SingleVariableDeclaration parameter : (List<SingleVariableDeclaration>) declaration.parameters()) {
for (IExtendedModifier extended : (List<IExtendedModifier>) parameter.modifiers()) {
if (extended.isAnnotation()) {
Annotation annotation= (Annotation) extended;
ITypeBinding binding= annotation.resolveTypeBinding();
if (binding != null && Bindings.isAnyNullAnnotation(binding, project)) {
ASTRewrite rewrite= sourceRewrite.getASTRewrite();
rewrite.getListRewrite(parameter, SingleVariableDeclaration.MODIFIERS2_PROPERTY).remove(annotation, null);
}
}
}
}
}
if (annotations) {
StubUtility2Core.createOverrideAnnotation(sourceRewrite.getASTRewrite(), sourceRewrite.getImportRewrite(), declaration, null);
}
if (fComments)
createMethodComment(sourceRewrite, declaration, replacements, javadoc);
}
}
}
}
/**
* Creates a target method declaration.
*
* @param sourceRewrite
* the source compilation unit rewrite
* @param targetRewrite
* the target rewrite
* @param targetDeclaration
* the target type declaration
* @param declaration
* the source method declaration
* @throws CoreException
* if a buffer could not be retrieved
*/
protected final void createMethodDeclaration(final CompilationUnitRewrite sourceRewrite, final ASTRewrite targetRewrite, final AbstractTypeDeclaration targetDeclaration, final MethodDeclaration declaration) throws CoreException {
Assert.isNotNull(targetDeclaration);
Assert.isNotNull(sourceRewrite);
Assert.isNotNull(targetRewrite);
Assert.isNotNull(declaration);
IJavaProject sourceProject= fSubType.getJavaProject();
ImportRewriteUtil.collectImports(sourceProject, declaration, fTypeBindings, fStaticBindings, true);
ASTRewrite rewrite= ASTRewrite.create(declaration.getAST());
ITrackedNodePosition position= rewrite.track(declaration);
if (declaration.getBody() != null)
rewrite.remove(declaration.getBody(), null);
ListRewrite list= rewrite.getListRewrite(declaration, declaration.getModifiersProperty());
Annotation annotation= null;
for (IExtendedModifier extended : (List<IExtendedModifier>) declaration.modifiers()) {
if (!extended.isAnnotation()) {
Modifier modifier= (Modifier) extended;
list.remove(modifier, null);
} else if (extended.isAnnotation()) {
annotation= (Annotation) extended;
ITypeBinding binding= annotation.resolveTypeBinding();
if (binding != null && binding.getQualifiedName().equals("java.lang.Override") || ! Bindings.isAnyNullAnnotation(binding, sourceProject)) //$NON-NLS-1$
list.remove(annotation, null);
}
}
for (SingleVariableDeclaration param : (List<SingleVariableDeclaration>) declaration.parameters()) {
ListRewrite modifierRewrite= rewrite.getListRewrite(param, SingleVariableDeclaration.MODIFIERS2_PROPERTY);
for (IExtendedModifier extended : (List<IExtendedModifier>) param.modifiers()) {
if (!extended.isAnnotation()) {
Modifier modifier= (Modifier) extended;
modifierRewrite.remove(modifier, null);
} else if (extended.isAnnotation()) {
annotation= (Annotation) extended;
ITypeBinding binding= annotation.resolveTypeBinding();
if (binding != null && ! Bindings.isAnyNullAnnotation(binding, sourceProject))
modifierRewrite.remove(annotation, null);
}
}
}
ICompilationUnit unit= sourceRewrite.getCu();
ITextFileBuffer buffer= RefactoringFileBuffers.acquire(unit);
try {
IDocument document= new Document(buffer.getDocument().get());
try {
rewrite.rewriteAST(document, unit.getJavaProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
targetRewrite.getListRewrite(targetDeclaration, targetDeclaration.getBodyDeclarationsProperty()).insertFirst(targetRewrite.createStringPlaceholder(normalizeText(document.get(position.getStartPosition(), position.getLength())), ASTNode.METHOD_DECLARATION), null);
} catch (MalformedTreeException exception) {
JavaPlugin.log(exception);
} catch (BadLocationException exception) {
JavaPlugin.log(exception);
}
} finally {
RefactoringFileBuffers.release(unit);
}
}
/**
* Creates the new signature of the source type.
*
* @param rewrite
* the source compilation unit rewrite
* @param declaration
* the type declaration
* @param status
* the refactoring status
* @param monitor
* the progress monitor to use
* @throws JavaModelException
* if the type parameters cannot be retrieved
*/
protected final void createTypeSignature(final CompilationUnitRewrite rewrite, final AbstractTypeDeclaration declaration, final RefactoringStatus status, final IProgressMonitor monitor) throws JavaModelException {
Assert.isNotNull(rewrite);
Assert.isNotNull(declaration);
Assert.isNotNull(status);
Assert.isNotNull(monitor);
try {
monitor.beginTask("", 1); //$NON-NLS-1$
monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
final AST ast= declaration.getAST();
final ITypeParameter[] parameters= fSubType.getTypeParameters();
Type type= ast.newSimpleType(ast.newSimpleName(fSuperName));
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= rewrite.getASTRewrite();
if (declaration instanceof TypeDeclaration)
rewriter.getListRewrite(declaration, TypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY).insertLast(type, rewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_add_super_interface, SET_EXTRACT_INTERFACE));
else if (declaration instanceof EnumDeclaration)
rewriter.getListRewrite(declaration, EnumDeclaration.SUPER_INTERFACE_TYPES_PROPERTY).insertLast(type, rewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_add_super_interface, SET_EXTRACT_INTERFACE));
monitor.worked(1);
} finally {
monitor.done();
}
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getElements()
*/
@Override
public final Object[] getElements() {
return new Object[] { fSubType };
}
/**
* Returns the list of extractable members from the type.
*
* @return the list of extractable members
* @throws JavaModelException
* if an error occurs
*/
public final IMember[] getExtractableMembers() throws JavaModelException {
final List<IJavaElement> list= new ArrayList<>();
for (IJavaElement child : fSubType.getChildren()) {
if (child instanceof IMember && isExtractableMember((IMember) child)) {
list.add(child);
}
}
final IMember[] members= new IMember[list.size()];
list.toArray(members);
return members;
}
/**
* Returns the extracted fields from the compilation unit.
*
* @param unit
* the compilation unit
* @return the extracted fields
*/
protected final IField[] getExtractedFields(final ICompilationUnit unit) {
Assert.isNotNull(unit);
final List<IJavaElement> list= new ArrayList<>();
for (IMember member : fMembers) {
if (member instanceof IField) {
final IJavaElement element= JavaModelUtil.findInCompilationUnit(unit, member);
if (element instanceof IField)
list.add(element);
}
}
final IField[] fields= new IField[list.size()];
list.toArray(fields);
return fields;
}
/**
* Returns the extracted methods from the compilation unit except the default methods.
*
* @param unit the compilation unit
* @return the extracted methods except the default method
* @throws JavaModelException if the element does not exist
*/
protected final IMethod[] getExtractedMethods(final ICompilationUnit unit) throws JavaModelException {
Assert.isNotNull(unit);
final List<IJavaElement> list= new ArrayList<>();
for (IMember member : fMembers) {
if (member instanceof IMethod) {
final IJavaElement element= JavaModelUtil.findInCompilationUnit(unit, member);
if (element instanceof IMethod && !JdtFlags.isDefaultMethod((IMethod) element))
list.add(element);
}
}
return list.toArray(new IMethod[list.size()]);
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getIdentifier()
*/
@Override
public final String getIdentifier() {
return IDENTIFIER;
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getProcessorName()
*/
@Override
public final String getProcessorName() {
return RefactoringCoreMessages.ExtractInterfaceProcessor_name;
}
/**
* Returns the type where to extract an interface.
*
* @return the type where to extract an interface
*/
public final IType getType() {
return fSubType;
}
/**
* Returns the new interface name.
*
* @return the new interface name
*/
public final String getTypeName() {
return fSuperName;
}
/**
* Should override annotations be generated?
*
* @return <code>true</code> if annotations should be generated, <code>false</code> otherwise
*/
public final boolean isAnnotations() {
return fAnnotations;
}
private RefactoringStatus initialize(JavaRefactoringArguments extended) {
String handle= extended.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
if (handle != null) {
final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(extended.getProject(), handle, false);
if (element == null || !element.exists() || element.getElementType() != IJavaElement.TYPE)
return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getProcessorName(), IJavaRefactorings.EXTRACT_INTERFACE);
else
fSubType= (IType) element;
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
final String name= extended.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME);
if (name != null) {
fSuperName= name;
final RefactoringStatus status= checkTypeName(name);
if (status.hasError())
return status;
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME));
final String comment= extended.getAttribute(ATTRIBUTE_COMMENTS);
if (comment != null) {
fComments= Boolean.valueOf(comment).booleanValue();
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_COMMENTS));
final String instance= extended.getAttribute(ATTRIBUTE_INSTANCEOF);
if (instance != null) {
fInstanceOf= Boolean.valueOf(instance).booleanValue();
} 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.valueOf(replace).booleanValue();
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_REPLACE));
int count= 1;
final List<IJavaElement> elements= new ArrayList<>();
String attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + count;
final RefactoringStatus status= new RefactoringStatus();
while ((handle= extended.getAttribute(attribute)) != null) {
final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(extended.getProject(), handle, false);
if (element == null || !element.exists())
status.merge(JavaRefactoringDescriptorUtil.createInputWarningStatus(element, getProcessorName(), IJavaRefactorings.EXTRACT_INTERFACE));
else
elements.add(element);
count++;
attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + count;
}
fMembers= elements.toArray(new IMember[elements.size()]);
fSettings= JavaPreferencesSettings.getCodeGenerationSettings(fSubType.getJavaProject());
if (!status.isOK())
return status;
return new RefactoringStatus();
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#isApplicable()
*/
@Override
public final boolean isApplicable() throws CoreException {
return Checks.isAvailable(fSubType) && !fSubType.isBinary() && !fSubType.isReadOnly() && !fSubType.isAnnotation() && !fSubType.isAnonymous();
}
/**
* Should comments be generated?
*
* @return <code>true</code> if comments should be generated,
* <code>false</code> otherwise
*/
public final boolean isComments() {
return fComments;
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#loadParticipants(org.eclipse.ltk.core.refactoring.RefactoringStatus,org.eclipse.ltk.core.refactoring.participants.SharableParticipants)
*/
@Override
public final RefactoringParticipant[] loadParticipants(final RefactoringStatus status, final SharableParticipants sharedParticipants) throws CoreException {
return new RefactoringParticipant[0];
}
/**
* Normalizes the indentation of the specified text.
*
* @param code
* the text to normalize
* @return the normalized text
* @throws JavaModelException
* if an error occurs
*/
protected final String normalizeText(final String code) throws JavaModelException {
Assert.isNotNull(code);
final String[] lines= Strings.convertIntoLines(code);
final IJavaProject project= fSubType.getJavaProject();
Strings.trimIndentation(lines, project, false);
return Strings.concatenate(lines, StubUtility.getLineDelimiterUsed(project));
}
/**
* Resets the environment.
*/
protected void resetEnvironment() {
fSuperSource= null;
resetWorkingCopies();
}
@Override
protected final void rewriteTypeOccurrences(final TextEditBasedChangeManager manager, final ASTRequestor requestor, final CompilationUnitRewrite rewrite, final ICompilationUnit unit, final CompilationUnit node, final Set<String> replacements, final IProgressMonitor monitor) throws CoreException {
try {
monitor.beginTask("", 100); //$NON-NLS-1$
monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
CompilationUnitRewrite currentRewrite= null;
final boolean isSubUnit= rewrite.getCu().equals(unit.getPrimary());
if (isSubUnit)
currentRewrite= rewrite;
else
currentRewrite= new CompilationUnitRewrite(unit, node);
final Collection<ITypeConstraintVariable> collection= fTypeOccurrences.get(unit);
if (collection != null && !collection.isEmpty()) {
final IProgressMonitor subMonitor= new SubProgressMonitor(monitor, 100);
try {
subMonitor.beginTask("", collection.size() * 10); //$NON-NLS-1$
subMonitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
TType estimate= null;
for (ITypeConstraintVariable constraint : collection) {
if (constraint != null) {
estimate= (TType) constraint.getData(SuperTypeConstraintsSolver.DATA_TYPE_ESTIMATE);
if (estimate != null) {
final CompilationUnitRange range= constraint.getRange();
if (isSubUnit)
rewriteTypeOccurrence(range, estimate, requestor, currentRewrite, node, replacements, currentRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.SuperTypeRefactoringProcessor_update_type_occurrence, SET_SUPER_TYPE));
else {
final ASTNode result= NodeFinder.perform(node, range.getSourceRange());
if (result != null)
rewriteTypeOccurrence(estimate, currentRewrite, result, currentRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.SuperTypeRefactoringProcessor_update_type_occurrence, SET_SUPER_TYPE));
}
subMonitor.worked(10);
}
}
}
} finally {
subMonitor.done();
}
}
if (!isSubUnit) {
final TextChange change= currentRewrite.createChange(true);
if (change != null)
manager.manage(unit, change);
}
} finally {
monitor.done();
}
}
/**
* Creates the necessary text edits to replace the subtype occurrences by a
* supertype.
*
* @param manager
* the text change manager
* @param sourceRewrite
* the compilation unit of the subtype (not in working copy mode)
* @param superUnit
* the compilation unit of the supertype (in working copy mode)
* @param replacements
* the set of variable binding keys of formal parameters which
* must be replaced
* @param status
* the refactoring status
* @param monitor
* the progress monitor to display progress
* @throws CoreException
* if an error occurs
*/
protected final void rewriteTypeOccurrences(final TextEditBasedChangeManager manager, final CompilationUnitRewrite sourceRewrite, final ICompilationUnit superUnit, final Set<String> replacements, final RefactoringStatus status, final IProgressMonitor monitor) throws CoreException {
Assert.isNotNull(manager);
Assert.isNotNull(sourceRewrite);
Assert.isNotNull(superUnit);
Assert.isNotNull(replacements);
Assert.isNotNull(status);
Assert.isNotNull(monitor);
try {
monitor.beginTask("", 300); //$NON-NLS-1$
monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
final ICompilationUnit subUnit= getSharedWorkingCopy(fSubType.getCompilationUnit().getPrimary(), new SubProgressMonitor(monitor, 20));
final ITextFileBuffer buffer= RefactoringFileBuffers.acquire(fSubType.getCompilationUnit());
final ASTRewrite rewrite= sourceRewrite.getASTRewrite();
try {
final IDocument document= new Document(buffer.getDocument().get());
try {
rewrite.rewriteAST(document, fSubType.getJavaProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
} catch (MalformedTreeException exception) {
JavaPlugin.log(exception);
} catch (BadLocationException exception) {
JavaPlugin.log(exception);
}
subUnit.getBuffer().setContents(document.get());
} finally {
RefactoringFileBuffers.release(fSubType.getCompilationUnit());
}
JavaModelUtil.reconcile(subUnit);
final IJavaProject project= subUnit.getJavaProject();
final ASTParser parser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL);
parser.setWorkingCopyOwner(fOwner);
parser.setResolveBindings(true);
parser.setProject(project);
parser.setCompilerOptions(RefactoringASTParser.getCompilerOptions(project));
parser.createASTs(new ICompilationUnit[] { subUnit}, new String[0], new ASTRequestor() {
@Override
public final void acceptAST(final ICompilationUnit unit, final CompilationUnit node) {
try {
final IType subType= (IType) JavaModelUtil.findInCompilationUnit(unit, fSubType);
final AbstractTypeDeclaration subDeclaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(subType, node);
if (subDeclaration != null) {
final ITypeBinding subBinding= subDeclaration.resolveBinding();
if (subBinding != null) {
String name= null;
ITypeBinding superBinding= null;
for (ITypeBinding binding : subBinding.getInterfaces()) {
name= binding.getName();
if (name.startsWith(fSuperName) && binding.getTypeArguments().length == subBinding.getTypeParameters().length) {
superBinding= binding;
}
}
if (superBinding != null) {
solveSuperTypeConstraints(unit, node, subType, subBinding, superBinding, new SubProgressMonitor(monitor, 80), status);
if (!status.hasFatalError()) {
rewriteTypeOccurrences(manager, this, sourceRewrite, unit, node, replacements, status, new SubProgressMonitor(monitor, 200));
if (manager.containsChangesIn(superUnit)) {
final TextEditBasedChange change= manager.get(superUnit);
if (change instanceof TextChange) {
final TextEdit edit= ((TextChange) change).getEdit();
if (edit != null) {
final IDocument document= new Document(superUnit.getBuffer().getContents());
try {
edit.apply(document, TextEdit.UPDATE_REGIONS);
} catch (MalformedTreeException exception) {
JavaPlugin.log(exception);
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
} catch (BadLocationException exception) {
JavaPlugin.log(exception);
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
}
fSuperSource= document.get();
manager.remove(superUnit);
}
}
}
}
}
}
}
} catch (JavaModelException exception) {
JavaPlugin.log(exception);
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
}
}
@Override
public final void acceptBinding(final String key, final IBinding binding) {
// Do nothing
}
}, new NullProgressMonitor());
} finally {
monitor.done();
}
}
/**
* Determines whether override annotations should be generated.
*
* @param annotations <code>true</code> to generate override annotations, <code>false</code> otherwise
*/
public final void setAnnotations(final boolean annotations) {
fAnnotations= annotations;
}
/**
* Determines whether comments should be generated.
*
* @param comments
* <code>true</code> to generate comments, <code>false</code>
* otherwise
*/
public final void setComments(final boolean comments) {
fComments= comments;
}
/**
* Sets the members to be extracted.
*
* @param members
* the members to be extracted
* @throws JavaModelException
* if an error occurs
*/
public final void setExtractedMembers(final IMember[] members) throws JavaModelException {
fMembers= members;
}
/**
* Sets the new interface name.
*
* @param name
* the new interface name
*/
public final void setTypeName(final String name) {
Assert.isNotNull(name);
fSuperName= name;
}
}