001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.corext.refactoring.reorg;
011:
012: import org.eclipse.text.edits.ReplaceEdit;
013:
014: import org.eclipse.core.runtime.CoreException;
015: import org.eclipse.core.runtime.IPath;
016: import org.eclipse.core.runtime.IProgressMonitor;
017: import org.eclipse.core.runtime.NullProgressMonitor;
018: import org.eclipse.core.runtime.OperationCanceledException;
019: import org.eclipse.core.runtime.SubProgressMonitor;
020:
021: import org.eclipse.core.resources.IFile;
022: import org.eclipse.core.resources.IResource;
023: import org.eclipse.core.resources.mapping.ResourceMapping;
024:
025: import org.eclipse.ltk.core.refactoring.Change;
026: import org.eclipse.ltk.core.refactoring.participants.ReorgExecutionLog;
027:
028: import org.eclipse.jdt.core.ICompilationUnit;
029: import org.eclipse.jdt.core.IMethod;
030: import org.eclipse.jdt.core.IType;
031: import org.eclipse.jdt.core.JavaModelException;
032: import org.eclipse.jdt.core.search.IJavaSearchConstants;
033: import org.eclipse.jdt.core.search.IJavaSearchScope;
034: import org.eclipse.jdt.core.search.SearchEngine;
035: import org.eclipse.jdt.core.search.SearchMatch;
036: import org.eclipse.jdt.core.search.SearchPattern;
037:
038: import org.eclipse.jdt.internal.corext.refactoring.IRefactoringSearchRequestor;
039: import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
040: import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine;
041: import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2;
042: import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
043: import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility;
044: import org.eclipse.jdt.internal.corext.refactoring.nls.changes.CreateTextFileChange;
045: import org.eclipse.jdt.internal.corext.refactoring.rename.TypeOccurrenceCollector;
046: import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil;
047: import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
048: import org.eclipse.jdt.internal.corext.util.JavaElementResourceMapping;
049: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
050: import org.eclipse.jdt.internal.corext.util.Messages;
051: import org.eclipse.jdt.internal.corext.util.SearchUtils;
052:
053: import org.eclipse.jdt.internal.ui.JavaPlugin;
054:
055: public final class CreateCopyOfCompilationUnitChange extends
056: CreateTextFileChange {
057:
058: private static TextChangeManager createChangeManager(
059: IProgressMonitor monitor, ICompilationUnit copy,
060: String newName) throws CoreException {
061: TextChangeManager manager = new TextChangeManager();
062: SearchResultGroup refs = getReferences(copy, monitor);
063: if (refs == null)
064: return manager;
065: if (refs.getCompilationUnit() == null)
066: return manager;
067:
068: String name = RefactoringCoreMessages.CopyRefactoring_update_ref;
069: SearchMatch[] results = refs.getSearchResults();
070: for (int j = 0; j < results.length; j++) {
071: SearchMatch searchResult = results[j];
072: if (searchResult.getAccuracy() == SearchMatch.A_INACCURATE)
073: continue;
074: int offset = searchResult.getOffset();
075: int length = searchResult.getLength();
076: TextChangeCompatibility.addTextEdit(manager.get(copy),
077: name, new ReplaceEdit(offset, length, newName));
078: }
079: return manager;
080: }
081:
082: private static SearchPattern createSearchPattern(IType type)
083: throws JavaModelException {
084: SearchPattern pattern = SearchPattern.createPattern(type,
085: IJavaSearchConstants.ALL_OCCURRENCES,
086: SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
087: IMethod[] constructors = JavaElementUtil
088: .getAllConstructors(type);
089: if (constructors.length == 0)
090: return pattern;
091: SearchPattern constructorDeclarationPattern = RefactoringSearchEngine
092: .createOrPattern(constructors,
093: IJavaSearchConstants.DECLARATIONS);
094: return SearchPattern.createOrPattern(pattern,
095: constructorDeclarationPattern);
096: }
097:
098: private static String getCopiedFileSource(IProgressMonitor monitor,
099: ICompilationUnit unit, String newTypeName)
100: throws CoreException {
101: ICompilationUnit copy = unit.getPrimary().getWorkingCopy(null);
102: try {
103: TextChangeManager manager = createChangeManager(monitor,
104: copy, newTypeName);
105: String result = manager.get(copy).getPreviewContent(
106: new NullProgressMonitor());
107: return result;
108: } finally {
109: copy.discardWorkingCopy();
110: }
111: }
112:
113: private static SearchResultGroup getReferences(
114: final ICompilationUnit copy, IProgressMonitor monitor)
115: throws JavaModelException {
116: final ICompilationUnit[] copies = new ICompilationUnit[] { copy };
117: IJavaSearchScope scope = SearchEngine
118: .createJavaSearchScope(copies);
119: final IType type = copy.findPrimaryType();
120: if (type == null)
121: return null;
122: SearchPattern pattern = createSearchPattern(type);
123: final RefactoringSearchEngine2 engine = new RefactoringSearchEngine2(
124: pattern);
125: engine.setScope(scope);
126: engine.setWorkingCopies(copies);
127: engine.searchPattern(monitor);
128: engine.setRequestor(new IRefactoringSearchRequestor() {
129: TypeOccurrenceCollector fTypeOccurrenceCollector = new TypeOccurrenceCollector(
130: type);
131:
132: public SearchMatch acceptSearchMatch(SearchMatch match) {
133: try {
134: return fTypeOccurrenceCollector.acceptSearchMatch2(
135: copy, match);
136: } catch (CoreException e) {
137: JavaPlugin.log(e);
138: return null;
139: }
140: }
141: });
142: final Object[] results = engine.getResults();
143: // Assert.isTrue(results.length <= 1);
144: // just 1 file or none, but inaccurate matches can play bad here (see
145: // https://bugs.eclipse.org/bugs/show_bug.cgi?id=106127)
146: for (int index = 0; index < results.length; index++) {
147: SearchResultGroup group = (SearchResultGroup) results[index];
148: if (group.getCompilationUnit().equals(copy))
149: return group;
150: }
151: return null;
152: }
153:
154: private final INewNameQuery fNameQuery;
155:
156: private final ICompilationUnit fOldCu;
157:
158: public CreateCopyOfCompilationUnitChange(IPath path, String source,
159: ICompilationUnit oldCu, INewNameQuery nameQuery) {
160: super (path, source, null, "java"); //$NON-NLS-1$
161: fOldCu = oldCu;
162: fNameQuery = nameQuery;
163: setEncoding(oldCu);
164: }
165:
166: public String getName() {
167: return Messages
168: .format(
169: RefactoringCoreMessages.CreateCopyOfCompilationUnitChange_create_copy,
170: new String[] { fOldCu.getElementName(),
171: getPathLabel(fOldCu.getResource()) });
172: }
173:
174: protected IFile getOldFile(IProgressMonitor monitor)
175: throws OperationCanceledException {
176: try {
177: monitor.beginTask("", 12); //$NON-NLS-1$
178: String oldSource = super .getSource();
179: IPath oldPath = super .getPath();
180: String newTypeName = fNameQuery.getNewName();
181: try {
182: String newSource = getCopiedFileSource(
183: new SubProgressMonitor(monitor, 9), fOldCu,
184: newTypeName);
185: setSource(newSource);
186: setPath(fOldCu.getResource().getParent().getFullPath()
187: .append(
188: JavaModelUtil.getRenamedCUName(fOldCu,
189: newTypeName)));
190: return super .getOldFile(new SubProgressMonitor(monitor,
191: 1));
192: } catch (CoreException e) {
193: setSource(oldSource);
194: setPath(oldPath);
195: return super .getOldFile(new SubProgressMonitor(monitor,
196: 2));
197: }
198: } finally {
199: monitor.done();
200: }
201: }
202:
203: private String getPathLabel(IResource resource) {
204: final StringBuffer buffer = new StringBuffer(resource
205: .getProject().getName());
206: final String path = resource.getParent()
207: .getProjectRelativePath().toString();
208: if (path.length() > 0) {
209: buffer.append('/');
210: buffer.append(path);
211: }
212: return buffer.toString();
213: }
214:
215: private void markAsExecuted(ICompilationUnit unit,
216: ResourceMapping mapping) {
217: ReorgExecutionLog log = (ReorgExecutionLog) getAdapter(ReorgExecutionLog.class);
218: if (log != null) {
219: log.markAsProcessed(unit);
220: log.markAsProcessed(mapping);
221: }
222: }
223:
224: public Change perform(IProgressMonitor monitor)
225: throws CoreException {
226: ResourceMapping mapping = JavaElementResourceMapping
227: .create(fOldCu);
228: final Change result = super .perform(monitor);
229: markAsExecuted(fOldCu, mapping);
230: return result;
231: }
232:
233: private void setEncoding(ICompilationUnit unit) {
234: IResource resource = unit.getResource();
235: // no file so the encoding is taken from the target
236: if (!(resource instanceof IFile))
237: return;
238: IFile file = (IFile) resource;
239: try {
240: String encoding = file.getCharset(false);
241: if (encoding != null) {
242: setEncoding(encoding, true);
243: } else {
244: encoding = file.getCharset(true);
245: if (encoding != null) {
246: setEncoding(encoding, false);
247: }
248: }
249: } catch (CoreException e) {
250: // Take encoding from target
251: }
252: }
253: }
|