]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-after/core refactoring/org/eclipse/jdt/internal/corext/refactoring/reorg/MoveCuUpdateCreator.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-after / core refactoring / org / eclipse / jdt / internal / corext / refactoring / reorg / MoveCuUpdateCreator.java
CommitLineData
1b2798f6
EK
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
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.jdt.internal.corext.refactoring.reorg;
12
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.HashMap;
16import java.util.Iterator;
17import java.util.List;
18import java.util.Map;
19
20import org.eclipse.core.runtime.Assert;
21import org.eclipse.core.runtime.CoreException;
22import org.eclipse.core.runtime.IProgressMonitor;
23import org.eclipse.core.runtime.OperationCanceledException;
24import org.eclipse.core.runtime.SubProgressMonitor;
25
26import org.eclipse.core.resources.IResource;
27
28import org.eclipse.text.edits.ReplaceEdit;
29import org.eclipse.text.edits.TextEdit;
30
31import org.eclipse.ltk.core.refactoring.RefactoringStatus;
32import org.eclipse.ltk.core.refactoring.TextChange;
33
34import org.eclipse.jdt.core.Flags;
35import org.eclipse.jdt.core.IBuffer;
36import org.eclipse.jdt.core.ICompilationUnit;
37import org.eclipse.jdt.core.IImportDeclaration;
38import org.eclipse.jdt.core.IJavaElement;
39import org.eclipse.jdt.core.IPackageFragment;
40import org.eclipse.jdt.core.IType;
41import org.eclipse.jdt.core.JavaModelException;
42import org.eclipse.jdt.core.ToolFactory;
43import org.eclipse.jdt.core.compiler.IScanner;
44import org.eclipse.jdt.core.compiler.ITerminalSymbols;
45import org.eclipse.jdt.core.compiler.InvalidInputException;
46import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
47import org.eclipse.jdt.core.search.IJavaSearchConstants;
48import org.eclipse.jdt.core.search.IJavaSearchScope;
49import org.eclipse.jdt.core.search.SearchEngine;
50import org.eclipse.jdt.core.search.SearchMatch;
51import org.eclipse.jdt.core.search.SearchPattern;
52import org.eclipse.jdt.core.search.TypeReferenceMatch;
53
54import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
55import org.eclipse.jdt.internal.corext.refactoring.CollectingSearchRequestor;
56import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
57import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
58import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine;
59import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
60import org.eclipse.jdt.internal.corext.refactoring.base.ReferencesInBinaryContext;
61import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility;
62import org.eclipse.jdt.internal.corext.refactoring.structure.ReferenceFinderUtil;
63import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
64import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
65import org.eclipse.jdt.internal.corext.util.Messages;
66import org.eclipse.jdt.internal.corext.util.SearchUtils;
67
68import org.eclipse.jdt.internal.ui.JavaPlugin;
69import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
70
71public class MoveCuUpdateCreator {
72
73 private final String fNewPackage;
74 private ICompilationUnit[] fCus;
75 private IPackageFragment fDestination;
76
77 private Map<ICompilationUnit, ImportRewrite> fImportRewrites; //ICompilationUnit -> ImportEdit
78
79 public MoveCuUpdateCreator(ICompilationUnit cu, IPackageFragment pack){
80 this(new ICompilationUnit[]{cu}, pack);
81 }
82
83 public MoveCuUpdateCreator(ICompilationUnit[] cus, IPackageFragment pack){
84 Assert.isNotNull(cus);
85 Assert.isNotNull(pack);
86 fCus= cus;
87 fDestination= pack;
88 fImportRewrites= new HashMap<ICompilationUnit, ImportRewrite>();
89 fNewPackage= fDestination.isDefaultPackage() ? "" : fDestination.getElementName() + '.'; //$NON-NLS-1$
90 }
91
92 public TextChangeManager createChangeManager(IProgressMonitor pm, RefactoringStatus status) throws JavaModelException{
93 pm.beginTask("", 5); //$NON-NLS-1$
94 try{
95 TextChangeManager changeManager= new TextChangeManager();
96 addUpdates(changeManager, new SubProgressMonitor(pm, 4), status);
97 return changeManager.generated_1628939679934031551(this);
98 } catch (JavaModelException e){
99 throw e;
100 } catch (CoreException e){
101 throw new JavaModelException(e);
102 } finally{
103 pm.done();
104 }
105
106 }
107
108 public void addImportRewriteUpdates(TextChangeManager changeManager) throws CoreException {
109 for (Iterator<ICompilationUnit> iter= fImportRewrites.keySet().iterator(); iter.hasNext();) {
110 ICompilationUnit cu= iter.next();
111 ImportRewrite importRewrite= fImportRewrites.get(cu);
112 if (importRewrite != null && importRewrite.hasRecordedChanges()) {
113 TextChangeCompatibility.addTextEdit(changeManager.get(cu), RefactoringCoreMessages.MoveCuUpdateCreator_update_imports, importRewrite.rewriteImports(null));
114 }
115 }
116 }
117
118 private void addUpdates(TextChangeManager changeManager, IProgressMonitor pm, RefactoringStatus status) throws CoreException {
119 pm.beginTask("", fCus.length); //$NON-NLS-1$
120 for (int i= 0; i < fCus.length; i++){
121 if (pm.isCanceled())
122 throw new OperationCanceledException();
123
124 addUpdates(changeManager, fCus[i], new SubProgressMonitor(pm, 1), status);
125 }
126 }
127
128 private void addUpdates(TextChangeManager changeManager, ICompilationUnit movedUnit, IProgressMonitor pm, RefactoringStatus status) throws CoreException{
129 try{
130 pm.beginTask("", 3); //$NON-NLS-1$
131 pm.subTask(Messages.format(RefactoringCoreMessages.MoveCuUpdateCreator_searching, BasicElementLabels.getFileName(movedUnit)));
132
133 if (isInAnotherFragmentOfSamePackage(movedUnit, fDestination)){
134 pm.worked(3);
135 return;
136 }
137
138 addImportToSourcePackageTypes(movedUnit, new SubProgressMonitor(pm, 1));
139 removeImportsToDestinationPackageTypes(movedUnit);
140 addReferenceUpdates(changeManager, movedUnit, new SubProgressMonitor(pm, 2), status);
141 } finally{
142 pm.done();
143 }
144 }
145
146 private void addReferenceUpdates(TextChangeManager changeManager, ICompilationUnit movedUnit, IProgressMonitor pm, RefactoringStatus status) throws JavaModelException, CoreException {
147 List<ICompilationUnit> cuList= Arrays.asList(fCus);
148 SearchResultGroup[] references= getReferences(movedUnit, pm, status);
149 for (int i= 0; i < references.length; i++) {
150 SearchResultGroup searchResultGroup= references[i];
151 ICompilationUnit referencingCu= searchResultGroup.getCompilationUnit();
152 if (referencingCu == null)
153 continue;
154
155 boolean simpleReferencesNeedNewImport= simpleReferencesNeedNewImport(movedUnit, referencingCu, cuList);
156 SearchMatch[] results= searchResultGroup.getSearchResults();
157 for (int j= 0; j < results.length; j++) {
158 // TODO: should update type references with results from addImport
159 TypeReference reference= (TypeReference) results[j];
160 reference.generated_8299490140507927106(changeManager, movedUnit, referencingCu, simpleReferencesNeedNewImport, results, j, this);
161 }
162 }
163 }
164
165 private void addStaticImport(ICompilationUnit movedUnit, IImportDeclaration importDecl, ImportRewrite rewrite) {
166 String old= importDecl.getElementName();
167 int oldPackLength= movedUnit.getParent().getElementName().length();
168
169 StringBuffer result= new StringBuffer(fDestination.getElementName());
170 if (oldPackLength == 0) // move FROM default package
171 result.append('.').append(old);
172 else if (result.length() == 0) // move TO default package
173 result.append(old.substring(oldPackLength + 1)); // cut "."
174 else
175 result.append(old.substring(oldPackLength));
176 int index= result.lastIndexOf("."); //$NON-NLS-1$
177 if (index > 0 && index < result.length() - 1)
178 rewrite.addStaticImport(result.substring(0, index), result.substring(index + 1, result.length()), true);
179 }
180
181 private String getQualifiedType(String packageName, String typeName) {
182 if (packageName.length() == 0)
183 return typeName;
184 else
185 return packageName + '.' + typeName;
186 }
187
188 private String createStringForNewImport(ICompilationUnit movedUnit, IImportDeclaration importDecl) {
189 String old= importDecl.getElementName();
190 int oldPackLength= movedUnit.getParent().getElementName().length();
191
192 StringBuffer result= new StringBuffer(fDestination.getElementName());
193 if (oldPackLength == 0) // move FROM default package
194 result.append('.').append(old);
195 else if (result.length() == 0) // move TO default package
196 result.append(old.substring(oldPackLength + 1)); // cut "."
197 else
198 result.append(old.substring(oldPackLength));
199 return result.toString();
200 }
201
202 private void removeImportsToDestinationPackageTypes(ICompilationUnit movedUnit) throws CoreException{
203 ImportRewrite importEdit= getImportRewrite(movedUnit);
204 IType[] destinationTypes= getDestinationPackageTypes();
205 for (int i= 0; i < destinationTypes.length; i++) {
206 importEdit.removeImport(destinationTypes[i].getFullyQualifiedName('.'));
207 }
208 }
209
210 private IType[] getDestinationPackageTypes() throws JavaModelException {
211 List<IType> types= new ArrayList<IType>();
212 if (fDestination.exists()) {
213 ICompilationUnit[] cus= fDestination.getCompilationUnits();
214 for (int i= 0; i < cus.length; i++) {
215 types.addAll(Arrays.asList(cus[i].getAllTypes()));
216 }
217 }
218 return types.toArray(new IType[types.size()]);
219 }
220
221 private void addImportToSourcePackageTypes(ICompilationUnit movedUnit, IProgressMonitor pm) throws CoreException{
222 List<ICompilationUnit> cuList= Arrays.asList(fCus);
223 IType[] allCuTypes= movedUnit.getAllTypes();
224 IType[] referencedTypes= ReferenceFinderUtil.getTypesReferencedIn(allCuTypes, pm);
225 ImportRewrite importEdit= getImportRewrite(movedUnit);
226 importEdit.setFilterImplicitImports(false);
227 IPackageFragment srcPack= (IPackageFragment)movedUnit.getParent();
228 for (int i= 0; i < referencedTypes.length; i++) {
229 IType iType= referencedTypes[i];
230 if (! iType.exists())
231 continue;
232 if (!JavaModelUtil.isSamePackage(iType.getPackageFragment(), srcPack))
233 continue;
234 if (cuList.contains(iType.getCompilationUnit()))
235 continue;
236 importEdit.addImport(iType.getFullyQualifiedName('.'));
237 }
238 }
239
240 private ImportRewrite getImportRewrite(ICompilationUnit cu) throws CoreException{
241 if (fImportRewrites.containsKey(cu))
242 return fImportRewrites.get(cu);
243 ImportRewrite importEdit= StubUtility.createImportRewrite(cu, true);
244 fImportRewrites.put(cu, importEdit);
245 return importEdit;
246 }
247
248 private boolean simpleReferencesNeedNewImport(ICompilationUnit movedUnit, ICompilationUnit referencingCu, List<ICompilationUnit> cuList) {
249 if (referencingCu.equals(movedUnit))
250 return false;
251 if (cuList.contains(referencingCu))
252 return false;
253 if (isReferenceInAnotherFragmentOfSamePackage(referencingCu, movedUnit)) {
254 /* Destination package is different from source, since
255 * isDestinationAnotherFragmentOfSamePackage(movedUnit) was false in addUpdates(.) */
256 return true;
257 }
258
259 //heuristic
260 if (referencingCu.getImport(movedUnit.getParent().getElementName() + ".*").exists()) //$NON-NLS-1$
261 return true; // has old star import
262 if (referencingCu.getParent().equals(movedUnit.getParent()))
263 return true; //is moved away from same package
264 return false;
265 }
266
267 private boolean isReferenceInAnotherFragmentOfSamePackage(ICompilationUnit referencingCu, ICompilationUnit movedUnit) {
268 if (referencingCu == null)
269 return false;
270 if (! (referencingCu.getParent() instanceof IPackageFragment))
271 return false;
272 IPackageFragment pack= (IPackageFragment) referencingCu.getParent();
273 return isInAnotherFragmentOfSamePackage(movedUnit, pack);
274 }
275
276 private static boolean isInAnotherFragmentOfSamePackage(ICompilationUnit cu, IPackageFragment pack) {
277 if (! (cu.getParent() instanceof IPackageFragment))
278 return false;
279 IPackageFragment cuPack= (IPackageFragment) cu.getParent();
280 return ! cuPack.equals(pack) && JavaModelUtil.isSamePackage(cuPack, pack);
281 }
282
283 private static SearchResultGroup[] getReferences(ICompilationUnit unit, IProgressMonitor pm, RefactoringStatus status) throws CoreException {
284 final SearchPattern pattern= RefactoringSearchEngine.createOrPattern(unit.getTypes(), IJavaSearchConstants.REFERENCES);
285 if (pattern != null) {
286 String binaryRefsDescription= Messages.format(RefactoringCoreMessages.ReferencesInBinaryContext_ref_in_binaries_description , BasicElementLabels.getFileName(unit));
287 ReferencesInBinaryContext binaryRefs= new ReferencesInBinaryContext(binaryRefsDescription);
288 Collector requestor= new Collector(((IPackageFragment) unit.getParent()), binaryRefs);
289 IJavaSearchScope scope= RefactoringScopeFactory.create(unit, true, false);
290
291 SearchResultGroup[] result= RefactoringSearchEngine.search(pattern, scope, requestor, new SubProgressMonitor(pm, 1), status);
292 binaryRefs.addErrorIfNecessary(status);
293 return result;
294 }
295 return new SearchResultGroup[] {};
296 }
297
298 private final static class Collector extends CollectingSearchRequestor {
299 private IPackageFragment fSource;
300 private IScanner fScanner;
301
302 public Collector(IPackageFragment source, ReferencesInBinaryContext binaryRefs) {
303 super(binaryRefs);
304 fSource= source;
305 fScanner= ToolFactory.createScanner(false, false, false, false);
306 }
307
308 /* (non-Javadoc)
309 * @see org.eclipse.jdt.internal.corext.refactoring.CollectingSearchRequestor#acceptSearchMatch(SearchMatch)
310 */
311 @Override
312 public void acceptSearchMatch(SearchMatch match) throws CoreException {
313 if (filterMatch(match))
314 return;
315
316 /*
317 * Processing is done in collector to reuse the buffer which was
318 * already required by the search engine to locate the matches.
319 */
320 // [start, end[ include qualification.
321 IJavaElement element= SearchUtils.getEnclosingJavaElement(match);
322 int accuracy= match.getAccuracy();
323 int start= match.getOffset();
324 int length= match.getLength();
325 boolean insideDocComment= match.isInsideDocComment();
326 IResource res= match.getResource();
327 if (element.getAncestor(IJavaElement.IMPORT_DECLARATION) != null) {
328 collectMatch(TypeReference.createImportReference(element, accuracy, start, length, insideDocComment, res));
329 } else {
330 ICompilationUnit unit= (ICompilationUnit) element.getAncestor(IJavaElement.COMPILATION_UNIT);
331 if (unit != null) {
332 IBuffer buffer= unit.getBuffer();
333 String matchText= buffer.getText(start, length);
334 if (fSource.isDefaultPackage()) {
335 collectMatch(TypeReference.createSimpleReference(element, accuracy, start, length, insideDocComment, res, matchText));
336 } else {
337 // assert: matchText doesn't start nor end with comment
338 int simpleNameStart= getLastSimpleNameStart(matchText);
339 if (simpleNameStart != 0) {
340 collectMatch(TypeReference.createQualifiedReference(element, accuracy, start, length, insideDocComment, res, start + simpleNameStart));
341 } else {
342 collectMatch(TypeReference.createSimpleReference(element, accuracy, start, length, insideDocComment, res, matchText));
343 }
344 }
345 }
346 }
347 }
348
349 private int getLastSimpleNameStart(String reference) {
350 fScanner.setSource(reference.toCharArray());
351 int lastIdentifierStart= -1;
352 try {
353 int tokenType= fScanner.getNextToken();
354 while (tokenType != ITerminalSymbols.TokenNameEOF) {
355 if (tokenType == ITerminalSymbols.TokenNameIdentifier)
356 lastIdentifierStart= fScanner.getCurrentTokenStartPosition();
357 tokenType= fScanner.getNextToken();
358 }
359 } catch (InvalidInputException e) {
360 JavaPlugin.log(e);
361 }
362 return lastIdentifierStart;
363 }
364 }
365
366
367 final static class TypeReference extends TypeReferenceMatch {
368 private String fSimpleTypeName;
369 private int fSimpleNameStart;
370
371 private TypeReference(IJavaElement enclosingElement, int accuracy, int start, int length,
372 boolean insideDocComment, IResource resource, int simpleNameStart, String simpleName) {
373 super(enclosingElement, accuracy, start, length,
374 insideDocComment, SearchEngine.getDefaultSearchParticipant(), resource);
375 fSimpleNameStart= simpleNameStart;
376 fSimpleTypeName= simpleName;
377 }
378
379 public static TypeReference createQualifiedReference(IJavaElement enclosingElement, int accuracy, int start, int length,
380 boolean insideDocComment, IResource resource, int simpleNameStart) {
381 Assert.isTrue(start < simpleNameStart && simpleNameStart < start + length);
382 return new TypeReference(enclosingElement, accuracy, start, length, insideDocComment, resource, simpleNameStart, null);
383 }
384
385 public static TypeReference createImportReference(IJavaElement enclosingElement, int accuracy, int start, int length,
386 boolean insideDocComment, IResource resource) {
387 return new TypeReference(enclosingElement, accuracy, start, length, insideDocComment, resource, -1, null);
388 }
389
390 public static TypeReference createSimpleReference(IJavaElement enclosingElement, int accuracy, int start, int length,
391 boolean insideDocComment, IResource resource, String simpleName) {
392 return new TypeReference(enclosingElement, accuracy, start, length, insideDocComment, resource, -1, simpleName);
393 }
394
395 public boolean isImportDeclaration() {
396 return SearchUtils.getEnclosingJavaElement(this).getAncestor(IJavaElement.IMPORT_DECLARATION) != null;
397 }
398
399 public boolean isQualified() {
400 return fSimpleNameStart != -1;
401 }
402
403 /**
404 * @return start offset of simple type name, or -1 iff ! isQualified()
405 */
406 public int getSimpleNameStart() {
407 return fSimpleNameStart;
408 }
409
410 /**
411 * @return simple type name, or null iff ! isSimpleName()
412 */
413 public String getSimpleName() {
414 return fSimpleTypeName;
415 }
416
417 public void generated_8299490140507927106(TextChangeManager changeManager, ICompilationUnit movedUnit, ICompilationUnit referencingCu, boolean simpleReferencesNeedNewImport, SearchMatch[] results, int j, MoveCuUpdateCreator movecuupdatecreator) throws CoreException, JavaModelException {
418 if (isImportDeclaration()) {
419 ImportRewrite rewrite= movecuupdatecreator.getImportRewrite(referencingCu);
420 IImportDeclaration importDecl= (IImportDeclaration) SearchUtils.getEnclosingJavaElement(results[j]);
421 if (Flags.isStatic(importDecl.getFlags())) {
422 rewrite.removeStaticImport(importDecl.getElementName());
423 movecuupdatecreator.addStaticImport(movedUnit, importDecl, rewrite);
424 } else {
425 rewrite.removeImport(importDecl.getElementName());
426 rewrite.addImport(movecuupdatecreator.createStringForNewImport(movedUnit, importDecl));
427 }
428 } else if (isQualified()) {
429 TextChange textChange= changeManager.get(referencingCu);
430 String changeName= RefactoringCoreMessages.MoveCuUpdateCreator_update_references;
431 TextEdit replaceEdit= new ReplaceEdit(getOffset(), getSimpleNameStart() - getOffset(), movecuupdatecreator.fNewPackage);
432 TextChangeCompatibility.addTextEdit(textChange, changeName, replaceEdit);
433 } else if (simpleReferencesNeedNewImport) {
434 ImportRewrite importEdit= movecuupdatecreator.getImportRewrite(referencingCu);
435 String typeName= getSimpleName();
436 importEdit.addImport(movecuupdatecreator.getQualifiedType(movecuupdatecreator.fDestination.getElementName(), typeName));
437 }
438 }
439 }
440
441}