/******************************************************************************* * Copyright (c) 2012-2015 Codenvy, S.A. * 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: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.jdt.refactoring.session; import org.eclipse.che.ide.ext.java.shared.dto.LinkedModeModel; import org.eclipse.che.ide.ext.java.shared.dto.refactoring.ChangeCreationResult; import org.eclipse.che.ide.ext.java.shared.dto.refactoring.ChangeInfo; import org.eclipse.che.ide.ext.java.shared.dto.refactoring.RefactoringResult; import org.eclipse.che.jdt.refactoring.DtoConverter; import org.eclipse.che.jdt.refactoring.RefactoringException; import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.NodeFinder; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.refactoring.IJavaRefactorings; import org.eclipse.jdt.core.refactoring.descriptors.RenameJavaElementDescriptor; import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder; import org.eclipse.jdt.internal.corext.refactoring.rename.RenamingNameSuggestor; import org.eclipse.jdt.ui.SharedASTProvider; import org.eclipse.jdt.ui.refactoring.RenameSupport; import org.eclipse.ltk.core.refactoring.Change; import org.eclipse.ltk.core.refactoring.CompositeChange; import org.eclipse.ltk.core.refactoring.PerformChangeOperation; import org.eclipse.ltk.core.refactoring.RefactoringCore; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import static org.eclipse.che.ide.ext.java.server.dto.DtoServerImpls.LinkedModeModelImpl; import static org.eclipse.che.ide.ext.java.server.dto.DtoServerImpls.LinkedPositionGroupImpl; import static org.eclipse.che.ide.ext.java.server.dto.DtoServerImpls.RegionImpl; /** * The class contains methods for the refactoring that uses the linked editor. * * @author Evgen Vidolob * @author Valeriy Svydenko */ public class RenameLinkedModeRefactoringSession extends RefactoringSession { private final IJavaElement element; private final ICompilationUnit compilationUnit; private final int offset; private String fOriginalName; public RenameLinkedModeRefactoringSession(IJavaElement element, ICompilationUnit compilationUnit, int offset) { super(null); this.element = element; this.compilationUnit = compilationUnit; this.offset = offset; } @Override public ChangeCreationResult createChange() throws RefactoringException { return super.createChange(); } @Override public Change getChange() { return super.getChange(); } @Override public RefactoringResult apply() { throw new UnsupportedOperationException("apply isn't supported on RenameLinkedModeRefactoringSession"); } public LinkedModeModel getModel() { CompilationUnit root = SharedASTProvider.getAST(compilationUnit, SharedASTProvider.WAIT_YES, null); LinkedPositionGroupImpl group = new LinkedPositionGroupImpl(); ASTNode selectedNode = NodeFinder.perform(root, offset, 0); if (!(selectedNode instanceof SimpleName)) { return null; } SimpleName nameNode = (SimpleName)selectedNode; fOriginalName = nameNode.getIdentifier(); final int pos = nameNode.getStartPosition(); ASTNode[] sameNodes = LinkedNodeFinder.findByNode(root, nameNode); //TODO: copied from LinkedNamesAssistProposal#apply(..): // sort for iteration order, starting with the node @ offset Arrays.sort(sameNodes, new Comparator<ASTNode>() { public int compare(ASTNode o1, ASTNode o2) { return rank(o1) - rank(o2); } /** * Returns the absolute rank of an <code>ASTNode</code>. Nodes * preceding <code>pos</code> are ranked last. * * @param node the node to compute the rank for * @return the rank of the node with respect to the invocation offset */ private int rank(ASTNode node) { int relativeRank = node.getStartPosition() + node.getLength() - pos; if (relativeRank < 0) return Integer.MAX_VALUE + relativeRank; else return relativeRank; } }); for (int i= 0; i < sameNodes.length; i++) { ASTNode elem= sameNodes[i]; RegionImpl position = new RegionImpl(); position.setOffset(elem.getStartPosition()); position.setLength(elem.getLength()); group.addPositions(position); } LinkedModeModelImpl model = new LinkedModeModelImpl(); model.addGroups(group); return model; } /** * Make rename operation. * @param newName the name which will be applied * @return result of the rename operation * @throws CoreException if an error occurs while creating the refactoring instance * @throws InvocationTargetException if an error occurred while executing the * operation. * @throws InterruptedException if the operation has been canceled by the * user. */ public RefactoringResult doRename(String newName) throws CoreException, InvocationTargetException, InterruptedException { if (fOriginalName.equals(newName)) { return DtoConverter.toRefactoringResultDto(new RefactoringStatus()); } RenameSupport renameSupport= undoAndCreateRenameSupport(newName); if (renameSupport == null) return DtoConverter.toRefactoringResultDto(RefactoringStatus.createFatalErrorStatus("Can't create rename refactoring")); RefactoringResult refactoringResult = DtoConverter.toRefactoringResultDto(renameSupport.perform()); PerformChangeOperation operation =renameSupport.getfPerformChangeOperation(); CompositeChange operationChange = (CompositeChange)operation.getUndoChange(); Change[] changes = operationChange.getChildren(); List<ChangeInfo> changesInfo = new ArrayList<>(); prepareChangesInfo(changes, changesInfo); refactoringResult.setChanges(changesInfo); return refactoringResult; } private RenameSupport undoAndCreateRenameSupport(String newName) throws CoreException { if (newName.length() == 0) return null; RenameJavaElementDescriptor descriptor= createRenameDescriptor(element, newName); return RenameSupport.create(descriptor); } /** * Creates a rename descriptor. * * @param javaElement element to rename * @param newName new name * @return a rename descriptor with current settings as used in the refactoring dialogs * @throws JavaModelException if an error occurs while accessing the element */ private RenameJavaElementDescriptor createRenameDescriptor(IJavaElement javaElement, String newName) throws JavaModelException { String contributionId; // see RefactoringExecutionStarter#createRenameSupport(..): int elementType= javaElement.getElementType(); switch (elementType) { case IJavaElement.JAVA_PROJECT: contributionId= IJavaRefactorings.RENAME_JAVA_PROJECT; break; case IJavaElement.PACKAGE_FRAGMENT_ROOT: contributionId= IJavaRefactorings.RENAME_SOURCE_FOLDER; break; case IJavaElement.PACKAGE_FRAGMENT: contributionId= IJavaRefactorings.RENAME_PACKAGE; break; case IJavaElement.COMPILATION_UNIT: contributionId= IJavaRefactorings.RENAME_COMPILATION_UNIT; break; case IJavaElement.TYPE: contributionId= IJavaRefactorings.RENAME_TYPE; break; case IJavaElement.METHOD: final IMethod method= (IMethod) javaElement; if (method.isConstructor()) return createRenameDescriptor(method.getDeclaringType(), newName); else contributionId= IJavaRefactorings.RENAME_METHOD; break; case IJavaElement.FIELD: IField field= (IField) javaElement; if (field.isEnumConstant()) contributionId= IJavaRefactorings.RENAME_ENUM_CONSTANT; else contributionId= IJavaRefactorings.RENAME_FIELD; break; case IJavaElement.TYPE_PARAMETER: contributionId= IJavaRefactorings.RENAME_TYPE_PARAMETER; break; case IJavaElement.LOCAL_VARIABLE: contributionId= IJavaRefactorings.RENAME_LOCAL_VARIABLE; break; default: return null; } RenameJavaElementDescriptor descriptor= (RenameJavaElementDescriptor) RefactoringCore.getRefactoringContribution(contributionId).createDescriptor(); descriptor.setJavaElement(javaElement); descriptor.setNewName(newName); if (elementType != IJavaElement.PACKAGE_FRAGMENT_ROOT) descriptor.setUpdateReferences(true); // IDialogSettings javaSettings= JavaPlugin.getDefault().getDialogSettings(); // IDialogSettings refactoringSettings= javaSettings.getSection(RefactoringWizardPage.REFACTORING_SETTINGS); //TODO: undocumented API // if (refactoringSettings == null) { // refactoringSettings= javaSettings.addNewSection(RefactoringWizardPage.REFACTORING_SETTINGS); // } switch (elementType) { case IJavaElement.METHOD: case IJavaElement.FIELD: descriptor.setDeprecateDelegate(/*refactoringSettings.getBoolean(DelegateUIHelper.DELEGATE_DEPRECATION)*/false); descriptor.setKeepOriginal(/*refactoringSettings.getBoolean(DelegateUIHelper.DELEGATE_UPDATING)*/ false); } switch (elementType) { case IJavaElement.TYPE: // case IJavaElement.COMPILATION_UNIT: // TODO descriptor.setUpdateSimilarDeclarations(/*refactoringSettings.getBoolean(RenameRefactoringWizard.TYPE_UPDATE_SIMILAR_ELEMENTS)*/ false); int strategy; try { strategy= 1; //refactoringSettings.getInt(RenameRefactoringWizard.TYPE_SIMILAR_MATCH_STRATEGY); } catch (NumberFormatException e) { strategy= RenamingNameSuggestor.STRATEGY_EXACT; } descriptor.setMatchStrategy(strategy); } switch (elementType) { case IJavaElement.PACKAGE_FRAGMENT: descriptor.setUpdateHierarchy(/*refactoringSettings.getBoolean(RenameRefactoringWizard.PACKAGE_RENAME_SUBPACKAGES)*/true); } switch (elementType) { case IJavaElement.PACKAGE_FRAGMENT: case IJavaElement.TYPE: String fileNamePatterns= /*refactoringSettings.get(RenameRefactoringWizard.QUALIFIED_NAMES_PATTERNS)*/"*"; if (fileNamePatterns != null && fileNamePatterns.length() != 0) { descriptor.setFileNamePatterns(fileNamePatterns); boolean updateQualifiedNames= /*refactoringSettings.getBoolean(RenameRefactoringWizard.UPDATE_QUALIFIED_NAMES)*/false; descriptor.setUpdateQualifiedNames(updateQualifiedNames); // fShowPreview|= updateQualifiedNames; } } switch (elementType) { case IJavaElement.PACKAGE_FRAGMENT: case IJavaElement.TYPE: case IJavaElement.FIELD: boolean updateTextualOccurrences= false; //refactoringSettings.getBoolean(RenameRefactoringWizard.UPDATE_TEXTUAL_MATCHES); descriptor.setUpdateTextualOccurrences(updateTextualOccurrences); // fShowPreview|= updateTextualOccurrences; } switch (elementType) { case IJavaElement.FIELD: descriptor.setRenameGetters(/*refactoringSettings.getBoolean(RenameRefactoringWizard.FIELD_RENAME_GETTER)*/false); descriptor.setRenameSetters(/*refactoringSettings.getBoolean(RenameRefactoringWizard.FIELD_RENAME_SETTER)*/false); } return descriptor; } }