]> git.uio.no Git - ifi-stolz-refaktor.git/blob - software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/changers/ExtractAndMoveMethodExecutor.java
Adding Executor interface and ExecutorManager.
[ifi-stolz-refaktor.git] / software / no.uio.ifi.refaktor / src / no / uio / ifi / refaktor / changers / ExtractAndMoveMethodExecutor.java
1 package no.uio.ifi.refaktor.changers;
2
3 import java.lang.reflect.Modifier;
4 import java.util.Random;
5
6 import no.uio.ifi.refaktor.changers.RefaktorChangerException.Reason;
7 import no.uio.ifi.refaktor.extractors.ExtractAndMoveMethodPrefixesExtractor;
8 import no.uio.ifi.refaktor.utils.CompilationUnitTextSelection;
9 import no.uio.ifi.refaktor.utils.RefaktorDebug;
10 import no.uio.ifi.refaktor.utils.RefaktorHandleUtils;
11
12 import org.eclipse.core.resources.IProject;
13 import org.eclipse.core.runtime.Assert;
14 import org.eclipse.core.runtime.CoreException;
15 import org.eclipse.core.runtime.IProgressMonitor;
16 import org.eclipse.jdt.core.IMethod;
17 import org.eclipse.jdt.core.JavaModelException;
18 import org.eclipse.jdt.core.dom.IVariableBinding;
19 import org.eclipse.jdt.internal.corext.refactoring.code.ExtractMethodRefactoring;
20 import org.eclipse.jdt.internal.corext.refactoring.structure.MoveInstanceMethodProcessor;
21 import org.eclipse.ltk.core.refactoring.participants.MoveRefactoring;
22
23 /**
24  * This class composes the refactorings known as
25  * Extract Method and Move Method.
26  * 
27  * Before extracting, it finds the possible targets for the move 
28  * with the help of a PropertyExtractor (see {@link ExtractAndMoveMethodPrefixesExtractor}), 
29  * that extracts, from the AST, as set of safe prefixes that forms the base
30  * for calculating the target for the Move Method.
31  * 
32  * The changer then tries to analyze which of the safe prefixes 
33  * that is the best candidate. The best candidate is used to find the
34  * destination of the composed refactoring.
35  * 
36  * When the destination is calculated, the changer
37  * first extracts a new method and then moves it to the
38  * chosen destination.
39  */
40 @SuppressWarnings("restriction")
41 public class ExtractAndMoveMethodExecutor implements Executor {
42         private CompilationUnitTextSelection compilationUnitTextSelection;
43         private ExtractAndMoveMethodPrefixesExtractor extractor;
44         private String newMethodName;
45         private String newMethodSignature;
46         private MoveMethodRefactoringTargetFinder targetFinder;
47         private RefactoringPerformer refactoringExecutor;
48
49         public ExtractAndMoveMethodExecutor(CompilationUnitTextSelection compilationUnitTextSelection) {
50                 this(compilationUnitTextSelection, generateName());
51         }
52
53         public ExtractAndMoveMethodExecutor(CompilationUnitTextSelection compilationUnitTextSelection, String newMethodName) {
54                 this.compilationUnitTextSelection = compilationUnitTextSelection;
55                 setNewMethodName(newMethodName);
56                 extractor = new ExtractAndMoveMethodPrefixesExtractor(compilationUnitTextSelection);
57         }
58
59         public void setNewMethodName(String newMethodName) {
60                 this.newMethodName = newMethodName;
61         }
62
63         public static String generateName() {
64                 return "generated_" + Math.abs(new Random().nextLong());
65         }
66
67         @Override
68         public void checkPreconditions() throws RefaktorChangerException {
69                 checkIfSelectionIsValid();
70                 extractProperty();
71                 checkIfUsefulTargetFound();
72         }
73
74         private void checkIfSelectionIsValid() {
75                 if (!extractor.selectionIsValid())
76                         throw new RefaktorChangerException(Reason.SELECTION_INVALID);
77         }
78
79         private void extractProperty() {
80                 extractor.extractProperty();
81         }
82
83         private void checkIfUsefulTargetFound() {
84                 if (!extractor.hasUsefulResults())
85                         throw new RefaktorChangerException(Reason.NO_TARGET_FOUND);
86         }
87
88         @Override
89         public void executeChange(IProgressMonitor monitor, UndoResources undoResources) throws CoreException {
90                 createRefactoringExecutor(monitor, undoResources);
91                 checkConditionsAndPerformExtractMethodRefactoring();
92                 checkConditionsAndPerformMoveMethodRefactoring();
93         }
94
95         private void checkConditionsAndPerformExtractMethodRefactoring() throws CoreException {
96                 ExtractMethodRefactoring extractMethodRefactoring = createExtractMethodRefactoring();
97                 refactoringExecutor.performRefactoring(extractMethodRefactoring);
98                 assertThatNewMethodNameWasUsedWhenPerformingRefactoring(extractMethodRefactoring);
99                 setNewMethodSignature(extractMethodRefactoring);
100                 createMoveMethodRefactoringTargetFinder(extractMethodRefactoring);
101         }
102
103         private void checkConditionsAndPerformMoveMethodRefactoring() throws JavaModelException, CoreException {
104                 // Here, the method we'd like to move must already exist since we need to look up an IMethod handle:
105                 refactoringExecutor.performRefactoring(createMoveRefactoring());
106         }
107
108         private ExtractMethodRefactoring createExtractMethodRefactoring() throws CoreException {
109                 ExtractMethodRefactoring extractMethodRefactoring = new ExtractMethodRefactoring(
110                                 compilationUnitTextSelection.getCompilationUnit(), 
111                                 compilationUnitTextSelection.getOffset(), 
112                                 compilationUnitTextSelection.getLength()
113                                 );
114
115                 extractMethodRefactoring.setMethodName(newMethodName);
116                 extractMethodRefactoring.setValidationContext(null);
117                 extractMethodRefactoring.setReplaceDuplicates(true);
118                 extractMethodRefactoring.setVisibility(Modifier.PUBLIC);
119                 extractMethodRefactoring.setLinkedProposalModel(null);
120                 return extractMethodRefactoring;
121         }
122
123         private MoveRefactoring createMoveRefactoring()
124                         throws JavaModelException {
125                 IMethod method = getHandleOfExtractedMethod();
126                 MoveInstanceMethodProcessor refactoringProcessor = new MoveInstanceMethodProcessor(method, null);
127                 if (refactoringProcessor.canEnableDelegateUpdating())
128                         refactoringProcessor.setDelegateUpdating(false);
129                 refactoringProcessor.setDeprecateDelegates(true);
130                 refactoringProcessor.setUseGetters(true);
131                 refactoringProcessor.setUseSetters(true);
132                 refactoringProcessor.setInlineDelegator(true);
133                 refactoringProcessor.setRemoveDelegator(true);
134
135                 String typeName = compilationUnitTextSelection.getNameOfSurroundingType();
136                 // Sanity check, removes a dependency on 'method' [vs]
137                 assert method.getDeclaringType().getElementName().equals(typeName) : method.getDeclaringType().getElementName() +" / " +typeName;
138                 // Set the name of the parameter that takes an object of 
139                 // the type of the class the method is moved from.
140                 refactoringProcessor.setTargetName(typeName.toLowerCase());
141
142                 IVariableBinding target = targetFinder.findTarget();
143                 refactoringProcessor.setTarget(target);
144
145                 RefaktorDebug.println("MoveMethod:\nTrying to move method " + method.getElementName() + " to " + target.getName());
146
147                 return new MoveRefactoring(refactoringProcessor);
148         }
149
150         private IVariableBinding getOriginalTargetFromPrefix() {
151                 return extractor.getMostFrequentPrefix().getVariableBindingOfFirstExpression();
152         }
153
154         private void assertThatNewMethodNameWasUsedWhenPerformingRefactoring(ExtractMethodRefactoring extractMethodRefactoring) {
155                 assert extractMethodRefactoring.getMethodName().equals(newMethodName);
156         }
157
158         private void setNewMethodSignature(ExtractMethodRefactoring extractMethodRefactoring) {
159                 newMethodSignature = extractMethodRefactoring.getSignature();
160         }
161
162         private void createMoveMethodRefactoringTargetFinder(ExtractMethodRefactoring extractMethodRefactoring)
163                         throws JavaModelException {
164                 targetFinder = new MoveMethodRefactoringTargetFinder(getHandleOfExtractedMethod(), getOriginalTargetFromPrefix(), extractMethodRefactoring.getParameterInfos());
165         }
166
167         private IMethod getHandleOfExtractedMethod() throws JavaModelException {
168                 String packageName = compilationUnitTextSelection.getPackageName();
169                 String typeName = compilationUnitTextSelection.getNameOfSurroundingType();
170                 IProject project = compilationUnitTextSelection.getProject();
171                 IMethod method = RefaktorHandleUtils.findMethodHandle(project, packageName, typeName, newMethodSignature);
172                 Assert.isNotNull(method, "Can't find "+packageName+"."+typeName+"#"+newMethodSignature);
173                 return method;
174         }
175
176         private void createRefactoringExecutor(IProgressMonitor monitor, UndoResources undoResources) {
177                 refactoringExecutor = new SimpleRefactoringPerformer(monitor, undoResources);
178         }
179
180 }