blob: 1b8e163db81d9bad1d6536ec0e1558944be9f2f1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.corext.refactoring.rename;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.IResourceMapper;
import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringCore;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.RenameArguments;
import org.eclipse.ltk.core.refactoring.resource.RenameResourceChange;
import org.eclipse.ltk.core.refactoring.resource.RenameResourceDescriptor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.refactoring.IJavaElementMapper;
import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
import org.eclipse.jdt.core.refactoring.RenameTypeArguments;
import org.eclipse.jdt.core.refactoring.descriptors.RenameJavaElementDescriptor;
import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory;
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.RefactoringAvailabilityTester;
import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationStateChange;
import org.eclipse.jdt.internal.corext.refactoring.changes.RenameCompilationUnitChange;
import org.eclipse.jdt.internal.corext.refactoring.participants.JavaProcessors;
import org.eclipse.jdt.internal.corext.refactoring.tagging.IQualifiedNameUpdating;
import org.eclipse.jdt.internal.corext.refactoring.tagging.IReferenceUpdating;
import org.eclipse.jdt.internal.corext.refactoring.tagging.ISimilarDeclarationUpdating;
import org.eclipse.jdt.internal.corext.refactoring.tagging.ITextUpdating;
import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
import org.eclipse.jdt.internal.corext.util.JavaConventionsUtil;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jdt.ui.refactoring.IRefactoringProcessorIds;
import org.eclipse.jdt.ui.refactoring.RefactoringSaveHelper;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
public final class RenameCompilationUnitProcessor extends JavaRenameProcessor implements IReferenceUpdating, ITextUpdating, IQualifiedNameUpdating, ISimilarDeclarationUpdating, IResourceMapper, IJavaElementMapper {
private RenameTypeProcessor fRenameTypeProcessor= null;
private boolean fWillRenameType= false;
private ICompilationUnit fCu;
/**
* Creates a new rename compilation unit processor.
* @param unit the compilation unit, or <code>null</code> if invoked by scripting
* @throws CoreException if the cu is broken
*/
public RenameCompilationUnitProcessor(ICompilationUnit unit) throws CoreException {
fCu= unit;
if (fCu != null) {
computeRenameTypeRefactoring();
setNewElementName(fCu.getElementName());
}
}
public RenameCompilationUnitProcessor(JavaRefactoringArguments arguments, RefactoringStatus status) {
RefactoringStatus initializeStatus= initialize(arguments);
status.merge(initializeStatus);
}
@Override
public String getIdentifier() {
return IRefactoringProcessorIds.RENAME_COMPILATION_UNIT_PROCESSOR;
}
@Override
public boolean isApplicable() {
return RefactoringAvailabilityTester.isRenameAvailable(fCu);
}
@Override
public String getProcessorName() {
return RefactoringCoreMessages.RenameCompilationUnitRefactoring_name;
}
@Override
protected String[] getAffectedProjectNatures() throws CoreException {
return JavaProcessors.computeAffectedNatures(fCu);
}
@Override
public Object[] getElements() {
return new Object[] {fCu};
}
@Override
protected RenameModifications computeRenameModifications() {
RenameModifications result= new RenameModifications();
result.rename(fCu, new RenameArguments(getNewElementName(), getUpdateReferences()));
if (fRenameTypeProcessor != null) {
String newTypeName= removeFileNameExtension(getNewElementName());
RenameTypeArguments arguments= new RenameTypeArguments(newTypeName, getUpdateReferences(), getUpdateSimilarDeclarations(), getSimilarElements());
result.rename(fRenameTypeProcessor.getType(), arguments, getUpdateSimilarDeclarations()
? new RenameTypeProcessor.ParticipantDescriptorFilter()
: null);
}
return result;
}
@Override
protected IFile[] getChangedFiles() throws CoreException {
if (!fWillRenameType) {
IFile file= ResourceUtil.getFile(fCu);
if (file != null)
return new IFile[] {file};
}
return new IFile[0];
}
@Override
public int getSaveMode() {
return RefactoringSaveHelper.SAVE_REFACTORING;
}
//---- IRenameProcessor -------------------------------------
@Override
public String getCurrentElementName() {
return getSimpleCUName();
}
@Override
public String getCurrentElementQualifier() {
IPackageFragment pack= (IPackageFragment) fCu.getParent();
return pack.getElementName();
}
@Override
public RefactoringStatus checkNewElementName(String newName) throws CoreException {
Assert.isNotNull(newName, "new name"); //$NON-NLS-1$
String typeName= removeFileNameExtension(newName);
RefactoringStatus result= Checks.checkCompilationUnitName(newName, fCu);
if (fWillRenameType)
result.merge(fRenameTypeProcessor.checkNewElementName(typeName));
if (Checks.isAlreadyNamed(fCu, newName))
result.addFatalError(RefactoringCoreMessages.RenameCompilationUnitRefactoring_same_name);
return result;
}
@Override
public void setNewElementName(String newName) {
super.setNewElementName(newName);
if (fWillRenameType)
fRenameTypeProcessor.setNewElementName(removeFileNameExtension(newName));
}
@Override
public Object getNewElement() {
IPackageFragment pack= (IPackageFragment) fCu.getParent();
if (JavaConventionsUtil.validateCompilationUnitName(getNewElementName(), pack).getSeverity() == IStatus.ERROR)
return null;
return pack.getCompilationUnit(getNewElementName());
}
//---- ITextUpdating ---------------------------------------------
@Override
public boolean canEnableTextUpdating() {
if (fRenameTypeProcessor == null)
return false;
return fRenameTypeProcessor.canEnableTextUpdating();
}
@Override
public boolean getUpdateTextualMatches() {
if (fRenameTypeProcessor == null)
return false;
return fRenameTypeProcessor.getUpdateTextualMatches();
}
@Override
public void setUpdateTextualMatches(boolean update) {
if (fRenameTypeProcessor != null)
fRenameTypeProcessor.setUpdateTextualMatches(update);
}
//---- IReferenceUpdating -----------------------------------
@Override
public void setUpdateReferences(boolean update) {
if (fRenameTypeProcessor != null)
fRenameTypeProcessor.setUpdateReferences(update);
}
@Override
public boolean getUpdateReferences(){
if (fRenameTypeProcessor == null)
return false;
return fRenameTypeProcessor.getUpdateReferences();
}
//---- IQualifiedNameUpdating -------------------------------
@Override
public boolean canEnableQualifiedNameUpdating() {
if (fRenameTypeProcessor == null)
return false;
return fRenameTypeProcessor.canEnableQualifiedNameUpdating();
}
@Override
public boolean getUpdateQualifiedNames() {
if (fRenameTypeProcessor == null)
return false;
return fRenameTypeProcessor.getUpdateQualifiedNames();
}
@Override
public void setUpdateQualifiedNames(boolean update) {
if (fRenameTypeProcessor == null)
return;
fRenameTypeProcessor.setUpdateQualifiedNames(update);
}
@Override
public String getFilePatterns() {
if (fRenameTypeProcessor == null)
return null;
return fRenameTypeProcessor.getFilePatterns();
}
@Override
public void setFilePatterns(String patterns) {
if (fRenameTypeProcessor == null)
return;
fRenameTypeProcessor.setFilePatterns(patterns);
}
// ---- ISimilarDeclarationUpdating ------------------------------
@Override
public boolean canEnableSimilarDeclarationUpdating() {
if (fRenameTypeProcessor == null)
return false;
else
return fRenameTypeProcessor.canEnableSimilarDeclarationUpdating();
}
@Override
public void setUpdateSimilarDeclarations(boolean update) {
if (fRenameTypeProcessor == null)
return;
fRenameTypeProcessor.setUpdateSimilarDeclarations(update);
}
@Override
public boolean getUpdateSimilarDeclarations() {
if (fRenameTypeProcessor == null)
return false;
return fRenameTypeProcessor.getUpdateSimilarDeclarations();
}
@Override
public int getMatchStrategy() {
if (fRenameTypeProcessor == null)
return RenamingNameSuggestor.STRATEGY_EXACT; // method should not be called in this case anyway ...
return fRenameTypeProcessor.getMatchStrategy();
}
@Override
public void setMatchStrategy(int selectedStrategy) {
if (fRenameTypeProcessor == null)
return;
fRenameTypeProcessor.setMatchStrategy(selectedStrategy);
}
public IJavaElement[] getSimilarElements() {
if (fRenameTypeProcessor == null)
return null;
return fRenameTypeProcessor.getSimilarElements();
}
@Override
public IResource getRefactoredResource(IResource element) {
if (fRenameTypeProcessor == null)
return element;
return fRenameTypeProcessor.getRefactoredResource(element);
}
@Override
public IJavaElement getRefactoredJavaElement(IJavaElement element) {
if (fRenameTypeProcessor == null)
return element;
return fRenameTypeProcessor.getRefactoredJavaElement(element);
}
// --- preconditions ----------------------------------
@Override
public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
if (fRenameTypeProcessor != null && ! fCu.isStructureKnown()){
fRenameTypeProcessor= null;
fWillRenameType= false;
return new RefactoringStatus();
}
//for a test case what it's needed, see bug 24248
//(the type might be gone from the editor by now)
if (fWillRenameType && fRenameTypeProcessor != null && ! fRenameTypeProcessor.getType().exists()){
fRenameTypeProcessor= null;
fWillRenameType= false;
return new RefactoringStatus();
}
// we purposely do not check activation of the renameTypeRefactoring here.
return new RefactoringStatus();
}
@Override
protected RefactoringStatus doCheckFinalConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException {
try{
if (fWillRenameType && (!fCu.isStructureKnown())){
RefactoringStatus result1= new RefactoringStatus();
RefactoringStatus result2= new RefactoringStatus();
result2.merge(Checks.checkCompilationUnitNewName(fCu, removeFileNameExtension(getNewElementName())));
if (result2.hasFatalError())
result1.addError(Messages.format(RefactoringCoreMessages.RenameCompilationUnitRefactoring_not_parsed_1, BasicElementLabels.getFileName(fCu)));
else
result1.addError(Messages.format(RefactoringCoreMessages.RenameCompilationUnitRefactoring_not_parsed, BasicElementLabels.getFileName(fCu)));
result1.merge(result2);
}
if (fWillRenameType) {
return fRenameTypeProcessor.checkFinalConditions(pm, context);
} else {
return Checks.checkCompilationUnitNewName(fCu, removeFileNameExtension(getNewElementName()));
}
} finally{
pm.done();
}
}
private void computeRenameTypeRefactoring() throws CoreException{
if (getSimpleCUName().indexOf('.') != -1) {
fRenameTypeProcessor= null;
fWillRenameType= false;
return;
}
IType type= getTypeWithTheSameName();
if (type != null) {
fRenameTypeProcessor= new RenameTypeProcessor(type);
} else {
fRenameTypeProcessor= null;
}
fWillRenameType= fRenameTypeProcessor != null && fCu.isStructureKnown();
}
private IType getTypeWithTheSameName() {
try {
IType[] topLevelTypes= fCu.getTypes();
String name= getSimpleCUName();
for (int i = 0; i < topLevelTypes.length; i++) {
if (name.equals(topLevelTypes[i].getElementName()))
return topLevelTypes[i];
}
return null;
} catch (CoreException e) {
return null;
}
}
private String getSimpleCUName() {
return removeFileNameExtension(fCu.getElementName());
}
/**
* Removes the extension (whatever comes after the last '.') from the given file name.
*
* @param fileName the file name
* @return main type name
*/
private static String removeFileNameExtension(String fileName) {
if (fileName.lastIndexOf(".") == -1) //$NON-NLS-1$
return fileName;
return fileName.substring(0, fileName.lastIndexOf(".")); //$NON-NLS-1$
}
@Override
public Change createChange(IProgressMonitor pm) throws CoreException {
// renaming the file is taken care of in renameTypeRefactoring
if (fWillRenameType)
return fRenameTypeProcessor.createChange(pm);
fRenameTypeProcessor= null;
final String newName= getNewElementName();
final IResource resource= fCu.getResource();
if (resource != null && resource.isLinked()) {
final IProject project= resource.getProject();
final String name= project.getName();
final String description= Messages.format(RefactoringCoreMessages.RenameCompilationUnitChange_descriptor_description_short, BasicElementLabels.getResourceName(resource.getName()));
final String header= Messages.format(RefactoringCoreMessages.RenameCompilationUnitChange_descriptor_description, new String[] { BasicElementLabels.getPathLabel(resource.getFullPath(), false), BasicElementLabels.getResourceName(resource.getName())});
final String comment= new JDTRefactoringDescriptorComment(name, this, header).asString();
final int flags= RefactoringDescriptor.STRUCTURAL_CHANGE;
final RenameResourceDescriptor descriptor= (RenameResourceDescriptor) RefactoringCore.getRefactoringContribution(RenameResourceDescriptor.ID).createDescriptor();
descriptor.setProject(name);
descriptor.setDescription(description);
descriptor.setComment(comment);
descriptor.setFlags(flags);
descriptor.setResourcePath(resource.getFullPath());
descriptor.setNewName(newName);
RenameResourceChange resourceChange= new RenameResourceChange(resource.getFullPath(), newName);
resourceChange.setDescriptor(new RefactoringChangeDescriptor(descriptor));
return new DynamicValidationStateChange(resourceChange);
}
String label= JavaElementLabels.getTextLabel(fCu, JavaElementLabels.ALL_FULLY_QUALIFIED);
final String name= fCu.getJavaProject().getElementName();
final String description= Messages.format(RefactoringCoreMessages.RenameCompilationUnitChange_descriptor_description_short, BasicElementLabels.getFileName(fCu));
final String header= Messages.format(RefactoringCoreMessages.RenameCompilationUnitChange_descriptor_description, new String[] { label, BasicElementLabels.getResourceName(newName)});
final String comment= new JDTRefactoringDescriptorComment(name, this, header).asString();
final int flags= RefactoringDescriptor.STRUCTURAL_CHANGE;
final RenameJavaElementDescriptor descriptor= RefactoringSignatureDescriptorFactory.createRenameJavaElementDescriptor(IJavaRefactorings.RENAME_COMPILATION_UNIT);
descriptor.setProject(name);
descriptor.setDescription(description);
descriptor.setComment(comment);
descriptor.setFlags(flags);
descriptor.setJavaElement(fCu);
descriptor.setNewName(newName);
return new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.RenameCompilationUnitRefactoring_name, new Change[] { new RenameCompilationUnitChange(fCu, newName)});
}
@Override
public Change postCreateChange(Change[] participantChanges, IProgressMonitor pm) throws CoreException {
if (fWillRenameType)
return fRenameTypeProcessor.postCreateChange(participantChanges, pm);
return super.postCreateChange(participantChanges, pm);
}
private RefactoringStatus initialize(JavaRefactoringArguments extended) {
final String handle= extended.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
if (handle == null) {
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
}
final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(extended.getProject(), handle, false);
if (element == null || !element.exists() || element.getElementType() != IJavaElement.COMPILATION_UNIT)
return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getProcessorName(), IJavaRefactorings.RENAME_COMPILATION_UNIT);
final String name= extended.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME);
if (name == null || name.length() == 0)
return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME));
fCu= (ICompilationUnit) element;
try {
computeRenameTypeRefactoring();
setNewElementName(name);
} catch (CoreException exception) {
JavaPlugin.log(exception);
return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getProcessorName(), IJavaRefactorings.RENAME_COMPILATION_UNIT);
}
return new RefactoringStatus();
}
/**
* @return the RenameTypeProcessor or <code>null</code> if no type will be renamed
*/
public RenameTypeProcessor getRenameTypeProcessor() {
return fRenameTypeProcessor;
}
public boolean isWillRenameType() {
return fWillRenameType;
}
}