]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-before/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/IntroduceIndirectionRefactoring.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / core refactoring / org / eclipse / jdt / internal / corext / refactoring / code / IntroduceIndirectionRefactoring.java
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  *******************************************************************************/
11 package org.eclipse.jdt.internal.corext.refactoring.code;
12
13 import java.lang.reflect.Modifier;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.HashMap;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Map;
20
21 import org.eclipse.core.runtime.Assert;
22 import org.eclipse.core.runtime.CoreException;
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.core.runtime.NullProgressMonitor;
25 import org.eclipse.core.runtime.OperationCanceledException;
26 import org.eclipse.core.runtime.SubProgressMonitor;
27
28 import org.eclipse.core.resources.IFile;
29
30 import org.eclipse.ltk.core.refactoring.Change;
31 import org.eclipse.ltk.core.refactoring.Refactoring;
32 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
33 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
34
35 import org.eclipse.jdt.core.Flags;
36 import org.eclipse.jdt.core.IClassFile;
37 import org.eclipse.jdt.core.ICompilationUnit;
38 import org.eclipse.jdt.core.IJavaElement;
39 import org.eclipse.jdt.core.IJavaProject;
40 import org.eclipse.jdt.core.IMember;
41 import org.eclipse.jdt.core.IMethod;
42 import org.eclipse.jdt.core.IPackageFragment;
43 import org.eclipse.jdt.core.IType;
44 import org.eclipse.jdt.core.ITypeHierarchy;
45 import org.eclipse.jdt.core.JavaModelException;
46 import org.eclipse.jdt.core.dom.AST;
47 import org.eclipse.jdt.core.dom.ASTNode;
48 import org.eclipse.jdt.core.dom.ASTParser;
49 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
50 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
51 import org.eclipse.jdt.core.dom.Block;
52 import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
53 import org.eclipse.jdt.core.dom.CompilationUnit;
54 import org.eclipse.jdt.core.dom.Expression;
55 import org.eclipse.jdt.core.dom.ExpressionStatement;
56 import org.eclipse.jdt.core.dom.IBinding;
57 import org.eclipse.jdt.core.dom.IExtendedModifier;
58 import org.eclipse.jdt.core.dom.IMethodBinding;
59 import org.eclipse.jdt.core.dom.ITypeBinding;
60 import org.eclipse.jdt.core.dom.Javadoc;
61 import org.eclipse.jdt.core.dom.MethodDeclaration;
62 import org.eclipse.jdt.core.dom.MethodInvocation;
63 import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
64 import org.eclipse.jdt.core.dom.Name;
65 import org.eclipse.jdt.core.dom.NodeFinder;
66 import org.eclipse.jdt.core.dom.ParameterizedType;
67 import org.eclipse.jdt.core.dom.PrimitiveType;
68 import org.eclipse.jdt.core.dom.ReturnStatement;
69 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
70 import org.eclipse.jdt.core.dom.Statement;
71 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
72 import org.eclipse.jdt.core.dom.ThisExpression;
73 import org.eclipse.jdt.core.dom.Type;
74 import org.eclipse.jdt.core.dom.TypeParameter;
75 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
76 import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
77 import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
78 import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
79 import org.eclipse.jdt.core.refactoring.descriptors.IntroduceIndirectionDescriptor;
80 import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
81 import org.eclipse.jdt.core.search.IJavaSearchConstants;
82 import org.eclipse.jdt.core.search.IJavaSearchScope;
83 import org.eclipse.jdt.core.search.SearchMatch;
84 import org.eclipse.jdt.core.search.SearchPattern;
85
86 import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory;
87 import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
88 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
89 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
90 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
91 import org.eclipse.jdt.internal.corext.dom.Bindings;
92 import org.eclipse.jdt.internal.corext.refactoring.Checks;
93 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
94 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
95 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
96 import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
97 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
98 import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
99 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine;
100 import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
101 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
102 import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
103 import org.eclipse.jdt.internal.corext.refactoring.rename.RippleMethodFinder2;
104 import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil;
105 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
106 import org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor;
107 import org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment;
108 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
109 import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
110 import org.eclipse.jdt.internal.corext.util.JdtFlags;
111 import org.eclipse.jdt.internal.corext.util.Messages;
112 import org.eclipse.jdt.internal.corext.util.MethodOverrideTester;
113
114 import org.eclipse.jdt.ui.CodeGeneration;
115 import org.eclipse.jdt.ui.JavaElementLabels;
116
117 import org.eclipse.jdt.internal.ui.JavaPlugin;
118 import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
119 import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
120
121 /**
122  *
123  * This refactoring creates a wrapper around a certain method and redirects callers of the original
124  * method to the newly created method (called "intermediary method").
125  *
126  * If invoked on a method call, the user may select whether to only update the selected call or
127  * all other calls as well. If invoked on a method declaration, the user may select whether to
128  * update calls at all. An intermediary method will be created in both cases.
129  *
130  * Creating indirections is possible for both source and binary methods. Select an invocation of the method or
131  * the declaring method itself, for example in the outline view.
132  *
133  * Note that in case of methods inside generic types, the parameters of the declaring type of the selected method
134  * will be added to the method definition, rendering it generic as well.
135  *
136  * If any of the calls cannot see the intermediary method due to visibility problems with enclosing types
137  * of the intermediary method, visibility will be adjusted. If the intermediary method is not able to
138  * see the target method, this refactoring will try to adjust the visibility of the target method and
139  * enclosing types as well. However, the latter is only possible if the target method is from source.
140  *
141  * @since 3.2
142  *
143  */
144 public class IntroduceIndirectionRefactoring extends Refactoring {
145
146         /**
147          * The compilation unit in which the user invoked this refactoring (if any)
148          */
149         private ICompilationUnit fSelectionCompilationUnit;
150         /**
151          * The class file (with source) in which the user invoked this refactoring (if any)
152          */
153         private IClassFile fSelectionClassFile;
154         /**
155          * The start of the user selection inside the selected
156          * compilation unit (if any)
157          */
158         private int fSelectionStart;
159         /**
160          * The length of the user selection inside the selected
161          * compilation unit (if any)
162          */
163         private int fSelectionLength;
164         /**
165          * The selected MethodInvocation (if any). This field is used
166          * to update this particular invocation in non-reference mode.
167          */
168         private MethodInvocation fSelectionMethodInvocation;
169
170         // Intermediary information:
171
172         /**
173          * The class in which to place the intermediary method
174          */
175         private IType fIntermediaryClass;
176         /**
177          * The binding of the intermediary class
178          */
179         private ITypeBinding fIntermediaryClassBinding;
180         /**
181          * The name of the intermediary method
182          */
183         private String fIntermediaryMethodName;
184         /**
185          * The type for the additional parameter for the intermediary. This
186          * type is determined from all known references.
187          */
188         private ITypeBinding fIntermediaryFirstParameterType;
189
190         // Target information:
191
192         /**
193          * The originally selected target method (i.e., the one to be encapsulated)
194          */
195         private IMethod fTargetMethod;
196         /**
197          * The binding of the originally selected target method
198          */
199         private IMethodBinding fTargetMethodBinding;
200
201         // Other information:
202
203         /**
204          * If true, all references to the target method are replaced with calls to
205          * the intermediary.
206          */
207         private boolean fUpdateReferences;
208         /**
209          * CompilationUnitRewrites for all affected cus
210          */
211         private Map<ICompilationUnit, CompilationUnitRewrite> fRewrites;
212         /**
213          * Text change manager (actually a CompilationUnitChange manager) which
214          * manages all changes.
215          */
216         private TextChangeManager fTextChangeManager;
217
218         // Visibility
219
220         /**
221          * The visibility adjustor
222          */
223         private MemberVisibilityAdjustor fAdjustor;
224         /**
225          * Visibility adjustments for the intermediary
226          */
227         private Map<IMember, IncomingMemberVisibilityAdjustment> fIntermediaryAdjustments;
228
229
230         private class NoOverrideProgressMonitor extends SubProgressMonitor {
231
232                 public NoOverrideProgressMonitor(IProgressMonitor monitor, int ticks) {
233                         super(monitor, ticks, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL);
234                 }
235
236                 @Override
237                 public void setTaskName(String name) {
238                         // do nothing
239                 }
240         }
241
242         // ********* CONSTRUCTORS AND CLASS CREATION ************
243
244         public IntroduceIndirectionRefactoring(ICompilationUnit unit, int offset, int length) {
245                 fSelectionCompilationUnit= unit;
246                 initialize(offset, length);
247         }
248
249         public IntroduceIndirectionRefactoring(IClassFile file, int offset, int length) {
250                 fSelectionClassFile= file;
251                 initialize(offset, length);
252         }
253
254         public IntroduceIndirectionRefactoring(IMethod method) {
255                 fTargetMethod= method;
256                 initialize(0, 0);
257         }
258
259     public IntroduceIndirectionRefactoring(JavaRefactoringArguments arguments, RefactoringStatus status) {
260                 this((ICompilationUnit) null, 0, 0);
261                 RefactoringStatus initializeStatus= initialize(arguments);
262                 status.merge(initializeStatus);
263     }
264
265         private void initialize(int offset, int length) {
266                 fSelectionStart= offset;
267                 fSelectionLength= length;
268                 fUpdateReferences= true;
269         }
270
271         // ********* UI INTERACTION AND STARTUP OPTIONS ************
272
273         @Override
274         public String getName() {
275                 return RefactoringCoreMessages.IntroduceIndirectionRefactoring_introduce_indirection_name;
276         }
277
278         public IJavaProject getProject() {
279                 if (fSelectionCompilationUnit != null)
280                         return fSelectionCompilationUnit.getJavaProject();
281                 if (fSelectionClassFile != null)
282                         return fSelectionClassFile.getJavaProject();
283                 if (fTargetMethod != null)
284                         return fTargetMethod.getJavaProject();
285                 return null;
286         }
287
288         public IPackageFragment getInvocationPackage() {
289                 return fSelectionCompilationUnit != null ? (IPackageFragment) fSelectionCompilationUnit.getAncestor(IJavaElement.PACKAGE_FRAGMENT) : null;
290         }
291
292         public boolean canEnableUpdateReferences() {
293                 return true;
294         }
295
296         public void setEnableUpdateReferences(boolean updateReferences) {
297                 fUpdateReferences= updateReferences;
298         }
299
300         public RefactoringStatus setIntermediaryMethodName(String newMethodName) {
301                 Assert.isNotNull(newMethodName);
302                 fIntermediaryMethodName= newMethodName;
303                 IJavaElement context= fIntermediaryClass != null ? fIntermediaryClass : (IMember) fTargetMethod;
304                 RefactoringStatus stat= Checks.checkMethodName(newMethodName, context);
305                 stat.merge(checkOverloading());
306                 return stat;
307         }
308
309         private RefactoringStatus checkOverloading() {
310                 try {
311                         if (fIntermediaryClass != null) {
312                                 IMethod[] toCheck= fIntermediaryClass.getMethods();
313                                 for (int i= 0; i < toCheck.length; i++) {
314                                         IMethod method= toCheck[i];
315                                         if (method.getElementName().equals(fIntermediaryMethodName))
316                                                 return RefactoringStatus.createWarningStatus(Messages.format(RefactoringCoreMessages.IntroduceIndirectionRefactoring_duplicate_method_name_in_declaring_class_error,
317                                                                 BasicElementLabels.getJavaElementName(fIntermediaryMethodName)));
318                                 }
319                         }
320                 } catch (JavaModelException e) {
321                         return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_could_not_parse_declaring_class_error);
322                 }
323                 return new RefactoringStatus();
324         }
325
326         public String getIntermediaryMethodName() {
327                 return fIntermediaryMethodName;
328         }
329
330         /**
331          * @param fullyQualifiedTypeName the fully qualified name of the intermediary method
332          * @return status for type name. Use {@link #setIntermediaryMethodName(String)} to check for overridden methods.
333          */
334         public RefactoringStatus setIntermediaryClassName(String fullyQualifiedTypeName) {
335                 IType target= null;
336
337                 try {
338                         if (fullyQualifiedTypeName.length() == 0)
339                                 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_class_not_selected_error);
340
341                         // find type (now including secondaries)
342                         target= getProject().findType(fullyQualifiedTypeName, new NullProgressMonitor());
343                         if (target == null || !target.exists())
344                                 return RefactoringStatus.createErrorStatus(Messages.format(RefactoringCoreMessages.IntroduceIndirectionRefactoring_class_does_not_exist_error, BasicElementLabels.getJavaElementName(fullyQualifiedTypeName)));
345                         if (target.isAnnotation())
346                                 return RefactoringStatus.createErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_create_in_annotation);
347                         if (target.isInterface())
348                                 return RefactoringStatus.createErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_create_on_interface);
349                 } catch (JavaModelException e) {
350                         return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_unable_determine_declaring_type);
351                 }
352
353                 if (target.isReadOnly())
354                         return RefactoringStatus.createErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_create_in_readonly);
355
356                 if (target.isBinary())
357                         return RefactoringStatus.createErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_create_in_binary);
358
359                 fIntermediaryClass= target;
360
361                 return new RefactoringStatus();
362         }
363
364         /**
365          * Returns the class name of the intermediary class, or the empty string if none has been set yet.
366          * @return the intermediary class name or the empty string
367          */
368         public String getIntermediaryClassName() {
369                 return fIntermediaryClass != null ? fIntermediaryClass.getFullyQualifiedName('.') : ""; //$NON-NLS-1$
370         }
371
372         // ********** CONDITION CHECKING **********
373
374         @Override
375         public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
376                 try {
377                         pm.beginTask(RefactoringCoreMessages.IntroduceIndirectionRefactoring_checking_activation, 1);
378                         fRewrites= new HashMap<ICompilationUnit, CompilationUnitRewrite>();
379
380                         // This refactoring has been invoked on
381                         // (1) a TextSelection inside an ICompilationUnit or inside an IClassFile (definitely with source), or
382                         // (2) an IMethod inside a ICompilationUnit or inside an IClassFile (with or without source)
383
384                         if (fTargetMethod == null) {
385                                 // (1) invoked on a text selection
386
387                                 if (fSelectionStart == 0)
388                                         return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_on_this_selection);
389
390                                 // if a text selection exists, source is available.
391                                 CompilationUnit selectionCURoot;
392                                 ASTNode selectionNode;
393                                 if (fSelectionCompilationUnit != null) {
394                                         // compilation unit - could use CuRewrite later on
395                                         selectionCURoot= getCachedCURewrite(fSelectionCompilationUnit).getRoot();
396                                         selectionNode= getSelectedNode(fSelectionCompilationUnit, selectionCURoot, fSelectionStart, fSelectionLength);
397                                 } else {
398                                         // binary class file - no cu rewrite
399                                         ASTParser parser= ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL);
400                                         parser.setResolveBindings(true);
401                                         parser.setSource(fSelectionClassFile);
402                                         selectionCURoot= (CompilationUnit) parser.createAST(null);
403                                         selectionNode= getSelectedNode(null, selectionCURoot, fSelectionStart, fSelectionLength);
404                                 }
405
406                                 if (selectionNode == null)
407                                         return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_on_this_selection);
408
409                                 IMethodBinding targetMethodBinding= null;
410
411                                 if (selectionNode.getNodeType() == ASTNode.METHOD_INVOCATION) {
412                                         targetMethodBinding= ((MethodInvocation) selectionNode).resolveMethodBinding();
413                                 } else if (selectionNode.getNodeType() == ASTNode.METHOD_DECLARATION) {
414                                         targetMethodBinding= ((MethodDeclaration) selectionNode).resolveBinding();
415                                 } else if (selectionNode.getNodeType() == ASTNode.SUPER_METHOD_INVOCATION) {
416                                         // Allow invocation on super methods calls. makes sense as other
417                                         // calls or even only the declaration can be updated.
418                                         targetMethodBinding= ((SuperMethodInvocation) selectionNode).resolveMethodBinding();
419                                 } else {
420                                         return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_on_this_selection);
421                                 }
422                                 fTargetMethodBinding= targetMethodBinding.getMethodDeclaration(); // resolve generics
423                                 fTargetMethod= (IMethod) fTargetMethodBinding.getJavaElement();
424
425                                 //allow single updating mode if an invocation was selected and the invocation can be updated
426                                 if (selectionNode instanceof MethodInvocation && fSelectionCompilationUnit != null)
427                                         fSelectionMethodInvocation= (MethodInvocation) selectionNode;
428
429                         } else {
430                                 // (2) invoked on an IMethod: Source may not be available
431
432                                 if (fTargetMethod.getDeclaringType().isAnnotation())
433                                         return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_on_annotation);
434
435                                 if (fTargetMethod.getCompilationUnit() != null) {
436                                         // source method
437                                         CompilationUnit selectionCURoot= getCachedCURewrite(fTargetMethod.getCompilationUnit()).getRoot();
438                                         MethodDeclaration declaration= ASTNodeSearchUtil.getMethodDeclarationNode(fTargetMethod, selectionCURoot);
439                                         fTargetMethodBinding= declaration.resolveBinding().getMethodDeclaration();
440                                 } else {
441                                         // binary method - no CURewrite available (and none needed as we cannot update the method anyway)
442                                         ASTParser parser= ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL);
443                                         parser.setProject(fTargetMethod.getJavaProject());
444                                         IBinding[] bindings= parser.createBindings(new IJavaElement[] { fTargetMethod }, null);
445                                         fTargetMethodBinding= ((IMethodBinding) bindings[0]).getMethodDeclaration();
446                                 }
447                         }
448
449                         if (fTargetMethod == null || fTargetMethodBinding == null || (!RefactoringAvailabilityTester.isIntroduceIndirectionAvailable(fTargetMethod)))
450                                 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_on_this_selection);
451
452                         if (fTargetMethod.getDeclaringType().isLocal() || fTargetMethod.getDeclaringType().isAnonymous())
453                                 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_for_local_or_anonymous_types);
454
455                         if (fTargetMethod.isConstructor())
456                                 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_for_constructors);
457
458                         if (fIntermediaryMethodName == null)
459                                 fIntermediaryMethodName= fTargetMethod.getElementName();
460
461                         if (fIntermediaryClass == null) {
462                                 if (fSelectionCompilationUnit != null && !fSelectionCompilationUnit.isReadOnly())
463                                         fIntermediaryClass= getEnclosingInitialSelectionMember().getDeclaringType();
464                                 else if (!fTargetMethod.isBinary() && !fTargetMethod.isReadOnly())
465                                         fIntermediaryClass= fTargetMethod.getDeclaringType();
466                         }
467
468                         return new RefactoringStatus();
469                 } finally {
470                         pm.done();
471                 }
472         }
473
474         @Override
475         public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
476
477                 RefactoringStatus result= new RefactoringStatus();
478                 fTextChangeManager= new TextChangeManager();
479                 fIntermediaryFirstParameterType= null;
480                 fIntermediaryClassBinding= null;
481                 for (Iterator<CompilationUnitRewrite> iter= fRewrites.values().iterator(); iter.hasNext();)
482                         iter.next().clearASTAndImportRewrites();
483
484                 int startupTicks= 5;
485                 int hierarchyTicks= 5;
486                 int visibilityTicks= 5;
487                 int referenceTicks= fUpdateReferences ? 30 : 5;
488                 int creationTicks= 5;
489
490                 pm.beginTask("", startupTicks + hierarchyTicks + visibilityTicks + referenceTicks + creationTicks); //$NON-NLS-1$
491                 pm.setTaskName(RefactoringCoreMessages.IntroduceIndirectionRefactoring_checking_conditions);
492
493                 result.merge(Checks.checkMethodName(fIntermediaryMethodName, fIntermediaryClass));
494                 if (result.hasFatalError())
495                         return result;
496
497                 if (fIntermediaryClass == null)
498                         return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_run_without_intermediary_type);
499
500                 // intermediary class is already non binary/non-enum/non-interface.
501                 CompilationUnitRewrite imRewrite= getCachedCURewrite(fIntermediaryClass.getCompilationUnit());
502                 fIntermediaryClassBinding= typeToBinding(fIntermediaryClass, imRewrite.getRoot());
503
504                 fAdjustor= new MemberVisibilityAdjustor(fIntermediaryClass, fIntermediaryClass);
505                 fIntermediaryAdjustments= new HashMap<IMember, IncomingMemberVisibilityAdjustment>();
506
507                 // check static method in non-static nested type
508                 if (fIntermediaryClassBinding.isNested() && !Modifier.isStatic(fIntermediaryClassBinding.getModifiers()))
509                         return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_create_in_nested_nonstatic, JavaStatusContext.create(fIntermediaryClass));
510
511                 pm.worked(startupTicks);
512                 if (pm.isCanceled())
513                         throw new OperationCanceledException();
514
515                 if (fUpdateReferences) {
516                         pm.setTaskName(RefactoringCoreMessages.IntroduceIndirectionRefactoring_checking_conditions + " " + RefactoringCoreMessages.IntroduceIndirectionRefactoring_looking_for_references); //$NON-NLS-1$
517                         result.merge(updateReferences(new NoOverrideProgressMonitor(pm, referenceTicks)));
518                         pm.setTaskName(RefactoringCoreMessages.IntroduceIndirectionRefactoring_checking_conditions);
519                 } else {
520                         // only update the declaration and/or a selected method invocation
521                         if (fSelectionMethodInvocation != null) {
522                                 fIntermediaryFirstParameterType= getExpressionType(fSelectionMethodInvocation);
523                                 final IMember enclosing= getEnclosingInitialSelectionMember();
524                                 // create an edit for this particular call
525                                 result.merge(updateMethodInvocation(fSelectionMethodInvocation, enclosing, getCachedCURewrite(fSelectionCompilationUnit)));
526
527                                 if (!isRewriteKept(fSelectionCompilationUnit))
528                                         createChangeAndDiscardRewrite(fSelectionCompilationUnit);
529
530                                 // does call see the intermediary method?
531                                 // => increase visibility of the type of the intermediary method.
532                                 result.merge(adjustVisibility(fIntermediaryClass, enclosing.getDeclaringType(), new NoOverrideProgressMonitor(pm, 0)));
533                         }
534                         pm.worked(referenceTicks);
535                 }
536
537                 if (pm.isCanceled())
538                         throw new OperationCanceledException();
539
540                 if (fIntermediaryFirstParameterType == null)
541                         fIntermediaryFirstParameterType= fTargetMethodBinding.getDeclaringClass();
542
543                 // The target type and method may have changed - update them
544
545                 IType actualTargetType= (IType) fIntermediaryFirstParameterType.getJavaElement();
546                 if (!fTargetMethod.getDeclaringType().equals(actualTargetType)) {
547                         IMethod actualTargetMethod= new MethodOverrideTester(actualTargetType, actualTargetType.newSupertypeHierarchy(null)).findOverriddenMethodInHierarchy(actualTargetType, fTargetMethod);
548                         fTargetMethod= actualTargetMethod;
549                         fTargetMethodBinding= findMethodBindingInHierarchy(fIntermediaryFirstParameterType, actualTargetMethod);
550                         Assert.isNotNull(fTargetMethodBinding);
551                 }
552
553                 result.merge(checkCanCreateIntermediaryMethod());
554                 createIntermediaryMethod();
555                 pm.worked(creationTicks);
556
557                 pm.setTaskName(RefactoringCoreMessages.IntroduceIndirectionRefactoring_checking_conditions + " " + RefactoringCoreMessages.IntroduceIndirectionRefactoring_adjusting_visibility); //$NON-NLS-1$
558                 result.merge(updateTargetVisibility(new NoOverrideProgressMonitor(pm, 0)));
559                 result.merge(updateIntermediaryVisibility(new NoOverrideProgressMonitor(pm, 0)));
560                 pm.worked(visibilityTicks);
561                 pm.setTaskName(RefactoringCoreMessages.IntroduceIndirectionRefactoring_checking_conditions);
562
563                 createChangeAndDiscardRewrite(fIntermediaryClass.getCompilationUnit());
564
565                 result.merge(Checks.validateModifiesFiles(getAllFilesToModify(), getValidationContext()));
566                 pm.done();
567
568                 return result;
569         }
570
571         private RefactoringStatus updateTargetVisibility(IProgressMonitor monitor) throws JavaModelException, CoreException {
572
573                 RefactoringStatus result= new RefactoringStatus();
574
575                 // Adjust the visibility of the method and of the referenced type. Note that
576                 // the target method may not be in the target type; and in this case, the type
577                 // of the target method does not need a visibility adjustment.
578
579                 // This method is called after all other changes have been
580                 // created. Changes induced by this method will be attached to those changes.
581
582                 result.merge(adjustVisibility((IType) fIntermediaryFirstParameterType.getJavaElement(), fIntermediaryClass, monitor));
583                 if (result.hasError())
584                         return result; // binary
585
586                 ModifierKeyword neededVisibility= getNeededVisibility(fTargetMethod, fIntermediaryClass);
587                 if (neededVisibility != null) {
588
589                         result.merge(adjustVisibility(fTargetMethod, neededVisibility,  monitor));
590                         if (result.hasError())
591                                 return result; // binary
592
593                         // Need to adjust the overridden methods of the target method.
594                         ITypeHierarchy hierarchy= fTargetMethod.getDeclaringType().newTypeHierarchy(null);
595                         MethodOverrideTester tester= new MethodOverrideTester(fTargetMethod.getDeclaringType(), hierarchy);
596                         IType[] subtypes= hierarchy.getAllSubtypes(fTargetMethod.getDeclaringType());
597                         for (int i= 0; i < subtypes.length; i++) {
598                                 IMethod method= tester.findOverridingMethodInType(subtypes[i], fTargetMethod);
599                                 if (method != null && method.exists()) {
600                                         result.merge(adjustVisibility(method, neededVisibility, monitor));
601                                         if (monitor.isCanceled())
602                                                 throw new OperationCanceledException();
603
604                                         if (result.hasError())
605                                                 return result; // binary
606                                 }
607                         }
608                 }
609
610                 return result;
611         }
612
613         private RefactoringStatus updateIntermediaryVisibility(NoOverrideProgressMonitor monitor) throws JavaModelException {
614                 return rewriteVisibility(fIntermediaryAdjustments, fRewrites, monitor);
615         }
616
617         private RefactoringStatus updateReferences(IProgressMonitor monitor) throws CoreException {
618
619                 RefactoringStatus result= new RefactoringStatus();
620
621                 monitor.beginTask("", 90); //$NON-NLS-1$
622
623                 if (monitor.isCanceled())
624                         throw new OperationCanceledException();
625
626                 IMethod[] ripple= RippleMethodFinder2.getRelatedMethods(fTargetMethod, false, new NoOverrideProgressMonitor(monitor, 10), null);
627
628                 if (monitor.isCanceled())
629                         throw new OperationCanceledException();
630
631                 SearchResultGroup[] references= Checks.excludeCompilationUnits(getReferences(ripple, new NoOverrideProgressMonitor(monitor, 10), result), result);
632
633                 if (result.hasFatalError())
634                         return result;
635
636                 result.merge(Checks.checkCompileErrorsInAffectedFiles(references));
637
638                 if (monitor.isCanceled())
639                         throw new OperationCanceledException();
640
641                 int ticksPerCU= references.length == 0 ? 0 : 70 / references.length;
642
643                 for (int i= 0; i < references.length; i++) {
644                         SearchResultGroup group= references[i];
645                         SearchMatch[] searchResults= group.getSearchResults();
646                         CompilationUnitRewrite currentCURewrite= getCachedCURewrite(group.getCompilationUnit());
647
648                         for (int j= 0; j < searchResults.length; j++) {
649
650                                 SearchMatch match= searchResults[j];
651                                 if (match.isInsideDocComment())
652                                         continue;
653
654                                 IMember enclosingMember= (IMember) match.getElement();
655                                 ASTNode target= getSelectedNode(group.getCompilationUnit(), currentCURewrite.getRoot(), match.getOffset(), match.getLength());
656
657                                 if (target instanceof SuperMethodInvocation) {
658                                         // Cannot retarget calls to super - add a warning
659                                         result.merge(createWarningAboutCall(enclosingMember, target, RefactoringCoreMessages.IntroduceIndirectionRefactoring_call_warning_super_keyword));
660                                         continue;
661                                 }
662
663                                 Assert.isTrue(target instanceof MethodInvocation, "Element of call should be a MethodInvocation."); //$NON-NLS-1$
664
665                                 MethodInvocation invocation= (MethodInvocation) target;
666                                 ITypeBinding typeBinding= getExpressionType(invocation);
667
668                                 if (fIntermediaryFirstParameterType == null) {
669                                         // no highest type yet
670                                         fIntermediaryFirstParameterType= typeBinding.getTypeDeclaration();
671                                 } else {
672                                         // check if current type is higher
673                                         result.merge(findCommonParent(typeBinding.getTypeDeclaration()));
674                                 }
675
676                                 if (result.hasFatalError())
677                                         return result;
678
679                                 // create an edit for this particular call
680                                 result.merge(updateMethodInvocation(invocation, enclosingMember, currentCURewrite));
681
682                                 // does call see the intermediary method?
683                                 // => increase visibility of the type of the intermediary method.
684                                 result.merge(adjustVisibility(fIntermediaryClass, enclosingMember.getDeclaringType(), new NoOverrideProgressMonitor(monitor, 0)));
685
686                                 if (monitor.isCanceled())
687                                         throw new OperationCanceledException();
688                         }
689
690                         if (!isRewriteKept(group.getCompilationUnit()))
691                                 createChangeAndDiscardRewrite(group.getCompilationUnit());
692
693                         monitor.worked(ticksPerCU);
694                 }
695
696                 monitor.done();
697                 return result;
698         }
699
700         private RefactoringStatus findCommonParent(ITypeBinding typeBinding) {
701
702                 RefactoringStatus status= new RefactoringStatus();
703
704                 ITypeBinding highest= fIntermediaryFirstParameterType;
705                 ITypeBinding current= typeBinding;
706
707                 if (current.equals(highest) || Bindings.isSuperType(highest, current))
708                         // current is the same as highest or highest is already a supertype of current in the same hierarchy => no change
709                         return status;
710
711                 // find lowest common supertype with the method
712                 // search in bottom-up order
713                 ITypeBinding[] currentAndSupers= getTypeAndAllSuperTypes(current);
714                 ITypeBinding[] highestAndSupers= getTypeAndAllSuperTypes(highest);
715
716                 ITypeBinding foundBinding= null;
717                 for (int i1= 0; i1 < currentAndSupers.length; i1++) {
718                         for (int i2= 0; i2 < highestAndSupers.length; i2++) {
719                                 if (highestAndSupers[i2].isEqualTo(currentAndSupers[i1])
720                                                 && (Bindings.findMethodInHierarchy(highestAndSupers[i2], fTargetMethodBinding.getName(), fTargetMethodBinding.getParameterTypes()) != null)) {
721                                         foundBinding= highestAndSupers[i2];
722                                         break;
723                                 }
724                         }
725                         if (foundBinding != null)
726                                 break;
727                 }
728
729                 if (foundBinding != null) {
730                         fIntermediaryFirstParameterType= foundBinding;
731                 } else {
732                         String type1= BasicElementLabels.getJavaElementName(fIntermediaryFirstParameterType.getQualifiedName());
733                         String type2= BasicElementLabels.getJavaElementName(current.getQualifiedName());
734                         status.addFatalError(Messages.format(RefactoringCoreMessages.IntroduceIndirectionRefactoring_open_hierarchy_error, new String[] { type1, type2 }));
735                 }
736
737                 return status;
738         }
739
740         // ******************** CHANGE CREATION ***********************
741
742         @Override
743         public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
744                 final Map<String, String> arguments= new HashMap<String, String>();
745                 String project= null;
746                 IJavaProject javaProject= fTargetMethod.getJavaProject();
747                 if (javaProject != null)
748                         project= javaProject.getElementName();
749                 int flags= JavaRefactoringDescriptor.JAR_MIGRATION | JavaRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE;
750                 final IType declaring= fTargetMethod.getDeclaringType();
751                 try {
752                         if (declaring.isLocal() || declaring.isAnonymous())
753                                 flags|= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
754                 } catch (JavaModelException exception) {
755                         JavaPlugin.log(exception);
756                 }
757                 final String description= Messages.format(RefactoringCoreMessages.IntroduceIndirectionRefactoring_descriptor_description_short, BasicElementLabels.getJavaElementName(fTargetMethod.getElementName()));
758                 final String header= Messages.format(RefactoringCoreMessages.IntroduceIndirectionRefactoring_descriptor_description, new String[] { JavaElementLabels.getTextLabel(fTargetMethod, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getTextLabel(declaring, JavaElementLabels.ALL_FULLY_QUALIFIED)});
759                 final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
760                 comment.addSetting(Messages.format(RefactoringCoreMessages.IntroduceIndirectionRefactoring_original_pattern, JavaElementLabels.getTextLabel(fTargetMethod, JavaElementLabels.ALL_FULLY_QUALIFIED)));
761                 comment.addSetting(Messages.format(RefactoringCoreMessages.IntroduceIndirectionRefactoring_method_pattern, BasicElementLabels.getJavaElementName(fIntermediaryMethodName)));
762                 comment.addSetting(Messages.format(RefactoringCoreMessages.IntroduceIndirectionRefactoring_declaring_pattern, JavaElementLabels.getTextLabel(fIntermediaryClass, JavaElementLabels.ALL_FULLY_QUALIFIED)));
763                 if (fUpdateReferences)
764                         comment.addSetting(RefactoringCoreMessages.JavaRefactoringDescriptor_update_references);
765                 final IntroduceIndirectionDescriptor descriptor= RefactoringSignatureDescriptorFactory.createIntroduceIndirectionDescriptor(project, description, comment.asString(), arguments, flags);
766                 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT, JavaRefactoringDescriptorUtil.elementToHandle(project, fTargetMethod));
767                 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME, fIntermediaryMethodName);
768                 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + 1, JavaRefactoringDescriptorUtil.elementToHandle(project, fIntermediaryClass));
769                 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_REFERENCES, Boolean.valueOf(fUpdateReferences).toString());
770                 return new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.IntroduceIndirectionRefactoring_introduce_indirection, fTextChangeManager.getAllChanges());
771         }
772
773         // ******************* CREATE INTERMEDIARY **********************
774
775         /**
776          * Checks whether the target method can be created. Note that this
777          * can only be done after fDelegateParameterType has been initialized.
778          * @return resulting status
779          * @throws JavaModelException should not happen
780          */
781         private RefactoringStatus checkCanCreateIntermediaryMethod() throws JavaModelException {
782                 // check if method already exists:
783                 List<ITypeBinding> parameterBindings= new ArrayList<ITypeBinding>();
784                 if (!isStaticTarget())
785                         parameterBindings.add(fIntermediaryFirstParameterType);
786                 parameterBindings.addAll(Arrays.asList(fTargetMethodBinding.getParameterTypes()));
787                 return Checks.checkMethodInType(fIntermediaryClassBinding, fIntermediaryMethodName, parameterBindings.toArray(new ITypeBinding[parameterBindings.size()]));
788         }
789
790         private void createIntermediaryMethod() throws CoreException {
791
792                 CompilationUnitRewrite imRewrite= getCachedCURewrite(fIntermediaryClass.getCompilationUnit());
793                 AST ast= imRewrite.getAST();
794                 MethodDeclaration intermediary= ast.newMethodDeclaration();
795
796                 // Intermediary class is non-anonymous
797                 AbstractTypeDeclaration type= (AbstractTypeDeclaration)typeToDeclaration(fIntermediaryClass, imRewrite.getRoot());
798
799                 // Name
800                 intermediary.setName(ast.newSimpleName(fIntermediaryMethodName));
801
802                 // Flags
803                 List<IExtendedModifier> modifiers= intermediary.modifiers();
804                 modifiers.add(imRewrite.getAST().newModifier(ModifierKeyword.PUBLIC_KEYWORD));
805                 modifiers.add(imRewrite.getAST().newModifier(ModifierKeyword.STATIC_KEYWORD));
806
807                 // Parameters
808                 String targetParameterName= StubUtility.suggestArgumentName(getProject(), fIntermediaryFirstParameterType.getName(), fTargetMethod.getParameterNames());
809
810                 ImportRewriteContext context= new ContextSensitiveImportRewriteContext(type, imRewrite.getImportRewrite());
811                 if (!isStaticTarget()) {
812                         // Add first param
813                         SingleVariableDeclaration parameter= imRewrite.getAST().newSingleVariableDeclaration();
814                         Type t= imRewrite.getImportRewrite().addImport(fIntermediaryFirstParameterType, imRewrite.getAST(), context);
815                         if (fIntermediaryFirstParameterType.isGenericType()) {
816                                 ParameterizedType parameterized= imRewrite.getAST().newParameterizedType(t);
817                                 ITypeBinding[] typeParameters= fIntermediaryFirstParameterType.getTypeParameters();
818                                 for (int i= 0; i < typeParameters.length; i++)
819                                         parameterized.typeArguments().add(imRewrite.getImportRewrite().addImport(typeParameters[i], imRewrite.getAST()));
820                                 t= parameterized;
821                         }
822                         parameter.setType(t);
823                         parameter.setName(imRewrite.getAST().newSimpleName(targetParameterName));
824                         intermediary.parameters().add(parameter);
825                 }
826                 // Add other params
827                 copyArguments(intermediary, imRewrite);
828
829                 // Add type parameters of declaring class (and enclosing classes)
830                 if (!isStaticTarget() && fIntermediaryFirstParameterType.isGenericType())
831                         addTypeParameters(imRewrite, intermediary.typeParameters(), fIntermediaryFirstParameterType);
832
833                 // Add type params of method
834                 copyTypeParameters(intermediary, imRewrite);
835
836                 // Return type
837                 intermediary.setReturnType2(imRewrite.getImportRewrite().addImport(fTargetMethodBinding.getReturnType(), ast, context));
838
839                 // Exceptions
840                 copyExceptions(intermediary, imRewrite);
841
842                 // Body
843                 MethodInvocation invocation= imRewrite.getAST().newMethodInvocation();
844                 invocation.setName(imRewrite.getAST().newSimpleName(fTargetMethod.getElementName()));
845                 if (isStaticTarget()) {
846                         Type importedType= imRewrite.getImportRewrite().addImport(fTargetMethodBinding.getDeclaringClass(), ast, context);
847                         invocation.setExpression(ASTNodeFactory.newName(ast, ASTNodes.asString(importedType)));
848                 } else {
849                         invocation.setExpression(imRewrite.getAST().newSimpleName(targetParameterName));
850                 }
851                 copyInvocationParameters(invocation, ast);
852                 Statement call= encapsulateInvocation(intermediary, invocation);
853
854                 final Block body= imRewrite.getAST().newBlock();
855                 body.statements().add(call);
856                 intermediary.setBody(body);
857
858                 // method comment
859                 ICompilationUnit targetCU= imRewrite.getCu();
860                 if (StubUtility.doAddComments(targetCU.getJavaProject())) {
861                         String comment= CodeGeneration.getMethodComment(targetCU, getIntermediaryClassName(), intermediary, null, StubUtility.getLineDelimiterUsed(targetCU));
862                         if (comment != null) {
863                                 Javadoc javadoc= (Javadoc) imRewrite.getASTRewrite().createStringPlaceholder(comment, ASTNode.JAVADOC);
864                                 intermediary.setJavadoc(javadoc);
865                         }
866                 }
867
868                 // Add the completed method to the intermediary type:
869                 ChildListPropertyDescriptor typeBodyDeclarationsProperty= typeToBodyDeclarationProperty(fIntermediaryClass, imRewrite.getRoot());
870
871                 ListRewrite bodyDeclarationsListRewrite= imRewrite.getASTRewrite().getListRewrite(type, typeBodyDeclarationsProperty);
872                 bodyDeclarationsListRewrite.insertAt(intermediary, ASTNodes.getInsertionIndex(intermediary, type.bodyDeclarations()), imRewrite
873                                 .createGroupDescription(RefactoringCoreMessages.IntroduceIndirectionRefactoring_group_description_create_new_method));
874         }
875
876         private void addTypeParameters(CompilationUnitRewrite imRewrite, List<TypeParameter> list, ITypeBinding parent) {
877
878                 ITypeBinding enclosing= parent.getDeclaringClass();
879                 if (enclosing != null)
880                         addTypeParameters(imRewrite, list, enclosing);
881
882                 ITypeBinding[] typeParameters= parent.getTypeParameters();
883                 for (int i= 0; i < typeParameters.length; i++) {
884                         TypeParameter ntp= imRewrite.getAST().newTypeParameter();
885                         ntp.setName(imRewrite.getAST().newSimpleName(typeParameters[i].getName()));
886                         ITypeBinding[] bounds= typeParameters[i].getTypeBounds();
887                         for (int j= 0; j < bounds.length; j++)
888                                 if (!"java.lang.Object".equals(bounds[j].getQualifiedName())) //$NON-NLS-1$
889                                         ntp.typeBounds().add(imRewrite.getImportRewrite().addImport(bounds[j], imRewrite.getAST()));
890                         list.add(ntp);
891                 }
892         }
893
894         private Statement encapsulateInvocation(MethodDeclaration declaration, MethodInvocation invocation) {
895                 final Type type= declaration.getReturnType2();
896
897                 if (type == null || (type instanceof PrimitiveType && PrimitiveType.VOID.equals( ((PrimitiveType) type).getPrimitiveTypeCode())))
898                         return invocation.getAST().newExpressionStatement(invocation);
899
900                 ReturnStatement statement= invocation.getAST().newReturnStatement();
901                 statement.setExpression(invocation);
902                 return statement;
903         }
904
905         private void copyInvocationParameters(MethodInvocation invocation, AST ast) throws JavaModelException {
906                 String[] names= fTargetMethod.getParameterNames();
907                 for (int i= 0; i < names.length; i++)
908                         invocation.arguments().add(ast.newSimpleName(names[i]));
909         }
910
911         private void copyArguments(MethodDeclaration intermediary, CompilationUnitRewrite rew) throws JavaModelException {
912                 String[] names= fTargetMethod.getParameterNames();
913                 ITypeBinding[] types= fTargetMethodBinding.getParameterTypes();
914                 for (int i= 0; i < names.length; i++) {
915                         ITypeBinding typeBinding= types[i];
916                         SingleVariableDeclaration newElement= rew.getAST().newSingleVariableDeclaration();
917                         newElement.setName(rew.getAST().newSimpleName(names[i]));
918
919                         if (i == (names.length - 1) && fTargetMethodBinding.isVarargs()) {
920                                 newElement.setVarargs(true);
921                                 if (typeBinding.isArray())
922                                         typeBinding= typeBinding.getComponentType();
923                         }
924
925                         newElement.setType(rew.getImportRewrite().addImport(typeBinding, rew.getAST()));
926                         intermediary.parameters().add(newElement);
927                 }
928         }
929
930         private void copyTypeParameters(MethodDeclaration intermediary, CompilationUnitRewrite rew) {
931                 ITypeBinding[] typeParameters= fTargetMethodBinding.getTypeParameters();
932                 for (int i= 0; i < typeParameters.length; i++) {
933                         ITypeBinding current= typeParameters[i];
934
935                         TypeParameter parameter= rew.getAST().newTypeParameter();
936                         parameter.setName(rew.getAST().newSimpleName(current.getName()));
937                         ITypeBinding[] bounds= current.getTypeBounds();
938                         for (int j= 0; j < bounds.length; j++)
939                                 if (!"java.lang.Object".equals(bounds[j].getQualifiedName())) //$NON-NLS-1$
940                                         parameter.typeBounds().add(rew.getImportRewrite().addImport(bounds[j], rew.getAST()));
941
942                         intermediary.typeParameters().add(parameter);
943                 }
944         }
945
946         private void copyExceptions(MethodDeclaration intermediary, CompilationUnitRewrite imRewrite) {
947                 ITypeBinding[] exceptionTypes= fTargetMethodBinding.getExceptionTypes();
948                 for (int i= 0; i < exceptionTypes.length; i++) {
949                         final String qualifiedName= imRewrite.getImportRewrite().addImport(exceptionTypes[i]);
950                         intermediary.thrownExceptions().add(ASTNodeFactory.newName(imRewrite.getAST(), qualifiedName));
951                 }
952         }
953
954         // ******************* UPDATE CALLS **********************
955
956         private RefactoringStatus updateMethodInvocation(MethodInvocation originalInvocation, IMember enclosing, CompilationUnitRewrite unitRewriter) throws JavaModelException {
957
958                 RefactoringStatus status= new RefactoringStatus();
959
960                 // If the method invocation utilizes type arguments, skip this
961                 // call as the new target method may have additional parameters
962                 if (originalInvocation.typeArguments().size() > 0)
963                         return createWarningAboutCall(enclosing, originalInvocation, RefactoringCoreMessages.IntroduceIndirectionRefactoring_call_warning_type_arguments);
964
965                 MethodInvocation newInvocation= unitRewriter.getAST().newMethodInvocation();
966                 List<Expression> newInvocationArgs= newInvocation.arguments();
967                 List<Expression> originalInvocationArgs= originalInvocation.arguments();
968
969                 // static call => always use a qualifier
970                 String qualifier= unitRewriter.getImportRewrite().addImport(fIntermediaryClassBinding);
971                 newInvocation.setExpression(ASTNodeFactory.newName(unitRewriter.getAST(), qualifier));
972                 newInvocation.setName(unitRewriter.getAST().newSimpleName(getIntermediaryMethodName()));
973
974                 final Expression expression= originalInvocation.getExpression();
975
976                 if (!isStaticTarget()) {
977                         // Add the expression as the first parameter
978                         if (expression == null) {
979                                 // There is no expression for this call. Use a (possibly qualified) "this" expression.
980                                 ThisExpression expr= unitRewriter.getAST().newThisExpression();
981                                 RefactoringStatus qualifierStatus= qualifyThisExpression(expr, originalInvocation, enclosing, unitRewriter);
982                                 status.merge(qualifierStatus);
983                                 if (qualifierStatus.hasEntries())
984                                         // warning means don't include this invocation
985                                         return status;
986                                 newInvocationArgs.add(expr);
987                         } else {
988                                 Expression expressionAsParam= (Expression) unitRewriter.getASTRewrite().createMoveTarget(expression);
989                                 newInvocationArgs.add(expressionAsParam);
990                         }
991                 } else {
992                         if (expression != null) {
993                                 // Check if expression is the class name. If not, there may
994                                 // be side effects (e.g. inside methods) -> don't update
995                                 if (! (expression instanceof Name) || ASTNodes.getTypeBinding((Name) expression) == null)
996                                         return createWarningAboutCall(enclosing, originalInvocation, RefactoringCoreMessages.IntroduceIndirectionRefactoring_call_warning_static_expression_access);
997                         }
998                 }
999
1000                 for (int i= 0; i < originalInvocationArgs.size(); i++) {
1001                         Expression originalInvocationArg= originalInvocationArgs.get(i);
1002                         Expression movedArg= (Expression) unitRewriter.getASTRewrite().createMoveTarget(originalInvocationArg);
1003                         newInvocationArgs.add(movedArg);
1004                 }
1005
1006                 unitRewriter.getASTRewrite().replace(originalInvocation, newInvocation,
1007                                 unitRewriter.createGroupDescription(RefactoringCoreMessages.IntroduceIndirectionRefactoring_group_description_replace_call));
1008
1009                 return status;
1010         }
1011
1012         /**
1013          * Attempts to qualify a "this" expression for a method invocation with an appropriate qualifier.
1014          * The invoked method is analyzed according to the following specs:
1015          *
1016          * 'this' must be qualified iff method is declared in an enclosing type or a supertype of an enclosing type
1017          *
1018          * 1) The method is declared somewhere outside of the cu of the invocation
1019          *      1a) inside a supertype of the current type
1020          *      1b) inside a supertype of an enclosing type
1021          * 2) The method is declared inside of the cu of the invocation
1022          *              2a) inside the type of the invocation
1023          *              2b) outside the type of the invocation
1024          *
1025          * In case of 1a) and 2b), qualify with the enclosing type.
1026          * @param expr a {@link ThisExpression}
1027          * @param originalInvocation the original method invocation
1028          * @param enclosing the enclosing member of the original method invocation
1029          * @param unitRewriter the rewrite
1030          * @return resulting status
1031          *
1032          */
1033         private RefactoringStatus qualifyThisExpression(ThisExpression expr, MethodInvocation originalInvocation, IMember enclosing, CompilationUnitRewrite unitRewriter) {
1034
1035                 RefactoringStatus status= new RefactoringStatus();
1036
1037                 IMethodBinding methodBinding= originalInvocation.resolveMethodBinding();
1038                 MethodDeclaration methodDeclaration= (MethodDeclaration) ASTNodes.findDeclaration(methodBinding, originalInvocation.getRoot());
1039
1040                 ITypeBinding currentTypeBinding= null;
1041                 if (methodDeclaration != null) {
1042                         // Case 1) : Declaring class is inside this cu => use its name if it's declared in an enclosing type
1043                         if (ASTNodes.isParent(originalInvocation, methodDeclaration.getParent()))
1044                                 currentTypeBinding= methodBinding.getDeclaringClass();
1045                         else
1046                                 currentTypeBinding= ASTNodes.getEnclosingType(originalInvocation);
1047                 } else {
1048                         // Case 2) : Declaring class is outside of this cu => find subclass in this cu
1049                         ASTNode currentTypeDeclaration= getEnclosingTypeDeclaration(originalInvocation);
1050                         currentTypeBinding= ASTNodes.getEnclosingType(currentTypeDeclaration);
1051                         while (currentTypeDeclaration != null && (Bindings.findMethodInHierarchy(currentTypeBinding, methodBinding.getName(), methodBinding.getParameterTypes()) == null)) {
1052                                 currentTypeDeclaration= getEnclosingTypeDeclaration(currentTypeDeclaration.getParent());
1053                                 currentTypeBinding= ASTNodes.getEnclosingType(currentTypeDeclaration);
1054                         }
1055                 }
1056
1057                 if (currentTypeBinding == null) {
1058                         status.merge(createWarningAboutCall(enclosing, originalInvocation, RefactoringCoreMessages.IntroduceIndirectionRefactoring_call_warning_declaring_type_not_found));
1059                         return status;
1060                 }
1061
1062                 currentTypeBinding= currentTypeBinding.getTypeDeclaration();
1063
1064                 ITypeBinding typeOfCall= ASTNodes.getEnclosingType(originalInvocation);
1065                 if (!typeOfCall.equals(currentTypeBinding)) {
1066                         if (currentTypeBinding.isAnonymous()) {
1067                                 // Cannot qualify, see bug 115277
1068                                 status.merge(createWarningAboutCall(enclosing, originalInvocation, RefactoringCoreMessages.IntroduceIndirectionRefactoring_call_warning_anonymous_cannot_qualify));
1069                         } else {
1070                                 expr.setQualifier(unitRewriter.getAST().newSimpleName(currentTypeBinding.getName()));
1071                         }
1072                 } else {
1073                         // do not qualify, only use "this.".
1074                 }
1075
1076                 return status;
1077         }
1078
1079         // ********* SMALL HELPERS ********************
1080
1081         /*
1082          * Helper method for finding an IMethod inside a binding hierarchy
1083          */
1084         private IMethodBinding findMethodBindingInHierarchy(ITypeBinding currentTypeBinding, IMethod methodDeclaration) {
1085                 IMethodBinding[] bindings= currentTypeBinding.getDeclaredMethods();
1086                 for (int i= 0; i < bindings.length; i++)
1087                         if (methodDeclaration.equals(bindings[i].getJavaElement()))
1088                                 return bindings[i];
1089
1090                 ITypeBinding superClass= currentTypeBinding.getSuperclass();
1091                 if (superClass != null) {
1092                         IMethodBinding b= findMethodBindingInHierarchy(superClass, methodDeclaration);
1093                         if (b != null)
1094                                 return b;
1095                 }
1096                 ITypeBinding[] interfaces= currentTypeBinding.getInterfaces();
1097                 for (int i= 0; i < interfaces.length; i++) {
1098                         IMethodBinding b= findMethodBindingInHierarchy(interfaces[i], methodDeclaration);
1099                         if (b != null)
1100                                 return b;
1101                 }
1102                 return null;
1103         }
1104
1105         /*
1106          * Helper method for retrieving a *bottom-up* list of super type bindings
1107          */
1108         private ITypeBinding[] getTypeAndAllSuperTypes(ITypeBinding type) {
1109                 List<ITypeBinding> result= new ArrayList<ITypeBinding>();
1110                 collectSuperTypes(type, result);
1111                 return result.toArray(new ITypeBinding[result.size()]);
1112         }
1113
1114         private void collectSuperTypes(ITypeBinding curr, List<ITypeBinding> list) {
1115                 if (list.add(curr.getTypeDeclaration())) {
1116                         ITypeBinding[] interfaces= curr.getInterfaces();
1117                         for (int i= 0; i < interfaces.length; i++) {
1118                                 collectSuperTypes(interfaces[i], list);
1119                         }
1120                         ITypeBinding superClass= curr.getSuperclass();
1121                         if (superClass != null) {
1122                                 collectSuperTypes(superClass, list);
1123                         }
1124                 }
1125         }
1126
1127         private CompilationUnitRewrite getCachedCURewrite(ICompilationUnit unit) {
1128                 CompilationUnitRewrite rewrite= fRewrites.get(unit);
1129                 if (rewrite == null) {
1130                         rewrite= new CompilationUnitRewrite(unit);
1131                         fRewrites.put(unit, rewrite);
1132                 }
1133                 return rewrite;
1134         }
1135
1136         private boolean isRewriteKept(ICompilationUnit compilationUnit) {
1137                 return fIntermediaryClass.getCompilationUnit().equals(compilationUnit);
1138         }
1139
1140         private void createChangeAndDiscardRewrite(ICompilationUnit compilationUnit) throws CoreException {
1141                 CompilationUnitRewrite rewrite= fRewrites.get(compilationUnit);
1142                 if (rewrite != null) {
1143                         fTextChangeManager.manage(compilationUnit, rewrite.createChange(true));
1144                         fRewrites.remove(compilationUnit);
1145                 }
1146         }
1147
1148         private SearchResultGroup[] getReferences(IMethod[] methods, IProgressMonitor pm, RefactoringStatus status) throws CoreException {
1149                 SearchPattern pattern= RefactoringSearchEngine.createOrPattern(methods, IJavaSearchConstants.REFERENCES);
1150                 IJavaSearchScope scope= RefactoringScopeFactory.create(fIntermediaryClass, false);
1151                 return RefactoringSearchEngine.search(pattern, scope, pm, status);
1152         }
1153
1154         private ITypeBinding typeToBinding(IType type, CompilationUnit root) throws JavaModelException {
1155                 ASTNode typeNode= typeToDeclaration(type, root);
1156                 if (type.isAnonymous()) {
1157                         return ((AnonymousClassDeclaration) typeNode).resolveBinding();
1158                 } else {
1159                         return ((AbstractTypeDeclaration) typeNode).resolveBinding();
1160                 }
1161         }
1162
1163         private ASTNode typeToDeclaration(IType type, CompilationUnit root) throws JavaModelException {
1164                 Name intermediateName= (Name) NodeFinder.perform(root, type.getNameRange());
1165                 if (type.isAnonymous()) {
1166                         return ASTNodes.getParent(intermediateName, AnonymousClassDeclaration.class);
1167                 } else {
1168                         return ASTNodes.getParent(intermediateName, AbstractTypeDeclaration.class);
1169                 }
1170         }
1171
1172         private ASTNode getEnclosingTypeDeclaration(ASTNode node) {
1173                 while (node != null) {
1174                         if (node instanceof AbstractTypeDeclaration) {
1175                                 return node;
1176                         } else if (node instanceof AnonymousClassDeclaration) {
1177                                 return node;
1178                         }
1179                         node= node.getParent();
1180                 }
1181                 return null;
1182         }
1183
1184         private ChildListPropertyDescriptor typeToBodyDeclarationProperty(IType type, CompilationUnit root) throws JavaModelException {
1185                 ASTNode typeDeclaration= typeToDeclaration(type, root);
1186                 if (typeDeclaration instanceof AbstractTypeDeclaration)
1187                         return ((AbstractTypeDeclaration) typeDeclaration).getBodyDeclarationsProperty();
1188                 else if (typeDeclaration instanceof AnonymousClassDeclaration)
1189                         return AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY;
1190
1191                 Assert.isTrue(false);
1192                 return null;
1193         }
1194
1195         private RefactoringStatus createWarningAboutCall(IMember enclosing, ASTNode concreteNode, String message) {
1196                 String name= JavaElementLabels.getElementLabel(enclosing, JavaElementLabels.ALL_DEFAULT);
1197                 String container= JavaElementLabels.getElementLabel(enclosing.getDeclaringType(), JavaElementLabels.ALL_FULLY_QUALIFIED);
1198                 return RefactoringStatus.createWarningStatus(Messages.format(message, new String[] { name, container }), JavaStatusContext.create(enclosing.getCompilationUnit(), concreteNode));
1199         }
1200
1201         private ITypeBinding getExpressionType(MethodInvocation invocation) {
1202                 Expression expression= invocation.getExpression();
1203                 ITypeBinding typeBinding= null;
1204                 if (expression == null) {
1205                         typeBinding= invocation.resolveMethodBinding().getDeclaringClass();
1206                 } else {
1207                         typeBinding= expression.resolveTypeBinding();
1208                 }
1209
1210                 Assert.isNotNull(typeBinding, "Type binding of target expression may not be null"); //$NON-NLS-1$
1211                 return typeBinding;
1212         }
1213
1214         private IFile[] getAllFilesToModify() {
1215                 List<ICompilationUnit> cus= new ArrayList<ICompilationUnit>();
1216                 cus.addAll(Arrays.asList(fTextChangeManager.getAllCompilationUnits()));
1217                 return ResourceUtil.getFiles(cus.toArray(new ICompilationUnit[cus.size()]));
1218         }
1219
1220         private boolean isStaticTarget() throws JavaModelException {
1221                 return Flags.isStatic(fTargetMethod.getFlags());
1222         }
1223
1224         private IMember getEnclosingInitialSelectionMember() throws JavaModelException {
1225                 return (IMember) fSelectionCompilationUnit.getElementAt(fSelectionStart);
1226         }
1227
1228         private static ASTNode getSelectedNode(ICompilationUnit unit, CompilationUnit root, int offset, int length) {
1229                 ASTNode node= null;
1230                 try {
1231                         if (unit != null)
1232                                 node= checkNode(NodeFinder.perform(root, offset, length, unit));
1233                         else
1234                                 node= checkNode(NodeFinder.perform(root, offset, length));
1235                 } catch (JavaModelException e) {
1236                         // Do nothing
1237                 }
1238                 if (node != null)
1239                         return node;
1240                 return checkNode(NodeFinder.perform(root, offset, length));
1241         }
1242
1243         private static ASTNode checkNode(ASTNode node) {
1244                 if (node == null)
1245                         return null;
1246                 if (node.getNodeType() == ASTNode.SIMPLE_NAME) {
1247                         node= node.getParent();
1248                 } else if (node.getNodeType() == ASTNode.EXPRESSION_STATEMENT) {
1249                         node= ((ExpressionStatement) node).getExpression();
1250                 }
1251                 switch (node.getNodeType()) {
1252                         case ASTNode.METHOD_INVOCATION:
1253                         case ASTNode.METHOD_DECLARATION:
1254                         case ASTNode.SUPER_METHOD_INVOCATION:
1255                                 return node;
1256                 }
1257                 return null;
1258         }
1259
1260         // ***************** VISIBILITY ********************
1261
1262         private ModifierKeyword getNeededVisibility(IMember whoToAdjust, IMember fromWhereToLook) throws JavaModelException {
1263                 return fAdjustor.getVisibilityThreshold(fromWhereToLook, whoToAdjust, new NullProgressMonitor());
1264         }
1265
1266         private RefactoringStatus adjustVisibility(IMember whoToAdjust, IMember fromWhereToLook, IProgressMonitor monitor) throws CoreException {
1267                 return adjustVisibility(whoToAdjust, getNeededVisibility(whoToAdjust, fromWhereToLook), true, monitor);
1268         }
1269
1270         private RefactoringStatus adjustVisibility(IMember whoToAdjust, ModifierKeyword neededVisibility, IProgressMonitor monitor) throws CoreException {
1271                 return adjustVisibility(whoToAdjust, neededVisibility, false, monitor);
1272         }
1273
1274         private RefactoringStatus adjustVisibility(IMember whoToAdjust, ModifierKeyword neededVisibility, boolean alsoIncreaseEnclosing, IProgressMonitor monitor) throws CoreException {
1275
1276                 Map<IMember, IncomingMemberVisibilityAdjustment> adjustments;
1277                 if (isRewriteKept(whoToAdjust.getCompilationUnit()))
1278                         adjustments= fIntermediaryAdjustments;
1279                 else
1280                         adjustments= new HashMap<IMember, IncomingMemberVisibilityAdjustment>();
1281
1282                 int existingAdjustments= adjustments.size();
1283                 addAdjustment(whoToAdjust, neededVisibility, adjustments);
1284
1285                 if (alsoIncreaseEnclosing)
1286                         while (whoToAdjust.getDeclaringType() != null) {
1287                                 whoToAdjust= whoToAdjust.getDeclaringType();
1288                                 addAdjustment(whoToAdjust, neededVisibility, adjustments);
1289                         }
1290
1291                 boolean hasNewAdjustments= (adjustments.size() - existingAdjustments) > 0;
1292                 if (hasNewAdjustments && ( (whoToAdjust.isReadOnly() || whoToAdjust.isBinary())))
1293                         return RefactoringStatus.createErrorStatus(Messages.format(RefactoringCoreMessages.IntroduceIndirectionRefactoring_cannot_update_binary_target_visibility, new String[] { JavaElementLabels
1294                                         .getElementLabel(whoToAdjust, JavaElementLabels.ALL_DEFAULT) }), JavaStatusContext.create(whoToAdjust));
1295
1296                 RefactoringStatus status= new RefactoringStatus();
1297
1298                 // Don't create a rewrite if it is not necessary
1299                 if (!hasNewAdjustments)
1300                         return status;
1301
1302                 try {
1303                         monitor.beginTask(RefactoringCoreMessages.MemberVisibilityAdjustor_adjusting, 2);
1304                         Map<ICompilationUnit, CompilationUnitRewrite> rewrites;
1305                         if (!isRewriteKept(whoToAdjust.getCompilationUnit())) {
1306                                 CompilationUnitRewrite rewrite= new CompilationUnitRewrite(whoToAdjust.getCompilationUnit());
1307                                 rewrite.setResolveBindings(false);
1308                                 rewrites= new HashMap<ICompilationUnit, CompilationUnitRewrite>();
1309                                 rewrites.put(whoToAdjust.getCompilationUnit(), rewrite);
1310                                 status.merge(rewriteVisibility(adjustments, rewrites, new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)));
1311                                 rewrite.attachChange((CompilationUnitChange) fTextChangeManager.get(whoToAdjust.getCompilationUnit()), true, new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
1312                         }
1313                 } finally {
1314                         monitor.done();
1315                 }
1316                 return status;
1317         }
1318
1319         private RefactoringStatus rewriteVisibility(Map<IMember, IncomingMemberVisibilityAdjustment> adjustments, Map<ICompilationUnit, CompilationUnitRewrite> rewrites, IProgressMonitor monitor) throws JavaModelException {
1320                 RefactoringStatus status= new RefactoringStatus();
1321                 fAdjustor.setRewrites(rewrites);
1322                 fAdjustor.setAdjustments(adjustments);
1323                 fAdjustor.setStatus(status);
1324                 fAdjustor.rewriteVisibility(monitor);
1325                 return status;
1326         }
1327
1328         private void addAdjustment(IMember whoToAdjust, ModifierKeyword neededVisibility, Map<IMember, IncomingMemberVisibilityAdjustment> adjustments) throws JavaModelException {
1329                 ModifierKeyword currentVisibility= ModifierKeyword.fromFlagValue(JdtFlags.getVisibilityCode(whoToAdjust));
1330                 if (MemberVisibilityAdjustor.hasLowerVisibility(currentVisibility, neededVisibility)
1331                                 && MemberVisibilityAdjustor.needsVisibilityAdjustments(whoToAdjust, neededVisibility, adjustments))
1332                         adjustments.put(whoToAdjust, new MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment(whoToAdjust, neededVisibility,
1333                                         RefactoringStatus.createWarningStatus(Messages.format(MemberVisibilityAdjustor.getMessage(whoToAdjust), new String[] {
1334                                                         MemberVisibilityAdjustor.getLabel(whoToAdjust), MemberVisibilityAdjustor.getLabel(neededVisibility) }), JavaStatusContext
1335                                                         .create(whoToAdjust))));
1336         }
1337
1338         private RefactoringStatus initialize(JavaRefactoringArguments arguments) {
1339                 String handle= arguments.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
1340                 if (handle != null) {
1341                         final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(arguments.getProject(), handle, false);
1342                         if (element == null || !element.exists() || element.getElementType() != IJavaElement.METHOD)
1343                                 return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getName(), IJavaRefactorings.INTRODUCE_INDIRECTION);
1344                         else
1345                                 fTargetMethod= (IMethod) element;
1346                 } else
1347                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
1348                 handle= arguments.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + 1);
1349                 if (handle != null) {
1350                         final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(arguments.getProject(), handle, false);
1351                         if (element == null || !element.exists() || element.getElementType() != IJavaElement.TYPE)
1352                                 return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getName(), IJavaRefactorings.INTRODUCE_INDIRECTION);
1353                         else
1354                                 fIntermediaryClass= (IType) element;
1355                 } else
1356                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + 1));
1357                 final String references= arguments.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_REFERENCES);
1358                 if (references != null) {
1359                         fUpdateReferences= Boolean.valueOf(references).booleanValue();
1360                 } else
1361                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_REFERENCES));
1362                 final String name= arguments.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME);
1363                 if (name != null && !"".equals(name)) //$NON-NLS-1$
1364                         return setIntermediaryMethodName(name);
1365                 else
1366                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME));
1367         }
1368 }