KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > code > InlineMethodRefactoring


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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  * Dmitry Stalnov (dstalnov@fusionone.com) - contributed fixes for:
11  * o inline call that is used in a field initializer
12  * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38137)
13  * o Allow 'this' constructor to be inlined
14  * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38093)
15  *******************************************************************************/

16 package org.eclipse.jdt.internal.corext.refactoring.code;
17
18 import java.util.ArrayList JavaDoc;
19 import java.util.HashMap JavaDoc;
20 import java.util.List JavaDoc;
21 import java.util.Map JavaDoc;
22
23 import org.eclipse.text.edits.MultiTextEdit;
24 import org.eclipse.text.edits.TextEdit;
25 import org.eclipse.text.edits.TextEditGroup;
26
27 import org.eclipse.core.runtime.Assert;
28 import org.eclipse.core.runtime.CoreException;
29 import org.eclipse.core.runtime.IProgressMonitor;
30 import org.eclipse.core.runtime.OperationCanceledException;
31 import org.eclipse.core.runtime.SubProgressMonitor;
32
33 import org.eclipse.core.resources.IFile;
34 import org.eclipse.core.resources.IResource;
35
36 import org.eclipse.ltk.core.refactoring.Change;
37 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
38 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
39 import org.eclipse.ltk.core.refactoring.TextChange;
40 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
41 import org.eclipse.ltk.core.refactoring.participants.ResourceChangeChecker;
42
43 import org.eclipse.jdt.core.Flags;
44 import org.eclipse.jdt.core.IClassFile;
45 import org.eclipse.jdt.core.ICompilationUnit;
46 import org.eclipse.jdt.core.IJavaElement;
47 import org.eclipse.jdt.core.IJavaProject;
48 import org.eclipse.jdt.core.IMethod;
49 import org.eclipse.jdt.core.IType;
50 import org.eclipse.jdt.core.ITypeHierarchy;
51 import org.eclipse.jdt.core.ITypeRoot;
52 import org.eclipse.jdt.core.JavaModelException;
53 import org.eclipse.jdt.core.dom.AST;
54 import org.eclipse.jdt.core.dom.ASTNode;
55 import org.eclipse.jdt.core.dom.BodyDeclaration;
56 import org.eclipse.jdt.core.dom.CompilationUnit;
57 import org.eclipse.jdt.core.dom.ConstructorInvocation;
58 import org.eclipse.jdt.core.dom.ExpressionStatement;
59 import org.eclipse.jdt.core.dom.IMethodBinding;
60 import org.eclipse.jdt.core.dom.ITypeBinding;
61 import org.eclipse.jdt.core.dom.MethodDeclaration;
62 import org.eclipse.jdt.core.dom.MethodInvocation;
63 import org.eclipse.jdt.core.dom.Modifier;
64 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
65 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
66 import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
67 import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
68
69 import org.eclipse.jdt.internal.corext.dom.NodeFinder;
70 import org.eclipse.jdt.internal.corext.refactoring.Checks;
71 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor;
72 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
73 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
74 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
75 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
76 import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange;
77 import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
78 import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility;
79 import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil;
80 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
81 import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
82 import org.eclipse.jdt.internal.corext.util.Messages;
83
84 import org.eclipse.jdt.ui.JavaElementLabels;
85
86 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider;
87
88 /*
89  * Open items:
90  * - generate import statements for newly generated local variable declarations.
91  * - forbid cases like foo(foo(10)) when inlining foo().
92  * - case ref.foo(); and we want to inline foo. Inline a method in a different context;
93  * - optimize code when the method to be inlined returns an argument and that one is
94  * assigned to a parameter again. No need for a separate local (important to be able
95  * to reverse extract method correctly).
96  */

