blob: d53d12527dcba6e77877872da9e88cdcb5252331 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.jsdt.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.filebuffers.ITextFileBuffer;
import org.eclipse.core.resources.IFile;
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.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.RefactoringArguments;
import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
import org.eclipse.ltk.core.refactoring.participants.SharableParticipants;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.wst.jsdt.core.IField;
import org.eclipse.wst.jsdt.core.IFunction;
import org.eclipse.wst.jsdt.core.IJavaScriptElement;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
import org.eclipse.wst.jsdt.core.IMember;
import org.eclipse.wst.jsdt.core.IPackageFragment;
import org.eclipse.wst.jsdt.core.ISourceReference;
import org.eclipse.wst.jsdt.core.IType;
import org.eclipse.wst.jsdt.core.ITypeParameter;
import org.eclipse.wst.jsdt.core.JavaScriptCore;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.core.dom.AST;
import org.eclipse.wst.jsdt.core.dom.ASTNode;
import org.eclipse.wst.jsdt.core.dom.ASTParser;
import org.eclipse.wst.jsdt.core.dom.ASTRequestor;
import org.eclipse.wst.jsdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.wst.jsdt.core.dom.FieldDeclaration;
import org.eclipse.wst.jsdt.core.dom.FunctionDeclaration;
import org.eclipse.wst.jsdt.core.dom.IBinding;
import org.eclipse.wst.jsdt.core.dom.IExtendedModifier;
import org.eclipse.wst.jsdt.core.dom.IFunctionBinding;
import org.eclipse.wst.jsdt.core.dom.ITypeBinding;
import org.eclipse.wst.jsdt.core.dom.IVariableBinding;
import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit;
import org.eclipse.wst.jsdt.core.dom.Modifier;
import org.eclipse.wst.jsdt.core.dom.ParameterizedType;
import org.eclipse.wst.jsdt.core.dom.SingleVariableDeclaration;
import org.eclipse.wst.jsdt.core.dom.Type;
import org.eclipse.wst.jsdt.core.dom.TypeDeclaration;
import org.eclipse.wst.jsdt.core.dom.VariableDeclarationFragment;
import org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.wst.jsdt.core.dom.rewrite.ITrackedNodePosition;
import org.eclipse.wst.jsdt.core.dom.rewrite.ListRewrite;
import org.eclipse.wst.jsdt.core.refactoring.IJavaScriptRefactorings;
import org.eclipse.wst.jsdt.core.refactoring.descriptors.JavaScriptRefactoringDescriptor;
import org.eclipse.wst.jsdt.internal.corext.codemanipulation.CodeGenerationSettings;
import org.eclipse.wst.jsdt.internal.corext.codemanipulation.StubUtility;
import org.eclipse.wst.jsdt.internal.corext.dom.Bindings;
import org.eclipse.wst.jsdt.internal.corext.dom.ModifierRewrite;
import org.eclipse.wst.jsdt.internal.corext.dom.NodeFinder;
import org.eclipse.wst.jsdt.internal.corext.refactoring.Checks;
import org.eclipse.wst.jsdt.internal.corext.refactoring.JDTRefactoringDescriptor;
import org.eclipse.wst.jsdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
import org.eclipse.wst.jsdt.internal.corext.refactoring.JavaRefactoringArguments;
import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringCoreMessages;
import org.eclipse.wst.jsdt.internal.corext.refactoring.base.JavaStatusContext;
import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.CreateCompilationUnitChange;
import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
import org.eclipse.wst.jsdt.internal.corext.refactoring.code.ScriptableRefactoring;
import org.eclipse.wst.jsdt.internal.corext.refactoring.reorg.ASTNodeDeleteUtil;
import org.eclipse.wst.jsdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsModel;
import org.eclipse.wst.jsdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsSolver;
import org.eclipse.wst.jsdt.internal.corext.refactoring.structure.constraints.SuperTypeRefactoringProcessor;
import org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.CompilationUnitRange;
import org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints.types.TType;
import org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints2.ISourceConstraintVariable;
import org.eclipse.wst.jsdt.internal.corext.refactoring.typeconstraints2.ITypeConstraintVariable;
import org.eclipse.wst.jsdt.internal.corext.refactoring.util.RefactoringASTParser;
import org.eclipse.wst.jsdt.internal.corext.refactoring.util.RefactoringFileBuffers;
import org.eclipse.wst.jsdt.internal.corext.refactoring.util.ResourceUtil;
import org.eclipse.wst.jsdt.internal.corext.refactoring.util.TextEditBasedChangeManager;
import org.eclipse.wst.jsdt.internal.corext.util.JavaModelUtil;
import org.eclipse.wst.jsdt.internal.corext.util.JdtFlags;
import org.eclipse.wst.jsdt.internal.corext.util.Messages;
import org.eclipse.wst.jsdt.internal.corext.util.Strings;
import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
import org.eclipse.wst.jsdt.internal.ui.preferences.JavaPreferencesSettings;
import org.eclipse.wst.jsdt.ui.CodeGeneration;
import org.eclipse.wst.jsdt.ui.JavaScriptElementLabels;
/**
* Refactoring processor to extract interfaces.
*/
public final class ExtractInterfaceProcessor extends SuperTypeRefactoringProcessor {
private static final String ATTRIBUTE_ABSTRACT= "abstract"; //$NON-NLS-1$
private static final String ATTRIBUTE_COMMENTS= "comments"; //$NON-NLS-1$
private static final String ATTRIBUTE_PUBLIC= "public"; //$NON-NLS-1$
/** The identifier of this processor */
public static final String IDENTIFIER= "org.eclipse.wst.jsdt.ui.extractInterfaceProcessor"; //$NON-NLS-1$
/** The extract interface group category set */
private static final GroupCategorySet SET_EXTRACT_INTERFACE= new GroupCategorySet(new GroupCategory("org.eclipse.wst.jsdt.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 JavaScriptModelException
* if an error occurs
*/
protected static boolean isExtractableMember(final IMember member) throws JavaScriptModelException {
Assert.isNotNull(member);
switch (member.getElementType()) {
case IJavaScriptElement.METHOD:
return JdtFlags.isPublic(member) && !JdtFlags.isStatic(member) && !((IFunction) member).isConstructor();
case IJavaScriptElement.FIELD:
return JdtFlags.isPublic(member) && JdtFlags.isStatic(member) && JdtFlags.isFinal(member) && !JdtFlags.isEnum(member);
default:
return false;
}
}
/** Should extracted methods be declared as abstract? */
private boolean fAbstract= true;
/** 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;
/** Should extracted methods be declared as public? */
private boolean fPublic= true;
/** 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();
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#checkFinalConditions(org.eclipse.core.runtime.IProgressMonitor,org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext)
*/
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()) {
final RefactoringStatus validation= Checks.validateModifiesFiles(ResourceUtil.getFiles(fChangeManager.getAllCompilationUnits()), getRefactoring().getValidationContext());
if (!validation.isOK())
return validation;
}
}
}
}
}
} finally {
monitor.done();
}
return status;
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor)
*/
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 JavaScriptModelException
* if an error occurs
*/
protected final RefactoringStatus checkSuperType() throws JavaScriptModelException {
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, new String[] { fSuperName }));
else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_existing_type, new String[] { fSuperName, fragment.getElementName() }));
}
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);
if (result.hasFatalError())
return result;
final String unitName= JavaModelUtil.getRenamedCUName(fSubType.getJavaScriptUnit(), name);
result.merge(Checks.checkCompilationUnitName(unitName));
if (result.hasFatalError())
return result;
final IPackageFragment fragment= fSubType.getPackageFragment();
if (fragment.getJavaScriptUnit(unitName).exists()) {
result.addFatalError(Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_existing_compilation_unit, new String[] { unitName, fragment.getElementName() }));
return result;
}
result.merge(checkSuperType());
return result;
} catch (JavaScriptModelException exception) {
return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error);
}
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#createChange(org.eclipse.core.runtime.IProgressMonitor)
*/
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 arguments= new HashMap();
String project= null;
final IJavaScriptProject javaProject= fSubType.getJavaScriptProject();
if (javaProject != null)
project= javaProject.getElementName();
int flags= JavaScriptRefactoringDescriptor.JAR_MIGRATION | JavaScriptRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE;
try {
if (fSubType.isLocal() || fSubType.isAnonymous())
flags|= JavaScriptRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
} catch (JavaScriptModelException exception) {
JavaScriptPlugin.log(exception);
}
final IPackageFragment fragment= fSubType.getPackageFragment();
final IJavaScriptUnit cu= fragment.getJavaScriptUnit(JavaModelUtil.getRenamedCUName(fSubType.getJavaScriptUnit(), fSuperName));
final IType type= cu.getType(fSuperName);
final String description= Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_description_descriptor_short, fSuperName);
final String header= Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_descriptor_description, new String[] { JavaScriptElementLabels.getElementLabel(type, JavaScriptElementLabels.ALL_FULLY_QUALIFIED), JavaScriptElementLabels.getElementLabel(fSubType, JavaScriptElementLabels.ALL_FULLY_QUALIFIED) });
final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_refactored_element_pattern, JavaScriptElementLabels.getElementLabel(type, JavaScriptElementLabels.ALL_FULLY_QUALIFIED)));
final String[] settings= new String[fMembers.length];
for (int index= 0; index < settings.length; index++)
settings[index]= JavaScriptElementLabels.getElementLabel(fMembers[index], JavaScriptElementLabels.ALL_FULLY_QUALIFIED);
comment.addSetting(JDTRefactoringDescriptorComment.createCompositeSetting(RefactoringCoreMessages.ExtractInterfaceProcessor_extracted_members_pattern, settings));
addSuperTypeSettings(comment, true);
final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaScriptRefactorings.EXTRACT_INTERFACE, project, description, comment.asString(), arguments, flags);
arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fSubType));
arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_NAME, fSuperName);
for (int index= 0; index < fMembers.length; index++)
arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + (index + 1), descriptor.elementToHandle(fMembers[index]));
arguments.put(ATTRIBUTE_ABSTRACT, Boolean.valueOf(fAbstract).toString());
arguments.put(ATTRIBUTE_COMMENTS, Boolean.valueOf(fComments).toString());
arguments.put(ATTRIBUTE_PUBLIC, Boolean.valueOf(fPublic).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.getJavaScriptUnit());
if (fSuperSource != null && fSuperSource.length() > 0)
change.add(new CreateCompilationUnitChange(fSubType.getPackageFragment().getJavaScriptUnit(JavaModelUtil.getRenamedCUName(fSubType.getJavaScriptUnit(), 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 JavaScriptModelException
* 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 JavaScriptModelException, 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.getJavaScriptUnit());
final AbstractTypeDeclaration declaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(fSubType, sourceRewrite.getRoot());
if (declaration != null) {
createTypeSignature(sourceRewrite, declaration, status, new SubProgressMonitor(monitor, 20));
final IField[] fields= getExtractedFields(fSubType.getJavaScriptUnit());
if (fields.length > 0)
ASTNodeDeleteUtil.markAsDeleted(fields, sourceRewrite, sourceRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_remove_field_label, SET_EXTRACT_INTERFACE));
if (fSubType.isInterface()) {
final IFunction[] methods= getExtractedMethods(fSubType.getJavaScriptUnit());
if (methods.length > 0)
ASTNodeDeleteUtil.markAsDeleted(methods, sourceRewrite, sourceRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_remove_method_label, SET_EXTRACT_INTERFACE));
}
final String name= JavaModelUtil.getRenamedCUName(fSubType.getJavaScriptUnit(), fSuperName);
final IJavaScriptUnit original= fSubType.getPackageFragment().getJavaScriptUnit(name);
final IJavaScriptUnit 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 replacements= new HashSet();
if (fReplace)
rewriteTypeOccurrences(manager, sourceRewrite, copy, replacements, status, new SubProgressMonitor(monitor, 220));
createMethodComments(sourceRewrite, replacements);
manager.manage(fSubType.getJavaScriptUnit(), sourceRewrite.createChange());
}
return manager;
} finally {
monitor.done();
}
}
/*
* @see org.eclipse.wst.jsdt.internal.corext.refactoring.structure.constraints.SuperTypeRefactoringProcessor#createContraintSolver(org.eclipse.wst.jsdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsModel)
*/
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.getJavaScriptProject(), 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 iterator= field.fragments().iterator(); iterator.hasNext();) {
current= (VariableDeclarationFragment) iterator.next();
if (!current.getName().getIdentifier().equals(fragment.getName().getIdentifier()))
rewriter.remove(current, null);
}
final IJavaScriptUnit unit= sourceRewrite.getCu();
final ITextFileBuffer buffer= RefactoringFileBuffers.acquire(unit);
try {
final IDocument document= new Document(buffer.getDocument().get());
try {
rewrite.rewriteAST(document, unit.getJavaScriptProject().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) {
JavaScriptPlugin.log(exception);
} catch (BadLocationException exception) {
JavaScriptPlugin.log(exception);
}
} finally {
RefactoringFileBuffers.release(unit);
}
}
/**
* {@inheritDoc}
*/
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() {
public final int compare(final Object first, final Object second) {
Assert.isNotNull(first);
Assert.isNotNull(second);
final ISourceReference predecessor= (ISourceReference) first;
final ISourceReference successor= (ISourceReference) second;
try {
return predecessor.getSourceRange().getOffset() - successor.getSourceRange().getOffset();
} catch (JavaScriptModelException 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 IFunction) {
createMethodDeclaration(sourceRewrite, targetRewrite, targetDeclaration, ASTNodeSearchUtil.getMethodDeclarationNode((IFunction) 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 FunctionDeclaration declaration, final Set replacements, final boolean javadoc) throws CoreException {
Assert.isNotNull(sourceRewrite);
Assert.isNotNull(declaration);
Assert.isNotNull(replacements);
final IFunctionBinding 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.getJavaScriptUnit(), fSubType.getElementName(), declaration, false, binding.getName(), string, names, StubUtility.getLineDelimiterUsed(fSubType.getJavaScriptProject()));
if (comment != null) {
final ASTRewrite rewrite= sourceRewrite.getASTRewrite();
if (declaration.getJavadoc() != null) {
rewrite.replace(declaration.getJavadoc(), rewrite.createStringPlaceholder(comment, ASTNode.JSDOC), sourceRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_rewrite_comment, SET_EXTRACT_INTERFACE));
} else if (javadoc) {
rewrite.set(declaration, FunctionDeclaration.JAVADOC_PROPERTY, rewrite.createStringPlaceholder(comment, ASTNode.JSDOC), sourceRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_add_comment, SET_EXTRACT_INTERFACE));
}
}
}
}
/**
* Creates the method annotations and comments of the extracted methods in
* the source type.
*
* @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
*/
protected final void createMethodComments(final CompilationUnitRewrite sourceRewrite, final Set replacements) throws CoreException {
Assert.isNotNull(sourceRewrite);
Assert.isNotNull(replacements);
if (fComments && fMembers.length > 0) {
final IJavaScriptProject project= fSubType.getJavaScriptProject();
final boolean javadoc= project.getOption(JavaScriptCore.COMPILER_DOC_COMMENT_SUPPORT, true).equals(JavaScriptCore.ENABLED);
IMember member= null;
for (int index= 0; index < fMembers.length; index++) {
member= fMembers[index];
if (member instanceof IFunction)
createMethodComment(sourceRewrite, ASTNodeSearchUtil.getMethodDeclarationNode((IFunction) member, sourceRewrite.getRoot()), 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 FunctionDeclaration declaration) throws CoreException {
Assert.isNotNull(targetDeclaration);
Assert.isNotNull(sourceRewrite);
Assert.isNotNull(targetRewrite);
Assert.isNotNull(declaration);
ImportRewriteUtil.collectImports(fSubType.getJavaScriptProject(), declaration, fTypeBindings, fStaticBindings, true);
final ASTRewrite rewrite= ASTRewrite.create(declaration.getAST());
final ITrackedNodePosition position= rewrite.track(declaration);
if (declaration.getBody() != null)
rewrite.remove(declaration.getBody(), null);
final ListRewrite list= rewrite.getListRewrite(declaration, declaration.getModifiersProperty());
boolean publicFound= false;
boolean abstractFound= false;
ITypeBinding binding= null;
Modifier modifier= null;
IExtendedModifier extended= null;
for (final Iterator iterator= declaration.modifiers().iterator(); iterator.hasNext();) {
extended= (IExtendedModifier) iterator.next();
if (!extended.isAnnotation()) {
modifier= (Modifier) extended;
if (fPublic && modifier.getKeyword().equals(Modifier.ModifierKeyword.PUBLIC_KEYWORD)) {
publicFound= true;
continue;
}
if (fAbstract && modifier.getKeyword().equals(Modifier.ModifierKeyword.ABSTRACT_KEYWORD)) {
abstractFound= true;
continue;
}
list.remove(modifier, null);
}
}
final ModifierRewrite rewriter= ModifierRewrite.create(rewrite, declaration);
if (fPublic && !publicFound)
rewriter.setVisibility(Modifier.PUBLIC, null);
if (fAbstract && !abstractFound)
rewriter.setModifiers(Modifier.ABSTRACT, 0, null);
final IJavaScriptUnit unit= sourceRewrite.getCu();
final ITextFileBuffer buffer= RefactoringFileBuffers.acquire(unit);
try {
final IDocument document= new Document(buffer.getDocument().get());
try {
rewrite.rewriteAST(document, unit.getJavaScriptProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
targetRewrite.getListRewrite(targetDeclaration, targetDeclaration.getBodyDeclarationsProperty()).insertFirst(targetRewrite.createStringPlaceholder(normalizeText(document.get(position.getStartPosition(), position.getLength())), ASTNode.FUNCTION_DECLARATION), null);
} catch (MalformedTreeException exception) {
JavaScriptPlugin.log(exception);
} catch (BadLocationException exception) {
JavaScriptPlugin.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 JavaScriptModelException
* if the type parameters cannot be retrieved
*/
protected final void createTypeSignature(final CompilationUnitRewrite rewrite, final AbstractTypeDeclaration declaration, final RefactoringStatus status, final IProgressMonitor monitor) throws JavaScriptModelException {
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 (int index= 0; index < parameters.length; index++)
parameterized.typeArguments().add(ast.newSimpleType(ast.newSimpleName(parameters[index].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));
monitor.worked(1);
} finally {
monitor.done();
}
}
/**
* Should extracted methods be declared as abstract?
*
* @return <code>true</code> if the should be declared as abstract,
* <code>false</code> otherwise
*/
public final boolean getAbstract() {
return fAbstract;
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getElements()
*/
public final Object[] getElements() {
return new Object[] { fSubType };
}
/**
* Returns the list of extractable members from the type.
*
* @return the list of extractable members
* @throws JavaScriptModelException
* if an error occurs
*/
public final IMember[] getExtractableMembers() throws JavaScriptModelException {
final List list= new ArrayList();
IJavaScriptElement[] children= fSubType.getChildren();
for (int index= 0; index < children.length; index++) {
if (children[index] instanceof IMember && isExtractableMember((IMember) children[index]))
list.add(children[index]);
}
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 IJavaScriptUnit unit) {
Assert.isNotNull(unit);
final List list= new ArrayList();
for (int index= 0; index < fMembers.length; index++) {
if (fMembers[index] instanceof IField) {
final IJavaScriptElement element= JavaModelUtil.findInCompilationUnit(unit, fMembers[index]);
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.
*
* @param unit
* the compilation unit
* @return the extracted methods
*/
protected final IFunction[] getExtractedMethods(final IJavaScriptUnit unit) {
Assert.isNotNull(unit);
final List list= new ArrayList();
for (int index= 0; index < fMembers.length; index++) {
if (fMembers[index] instanceof IFunction) {
final IJavaScriptElement element= JavaModelUtil.findInCompilationUnit(unit, fMembers[index]);
if (element instanceof IFunction)
list.add(element);
}
}
final IFunction[] methods= new IFunction[list.size()];
list.toArray(methods);
return methods;
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getIdentifier()
*/
public final String getIdentifier() {
return IDENTIFIER;
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getProcessorName()
*/
public final String getProcessorName() {
return RefactoringCoreMessages.ExtractInterfaceProcessor_name;
}
/**
* Should extracted methods be declared as public?
*
* @return <code>true</code> if the should be declared as public,
* <code>false</code> otherwise
*/
public final boolean getPublic() {
return fPublic;
}
/**
* 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;
}
/**
* {@inheritDoc}
*/
public final RefactoringStatus initialize(final RefactoringArguments arguments) {
if (arguments instanceof JavaRefactoringArguments) {
final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments;
String handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT);
if (handle != null) {
final IJavaScriptElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false);
if (element == null || !element.exists() || element.getElementType() != IJavaScriptElement.TYPE)
return ScriptableRefactoring.createInputFatalStatus(element, getRefactoring().getName(), IJavaScriptRefactorings.EXTRACT_INTERFACE);
else
fSubType= (IType) element;
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT));
final String name= extended.getAttribute(JDTRefactoringDescriptor.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, JDTRefactoringDescriptor.ATTRIBUTE_NAME));
final String deferred= extended.getAttribute(ATTRIBUTE_ABSTRACT);
if (deferred != null) {
fAbstract= Boolean.valueOf(deferred).booleanValue();
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_ABSTRACT));
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 visibility= extended.getAttribute(ATTRIBUTE_PUBLIC);
if (visibility != null) {
fPublic= Boolean.valueOf(visibility).booleanValue();
} else
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_PUBLIC));
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 elements= new ArrayList();
String attribute= JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + count;
final RefactoringStatus status= new RefactoringStatus();
while ((handle= extended.getAttribute(attribute)) != null) {
final IJavaScriptElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false);
if (element == null || !element.exists())
status.merge(ScriptableRefactoring.createInputWarningStatus(element, getRefactoring().getName(), IJavaScriptRefactorings.EXTRACT_INTERFACE));
else
elements.add(element);
count++;
attribute= JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + count;
}
fMembers= (IMember[]) elements.toArray(new IMember[elements.size()]);
fSettings= JavaPreferencesSettings.getCodeGenerationSettings(fSubType.getJavaScriptProject());
if (!status.isOK())
return status;
} else
return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
return new RefactoringStatus();
}
/*
* @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#isApplicable()
*/
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)
*/
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 JavaScriptModelException
* if an error occurs
*/
protected final String normalizeText(final String code) throws JavaScriptModelException {
Assert.isNotNull(code);
final String[] lines= Strings.convertIntoLines(code);
final IJavaScriptProject project= fSubType.getJavaScriptProject();
Strings.trimIndentation(lines, project, false);
return Strings.concatenate(lines, StubUtility.getLineDelimiterUsed(project));
}
/**
* Resets the environment.
*/
protected void resetEnvironment() {
fSuperSource= null;
resetWorkingCopies();
}
/**
* {@inheritDoc}
*/
protected final void rewriteTypeOccurrences(final TextEditBasedChangeManager manager, final ASTRequestor requestor, final CompilationUnitRewrite rewrite, final IJavaScriptUnit unit, final JavaScriptUnit node, final Set 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 collection= (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;
ISourceConstraintVariable variable= null;
ITypeConstraintVariable constraint= null;
for (final Iterator iterator= collection.iterator(); iterator.hasNext();) {
variable= (ISourceConstraintVariable) iterator.next();
if (variable instanceof ITypeConstraintVariable) {
constraint= (ITypeConstraintVariable) variable;
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();
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 IJavaScriptUnit superUnit, final Set 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 IJavaScriptUnit subUnit= getSharedWorkingCopy(fSubType.getJavaScriptUnit().getPrimary(), new SubProgressMonitor(monitor, 20));
final ITextFileBuffer buffer= RefactoringFileBuffers.acquire(fSubType.getJavaScriptUnit());
final ASTRewrite rewrite= sourceRewrite.getASTRewrite();
try {
final IDocument document= new Document(buffer.getDocument().get());
try {
rewrite.rewriteAST(document, fSubType.getJavaScriptProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
} catch (MalformedTreeException exception) {
JavaScriptPlugin.log(exception);
} catch (BadLocationException exception) {
JavaScriptPlugin.log(exception);
}
subUnit.getBuffer().setContents(document.get());
} finally {
RefactoringFileBuffers.release(fSubType.getJavaScriptUnit());
}
JavaModelUtil.reconcile(subUnit);
final IJavaScriptProject project= subUnit.getJavaScriptProject();
final ASTParser parser= ASTParser.newParser(AST.JLS3);
parser.setWorkingCopyOwner(fOwner);
parser.setResolveBindings(true);
parser.setProject(project);
parser.setCompilerOptions(RefactoringASTParser.getCompilerOptions(project));
parser.createASTs(new IJavaScriptUnit[] { subUnit}, new String[0], new ASTRequestor() {
public final void acceptAST(final IJavaScriptUnit unit, final JavaScriptUnit 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;
final ITypeBinding[] superBindings= subBinding.getInterfaces();
for (int index= 0; index < superBindings.length; index++) {
name= superBindings[index].getName();
if (name.startsWith(fSuperName) && superBindings[index].getTypeArguments().length == subBinding.getTypeParameters().length)
superBinding= superBindings[index];
}
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) {
JavaScriptPlugin.log(exception);
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
} catch (BadLocationException exception) {
JavaScriptPlugin.log(exception);
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
}
fSuperSource= document.get();
manager.remove(superUnit);
}
}
}
}
}
}
}
} catch (JavaScriptModelException exception) {
JavaScriptPlugin.log(exception);
status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
}
}
public final void acceptBinding(final String key, final IBinding binding) {
// Do nothing
}
}, new NullProgressMonitor());
} finally {
monitor.done();
}
}
/**
* Determines whether extracted methods should be declared as abstract.
*
* @param declare
* <code>true</code> to declare them public, <code>false</code>
* otherwise
*/
public final void setAbstract(final boolean declare) {
fAbstract= declare;
}
/**
* 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 JavaScriptModelException
* if an error occurs
*/
public final void setExtractedMembers(final IMember[] members) throws JavaScriptModelException {
fMembers= members;
}
/**
* Determines whether extracted methods should be declared as public.
*
* @param declare
* <code>true</code> to declare them public, <code>false</code>
* otherwise
*/
public final void setPublic(final boolean declare) {
fPublic= declare;
}
/**
* Sets the new interface name.
*
* @param name
* the new interface name
*/
public final void setTypeName(final String name) {
Assert.isNotNull(name);
fSuperName= name;
}
}