0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.jdt.internal.corext.refactoring.rename;
0011:
0012: import java.util.ArrayList;
0013: import java.util.Arrays;
0014: import java.util.Collection;
0015: import java.util.HashMap;
0016: import java.util.HashSet;
0017: import java.util.Iterator;
0018: import java.util.List;
0019: import java.util.Set;
0020: import java.util.Map.Entry;
0021:
0022: import org.eclipse.text.edits.MalformedTreeException;
0023: import org.eclipse.text.edits.ReplaceEdit;
0024: import org.eclipse.text.edits.TextEdit;
0025:
0026: import org.eclipse.core.runtime.Assert;
0027: import org.eclipse.core.runtime.CoreException;
0028: import org.eclipse.core.runtime.IPath;
0029: import org.eclipse.core.runtime.IProgressMonitor;
0030: import org.eclipse.core.runtime.SubProgressMonitor;
0031:
0032: import org.eclipse.core.resources.IContainer;
0033: import org.eclipse.core.resources.IFile;
0034: import org.eclipse.core.resources.IFolder;
0035: import org.eclipse.core.resources.IResource;
0036:
0037: import org.eclipse.ltk.core.refactoring.Change;
0038: import org.eclipse.ltk.core.refactoring.CompositeChange;
0039: import org.eclipse.ltk.core.refactoring.IResourceMapper;
0040: import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
0041: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
0042: import org.eclipse.ltk.core.refactoring.RefactoringStatusContext;
0043: import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
0044: import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
0045: import org.eclipse.ltk.core.refactoring.participants.RenameArguments;
0046:
0047: import org.eclipse.jdt.core.Flags;
0048: import org.eclipse.jdt.core.IClassFile;
0049: import org.eclipse.jdt.core.ICompilationUnit;
0050: import org.eclipse.jdt.core.IImportDeclaration;
0051: import org.eclipse.jdt.core.IJavaElement;
0052: import org.eclipse.jdt.core.IJavaProject;
0053: import org.eclipse.jdt.core.IMethod;
0054: import org.eclipse.jdt.core.IPackageFragment;
0055: import org.eclipse.jdt.core.IPackageFragmentRoot;
0056: import org.eclipse.jdt.core.IType;
0057: import org.eclipse.jdt.core.JavaModelException;
0058: import org.eclipse.jdt.core.Signature;
0059: import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
0060: import org.eclipse.jdt.core.refactoring.IJavaElementMapper;
0061: import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
0062: import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
0063: import org.eclipse.jdt.core.refactoring.descriptors.RenameJavaElementDescriptor;
0064: import org.eclipse.jdt.core.search.IJavaSearchConstants;
0065: import org.eclipse.jdt.core.search.IJavaSearchScope;
0066: import org.eclipse.jdt.core.search.SearchEngine;
0067: import org.eclipse.jdt.core.search.SearchMatch;
0068: import org.eclipse.jdt.core.search.SearchPattern;
0069: import org.eclipse.jdt.core.search.SearchRequestor;
0070:
0071: import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
0072: import org.eclipse.jdt.internal.corext.refactoring.Checks;
0073: import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
0074: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
0075: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
0076: import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
0077: import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
0078: import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
0079: import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine;
0080: import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
0081: import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
0082: import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
0083: import org.eclipse.jdt.internal.corext.refactoring.changes.RenamePackageChange;
0084: import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility;
0085: import org.eclipse.jdt.internal.corext.refactoring.code.ScriptableRefactoring;
0086: import org.eclipse.jdt.internal.corext.refactoring.participants.JavaProcessors;
0087: import org.eclipse.jdt.internal.corext.refactoring.rename.RenamePackageProcessor.ImportsManager.ImportChange;
0088: import org.eclipse.jdt.internal.corext.refactoring.tagging.IQualifiedNameUpdating;
0089: import org.eclipse.jdt.internal.corext.refactoring.tagging.IReferenceUpdating;
0090: import org.eclipse.jdt.internal.corext.refactoring.tagging.ITextUpdating;
0091: import org.eclipse.jdt.internal.corext.refactoring.util.Changes;
0092: import org.eclipse.jdt.internal.corext.refactoring.util.CommentAnalyzer;
0093: import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil;
0094: import org.eclipse.jdt.internal.corext.refactoring.util.QualifiedNameFinder;
0095: import org.eclipse.jdt.internal.corext.refactoring.util.QualifiedNameSearchResult;
0096: import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
0097: import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
0098: import org.eclipse.jdt.internal.corext.util.Messages;
0099: import org.eclipse.jdt.internal.corext.util.Resources;
0100: import org.eclipse.jdt.internal.corext.util.SearchUtils;
0101:
0102: import org.eclipse.jdt.internal.ui.JavaPlugin;
0103: import org.eclipse.jdt.internal.ui.refactoring.RefactoringSaveHelper;
0104:
0105: public class RenamePackageProcessor extends JavaRenameProcessor
0106: implements IReferenceUpdating, ITextUpdating,
0107: IQualifiedNameUpdating, IResourceMapper, IJavaElementMapper {
0108:
0109: private static final String ATTRIBUTE_QUALIFIED = "qualified"; //$NON-NLS-1$
0110: private static final String ATTRIBUTE_TEXTUAL_MATCHES = "textual"; //$NON-NLS-1$
0111: private static final String ATTRIBUTE_PATTERNS = "patterns"; //$NON-NLS-1$
0112: private static final String ATTRIBUTE_HIERARCHICAL = "hierarchical"; //$NON-NLS-1$
0113:
0114: private IPackageFragment fPackage;
0115:
0116: private TextChangeManager fChangeManager;
0117: private ImportsManager fImportsManager;
0118: private QualifiedNameSearchResult fQualifiedNameSearchResult;
0119:
0120: private boolean fUpdateReferences;
0121: private boolean fUpdateTextualMatches;
0122: private boolean fUpdateQualifiedNames;
0123: private String fFilePatterns;
0124: private boolean fRenameSubpackages;
0125:
0126: public static final String IDENTIFIER = "org.eclipse.jdt.ui.renamePackageProcessor"; //$NON-NLS-1$
0127: private RenamePackageChange fRenamePackageChange;
0128:
0129: /**
0130: * Creates a new rename package processor.
0131: * @param fragment the package fragment, or <code>null</code> if invoked by scripting
0132: */
0133: public RenamePackageProcessor(IPackageFragment fragment) {
0134: fPackage = fragment;
0135: if (fPackage != null)
0136: setNewElementName(fPackage.getElementName());
0137: fUpdateReferences = true;
0138: fUpdateTextualMatches = false;
0139: fRenameSubpackages = false;
0140: }
0141:
0142: public String getIdentifier() {
0143: return IDENTIFIER;
0144: }
0145:
0146: public boolean isApplicable() throws CoreException {
0147: return RefactoringAvailabilityTester
0148: .isRenameAvailable(fPackage);
0149: }
0150:
0151: public String getProcessorName() {
0152: return RefactoringCoreMessages.RenamePackageRefactoring_name;
0153: }
0154:
0155: protected String[] getAffectedProjectNatures() throws CoreException {
0156: return JavaProcessors.computeAffectedNatures(fPackage);
0157: }
0158:
0159: public Object[] getElements() {
0160: return new Object[] { fPackage };
0161: }
0162:
0163: protected RenameModifications computeRenameModifications()
0164: throws CoreException {
0165: RenameModifications result = new RenameModifications();
0166: result.rename(fPackage, new RenameArguments(
0167: getNewElementName(), getUpdateReferences()),
0168: fRenameSubpackages);
0169: return result;
0170: }
0171:
0172: protected IFile[] getChangedFiles() throws CoreException {
0173: Set combined = new HashSet();
0174: combined.addAll(Arrays.asList(ResourceUtil
0175: .getFiles(fChangeManager.getAllCompilationUnits())));
0176: if (fRenameSubpackages) {
0177: IPackageFragment[] allPackages = JavaElementUtil
0178: .getPackageAndSubpackages(fPackage);
0179: for (int i = 0; i < allPackages.length; i++) {
0180: combined.addAll(Arrays
0181: .asList(ResourceUtil.getFiles(allPackages[i]
0182: .getCompilationUnits())));
0183: }
0184: } else {
0185: combined.addAll(Arrays.asList(ResourceUtil
0186: .getFiles(fPackage.getCompilationUnits())));
0187: }
0188: if (fQualifiedNameSearchResult != null)
0189: combined.addAll(Arrays.asList(fQualifiedNameSearchResult
0190: .getAllFiles()));
0191: return (IFile[]) combined.toArray(new IFile[combined.size()]);
0192: }
0193:
0194: public int getSaveMode() {
0195: return RefactoringSaveHelper.SAVE_ALL;
0196: }
0197:
0198: //---- ITextUpdating -------------------------------------------------
0199:
0200: public boolean canEnableTextUpdating() {
0201: return true;
0202: }
0203:
0204: public boolean getUpdateTextualMatches() {
0205: return fUpdateTextualMatches;
0206: }
0207:
0208: public void setUpdateTextualMatches(boolean update) {
0209: fUpdateTextualMatches = update;
0210: }
0211:
0212: //---- IReferenceUpdating --------------------------------------
0213:
0214: public boolean canEnableUpdateReferences() {
0215: return true;
0216: }
0217:
0218: public void setUpdateReferences(boolean update) {
0219: fUpdateReferences = update;
0220: }
0221:
0222: public boolean getUpdateReferences() {
0223: return fUpdateReferences;
0224: }
0225:
0226: //---- IQualifiedNameUpdating ----------------------------------
0227:
0228: public boolean canEnableQualifiedNameUpdating() {
0229: return !fPackage.isDefaultPackage();
0230: }
0231:
0232: public boolean getUpdateQualifiedNames() {
0233: return fUpdateQualifiedNames;
0234: }
0235:
0236: public void setUpdateQualifiedNames(boolean update) {
0237: fUpdateQualifiedNames = update;
0238: }
0239:
0240: public String getFilePatterns() {
0241: return fFilePatterns;
0242: }
0243:
0244: public void setFilePatterns(String patterns) {
0245: Assert.isNotNull(patterns);
0246: fFilePatterns = patterns;
0247: }
0248:
0249: //---- IResourceMapper ----------------------------------
0250:
0251: public IResource getRefactoredResource(IResource element) {
0252: IFolder packageFolder = (IFolder) fPackage.getResource();
0253: if (packageFolder == null)
0254: return element;
0255:
0256: IContainer newPackageFolder = (IContainer) getNewPackage()
0257: .getResource();
0258:
0259: if (packageFolder.equals(element))
0260: return newPackageFolder;
0261:
0262: IPath packagePath = packageFolder.getProjectRelativePath();
0263: IPath elementPath = element.getProjectRelativePath();
0264:
0265: if (packagePath.isPrefixOf(elementPath)) {
0266: if (fRenameSubpackages
0267: || (element instanceof IFile && packageFolder
0268: .equals(element.getParent()))) {
0269: IPath pathInPackage = elementPath
0270: .removeFirstSegments(packagePath.segmentCount());
0271: if (element instanceof IFile)
0272: return newPackageFolder.getFile(pathInPackage);
0273: else
0274: return newPackageFolder.getFolder(pathInPackage);
0275: }
0276: }
0277: return element;
0278: }
0279:
0280: //---- IJavaElementMapper ----------------------------------
0281:
0282: public IJavaElement getRefactoredJavaElement(IJavaElement original) {
0283: return new GenericRefactoringHandleTransplanter() {
0284: protected IPackageFragment transplantHandle(
0285: IPackageFragmentRoot parent,
0286: IPackageFragment element) {
0287: if (!fRenameSubpackages) {
0288: if (fPackage.equals(element))
0289: return getNewPackage();
0290: } else {
0291: String packName = element.getElementName();
0292: String packageName = fPackage.getElementName();
0293: if (fPackage.getParent().equals(parent)
0294: && packName.startsWith(packageName + '.')) {
0295: String newPackName = getNewElementName()
0296: + packName.substring(packageName
0297: .length() - 1);
0298: return getPackageFragmentRoot()
0299: .getPackageFragment(newPackName);
0300: }
0301: }
0302: return super .transplantHandle(parent, element);
0303: }
0304:
0305: protected IMethod transplantHandle(IType parent,
0306: IMethod element) {
0307: String[] parameterTypes = resolveParameterTypes(element);
0308: return parent.getMethod(element.getElementName(),
0309: parameterTypes);
0310: }
0311:
0312: private String[] resolveParameterTypes(IMethod method) {
0313: final String[] oldParameterTypes = method
0314: .getParameterTypes();
0315: final String[] newparams = new String[oldParameterTypes.length];
0316:
0317: final String[] possibleOldSigs = new String[2];
0318: //using type signature, since there is no package signature
0319: possibleOldSigs[0] = Signature.createTypeSignature(
0320: fPackage.getElementName(), false);
0321: possibleOldSigs[1] = Signature.createTypeSignature(
0322: fPackage.getElementName(), true);
0323:
0324: final String[] possibleNewSigs = new String[2];
0325: possibleNewSigs[0] = Signature.createTypeSignature(
0326: getNewElementName(), false);
0327: possibleNewSigs[1] = Signature.createTypeSignature(
0328: getNewElementName(), true);
0329:
0330: // Textually replace all occurrences
0331: // This handles stuff like Map<SomeClass, some.package.SomeClass>
0332: for (int i = 0; i < oldParameterTypes.length; i++) {
0333: newparams[i] = oldParameterTypes[i];
0334: for (int j = 0; j < possibleOldSigs.length; j++) {
0335: newparams[i] = replaceAll(newparams[i],
0336: possibleOldSigs[j], possibleNewSigs[j]);
0337: }
0338: }
0339: return newparams;
0340: }
0341:
0342: private String replaceAll(final String source,
0343: final String replaceFrom, final String replaceTo) {
0344: final StringBuffer buf = new StringBuffer(source
0345: .length());
0346: int currentIndex = 0;
0347: int matchIndex;
0348: while ((matchIndex = source.indexOf(replaceFrom,
0349: currentIndex)) != -1) {
0350: buf.append(source.substring(currentIndex,
0351: matchIndex));
0352: buf.append(replaceTo);
0353: currentIndex = matchIndex + replaceFrom.length();
0354: }
0355: buf.append(source.substring(currentIndex));
0356: return buf.toString();
0357: }
0358: }.transplantHandle(original);
0359: }
0360:
0361: //----
0362:
0363: public boolean canEnableRenameSubpackages()
0364: throws JavaModelException {
0365: return fPackage.hasSubpackages();
0366: }
0367:
0368: public boolean getRenameSubpackages() {
0369: return fRenameSubpackages;
0370: }
0371:
0372: public void setRenameSubpackages(boolean rename) {
0373: fRenameSubpackages = rename;
0374: }
0375:
0376: //---- IRenameProcessor ----------------------------------------------
0377:
0378: public final String getCurrentElementName() {
0379: return fPackage.getElementName();
0380: }
0381:
0382: public String getCurrentElementQualifier() {
0383: return ""; //$NON-NLS-1$
0384: }
0385:
0386: public RefactoringStatus checkNewElementName(String newName)
0387: throws CoreException {
0388: Assert.isNotNull(newName, "new name"); //$NON-NLS-1$
0389: RefactoringStatus result = Checks.checkPackageName(newName,
0390: fPackage);
0391: if (result.hasFatalError())
0392: return result;
0393: if (Checks.isAlreadyNamed(fPackage, newName)) {
0394: result
0395: .addFatalError(RefactoringCoreMessages.RenamePackageRefactoring_another_name);
0396: return result;
0397: }
0398: result.merge(checkPackageInCurrentRoot(newName));
0399: return result;
0400: }
0401:
0402: public Object getNewElement() {
0403: return getNewPackage();
0404: }
0405:
0406: private IPackageFragment getNewPackage() {
0407: IPackageFragmentRoot root = getPackageFragmentRoot();
0408: return root.getPackageFragment(getNewElementName());
0409: }
0410:
0411: public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
0412: throws CoreException {
0413: return new RefactoringStatus();
0414: }
0415:
0416: protected RefactoringStatus doCheckFinalConditions(
0417: IProgressMonitor pm, CheckConditionsContext context)
0418: throws CoreException {
0419: try {
0420: pm
0421: .beginTask(
0422: "", 23 + (fUpdateQualifiedNames ? 10 : 0) + (fUpdateTextualMatches ? 10 : 0)); //$NON-NLS-1$
0423: pm
0424: .setTaskName(RefactoringCoreMessages.RenamePackageRefactoring_checking);
0425: RefactoringStatus result = new RefactoringStatus();
0426: result.merge(checkNewElementName(getNewElementName()));
0427: pm.worked(1);
0428: result.merge(checkForMainAndNativeMethods());
0429: pm.worked(2);
0430:
0431: if (fPackage.isReadOnly()) {
0432: String message = Messages
0433: .format(
0434: RefactoringCoreMessages.RenamePackageRefactoring_Packagered_only,
0435: fPackage.getElementName());
0436: result.addFatalError(message);
0437: } else if (Resources.isReadOnly(fPackage.getResource())) {
0438: String message = Messages
0439: .format(
0440: RefactoringCoreMessages.RenamePackageRefactoring_resource_read_only,
0441: fPackage.getElementName());
0442: result.addError(message);
0443: }
0444:
0445: result.merge(checkPackageName(getNewElementName()));
0446: if (result.hasFatalError())
0447: return result;
0448:
0449: fChangeManager = new TextChangeManager();
0450: fImportsManager = new ImportsManager();
0451:
0452: SubProgressMonitor subPm = new SubProgressMonitor(pm, 16);
0453: if (fRenameSubpackages) {
0454: IPackageFragment[] allSubpackages = JavaElementUtil
0455: .getPackageAndSubpackages(fPackage);
0456: subPm.beginTask("", allSubpackages.length); //$NON-NLS-1$
0457: for (int i = 0; i < allSubpackages.length; i++) {
0458: new PackageRenamer(allSubpackages[i], this ,
0459: fChangeManager, fImportsManager).doRename(
0460: new SubProgressMonitor(subPm, 1), result);
0461: }
0462: subPm.done();
0463: } else {
0464: new PackageRenamer(fPackage, this , fChangeManager,
0465: fImportsManager).doRename(subPm, result);
0466: }
0467:
0468: fImportsManager.rewriteImports(fChangeManager,
0469: new SubProgressMonitor(pm, 3));
0470:
0471: if (fUpdateTextualMatches) {
0472: pm
0473: .subTask(RefactoringCoreMessages.RenamePackageRefactoring_searching_text);
0474: TextMatchUpdater.perform(
0475: new SubProgressMonitor(pm, 10),
0476: RefactoringScopeFactory.create(fPackage), this ,
0477: fChangeManager, new SearchResultGroup[0]);
0478: }
0479:
0480: if (fUpdateQualifiedNames)
0481: computeQualifiedNameMatches(new SubProgressMonitor(pm,
0482: 10));
0483:
0484: return result;
0485: } finally {
0486: pm.done();
0487: }
0488: }
0489:
0490: public IPackageFragment getPackage() {
0491: return fPackage;
0492: }
0493:
0494: private RefactoringStatus checkForMainAndNativeMethods()
0495: throws CoreException {
0496: RefactoringStatus result = new RefactoringStatus();
0497: if (fRenameSubpackages) {
0498: IPackageFragment[] allSubpackages = JavaElementUtil
0499: .getPackageAndSubpackages(fPackage);
0500: for (int i = 0; i < allSubpackages.length; i++) {
0501: ICompilationUnit[] cus = allSubpackages[i]
0502: .getCompilationUnits();
0503: for (int c = 0; c < cus.length; c++)
0504: result.merge(Checks
0505: .checkForMainAndNativeMethods(cus[c]));
0506: }
0507: } else {
0508: ICompilationUnit[] cus = fPackage.getCompilationUnits();
0509: for (int i = 0; i < cus.length; i++)
0510: result.merge(Checks
0511: .checkForMainAndNativeMethods(cus[i]));
0512: }
0513: return result;
0514: }
0515:
0516: /*
0517: * returns true if the new name is ok if the specified root.
0518: * if a package fragment with this name exists and has java resources,
0519: * then the name is not ok.
0520: */
0521: public static boolean isPackageNameOkInRoot(String newName,
0522: IPackageFragmentRoot root) throws CoreException {
0523: IPackageFragment pack = root.getPackageFragment(newName);
0524: if (!pack.exists())
0525: return true;
0526: else if (pack.containsJavaResources())
0527: return false;
0528: else if (pack.getNonJavaResources().length != 0)
0529: return false;
0530: else
0531: return true;
0532: }
0533:
0534: private RefactoringStatus checkPackageInCurrentRoot(String newName)
0535: throws CoreException {
0536: if (fRenameSubpackages) {
0537: String currentName = getCurrentElementName();
0538: if (isAncestorPackage(currentName, newName)) {
0539: // renaming to subpackage (a -> a.b) is always OK, since all subpackages are also renamed
0540: return null;
0541: }
0542: if (!isAncestorPackage(newName, currentName)) {
0543: // renaming to an unrelated package
0544: if (!isPackageNameOkInRoot(newName,
0545: getPackageFragmentRoot())) {
0546: return RefactoringStatus
0547: .createFatalErrorStatus(RefactoringCoreMessages.RenamePackageRefactoring_package_exists);
0548: }
0549: }
0550: // renaming to superpackage (a.b -> a) or another package is OK iff
0551: // 'a.b' does not contain any subpackage that would collide with another subpackage of 'a'
0552: // (e.g. a.b.c collides if a.c already exists, but a.b.b does not collide with a.b)
0553: IPackageFragment[] packsToRename = JavaElementUtil
0554: .getPackageAndSubpackages(fPackage);
0555: for (int i = 0; i < packsToRename.length; i++) {
0556: IPackageFragment pack = packsToRename[i];
0557: String newPack = newName
0558: + pack.getElementName().substring(
0559: currentName.length());
0560: if (!isAncestorPackage(currentName, newPack)
0561: && !isPackageNameOkInRoot(newPack,
0562: getPackageFragmentRoot())) {
0563: String msg = Messages
0564: .format(
0565: RefactoringCoreMessages.RenamePackageProcessor_subpackage_collides,
0566: newPack);
0567: return RefactoringStatus
0568: .createFatalErrorStatus(msg);
0569: }
0570: }
0571: return null;
0572:
0573: } else if (!isPackageNameOkInRoot(newName,
0574: getPackageFragmentRoot())) {
0575: return RefactoringStatus
0576: .createFatalErrorStatus(RefactoringCoreMessages.RenamePackageRefactoring_package_exists);
0577: } else {
0578: return null;
0579: }
0580: }
0581:
0582: private boolean isAncestorPackage(String ancestor, String descendant) {
0583: int a = ancestor.length();
0584: int d = descendant.length();
0585: if (a == d || (a < d && descendant.charAt(a) == '.'))
0586: return descendant.startsWith(ancestor);
0587: else
0588: return false;
0589: }
0590:
0591: private IPackageFragmentRoot getPackageFragmentRoot() {
0592: return ((IPackageFragmentRoot) fPackage.getParent());
0593: }
0594:
0595: private RefactoringStatus checkPackageName(String newName)
0596: throws CoreException {
0597: RefactoringStatus status = new RefactoringStatus();
0598: IPackageFragmentRoot[] roots = fPackage.getJavaProject()
0599: .getPackageFragmentRoots();
0600: Set topLevelTypeNames = getTopLevelTypeNames();
0601: for (int i = 0; i < roots.length; i++) {
0602: if (!isPackageNameOkInRoot(newName, roots[i])) {
0603: String message = Messages
0604: .format(
0605: RefactoringCoreMessages.RenamePackageRefactoring_aleady_exists,
0606: new Object[] { getNewElementName(),
0607: roots[i].getElementName() });
0608: status.merge(RefactoringStatus
0609: .createWarningStatus(message));
0610: status.merge(checkTypeNameConflicts(roots[i], newName,
0611: topLevelTypeNames));
0612: }
0613: }
0614: return status;
0615: }
0616:
0617: private Set getTopLevelTypeNames() throws CoreException {
0618: ICompilationUnit[] cus = fPackage.getCompilationUnits();
0619: Set result = new HashSet(2 * cus.length);
0620: for (int i = 0; i < cus.length; i++) {
0621: result.addAll(getTopLevelTypeNames(cus[i]));
0622: }
0623: return result;
0624: }
0625:
0626: private static Collection getTopLevelTypeNames(
0627: ICompilationUnit iCompilationUnit) throws CoreException {
0628: IType[] types = iCompilationUnit.getTypes();
0629: List result = new ArrayList(types.length);
0630: for (int i = 0; i < types.length; i++) {
0631: result.add(types[i].getElementName());
0632: }
0633: return result;
0634: }
0635:
0636: private RefactoringStatus checkTypeNameConflicts(
0637: IPackageFragmentRoot root, String newName,
0638: Set topLevelTypeNames) throws CoreException {
0639: IPackageFragment otherPack = root.getPackageFragment(newName);
0640: if (fPackage.equals(otherPack))
0641: return null;
0642: ICompilationUnit[] cus = otherPack.getCompilationUnits();
0643: RefactoringStatus result = new RefactoringStatus();
0644: for (int i = 0; i < cus.length; i++) {
0645: result.merge(checkTypeNameConflicts(cus[i],
0646: topLevelTypeNames));
0647: }
0648: return result;
0649: }
0650:
0651: private RefactoringStatus checkTypeNameConflicts(
0652: ICompilationUnit iCompilationUnit, Set topLevelTypeNames)
0653: throws CoreException {
0654: RefactoringStatus result = new RefactoringStatus();
0655: IType[] types = iCompilationUnit.getTypes();
0656: String packageName = iCompilationUnit.getParent()
0657: .getElementName();
0658: for (int i = 0; i < types.length; i++) {
0659: String name = types[i].getElementName();
0660: if (topLevelTypeNames.contains(name)) {
0661: String[] keys = { packageName, name };
0662: String msg = Messages
0663: .format(
0664: RefactoringCoreMessages.RenamePackageRefactoring_contains_type,
0665: keys);
0666: RefactoringStatusContext context = JavaStatusContext
0667: .create(types[i]);
0668: result.addError(msg, context);
0669: }
0670: }
0671: return result;
0672: }
0673:
0674: public Change createChange(IProgressMonitor monitor)
0675: throws CoreException {
0676: try {
0677: monitor
0678: .beginTask(
0679: RefactoringCoreMessages.RenamePackageRefactoring_creating_change,
0680: 1);
0681: final RenameJavaElementDescriptor descriptor = createRefactoringDescriptor();
0682: final DynamicValidationRefactoringChange result = new DynamicValidationRefactoringChange(
0683: descriptor,
0684: RefactoringCoreMessages.RenamePackageRefactoring_change_name);
0685: result.addAll(fChangeManager.getAllChanges());
0686: fRenamePackageChange = new RenamePackageChange(fPackage,
0687: getNewElementName(), fRenameSubpackages);
0688: result.add(fRenamePackageChange);
0689: monitor.worked(1);
0690: return result;
0691: } finally {
0692: fChangeManager = null;
0693: fImportsManager = null;
0694: monitor.done();
0695: }
0696: }
0697:
0698: private RenameJavaElementDescriptor createRefactoringDescriptor() {
0699: String project = null;
0700: IJavaProject javaProject = fPackage.getJavaProject();
0701: if (javaProject != null)
0702: project = javaProject.getElementName();
0703: final int flags = JavaRefactoringDescriptor.JAR_MIGRATION
0704: | JavaRefactoringDescriptor.JAR_REFACTORING
0705: | RefactoringDescriptor.STRUCTURAL_CHANGE
0706: | RefactoringDescriptor.MULTI_CHANGE;
0707: final String description = Messages
0708: .format(
0709: RefactoringCoreMessages.RenamePackageProcessor_descriptor_description_short,
0710: fPackage.getElementName());
0711: final String header = Messages
0712: .format(
0713: RefactoringCoreMessages.RenamePackageProcessor_descriptor_description,
0714: new String[] { fPackage.getElementName(),
0715: getNewElementName() });
0716: final JDTRefactoringDescriptorComment comment = new JDTRefactoringDescriptorComment(
0717: project, this , header);
0718: if (fRenameSubpackages)
0719: comment
0720: .addSetting(RefactoringCoreMessages.RenamePackageProcessor_rename_subpackages);
0721: final RenameJavaElementDescriptor descriptor = new RenameJavaElementDescriptor(
0722: IJavaRefactorings.RENAME_PACKAGE);
0723: descriptor.setProject(project);
0724: descriptor.setDescription(description);
0725: descriptor.setComment(comment.asString());
0726: descriptor.setFlags(flags);
0727: descriptor.setJavaElement(fPackage);
0728: descriptor.setNewName(getNewElementName());
0729: descriptor.setUpdateReferences(fUpdateReferences);
0730: descriptor.setUpdateTextualOccurrences(fUpdateTextualMatches);
0731: descriptor.setUpdateQualifiedNames(fUpdateQualifiedNames);
0732: if (fUpdateQualifiedNames && fFilePatterns != null
0733: && !"".equals(fFilePatterns)) //$NON-NLS-1$
0734: descriptor.setFileNamePatterns(fFilePatterns);
0735: descriptor.setUpdateHierarchy(fRenameSubpackages);
0736: return descriptor;
0737: }
0738:
0739: public Change postCreateChange(Change[] participantChanges,
0740: IProgressMonitor pm) throws CoreException {
0741: if (fQualifiedNameSearchResult != null) {
0742: CompositeChange parent = (CompositeChange) fRenamePackageChange
0743: .getParent();
0744: try {
0745: /*
0746: * Sneak text changes in before the package rename to ensure
0747: * modified files are still at original location (see
0748: * https://bugs.eclipse.org/bugs/show_bug.cgi?id=154238)
0749: */
0750: parent.remove(fRenamePackageChange);
0751: parent.add(fQualifiedNameSearchResult
0752: .getSingleChange(Changes
0753: .getModifiedFiles(participantChanges)));
0754: } finally {
0755: fQualifiedNameSearchResult = null;
0756: parent.add(fRenamePackageChange);
0757: fRenamePackageChange = null;
0758: }
0759: }
0760: return null;
0761: }
0762:
0763: private void computeQualifiedNameMatches(IProgressMonitor pm)
0764: throws CoreException {
0765: if (fQualifiedNameSearchResult == null)
0766: fQualifiedNameSearchResult = new QualifiedNameSearchResult();
0767: QualifiedNameFinder.process(fQualifiedNameSearchResult,
0768: fPackage.getElementName(), getNewElementName(),
0769: fFilePatterns, fPackage.getJavaProject().getProject(),
0770: pm);
0771: }
0772:
0773: public String getNewPackageName(String oldSubPackageName) {
0774: String oldPackageName = getPackage().getElementName();
0775: return getNewElementName()
0776: + oldSubPackageName.substring(oldPackageName.length());
0777: }
0778:
0779: private static class PackageRenamer {
0780: private final IPackageFragment fPackage;
0781: private final RenamePackageProcessor fProcessor;
0782: private final TextChangeManager fTextChangeManager;
0783: private final ImportsManager fImportsManager;
0784:
0785: /** references to fPackage (can include star imports which also import namesake package fragments) */
0786: private SearchResultGroup[] fOccurrences;
0787:
0788: /** References in CUs from fOccurrences and fPackage to types in namesake packages.
0789: * <p>These need an import with the old package name.
0790: * <p>- from fOccurrences (without namesakes): may have shared star import
0791: * (star-import not updated here, but for fOccurrences)
0792: * <p>- from fPackage: may have unimported references to types of namesake packages
0793: * <p>- both: may have unused imports of namesake packages.
0794: * <p>Mutable List of SearchResultGroup. */
0795: private List fReferencesToTypesInNamesakes;
0796:
0797: /** References in CUs from namesake packages to types in fPackage.
0798: * <p>These need an import with the new package name.
0799: * <p>Mutable List of SearchResultGroup. */
0800: private List fReferencesToTypesInPackage;
0801:
0802: public PackageRenamer(IPackageFragment pack,
0803: RenamePackageProcessor processor,
0804: TextChangeManager textChangeManager,
0805: ImportsManager importsManager) {
0806: fPackage = pack;
0807: fProcessor = processor;
0808: fTextChangeManager = textChangeManager;
0809: fImportsManager = importsManager;
0810: }
0811:
0812: void doRename(IProgressMonitor pm, RefactoringStatus result)
0813: throws CoreException {
0814: pm.beginTask("", 16); //$NON-NLS-1$
0815: if (fProcessor.getUpdateReferences()) {
0816: pm
0817: .setTaskName(RefactoringCoreMessages.RenamePackageRefactoring_searching);
0818: fOccurrences = getReferences(new SubProgressMonitor(pm,
0819: 4), result);
0820: fReferencesToTypesInNamesakes = getReferencesToTypesInNamesakes(
0821: new SubProgressMonitor(pm, 4), result);
0822: fReferencesToTypesInPackage = getReferencesToTypesInPackage(
0823: new SubProgressMonitor(pm, 4), result);
0824: pm
0825: .setTaskName(RefactoringCoreMessages.RenamePackageRefactoring_checking);
0826: result.merge(analyzeAffectedCompilationUnits());
0827: pm.worked(1);
0828: } else {
0829: fOccurrences = new SearchResultGroup[0];
0830: pm.worked(13);
0831: }
0832:
0833: if (result.hasFatalError())
0834: return;
0835:
0836: if (fProcessor.getUpdateReferences())
0837: addReferenceUpdates(new SubProgressMonitor(pm, 3));
0838: else
0839: pm.worked(3);
0840:
0841: pm.done();
0842: }
0843:
0844: private SearchResultGroup[] getReferences(IProgressMonitor pm,
0845: RefactoringStatus status) throws CoreException {
0846: IJavaSearchScope scope = RefactoringScopeFactory
0847: .create(fPackage);
0848: SearchPattern pattern = SearchPattern.createPattern(
0849: fPackage, IJavaSearchConstants.REFERENCES);
0850: return RefactoringSearchEngine.search(pattern, scope, pm,
0851: status);
0852: }
0853:
0854: private void addReferenceUpdates(IProgressMonitor pm)
0855: throws CoreException {
0856: pm
0857: .beginTask(
0858: "", fOccurrences.length + fReferencesToTypesInPackage.size() + fReferencesToTypesInNamesakes.size()); //$NON-NLS-1$
0859: for (int i = 0; i < fOccurrences.length; i++) {
0860: ICompilationUnit cu = fOccurrences[i]
0861: .getCompilationUnit();
0862: if (cu == null)
0863: continue;
0864: SearchMatch[] results = fOccurrences[i]
0865: .getSearchResults();
0866: for (int j = 0; j < results.length; j++) {
0867: SearchMatch result = results[j];
0868: IJavaElement enclosingElement = SearchUtils
0869: .getEnclosingJavaElement(result);
0870: if (enclosingElement instanceof IImportDeclaration) {
0871: IImportDeclaration importDeclaration = (IImportDeclaration) enclosingElement;
0872: String updatedImport = getUpdatedImport(importDeclaration);
0873: updateImport(cu, importDeclaration,
0874: updatedImport);
0875: } else { // is reference
0876: TextChangeCompatibility
0877: .addTextEdit(
0878: fTextChangeManager.get(cu),
0879: RefactoringCoreMessages.RenamePackageRefactoring_update_reference,
0880: createTextChange(result));
0881: }
0882: }
0883: if (fReferencesToTypesInNamesakes.size() != 0) {
0884: SearchResultGroup typeRefsRequiringOldNameImport = extractGroupFor(
0885: cu, fReferencesToTypesInNamesakes);
0886: if (typeRefsRequiringOldNameImport != null)
0887: addTypeImports(typeRefsRequiringOldNameImport);
0888: }
0889: if (fReferencesToTypesInPackage.size() != 0) {
0890: SearchResultGroup typeRefsRequiringNewNameImport = extractGroupFor(
0891: cu, fReferencesToTypesInPackage);
0892: if (typeRefsRequiringNewNameImport != null)
0893: updateTypeImports(typeRefsRequiringNewNameImport);
0894: }
0895: pm.worked(1);
0896: }
0897:
0898: if (fReferencesToTypesInNamesakes.size() != 0) {
0899: for (Iterator iter = fReferencesToTypesInNamesakes
0900: .iterator(); iter.hasNext();) {
0901: SearchResultGroup referencesToTypesInNamesakes = (SearchResultGroup) iter
0902: .next();
0903: addTypeImports(referencesToTypesInNamesakes);
0904: pm.worked(1);
0905: }
0906: }
0907: if (fReferencesToTypesInPackage.size() != 0) {
0908: for (Iterator iter = fReferencesToTypesInPackage
0909: .iterator(); iter.hasNext();) {
0910: SearchResultGroup namesakeReferencesToPackage = (SearchResultGroup) iter
0911: .next();
0912: updateTypeImports(namesakeReferencesToPackage);
0913: pm.worked(1);
0914: }
0915: }
0916: pm.done();
0917: }
0918:
0919: /** Removes the found SearchResultGroup from the list iff found.
0920: * @param cu
0921: * @param searchResultGroups List of SearchResultGroup
0922: * @return the SearchResultGroup for cu, or null iff not found */
0923: private static SearchResultGroup extractGroupFor(
0924: ICompilationUnit cu, List searchResultGroups) {
0925: for (Iterator iter = searchResultGroups.iterator(); iter
0926: .hasNext();) {
0927: SearchResultGroup group = (SearchResultGroup) iter
0928: .next();
0929: if (cu.equals(group.getCompilationUnit())) {
0930: iter.remove();
0931: return group;
0932: }
0933: }
0934: return null;
0935: }
0936:
0937: private TextEdit createTextChange(SearchMatch searchResult) {
0938: return new ReplaceEdit(searchResult.getOffset(),
0939: searchResult.getLength(), getNewPackageName());
0940: }
0941:
0942: private RefactoringStatus analyzeAffectedCompilationUnits()
0943: throws CoreException {
0944: //TODO: also for both fReferencesTo...; only check each CU once!
0945: RefactoringStatus result = new RefactoringStatus();
0946: fOccurrences = Checks.excludeCompilationUnits(fOccurrences,
0947: result);
0948: if (result.hasFatalError())
0949: return result;
0950:
0951: result.merge(Checks
0952: .checkCompileErrorsInAffectedFiles(fOccurrences));
0953: return result;
0954: }
0955:
0956: /**
0957: * @return search scope with
0958: * <p>- fPackage and
0959: * <p>- all CUs from fOccurrences which are not in a namesake package
0960: */
0961: private IJavaSearchScope getPackageAndOccurrencesWithoutNamesakesScope() {
0962: List scopeList = new ArrayList();
0963: scopeList.add(fPackage);
0964: for (int i = 0; i < fOccurrences.length; i++) {
0965: ICompilationUnit cu = fOccurrences[i]
0966: .getCompilationUnit();
0967: if (cu == null)
0968: continue;
0969: IPackageFragment pack = (IPackageFragment) cu
0970: .getParent();
0971: if (!pack.getElementName().equals(
0972: fPackage.getElementName()))
0973: scopeList.add(cu);
0974: }
0975: return SearchEngine
0976: .createJavaSearchScope((IJavaElement[]) scopeList
0977: .toArray(new IJavaElement[scopeList.size()]));
0978: }
0979:
0980: private List getReferencesToTypesInNamesakes(
0981: IProgressMonitor pm, RefactoringStatus status)
0982: throws CoreException {
0983: pm.beginTask("", 2); //$NON-NLS-1$
0984: // e.g. renaming B-p.p; project C requires B, X and has ref to B-p.p and X-p.p;
0985: // goal: find refs to X-p.p in CUs from fOccurrences
0986:
0987: // (1) find namesake packages (scope: all packages referenced by CUs in fOccurrences and fPackage)
0988: IJavaElement[] elements = new IJavaElement[fOccurrences.length + 1];
0989: for (int i = 0; i < fOccurrences.length; i++) {
0990: elements[i] = fOccurrences[i].getCompilationUnit();
0991: }
0992: elements[fOccurrences.length] = fPackage;
0993: IJavaSearchScope namesakePackagesScope = RefactoringScopeFactory
0994: .createReferencedScope(elements);
0995: IPackageFragment[] namesakePackages = getNamesakePackages(
0996: namesakePackagesScope,
0997: new SubProgressMonitor(pm, 1));
0998: if (namesakePackages.length == 0) {
0999: pm.done();
1000: return new ArrayList(0);
1001: }
1002:
1003: // (2) find refs in fOccurrences and fPackage to namesake packages
1004: // (from fOccurrences (without namesakes): may have shared star import)
1005: // (from fPackage: may have unimported references to types of namesake packages)
1006: IType[] typesToSearch = getTypesInPackages(namesakePackages);
1007: if (typesToSearch.length == 0) {
1008: pm.done();
1009: return new ArrayList(0);
1010: }
1011: SearchPattern pattern = RefactoringSearchEngine
1012: .createOrPattern(typesToSearch,
1013: IJavaSearchConstants.REFERENCES);
1014: IJavaSearchScope scope = getPackageAndOccurrencesWithoutNamesakesScope();
1015: SearchResultGroup[] results = RefactoringSearchEngine
1016: .search(pattern, scope, new SubProgressMonitor(pm,
1017: 1), status);
1018: pm.done();
1019: return new ArrayList(Arrays.asList(results));
1020: }
1021:
1022: private List getReferencesToTypesInPackage(IProgressMonitor pm,
1023: RefactoringStatus status) throws CoreException {
1024: pm.beginTask("", 2); //$NON-NLS-1$
1025: IJavaSearchScope referencedFromNamesakesScope = RefactoringScopeFactory
1026: .create(fPackage);
1027: IPackageFragment[] namesakePackages = getNamesakePackages(
1028: referencedFromNamesakesScope,
1029: new SubProgressMonitor(pm, 1));
1030: if (namesakePackages.length == 0) {
1031: pm.done();
1032: return new ArrayList(0);
1033: }
1034:
1035: IJavaSearchScope scope = SearchEngine
1036: .createJavaSearchScope(namesakePackages);
1037: IType[] typesToSearch = getTypesInPackage(fPackage);
1038: if (typesToSearch.length == 0) {
1039: pm.done();
1040: return new ArrayList(0);
1041: }
1042: SearchPattern pattern = RefactoringSearchEngine
1043: .createOrPattern(typesToSearch,
1044: IJavaSearchConstants.REFERENCES);
1045: SearchResultGroup[] results = RefactoringSearchEngine
1046: .search(pattern, scope, new SubProgressMonitor(pm,
1047: 1), status);
1048: pm.done();
1049: return new ArrayList(Arrays.asList(results));
1050: }
1051:
1052: private IType[] getTypesInPackage(
1053: IPackageFragment packageFragment)
1054: throws JavaModelException {
1055: List types = new ArrayList();
1056: addContainedTypes(packageFragment, types);
1057: return (IType[]) types.toArray(new IType[types.size()]);
1058: }
1059:
1060: /**
1061: * @param scope
1062: * @param pm
1063: * @return all package fragments in <code>scope</code> with same name as <code>fPackage</code>, excluding fPackage
1064: * @throws CoreException
1065: */
1066: private IPackageFragment[] getNamesakePackages(
1067: IJavaSearchScope scope, IProgressMonitor pm)
1068: throws CoreException {
1069: SearchPattern pattern = SearchPattern.createPattern(
1070: fPackage.getElementName(),
1071: IJavaSearchConstants.PACKAGE,
1072: IJavaSearchConstants.DECLARATIONS,
1073: SearchPattern.R_EXACT_MATCH
1074: | SearchPattern.R_CASE_SENSITIVE);
1075:
1076: final HashSet packageFragments = new HashSet();
1077: SearchRequestor requestor = new SearchRequestor() {
1078: public void acceptSearchMatch(SearchMatch match)
1079: throws CoreException {
1080: IJavaElement enclosingElement = SearchUtils
1081: .getEnclosingJavaElement(match);
1082: if (enclosingElement instanceof IPackageFragment) {
1083: IPackageFragment pack = (IPackageFragment) enclosingElement;
1084: if (!fPackage.equals(pack))
1085: packageFragments.add(pack);
1086: }
1087: }
1088: };
1089: new SearchEngine().search(pattern, SearchUtils
1090: .getDefaultSearchParticipants(), scope, requestor,
1091: pm);
1092:
1093: return (IPackageFragment[]) packageFragments
1094: .toArray(new IPackageFragment[packageFragments
1095: .size()]);
1096: }
1097:
1098: private IType[] getTypesInPackages(
1099: IPackageFragment[] packageFragments)
1100: throws JavaModelException {
1101: List types = new ArrayList();
1102: for (int i = 0; i < packageFragments.length; i++) {
1103: IPackageFragment pack = packageFragments[i];
1104: addContainedTypes(pack, types);
1105: }
1106: return (IType[]) types.toArray(new IType[types.size()]);
1107: }
1108:
1109: private void addContainedTypes(IPackageFragment pack,
1110: List typesCollector) throws JavaModelException {
1111: IJavaElement[] children = pack.getChildren();
1112: for (int c = 0; c < children.length; c++) {
1113: IJavaElement child = children[c];
1114: if (child instanceof ICompilationUnit) {
1115: typesCollector.addAll(Arrays
1116: .asList(((ICompilationUnit) child)
1117: .getTypes()));
1118: } else if (child instanceof IClassFile) {
1119: typesCollector.add(((IClassFile) child).getType());
1120: }
1121: }
1122: }
1123:
1124: private void updateImport(ICompilationUnit cu,
1125: IImportDeclaration importDeclaration,
1126: String updatedImport) throws JavaModelException {
1127: ImportChange importChange = fImportsManager
1128: .getImportChange(cu);
1129: if (Flags.isStatic(importDeclaration.getFlags())) {
1130: importChange.removeStaticImport(importDeclaration
1131: .getElementName());
1132: importChange.addStaticImport(Signature
1133: .getQualifier(updatedImport), Signature
1134: .getSimpleName(updatedImport));
1135: } else {
1136: importChange.removeImport(importDeclaration
1137: .getElementName());
1138: importChange.addImport(updatedImport);
1139: }
1140: }
1141:
1142: /**
1143: * Add new imports to types in <code>typeReferences</code> with package <code>fPackage</code>.
1144: * @param typeReferences
1145: * @throws CoreException
1146: */
1147: private void addTypeImports(SearchResultGroup typeReferences)
1148: throws CoreException {
1149: SearchMatch[] searchResults = typeReferences
1150: .getSearchResults();
1151: for (int i = 0; i < searchResults.length; i++) {
1152: SearchMatch result = searchResults[i];
1153: IJavaElement enclosingElement = SearchUtils
1154: .getEnclosingJavaElement(result);
1155: if (!(enclosingElement instanceof IImportDeclaration)) {
1156: String reference = getNormalizedTypeReference(result);
1157: if (!reference
1158: .startsWith(fPackage.getElementName())) {
1159: // is unqualified
1160: reference = cutOffInnerTypes(reference);
1161: ImportChange importChange = fImportsManager
1162: .getImportChange(typeReferences
1163: .getCompilationUnit());
1164: importChange.addImport(fPackage
1165: .getElementName()
1166: + '.' + reference);
1167: }
1168: }
1169: }
1170: }
1171:
1172: /**
1173: * Add new imports to types in <code>typeReferences</code> with package <code>fNewElementName</code>
1174: * and remove old import with <code>fPackage</code>.
1175: * @param typeReferences
1176: * @throws CoreException
1177: */
1178: private void updateTypeImports(SearchResultGroup typeReferences)
1179: throws CoreException {
1180: SearchMatch[] searchResults = typeReferences
1181: .getSearchResults();
1182: for (int i = 0; i < searchResults.length; i++) {
1183: SearchMatch result = searchResults[i];
1184: IJavaElement enclosingElement = SearchUtils
1185: .getEnclosingJavaElement(result);
1186: if (enclosingElement instanceof IImportDeclaration) {
1187: IImportDeclaration importDeclaration = (IImportDeclaration) enclosingElement;
1188: updateImport(typeReferences.getCompilationUnit(),
1189: importDeclaration,
1190: getUpdatedImport(importDeclaration));
1191: } else {
1192: String reference = getNormalizedTypeReference(result);
1193: if (!reference
1194: .startsWith(fPackage.getElementName())) {
1195: reference = cutOffInnerTypes(reference);
1196: ImportChange importChange = fImportsManager
1197: .getImportChange(typeReferences
1198: .getCompilationUnit());
1199: importChange.removeImport(fPackage
1200: .getElementName()
1201: + '.' + reference);
1202: importChange.addImport(getNewPackageName()
1203: + '.' + reference);
1204: } // else: already found & updated with package reference search
1205: }
1206: }
1207: }
1208:
1209: private static String getNormalizedTypeReference(
1210: SearchMatch searchResult) throws JavaModelException {
1211: ICompilationUnit cu = SearchUtils
1212: .getCompilationUnit(searchResult);
1213: String reference = cu.getBuffer().getText(
1214: searchResult.getOffset(), searchResult.getLength());
1215: //reference may be package-qualified -> normalize (remove comments, etc.):
1216: return CommentAnalyzer.normalizeReference(reference);
1217: }
1218:
1219: private static String cutOffInnerTypes(String reference) {
1220: int dotPos = reference.indexOf('.'); // cut off inner types
1221: if (dotPos != -1)
1222: reference = reference.substring(0, dotPos);
1223: return reference;
1224: }
1225:
1226: private String getUpdatedImport(
1227: IImportDeclaration importDeclaration) {
1228: String fullyQualifiedImportType = importDeclaration
1229: .getElementName();
1230: int offsetOfDotBeforeTypeName = fPackage.getElementName()
1231: .length();
1232: String result = getNewPackageName()
1233: + fullyQualifiedImportType
1234: .substring(offsetOfDotBeforeTypeName);
1235: return result;
1236: }
1237:
1238: private String getNewPackageName() {
1239: return fProcessor.getNewPackageName(fPackage
1240: .getElementName());
1241: }
1242: }
1243:
1244: /**
1245: * Collector for import additions/removals.
1246: * Saves all changes for a one-pass rewrite.
1247: */
1248: static class ImportsManager {
1249: public static class ImportChange {
1250: private ArrayList/*<String>*/fStaticToRemove = new ArrayList();
1251: private ArrayList/*<String[2]>*/fStaticToAdd = new ArrayList();
1252: private ArrayList/*<String>*/fToRemove = new ArrayList();
1253: private ArrayList/*<String>*/fToAdd = new ArrayList();
1254:
1255: public void removeStaticImport(String elementName) {
1256: fStaticToRemove.add(elementName);
1257: }
1258:
1259: public void addStaticImport(String declaringType,
1260: String memberName) {
1261: fStaticToAdd.add(new String[] { declaringType,
1262: memberName });
1263: }
1264:
1265: public void removeImport(String elementName) {
1266: fToRemove.add(elementName);
1267: }
1268:
1269: public void addImport(String elementName) {
1270: fToAdd.add(elementName);
1271: }
1272: }
1273:
1274: private HashMap/*<ICompilationUnit, ImportChange>*/fImportChanges = new HashMap();
1275:
1276: public ImportChange getImportChange(ICompilationUnit cu) {
1277: ImportChange importChange = (ImportChange) fImportChanges
1278: .get(cu);
1279: if (importChange == null) {
1280: importChange = new ImportChange();
1281: fImportChanges.put(cu, importChange);
1282: }
1283: return importChange;
1284: }
1285:
1286: public void rewriteImports(TextChangeManager changeManager,
1287: IProgressMonitor pm) throws CoreException {
1288: for (Iterator iter = fImportChanges.entrySet().iterator(); iter
1289: .hasNext();) {
1290: Entry entry = (Entry) iter.next();
1291: ICompilationUnit cu = (ICompilationUnit) entry.getKey();
1292: ImportChange importChange = (ImportChange) entry
1293: .getValue();
1294:
1295: ImportRewrite importRewrite = StubUtility
1296: .createImportRewrite(cu, true);
1297: importRewrite.setFilterImplicitImports(false);
1298: for (Iterator iterator = importChange.fStaticToRemove
1299: .iterator(); iterator.hasNext();) {
1300: importRewrite.removeStaticImport((String) iterator
1301: .next());
1302: }
1303: for (Iterator iterator = importChange.fToRemove
1304: .iterator(); iterator.hasNext();) {
1305: importRewrite
1306: .removeImport((String) iterator.next());
1307: }
1308: for (Iterator iterator = importChange.fStaticToAdd
1309: .iterator(); iterator.hasNext();) {
1310: String[] toAdd = (String[]) iterator.next();
1311: importRewrite.addStaticImport(toAdd[0], toAdd[1],
1312: true);
1313: }
1314: for (Iterator iterator = importChange.fToAdd.iterator(); iterator
1315: .hasNext();) {
1316: importRewrite.addImport((String) iterator.next());
1317: }
1318:
1319: if (importRewrite.hasRecordedChanges()) {
1320: TextEdit importEdit = importRewrite
1321: .rewriteImports(pm);
1322: String name = RefactoringCoreMessages.RenamePackageRefactoring_update_imports;
1323: try {
1324: TextChangeCompatibility
1325: .addTextEdit(changeManager.get(cu),
1326: name, importEdit);
1327: } catch (MalformedTreeException e) {
1328: JavaPlugin
1329: .logErrorMessage("MalformedTreeException while processing cu " + cu); //$NON-NLS-1$
1330: throw e;
1331: }
1332: }
1333: }
1334: }
1335: }
1336:
1337: public RefactoringStatus initialize(RefactoringArguments arguments) {
1338: if (arguments instanceof JavaRefactoringArguments) {
1339: final JavaRefactoringArguments extended = (JavaRefactoringArguments) arguments;
1340: final String handle = extended
1341: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
1342: if (handle != null) {
1343: final IJavaElement element = JavaRefactoringDescriptorUtil
1344: .handleToElement(extended.getProject(), handle,
1345: false);
1346: if (element == null
1347: || !element.exists()
1348: || element.getElementType() != IJavaElement.PACKAGE_FRAGMENT)
1349: return ScriptableRefactoring
1350: .createInputFatalStatus(element,
1351: getRefactoring().getName(),
1352: IJavaRefactorings.RENAME_PACKAGE);
1353: else
1354: fPackage = (IPackageFragment) element;
1355: } else
1356: return RefactoringStatus
1357: .createFatalErrorStatus(Messages
1358: .format(
1359: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1360: JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
1361: final String name = extended
1362: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME);
1363: if (name != null && !"".equals(name)) //$NON-NLS-1$
1364: setNewElementName(name);
1365: else
1366: return RefactoringStatus
1367: .createFatalErrorStatus(Messages
1368: .format(
1369: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1370: JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME));
1371: final String patterns = extended
1372: .getAttribute(ATTRIBUTE_PATTERNS);
1373: if (patterns != null && !"".equals(patterns)) //$NON-NLS-1$
1374: fFilePatterns = patterns;
1375: else
1376: fFilePatterns = ""; //$NON-NLS-1$
1377: final String references = extended
1378: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_REFERENCES);
1379: if (references != null) {
1380: fUpdateReferences = Boolean.valueOf(references)
1381: .booleanValue();
1382: } else
1383: return RefactoringStatus
1384: .createFatalErrorStatus(Messages
1385: .format(
1386: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1387: JavaRefactoringDescriptorUtil.ATTRIBUTE_REFERENCES));
1388: final String matches = extended
1389: .getAttribute(ATTRIBUTE_TEXTUAL_MATCHES);
1390: if (matches != null) {
1391: fUpdateTextualMatches = Boolean.valueOf(matches)
1392: .booleanValue();
1393: } else
1394: return RefactoringStatus
1395: .createFatalErrorStatus(Messages
1396: .format(
1397: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1398: ATTRIBUTE_TEXTUAL_MATCHES));
1399: final String qualified = extended
1400: .getAttribute(ATTRIBUTE_QUALIFIED);
1401: if (qualified != null) {
1402: fUpdateQualifiedNames = Boolean.valueOf(qualified)
1403: .booleanValue();
1404: } else
1405: return RefactoringStatus
1406: .createFatalErrorStatus(Messages
1407: .format(
1408: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1409: ATTRIBUTE_QUALIFIED));
1410: final String hierarchical = extended
1411: .getAttribute(ATTRIBUTE_HIERARCHICAL);
1412: if (hierarchical != null) {
1413: fRenameSubpackages = Boolean.valueOf(hierarchical)
1414: .booleanValue();
1415: } else
1416: return RefactoringStatus
1417: .createFatalErrorStatus(Messages
1418: .format(
1419: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1420: ATTRIBUTE_HIERARCHICAL));
1421: } else
1422: return RefactoringStatus
1423: .createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
1424: return new RefactoringStatus();
1425: }
1426: }
|