97 public class InlineMethodRefactoring extends ScriptableRefactoring {
98
99     private static final String JavaDoc ATTRIBUTE_MODE= "mode"; //$NON-NLS-1$
100
private static final String JavaDoc ATTRIBUTE_DELETE= "delete"; //$NON-NLS-1$
101

102     public static class Mode {
103         private Mode() {
104         }
105         public static final Mode INLINE_ALL= new Mode();
106         public static final Mode INLINE_SINGLE= new Mode();
107     }
108
109     private ITypeRoot fInitialTypeRoot;
110     private ASTNode fInitialNode;
111     private TextChangeManager fChangeManager;
112     private SourceProvider fSourceProvider;
113     private TargetProvider fTargetProvider;
114     /**
115      * must never be true if fInitialUnit instanceof IClassFile
116      */

117     private boolean fDeleteSource;
118     private Mode fCurrentMode;
119     private Mode fInitialMode;
120     private int fSelectionStart;
121     private int fSelectionLength;
122
123     private InlineMethodRefactoring(ITypeRoot typeRoot, ASTNode node, int offset, int length) {
124         Assert.isNotNull(typeRoot);
125         Assert.isTrue(JavaElementUtil.isSourceAvailable(typeRoot));
126         Assert.isNotNull(node);
127         fInitialTypeRoot= typeRoot;
128         fInitialNode= node;
129         fSelectionStart= offset;
130         fSelectionLength= length;
131     }
132
133     private InlineMethodRefactoring(ICompilationUnit unit, MethodInvocation node, int offset, int length) {
134         this(unit, (ASTNode)node, offset, length);
135         fTargetProvider= TargetProvider.create(unit, node);
136         fInitialMode= fCurrentMode= Mode.INLINE_SINGLE;
137         fDeleteSource= false;
138     }
139
140     private InlineMethodRefactoring(ICompilationUnit unit, SuperMethodInvocation node, int offset, int length) {
141         this(unit, (ASTNode)node, offset, length);
142         fTargetProvider= TargetProvider.create(unit, node);
143         fInitialMode= fCurrentMode= Mode.INLINE_SINGLE;
144         fDeleteSource= false;
145     }
146
147     private InlineMethodRefactoring(ICompilationUnit unit, ConstructorInvocation node, int offset, int length) {
148         this(unit, (ASTNode)node, offset, length);
149         fTargetProvider= TargetProvider.create(unit, node);
150         fInitialMode= fCurrentMode= Mode.INLINE_SINGLE;
151         fDeleteSource= false;
152     }
153
154     private InlineMethodRefactoring(ITypeRoot typeRoot, MethodDeclaration node, int offset, int length) {
155         this(typeRoot, (ASTNode)node, offset, length);
156         fSourceProvider= new SourceProvider(typeRoot, node);
157         fTargetProvider= TargetProvider.create(node);
158         fInitialMode= fCurrentMode= Mode.INLINE_ALL;
159         fDeleteSource= canEnableDeleteSource();
160     }
161     
162     /**
163      * Creates a new inline method refactoring
164      * @param unit the compilation unit or class file
165      * @param node the compilation unit node
166      * @param selectionStart
167      * @param selectionLength
168      */

169     public static InlineMethodRefactoring create(ITypeRoot unit, CompilationUnit node, int selectionStart, int selectionLength) {
170         ASTNode target= getTargetNode(unit, node, selectionStart, selectionLength);
171         if (target == null)
172             return null;
173         if (target.getNodeType() == ASTNode.METHOD_DECLARATION) {
174             
175             return new InlineMethodRefactoring(unit, (MethodDeclaration)target, selectionStart, selectionLength);
176         } else {
177             ICompilationUnit cu= (ICompilationUnit) unit;
178             if (target.getNodeType() == ASTNode.METHOD_INVOCATION) {
179                 return new InlineMethodRefactoring(cu, (MethodInvocation)target, selectionStart, selectionLength);
180             } else if (target.getNodeType() == ASTNode.SUPER_METHOD_INVOCATION) {
181                 return new InlineMethodRefactoring(cu, (SuperMethodInvocation)target, selectionStart, selectionLength);
182             } else if (target.getNodeType() == ASTNode.CONSTRUCTOR_INVOCATION) {
183                 return new InlineMethodRefactoring(cu, (ConstructorInvocation)target, selectionStart, selectionLength);
184             }
185         }
186         return null;
187     }
188     
189     public String JavaDoc getName() {
190         return RefactoringCoreMessages.InlineMethodRefactoring_name;
191     }
192     
193     public boolean canEnableDeleteSource() {
194         return ! (fSourceProvider.getTypeRoot() instanceof IClassFile);
195     }
196     
197     public boolean getDeleteSource() {
198         return fDeleteSource;
199     }
200
201     public void setDeleteSource(boolean remove) {
202         if (remove)
203             Assert.isTrue(canEnableDeleteSource());
204         fDeleteSource= remove;
205     }
206     
207     public Mode getInitialMode() {
208         return fInitialMode;
209     }
210     
211     public RefactoringStatus setCurrentMode(Mode mode) throws JavaModelException {
212         if (fCurrentMode == mode)
213             return new RefactoringStatus();
214         Assert.isTrue(getInitialMode() == Mode.INLINE_SINGLE);
215         fCurrentMode= mode;
216         if (mode == Mode.INLINE_SINGLE) {
217             if (fInitialNode instanceof MethodInvocation)
218                 fTargetProvider= TargetProvider.create((ICompilationUnit) fInitialTypeRoot, (MethodInvocation)fInitialNode);
219             else if (fInitialNode instanceof SuperMethodInvocation)
220                 fTargetProvider= TargetProvider.create((ICompilationUnit) fInitialTypeRoot, (SuperMethodInvocation)fInitialNode);
221             else if (fInitialNode instanceof ConstructorInvocation)
222                 fTargetProvider= TargetProvider.create((ICompilationUnit) fInitialTypeRoot, (ConstructorInvocation)fInitialNode);
223             else
224                 throw new IllegalStateException JavaDoc(String.valueOf(fInitialNode));
225         } else {
226             fTargetProvider= TargetProvider.create(fSourceProvider.getDeclaration());
227         }
228         return fTargetProvider.checkActivation();
229     }
230     
231     public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
232         RefactoringStatus result= new RefactoringStatus();
233         if (fSourceProvider == null && Invocations.isInvocation(fInitialNode)) {
234             fSourceProvider= resolveSourceProvider(result, fInitialTypeRoot, fInitialNode);
235             if (result.hasFatalError())
236                 return result;
237         }
238         fTargetProvider.setSourceProvider(fSourceProvider);
239         result.merge(fSourceProvider.checkActivation());
240         result.merge(fTargetProvider.checkActivation());
241         return result;
242     }
243     
244     public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
245         pm.beginTask("", 20); //$NON-NLS-1$
246
fChangeManager= new TextChangeManager();
247         RefactoringStatus result= new RefactoringStatus();
248         fSourceProvider.initialize();
249         fTargetProvider.initialize();
250         pm.setTaskName(RefactoringCoreMessages.InlineMethodRefactoring_searching);
251         RefactoringStatus searchStatus= new RefactoringStatus();
252         ICompilationUnit[] units= fTargetProvider.getAffectedCompilationUnits(searchStatus, new SubProgressMonitor(pm, 1));
253         if (searchStatus.hasFatalError()) {
254             result.merge(searchStatus);
255             return result;
256         }
257         IFile[] filesToBeModified= getFilesToBeModified(units);
258         result.merge(Checks.validateModifiesFiles(filesToBeModified, getValidationContext()));
259         if (result.hasFatalError())
260             return result;
261         result.merge(ResourceChangeChecker.checkFilesToBeChanged(filesToBeModified, new SubProgressMonitor(pm, 1)));
262         checkOverridden(result, new SubProgressMonitor(pm, 4));
263         IProgressMonitor sub= new SubProgressMonitor(pm, 15);
264         sub.beginTask("", units.length * 3); //$NON-NLS-1$
265
for (int c= 0; c < units.length; c++) {
266             ICompilationUnit unit= units[c];
267             sub.subTask(Messages.format(RefactoringCoreMessages.InlineMethodRefactoring_processing, unit.getElementName()));
268             CallInliner inliner= null;
269             try {
270                 boolean added= false;
271                 MultiTextEdit root= new MultiTextEdit();
272                 CompilationUnitChange change= (CompilationUnitChange)fChangeManager.get(unit);
273                 change.setEdit(root);
274                 BodyDeclaration[] bodies= fTargetProvider.getAffectedBodyDeclarations(unit, new SubProgressMonitor(pm, 1));
275                 if (bodies.length == 0)
276                     continue;
277                 inliner= new CallInliner(unit, (CompilationUnit) bodies[0].getRoot(), fSourceProvider);
278                 for (int b= 0; b < bodies.length; b++) {
279                     BodyDeclaration body= bodies[b];
280                     inliner.initialize(body);
281                     RefactoringStatus nestedInvocations= new RefactoringStatus();
282                     ASTNode[] invocations= removeNestedCalls(nestedInvocations, unit,
283                         fTargetProvider.getInvocations(body, new SubProgressMonitor(sub, 2)));
284                     for (int i= 0; i < invocations.length; i++) {
285                         ASTNode invocation= invocations[i];
286                         result.merge(inliner.initialize(invocation, fTargetProvider.getStatusSeverity()));
287                         if (result.hasFatalError())
288                             break;
289                         if (result.getSeverity() < fTargetProvider.getStatusSeverity()) {
290                             added= true;
291                             TextEditGroup group= new TextEditGroup(RefactoringCoreMessages.InlineMethodRefactoring_edit_inline);
292                             change.addTextEditGroup(group);
293                             result.merge(inliner.perform(group));
294                         } else {
295                             fDeleteSource= false;
296                         }
297                     }
298                     // do this after we have inlined the method calls. We still want
299
// to generate the modifications.
300
if (!nestedInvocations.isOK()) {
301                         result.merge(nestedInvocations);
302                         fDeleteSource= false;
303                     }
304                 }
305                 if (!added) {
306                     fChangeManager.remove(unit);
307                 } else {
308                     root.addChild(inliner.getModifications());
309                     ImportRewrite rewrite= inliner.getImportEdit();
310                     if (rewrite.hasRecordedChanges()) {
311                         TextEdit edit= rewrite.rewriteImports(null);
312                         if (edit instanceof MultiTextEdit ? ((MultiTextEdit)edit).getChildrenSize() > 0 : true) {
313                             root.addChild(edit);
314                             change.addTextEditGroup(
315                                 new TextEditGroup(RefactoringCoreMessages.InlineMethodRefactoring_edit_import, new TextEdit[] {edit}));
316                         }
317                     }
318                 }
319             } finally {
320                 if (inliner != null)
321                     inliner.dispose();
322             }
323             sub.worked(1);
324             if (sub.isCanceled())
325                 throw new OperationCanceledException();
326         }
327         result.merge(searchStatus);
328         sub.done();
329         pm.done();
330         return result;
331     }
332
333     public Change createChange(IProgressMonitor pm) throws CoreException {
334         if (fDeleteSource && fCurrentMode == Mode.INLINE_ALL) {
335             TextChange change= fChangeManager.get((ICompilationUnit) fSourceProvider.getTypeRoot());
336             TextEdit delete= fSourceProvider.getDeleteEdit();
337             TextEditGroup description= new TextEditGroup(
338                 RefactoringCoreMessages.InlineMethodRefactoring_edit_delete, new TextEdit[] { delete });
339             TextEdit root= change.getEdit();
340             if (root != null) {
341                 // TODO instead of finding the right insert position the call inliner should
342
// reuse the AST & rewriter of the source provide and we should rewrite the
343
// whole AST at the end. However, since recursive calls aren't allowed there
344
// shouldn't be a text edit overlap.
345
// root.addChild(delete);
346
TextChangeCompatibility.insert(root, delete);
347             } else {
348                 change.setEdit(delete);
349             }
350             change.addTextEditGroup(description);
351         }
352         final Map JavaDoc arguments= new HashMap JavaDoc();
353         String JavaDoc project= null;
354         IJavaProject javaProject= fInitialTypeRoot.getJavaProject();
355         if (javaProject != null)
356             project= javaProject.getElementName();
357         int flags= RefactoringDescriptor.STRUCTURAL_CHANGE | JavaRefactoringDescriptor.JAR_REFACTORING | JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
358         final IMethodBinding binding= fSourceProvider.getDeclaration().resolveBinding();
359         final ITypeBinding declaring= binding.getDeclaringClass();
360         if (!Modifier.isPrivate(binding.getModifiers()))
361             flags|= RefactoringDescriptor.MULTI_CHANGE;
362         final String JavaDoc description= Messages.format(RefactoringCoreMessages.InlineMethodRefactoring_descriptor_description_short, binding.getName());
363         final String JavaDoc header= Messages.format(RefactoringCoreMessages.InlineMethodRefactoring_descriptor_description, new String JavaDoc[] { BindingLabelProvider.getBindingLabel(binding, JavaElementLabels.ALL_FULLY_QUALIFIED), BindingLabelProvider.getBindingLabel(declaring, JavaElementLabels.ALL_FULLY_QUALIFIED)});
364         final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
365         comment.addSetting(Messages.format(RefactoringCoreMessages.InlineMethodRefactoring_original_pattern, BindingLabelProvider.getBindingLabel(binding, JavaElementLabels.ALL_FULLY_QUALIFIED)));
366         if (fDeleteSource)
367             comment.addSetting(RefactoringCoreMessages.InlineMethodRefactoring_remove_method);
368         if (fCurrentMode == Mode.INLINE_ALL)
369             comment.addSetting(RefactoringCoreMessages.InlineMethodRefactoring_replace_references);
370         final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaRefactorings.INLINE_METHOD, project, description, comment.asString(), arguments, flags);
371         arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fInitialTypeRoot));
372         arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION, new Integer JavaDoc(fSelectionStart).toString() + " " + new Integer JavaDoc(fSelectionLength).toString()); //$NON-NLS-1$
373
arguments.put(ATTRIBUTE_DELETE, Boolean.valueOf(fDeleteSource).toString());
374         arguments.put(ATTRIBUTE_MODE, new Integer JavaDoc(fCurrentMode == Mode.INLINE_ALL ? 1 : 0).toString());
375         return new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.InlineMethodRefactoring_edit_inlineCall, fChangeManager.getAllChanges());
376     }
377     
378     private static SourceProvider resolveSourceProvider(RefactoringStatus status, ITypeRoot typeRoot, ASTNode invocation) throws JavaModelException {
379         CompilationUnit root= (CompilationUnit)invocation.getRoot();
380         IMethodBinding methodBinding= Invocations.resolveBinding(invocation);
381         if (methodBinding == null) {
382             status.addFatalError(RefactoringCoreMessages.InlineMethodRefactoring_error_noMethodDeclaration);
383             return null;
384         }
385         MethodDeclaration declaration= (MethodDeclaration)root.findDeclaringNode(methodBinding);
386         if (declaration != null) {
387             return new SourceProvider(typeRoot, declaration);
388         }
389         IMethod method= (IMethod)methodBinding.getJavaElement();
390         if (method != null) {
391             CompilationUnit methodDeclarationAstRoot;
392             ICompilationUnit methodCu= method.getCompilationUnit();
393             if (methodCu != null) {
394                 methodDeclarationAstRoot= new RefactoringASTParser(AST.JLS3).parse(methodCu, true);
395             } else {
396                 IClassFile classFile= method.getClassFile();
397                 if (! JavaElementUtil.isSourceAvailable(classFile)) {
398                     String JavaDoc methodLabel= JavaElementLabels.getTextLabel(method, JavaElementLabels.M_FULLY_QUALIFIED | JavaElementLabels.M_PARAMETER_TYPES);
399                     status.addFatalError(Messages.format(RefactoringCoreMessages.InlineMethodRefactoring_error_classFile, methodLabel));
400                     return null;
401                 }
402                 methodDeclarationAstRoot= new RefactoringASTParser(AST.JLS3).parse(classFile, true);
403             }
404             ASTNode node= methodDeclarationAstRoot.findDeclaringNode(methodBinding.getMethodDeclaration().getKey());
405             if (node instanceof MethodDeclaration) {
406                 return new SourceProvider(methodDeclarationAstRoot.getTypeRoot(), (MethodDeclaration) node);
407             }
408         }
409         status.addFatalError(RefactoringCoreMessages.InlineMethodRefactoring_error_noMethodDeclaration);
410         return null;
411     }
412     
413     private static ASTNode getTargetNode(ITypeRoot typeRoot, CompilationUnit root, int offset, int length) {
414         ASTNode node= null;
415         try {
416             node= checkNode(NodeFinder.perform(root, offset, length, typeRoot), typeRoot);
417         } catch(JavaModelException e) {
418             // Do nothing
419
}
420         if (node != null)
421             return node;
422         return checkNode(NodeFinder.perform(root, offset, length), typeRoot);
423     }
424
425     private static ASTNode checkNode(ASTNode node, IJavaElement unit) {
426         if (node == null)
427             return null;
428         if (node.getNodeType() == ASTNode.SIMPLE_NAME) {
429             node= node.getParent();
430         } else if (node.getNodeType() == ASTNode.EXPRESSION_STATEMENT) {
431             node= ((ExpressionStatement)node).getExpression();
432         }
433         switch(node.getNodeType()) {
434             case ASTNode.METHOD_DECLARATION:
435                     return node;
436             case ASTNode.METHOD_INVOCATION:
437             case ASTNode.SUPER_METHOD_INVOCATION:
438             case ASTNode.CONSTRUCTOR_INVOCATION:
439                 return unit instanceof ICompilationUnit ? node : null; // don't start on invocations in binary
440
}
441         return null;
442     }
443     
444     private IFile[] getFilesToBeModified(ICompilationUnit[] units) {
445         List JavaDoc result= new ArrayList JavaDoc(units.length + 1);
446         IFile file;
447         for (int i= 0; i < units.length; i++) {
448             file= getFile(units[i]);
449             if (file != null)
450                 result.add(file);
451         }
452         if (fDeleteSource) {
453             file= getFile((ICompilationUnit) fSourceProvider.getTypeRoot());
454             if (file != null && !result.contains(file))
455                 result.add(file);
456         }
457         return (IFile[])result.toArray(new IFile[result.size()]);
458     }
459     
460     private IFile getFile(ICompilationUnit unit) {
461         unit= unit.getPrimary();
462         IResource resource= unit.getResource();
463         if (resource != null && resource.getType() == IResource.FILE)
464             return (IFile)resource;
465         return null;
466     }
467     
468     private void checkOverridden(RefactoringStatus status, IProgressMonitor pm) throws JavaModelException {
469         pm.beginTask("", 9); //$NON-NLS-1$
470
pm.setTaskName(RefactoringCoreMessages.InlineMethodRefactoring_checking_overridden);
471         MethodDeclaration decl= fSourceProvider.getDeclaration();
472         IMethod method= (IMethod) decl.resolveBinding().getJavaElement();
473         if (method == null || Flags.isPrivate(method.getFlags())) {
474             pm.worked(8);
475             return;
476         }
477         IType type= method.getDeclaringType();
478         ITypeHierarchy hierarchy= type.newTypeHierarchy(new SubProgressMonitor(pm, 6));
479         checkSubTypes(status, method, hierarchy.getAllSubtypes(type), new SubProgressMonitor(pm, 1));
480         checkSuperClasses(status, method, hierarchy.getAllSuperclasses(type), new SubProgressMonitor(pm, 1));
481         checkSuperInterfaces(status, method, hierarchy.getAllSuperInterfaces(type), new SubProgressMonitor(pm, 1));
482         pm.setTaskName(""); //$NON-NLS-1$
483
}
484
485     private void checkSubTypes(RefactoringStatus result, IMethod method, IType[] types, IProgressMonitor pm) {
486         checkTypes(
487             result, method, types,
488             RefactoringCoreMessages.InlineMethodRefactoring_checking_overridden_error,
489             pm);
490     }
491     
492     private void checkSuperClasses(RefactoringStatus result, IMethod method, IType[] types, IProgressMonitor pm) {
493         checkTypes(
494             result, method, types,
495             RefactoringCoreMessages.InlineMethodRefactoring_checking_overrides_error,
496             pm);
497     }
498
499     private void checkSuperInterfaces(RefactoringStatus result, IMethod method, IType[] types, IProgressMonitor pm) {
500         checkTypes(
501             result, method, types,
502             RefactoringCoreMessages.InlineMethodRefactoring_checking_implements_error,
503             pm);
504     }
505     private void checkTypes(RefactoringStatus result, IMethod method, IType[] types, String JavaDoc key, IProgressMonitor pm) {
506         pm.beginTask("", types.length); //$NON-NLS-1$
507
for (int i= 0; i < types.length; i++) {
508             pm.worked(1);
509             IMethod[] overridden= types[i].findMethods(method);
510             if (overridden != null && overridden.length > 0) {
511                 result.addError(
512                     Messages.format(key, types[i].getElementName()),
513                     JavaStatusContext.create(overridden[0]));
514             }
515         }
516     }
517     
518     private ASTNode[] removeNestedCalls(RefactoringStatus status, ICompilationUnit unit, ASTNode[] invocations) {
519         if (invocations.length <= 1)
520             return invocations;
521         ASTNode[] parents= new ASTNode[invocations.length];
522         for (int i= 0; i < invocations.length; i++) {
523             parents[i]= invocations[i].getParent();
524         }
525         for (int i= 0; i < invocations.length; i++) {
526             removeNestedCalls(status, unit, parents, invocations, i);
527         }
528         List JavaDoc result= new ArrayList JavaDoc();
529         for (int i= 0; i < invocations.length; i++) {
530             if (invocations[i] != null)
531                 result.add(invocations[i]);
532         }
533         return (ASTNode[])result.toArray(new ASTNode[result.size()]);
534     }
535     
536     private void removeNestedCalls(RefactoringStatus status, ICompilationUnit unit, ASTNode[] parents, ASTNode[] invocations, int index) {
537         ASTNode invocation= invocations[index];
538         for (int i= 0; i < parents.length; i++) {
539             ASTNode parent= parents[i];
540             while (parent != null) {
541                 if (parent == invocation) {
542                     status.addError(RefactoringCoreMessages.InlineMethodRefactoring_nestedInvocation,
543                         JavaStatusContext.create(unit, parent));
544                     invocations[index]= null;
545                 }
546                 parent= parent.getParent();
547             }
548         }
549     }
550
551     public RefactoringStatus initialize(final RefactoringArguments arguments) {
552         if (arguments instanceof JavaRefactoringArguments) {
553             final JavaRefactoringArguments generic= (JavaRefactoringArguments) arguments;
554             final String JavaDoc delete= generic.getAttribute(ATTRIBUTE_DELETE);
555             if (delete != null) {
556                 fDeleteSource= Boolean.valueOf(delete).booleanValue();
557             } else
558                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_DELETE));
559             final String JavaDoc value= generic.getAttribute(ATTRIBUTE_MODE);
560             if (value != null && !"".equals(value)) {//$NON-NLS-1$
561
int mode= 0;
562                 try {
563                     mode= Integer.parseInt(value);
564                 } catch (NumberFormatException JavaDoc exception) {
565                     return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_MODE));
566                 }
567                 try {
568                     setCurrentMode(mode == 1 ? Mode.INLINE_ALL : Mode.INLINE_SINGLE);
569                 } catch (JavaModelException exception) {
570                     return RefactoringStatus.createFatalErrorStatus(exception.getLocalizedMessage());
571                 }
572             }
573         } else
574             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
575         return new RefactoringStatus();
576     }
577 }
578
Popular Tags