1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.corext.refactoring.reorg;
13 import org.eclipse.core.runtime.CoreException;
14 import org.eclipse.core.runtime.IPath;
15 import org.eclipse.core.runtime.IProgressMonitor;
16 import org.eclipse.core.runtime.NullProgressMonitor;
17 import org.eclipse.core.runtime.OperationCanceledException;
18 import org.eclipse.core.runtime.SubProgressMonitor;
20 import org.eclipse.core.resources.IFile;
21 import org.eclipse.core.resources.IResource;
22 import org.eclipse.core.resources.mapping.ResourceMapping;
24 import org.eclipse.text.edits.ReplaceEdit;
26 import org.eclipse.ltk.core.refactoring.Change;
27 import org.eclipse.ltk.core.refactoring.participants.ReorgExecutionLog;
29 import org.eclipse.jdt.core.ICompilationUnit;
30 import org.eclipse.jdt.core.IMethod;
31 import org.eclipse.jdt.core.IType;
32 import org.eclipse.jdt.core.JavaModelException;
33 import org.eclipse.jdt.core.search.IJavaSearchConstants;
34 import org.eclipse.jdt.core.search.IJavaSearchScope;
35 import org.eclipse.jdt.core.search.SearchEngine;
36 import org.eclipse.jdt.core.search.SearchMatch;
37 import org.eclipse.jdt.core.search.SearchPattern;
39 import org.eclipse.jdt.internal.corext.refactoring.IRefactoringSearchRequestor;
40 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
41 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine;
42 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2;
43 import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
44 import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility;
45 import org.eclipse.jdt.internal.corext.refactoring.nls.changes.CreateTextFileChange;
46 import org.eclipse.jdt.internal.corext.refactoring.rename.TypeOccurrenceCollector;
47 import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil;
48 import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
49 import org.eclipse.jdt.internal.corext.util.JavaElementResourceMapping;
50 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
51 import org.eclipse.jdt.internal.corext.util.Messages;
52 import org.eclipse.jdt.internal.corext.util.SearchUtils;
54 import org.eclipse.jdt.internal.ui.JavaPlugin;
55 import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
57 public final class CreateCopyOfCompilationUnitChange extends CreateTextFileChange {
59 private static TextChangeManager createChangeManager(IProgressMonitor monitor, ICompilationUnit copy, String newName) throws CoreException {
60 TextChangeManager manager= new TextChangeManager();
61 SearchResultGroup refs= getReferences(copy, monitor);
64 if (refs.getCompilationUnit() == null)
67 String name= RefactoringCoreMessages.CopyRefactoring_update_ref;
68 SearchMatch[] results= refs.getSearchResults();
69 for (int j= 0; j < results.length; j++) {
70 SearchMatch searchResult= results[j];
71 if (searchResult.getAccuracy() == SearchMatch.A_INACCURATE)
73 int offset= searchResult.getOffset();
74 int length= searchResult.getLength();
75 TextChangeCompatibility.addTextEdit(manager.get(copy), name, new ReplaceEdit(offset, length, newName));
80 private static SearchPattern createSearchPattern(IType type) throws JavaModelException {
81 SearchPattern pattern= SearchPattern.createPattern(type, IJavaSearchConstants.ALL_OCCURRENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
82 IMethod[] constructors= JavaElementUtil.getAllConstructors(type);
83 if (constructors.length == 0)
85 SearchPattern constructorDeclarationPattern= RefactoringSearchEngine.createOrPattern(constructors, IJavaSearchConstants.DECLARATIONS);
86 return SearchPattern.createOrPattern(pattern, constructorDeclarationPattern);
89 private static String getCopiedFileSource(IProgressMonitor monitor, ICompilationUnit unit, String newTypeName) throws CoreException {
90 ICompilationUnit copy= unit.getPrimary().getWorkingCopy(null);
92 TextChangeManager manager= createChangeManager(monitor, copy, newTypeName);
93 String result= manager.get(copy).getPreviewContent(new NullProgressMonitor());
96 copy.discardWorkingCopy();
100 private static SearchResultGroup getReferences(final ICompilationUnit copy, IProgressMonitor monitor) throws JavaModelException {
101 final ICompilationUnit[] copies= new ICompilationUnit[] { copy};
102 IJavaSearchScope scope= SearchEngine.createJavaSearchScope(copies);
103 final IType type= copy.findPrimaryType();
106 SearchPattern pattern= createSearchPattern(type);
107 final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(pattern);
108 engine.setScope(scope);
109 engine.setWorkingCopies(copies);
110 engine.setRequestor(new IRefactoringSearchRequestor() {
111 TypeOccurrenceCollector fTypeOccurrenceCollector= new TypeOccurrenceCollector(type);
112 public SearchMatch acceptSearchMatch(SearchMatch match) {
114 return fTypeOccurrenceCollector.acceptSearchMatch2(copy, match);
115 } catch (CoreException e) {
122 engine.searchPattern(monitor);
123 final Object[] results= engine.getResults();
124 // Assert.isTrue(results.length <= 1);
125 // just 1 file or none, but inaccurate matches can play bad here (see
126 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=106127)
127 for (int index= 0; index < results.length; index++) {
128 SearchResultGroup group= (SearchResultGroup) results[index];
129 if (group.getCompilationUnit().equals(copy))
135 private final INewNameQuery fNameQuery;
137 private final ICompilationUnit fOldCu;
139 public CreateCopyOfCompilationUnitChange(IPath path, String source, ICompilationUnit oldCu, INewNameQuery nameQuery) {
140 super(path, source, null, "java"); //$NON-NLS-1$
142 fNameQuery= nameQuery;
147 public String getName() {
148 String cuName= BasicElementLabels.getResourceName(fOldCu.getElementName());
149 String cuContainerName= BasicElementLabels.getPathLabel(fOldCu.getParent().getPath(), false);
150 return Messages.format(RefactoringCoreMessages.CreateCopyOfCompilationUnitChange_create_copy, new String[] { cuName, cuContainerName});
154 protected IFile getOldFile(IProgressMonitor monitor) throws OperationCanceledException {
156 monitor.beginTask("", 12); //$NON-NLS-1$
157 String oldSource= super.getSource();
158 IPath oldPath= super.getPath();
159 String newTypeName= fNameQuery.getNewName();
161 String newSource= getCopiedFileSource(new SubProgressMonitor(monitor, 9), fOldCu, newTypeName);
162 setSource(newSource);
163 setPath(fOldCu.getResource().getParent().getFullPath().append(JavaModelUtil.getRenamedCUName(fOldCu, newTypeName)));
164 return super.getOldFile(new SubProgressMonitor(monitor, 1));
165 } catch (CoreException e) {
166 setSource(oldSource);
168 return super.getOldFile(new SubProgressMonitor(monitor, 2));
175 private void markAsExecuted(ICompilationUnit unit, ResourceMapping mapping) {
176 ReorgExecutionLog log= (ReorgExecutionLog) getAdapter(ReorgExecutionLog.class);
178 log.markAsProcessed(unit);
179 log.markAsProcessed(mapping);
184 public Change perform(IProgressMonitor monitor) throws CoreException {
185 ResourceMapping mapping= JavaElementResourceMapping.create(fOldCu);
186 final Change result= super.perform(monitor);
187 markAsExecuted(fOldCu, mapping);
191 private void setEncoding(ICompilationUnit unit) {
192 IResource resource= unit.getResource();
193 // no file so the encoding is taken from the target
194 if (!(resource instanceof IFile))
196 IFile file= (IFile) resource;
198 String encoding= file.getCharset(false);
199 if (encoding != null) {
200 setEncoding(encoding, true);
202 encoding= file.getCharset(true);
203 if (encoding != null) {
204 setEncoding(encoding, false);
207 } catch (CoreException e) {
208 // Take encoding from target