KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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.util.ArrayList JavaDoc;
14 import java.util.HashSet JavaDoc;
15 import java.util.List JavaDoc;
16 import java.util.Set JavaDoc;
17
18 import org.eclipse.core.runtime.CoreException;
19
20 import org.eclipse.jface.text.IRegion;
21
22 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
23
24 import org.eclipse.jdt.core.ICompilationUnit;
25 import org.eclipse.jdt.core.JavaModelException;
26 import org.eclipse.jdt.core.compiler.ITerminalSymbols;
27 import org.eclipse.jdt.core.dom.AST;
28 import org.eclipse.jdt.core.dom.ASTNode;
29 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
30 import org.eclipse.jdt.core.dom.Assignment;
31 import org.eclipse.jdt.core.dom.Block;
32 import org.eclipse.jdt.core.dom.BodyDeclaration;
33 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
34 import org.eclipse.jdt.core.dom.CompilationUnit;
35 import org.eclipse.jdt.core.dom.ConstructorInvocation;
36 import org.eclipse.jdt.core.dom.DoStatement;
37 import org.eclipse.jdt.core.dom.Expression;
38 import org.eclipse.jdt.core.dom.ForStatement;
39 import org.eclipse.jdt.core.dom.IMethodBinding;
40 import org.eclipse.jdt.core.dom.ITypeBinding;
41 import org.eclipse.jdt.core.dom.IVariableBinding;
42 import org.eclipse.jdt.core.dom.Initializer;
43 import org.eclipse.jdt.core.dom.Message;
44 import org.eclipse.jdt.core.dom.MethodDeclaration;
45 import org.eclipse.jdt.core.dom.Name;
46 import org.eclipse.jdt.core.dom.PrimitiveType;
47 import org.eclipse.jdt.core.dom.SimpleName;
48 import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
49 import org.eclipse.jdt.core.dom.SwitchCase;
50 import org.eclipse.jdt.core.dom.Type;
51 import org.eclipse.jdt.core.dom.VariableDeclaration;
52 import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
53 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
54 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
55 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
56
57 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
58 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
59 import org.eclipse.jdt.internal.corext.dom.Bindings;
60 import org.eclipse.jdt.internal.corext.dom.LocalVariableIndex;
61 import org.eclipse.jdt.internal.corext.dom.Selection;
62 import org.eclipse.jdt.internal.corext.refactoring.Checks;
63 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
64 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
65 import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowContext;
66 import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowInfo;
67 import org.eclipse.jdt.internal.corext.refactoring.code.flow.InOutFlowAnalyzer;
68 import org.eclipse.jdt.internal.corext.refactoring.code.flow.InputFlowAnalyzer;
69 import org.eclipse.jdt.internal.corext.refactoring.util.CodeAnalyzer;
70 import org.eclipse.jdt.internal.corext.util.Messages;
71
72 /* package */ class ExtractMethodAnalyzer extends CodeAnalyzer {
73
74     public static final int ERROR= -2;
75     public static final int UNDEFINED= -1;
76     public static final int NO= 0;
77     public static final int EXPRESSION= 1;
78     public static final int ACCESS_TO_LOCAL= 2;
79     public static final int RETURN_STATEMENT_VOID= 3;
80     public static final int RETURN_STATEMENT_VALUE= 4;
81     public static final int MULTIPLE= 5;
82
83     /** This is either a method declaration or an initializer */
84     private BodyDeclaration fEnclosingBodyDeclaration;
85     private IMethodBinding fEnclosingMethodBinding;
86     private int fMaxVariableId;
87
88     private int fReturnKind;
89     private Type fReturnType;
90     
91     private FlowInfo fInputFlowInfo;
92     private FlowContext fInputFlowContext;
93     
94     private IVariableBinding[] fArguments;
95     private IVariableBinding[] fMethodLocals;
96     private ITypeBinding[] fTypeVariables;
97     
98     private IVariableBinding fReturnValue;
99     private IVariableBinding[] fCallerLocals;
100     private IVariableBinding fReturnLocal;
101     
102     private ITypeBinding[] fAllExceptions;
103     private ITypeBinding fExpressionBinding;
104
105     private boolean fForceStatic;
106     private boolean fIsLastStatementSelected;
107     
108     public ExtractMethodAnalyzer(ICompilationUnit unit, Selection selection) throws JavaModelException {
109         super(unit, selection, false);
110     }
111     
112     public BodyDeclaration getEnclosingBodyDeclaration() {
113         return fEnclosingBodyDeclaration;
114     }
115     
116     public int getReturnKind() {
117         return fReturnKind;
118     }
119     
120     public boolean extractsExpression() {
121         return fReturnKind == EXPRESSION;
122     }
123     
124     public Type getReturnType() {
125         return fReturnType;
126     }
127
128     public boolean generateImport() {
129         switch (fReturnKind) {
130             case EXPRESSION:
131                 return true;
132             default:
133                 return false;
134         }
135     }
136     
137     public IVariableBinding[] getArguments() {
138         return fArguments;
139     }
140     
141     public IVariableBinding[] getMethodLocals() {
142         return fMethodLocals;
143     }
144     
145     public IVariableBinding getReturnValue() {
146         return fReturnValue;
147     }
148     
149     public IVariableBinding[] getCallerLocals() {
150         return fCallerLocals;
151     }
152     
153     public IVariableBinding getReturnLocal() {
154         return fReturnLocal;
155     }
156     
157     public ITypeBinding getExpressionBinding() {
158         return fExpressionBinding;
159     }
160     
161     public boolean getForceStatic() {
162         return fForceStatic;
163     }
164     
165     public ITypeBinding[] getTypeVariables() {
166         return fTypeVariables;
167     }
168     
169     //---- Activation checking ---------------------------------------------------------------------------
170

171     public RefactoringStatus checkInitialConditions(ImportRewrite rewriter) {
172         RefactoringStatus result= getStatus();
173         checkExpression(result);
174         if (result.hasFatalError())
175             return result;
176             
177         fReturnKind= UNDEFINED;
178         fMaxVariableId= LocalVariableIndex.perform(fEnclosingBodyDeclaration);
179         if (analyzeSelection(result).hasFatalError())
180             return result;
181
182         int returns= fReturnKind == NO ? 0 : 1;
183         if (fReturnValue != null) {
184             fReturnKind= ACCESS_TO_LOCAL;
185             returns++;
186         }
187         if (isExpressionSelected()) {
188             fReturnKind= EXPRESSION;
189             returns++;
190         }
191             
192         if (returns > 1) {
193             result.addFatalError(RefactoringCoreMessages.ExtractMethodAnalyzer_ambiguous_return_value, JavaStatusContext.create(fCUnit, getSelection()));
194             fReturnKind= MULTIPLE;
195             return result;
196         }
197         initReturnType(rewriter);
198         return result;
199     }
200     
201     private void checkExpression(RefactoringStatus status) {
202         ASTNode[] nodes= getSelectedNodes();
203         if (nodes != null && nodes.length == 1) {
204             ASTNode node= nodes[0];
205             if (node instanceof Type) {
206                 status.addFatalError(RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_type_reference, JavaStatusContext.create(fCUnit, node));
207             } else if (node.getLocationInParent() == SwitchCase.EXPRESSION_PROPERTY) {
208                 status.addFatalError(RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_switch_case, JavaStatusContext.create(fCUnit, node));
209             }
210         }
211     }
212     
213     private void initReturnType(ImportRewrite rewriter) {
214         AST ast= fEnclosingBodyDeclaration.getAST();
215         fReturnType= null;
216         switch (fReturnKind) {
217             case ACCESS_TO_LOCAL:
218                 VariableDeclaration declaration= ASTNodes.findVariableDeclaration(fReturnValue, fEnclosingBodyDeclaration);
219                 fReturnType= ASTNodeFactory.newType(ast, declaration);
220                 break;
221             case EXPRESSION:
222                 Expression expression= (Expression)getFirstSelectedNode();
223                 if (expression.getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) {
224                     fExpressionBinding= ((ClassInstanceCreation)expression).getType().resolveBinding();
225                 } else {
226                     fExpressionBinding= expression.resolveTypeBinding();
227                 }
228                 if (fExpressionBinding != null) {
229                     if (fExpressionBinding.isNullType()) {
230                         getStatus().addFatalError(RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_null_type, JavaStatusContext.create(fCUnit, expression));
231                     } else {
232                         ITypeBinding normalizedBinding= Bindings.normalizeForDeclarationUse(fExpressionBinding, ast);
233                         if (normalizedBinding != null) {
234                             fReturnType= rewriter.addImport(normalizedBinding, ast);
235                         }
236                     }
237                 } else {
238                     fReturnType= ast.newPrimitiveType(PrimitiveType.VOID);
239                     getStatus().addError(RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_determine_return_type, JavaStatusContext.create(fCUnit, expression));
240                 }
241                 break;
242             case RETURN_STATEMENT_VALUE:
243                 if (fEnclosingBodyDeclaration.getNodeType() == ASTNode.METHOD_DECLARATION)
244                     fReturnType= ((MethodDeclaration)fEnclosingBodyDeclaration).getReturnType2();
245                 break;
246             default:
247                 fReturnType= ast.newPrimitiveType(PrimitiveType.VOID);
248         }
249         if (fReturnType == null)
250             fReturnType= ast.newPrimitiveType(PrimitiveType.VOID);
251     }
252     
253     // !!! -- +/- same as in ExtractTempRefactoring
254
public boolean isLiteralNodeSelected() {
255         ASTNode[] nodes= getSelectedNodes();
256         if (nodes.length != 1)
257             return false;
258         ASTNode node= nodes[0];
259         switch (node.getNodeType()) {
260             case ASTNode.BOOLEAN_LITERAL :
261             case ASTNode.CHARACTER_LITERAL :
262             case ASTNode.NULL_LITERAL :
263             case ASTNode.NUMBER_LITERAL :
264                 return true;
265             
266             default :
267                 return false;
268         }
269     }
270
271     //---- Input checking -----------------------------------------------------------------------------------
272

273     public void checkInput(RefactoringStatus status, String JavaDoc methodName, AST ast) {
274         ITypeBinding[] arguments= getArgumentTypes();
275         ITypeBinding type= ASTNodes.getEnclosingType(fEnclosingBodyDeclaration);
276         status.merge(Checks.checkMethodInType(type, methodName, arguments));
277         status.merge(Checks.checkMethodInHierarchy(type.getSuperclass(), methodName, null, arguments));
278     }
279     
280     private ITypeBinding[] getArgumentTypes() {
281         ITypeBinding[] result= new ITypeBinding[fArguments.length];
282         for (int i= 0; i < fArguments.length; i++) {
283             result[i]= fArguments[i].getType();
284         }
285         return result;
286     }
287     
288     private RefactoringStatus analyzeSelection(RefactoringStatus status) {
289         fInputFlowContext= new FlowContext(0, fMaxVariableId + 1);
290         fInputFlowContext.setConsiderAccessMode(true);
291         fInputFlowContext.setComputeMode(FlowContext.ARGUMENTS);
292         
293         InOutFlowAnalyzer flowAnalyzer= new InOutFlowAnalyzer(fInputFlowContext);
294         fInputFlowInfo= flowAnalyzer.perform(getSelectedNodes());
295         
296         if (fInputFlowInfo.branches()) {
297             status.addFatalError(RefactoringCoreMessages.ExtractMethodAnalyzer_branch_mismatch, JavaStatusContext.create(fCUnit, getSelection()));
298             fReturnKind= ERROR;
299             return status;
300         }
301         if (fInputFlowInfo.isValueReturn()) {
302             fReturnKind= RETURN_STATEMENT_VALUE;
303         } else if (fInputFlowInfo.isVoidReturn() || (fInputFlowInfo.isPartialReturn() && isVoidMethod() && isLastStatementSelected())) {
304             fReturnKind= RETURN_STATEMENT_VOID;
305         } else if (fInputFlowInfo.isNoReturn() || fInputFlowInfo.isThrow() || fInputFlowInfo.isUndefined()) {
306             fReturnKind= NO;
307         }
308         
309         if (fReturnKind == UNDEFINED) {
310             status.addError(RefactoringCoreMessages.FlowAnalyzer_execution_flow, JavaStatusContext.create(fCUnit, getSelection()));
311             fReturnKind= NO;
312         }
313         computeInput();
314         computeExceptions();
315         computeOutput(status);
316         if (status.hasFatalError())
317             return status;
318         
319         adjustArgumentsAndMethodLocals();
320         compressArrays();
321         return status;
322     }
323     
324     private boolean isVoidMethod() {
325         // if we have an initializer
326
if (fEnclosingMethodBinding == null)
327             return true;
328         ITypeBinding binding= fEnclosingMethodBinding.getReturnType();
329         if (fEnclosingBodyDeclaration.getAST().resolveWellKnownType("void").equals(binding)) //$NON-NLS-1$
330
return true;
331         return false;
332     }
333     
334     public boolean isLastStatementSelected() {
335         return fIsLastStatementSelected;
336     }
337
338     private void computeLastStatementSelected() {
339         ASTNode[] nodes= getSelectedNodes();
340         if (nodes.length == 0) {
341             fIsLastStatementSelected= false;
342         } else {
343             Block body= null;
344             if (fEnclosingBodyDeclaration instanceof MethodDeclaration) {
345                 body= ((MethodDeclaration) fEnclosingBodyDeclaration).getBody();
346             } else if (fEnclosingBodyDeclaration instanceof Initializer) {
347                 body= ((Initializer) fEnclosingBodyDeclaration).getBody();
348             }
349             if (body != null) {
350                 List JavaDoc statements= body.statements();
351                 fIsLastStatementSelected= nodes[nodes.length - 1] == statements.get(statements.size() - 1);
352             }
353         }
354     }
355
356     private void computeInput() {
357         int argumentMode= FlowInfo.READ | FlowInfo.READ_POTENTIAL | FlowInfo.WRITE_POTENTIAL | FlowInfo.UNKNOWN;
358         fArguments= removeSelectedDeclarations(fInputFlowInfo.get(fInputFlowContext, argumentMode));
359         fMethodLocals= removeSelectedDeclarations(fInputFlowInfo.get(fInputFlowContext, FlowInfo.WRITE | FlowInfo.WRITE_POTENTIAL));
360         fTypeVariables= computeTypeVariables(fInputFlowInfo.getTypeVariables());
361     }
362     
363     private IVariableBinding[] removeSelectedDeclarations(IVariableBinding[] bindings) {
364         List JavaDoc result= new ArrayList JavaDoc(bindings.length);
365         Selection selection= getSelection();
366         for (int i= 0; i < bindings.length; i++) {
367             ASTNode decl= ((CompilationUnit)fEnclosingBodyDeclaration.getRoot()).findDeclaringNode(bindings[i]);
368             if (!selection.covers(decl))
369                 result.add(bindings[i]);
370         }
371         return (IVariableBinding[])result.toArray(new IVariableBinding[result.size()]);
372     }
373     
374     private ITypeBinding[] computeTypeVariables(ITypeBinding[] bindings) {
375         Selection selection= getSelection();
376         Set JavaDoc result= new HashSet JavaDoc();
377         // first remove all type variables that come from outside of the method
378
// or are covered by the selection
379
CompilationUnit compilationUnit= (CompilationUnit)fEnclosingBodyDeclaration.getRoot();
380         for (int i= 0; i < bindings.length; i++) {
381             ASTNode decl= compilationUnit.findDeclaringNode(bindings[i]);
382             if (decl == null || (!selection.covers(decl) && decl.getParent() instanceof MethodDeclaration))
383                 result.add(bindings[i]);
384         }
385         // all all type variables which are needed since a local variable uses it
386
for (int i= 0; i < fArguments.length; i++) {
387             IVariableBinding arg= fArguments[i];
388             ITypeBinding type= arg.getType();
389             if (type != null && type.isTypeVariable()) {
390                 ASTNode decl= compilationUnit.findDeclaringNode(type);
391                 if (decl == null || (!selection.covers(decl) && decl.getParent() instanceof MethodDeclaration))
392                     result.add(type);
393             }
394         }
395         return (ITypeBinding[])result.toArray(new ITypeBinding[result.size()]);
396     }
397     
398     private void computeOutput(RefactoringStatus status) {
399         // First find all writes inside the selection.
400
FlowContext flowContext= new FlowContext(0, fMaxVariableId + 1);
401         flowContext.setConsiderAccessMode(true);
402         flowContext.setComputeMode(FlowContext.RETURN_VALUES);
403         FlowInfo returnInfo= new InOutFlowAnalyzer(flowContext).perform(getSelectedNodes());
404         IVariableBinding[] returnValues= returnInfo.get(flowContext, FlowInfo.WRITE | FlowInfo.WRITE_POTENTIAL | FlowInfo.UNKNOWN);
405         
406         // Compute a selection that exactly covers the selected nodes
407
IRegion region= getSelectedNodeRange();
408         Selection selection= Selection.createFromStartLength(region.getOffset(), region.getLength());
409         
410         int counter= 0;
411         flowContext.setComputeMode(FlowContext.ARGUMENTS);
412         FlowInfo argInfo= new InputFlowAnalyzer(flowContext, selection, true).perform(fEnclosingBodyDeclaration);
413         IVariableBinding[] reads= argInfo.get(flowContext, FlowInfo.READ | FlowInfo.READ_POTENTIAL | FlowInfo.UNKNOWN);
414         outer: for (int i= 0; i < returnValues.length && counter <= 1; i++) {
415             IVariableBinding binding= returnValues[i];
416             for (int x= 0; x < reads.length; x++) {
417                 if (reads[x] == binding) {
418                     counter++;
419                     fReturnValue= binding;
420                     continue outer;
421                 }
422             }
423         }
424         switch (counter) {
425             case 0:
426                 fReturnValue= null;
427                 break;
428             case 1:
429                 break;
430             default:
431                 fReturnValue= null;
432                 status.addFatalError(RefactoringCoreMessages.ExtractMethodAnalyzer_assignments_to_local, JavaStatusContext.create(fCUnit, getSelection()));
433                 return;
434         }
435         List JavaDoc callerLocals= new ArrayList JavaDoc(5);
436         FlowInfo localInfo= new InputFlowAnalyzer(flowContext, selection, false).perform(fEnclosingBodyDeclaration);
437         IVariableBinding[] writes= localInfo.get(flowContext, FlowInfo.WRITE | FlowInfo.WRITE_POTENTIAL | FlowInfo.UNKNOWN);
438         for (int i= 0; i < writes.length; i++) {
439             IVariableBinding write= writes[i];
440             if (getSelection().covers(ASTNodes.findDeclaration(write, fEnclosingBodyDeclaration)))
441                 callerLocals.add(write);
442         }
443         fCallerLocals= (IVariableBinding[])callerLocals.toArray(new IVariableBinding[callerLocals.size()]);
444         if (fReturnValue != null && getSelection().covers(ASTNodes.findDeclaration(fReturnValue, fEnclosingBodyDeclaration)))
445             fReturnLocal= fReturnValue;
446     }
447     
448     private void adjustArgumentsAndMethodLocals() {
449         for (int i= 0; i < fArguments.length; i++) {
450             IVariableBinding argument= fArguments[i];
451             // Both arguments and locals consider FlowInfo.WRITE_POTENTIAL. But at the end a variable
452
// can either be a local of an argument. Fix this based on the compute return type which
453
// didn't exist when we computed the locals and arguments (see computeInput())
454
if (fInputFlowInfo.hasAccessMode(fInputFlowContext, argument, FlowInfo.WRITE_POTENTIAL)) {
455                 if (argument != fReturnValue)
456                     fArguments[i]= null;
457                 // We didn't remove the argument. So we have to remove the local declaration
458
if (fArguments[i] != null) {
459                     for (int l= 0; l < fMethodLocals.length; l++) {
460                         if (fMethodLocals[l] == argument)
461                             fMethodLocals[l]= null;
462                     }
463                 }
464             }
465         }
466     }
467     
468     private void compressArrays() {
469         fArguments= compressArray(fArguments);
470         fCallerLocals= compressArray(fCallerLocals);
471         fMethodLocals= compressArray(fMethodLocals);
472     }
473     
474     private IVariableBinding[] compressArray(IVariableBinding[] array) {
475         if (array == null)
476             return null;
477         int size= 0;
478         for (int i= 0; i < array.length; i++) {
479             if (array[i] != null)
480                 size++;
481         }
482         if (size == array.length)
483             return array;
484         IVariableBinding[] result= new IVariableBinding[size];
485         for (int i= 0, r= 0; i < array.length; i++) {
486             if (array[i] != null)
487                 result[r++]= array[i];
488         }
489         return result;
490     }
491     
492     //---- Change creation ----------------------------------------------------------------------------------
493

494     public void aboutToCreateChange() {
495     }
496
497     //---- Exceptions -----------------------------------------------------------------------------------------
498

499     public ITypeBinding[] getExceptions(boolean includeRuntimeExceptions, AST ast) {
500         if (includeRuntimeExceptions)
501             return fAllExceptions;
502         List JavaDoc result= new ArrayList JavaDoc(fAllExceptions.length);
503         for (int i= 0; i < fAllExceptions.length; i++) {
504             ITypeBinding exception= fAllExceptions[i];
505             if (!includeRuntimeExceptions && Bindings.isRuntimeException(exception))
506                 continue;
507             result.add(exception);
508         }
509         return (ITypeBinding[]) result.toArray(new ITypeBinding[result.size()]);
510     }
511     
512     private void computeExceptions() {
513         fAllExceptions= ExceptionAnalyzer.perform(getSelectedNodes());
514     }
515     
516     //---- Special visitor methods ---------------------------------------------------------------------------
517

518     protected void handleNextSelectedNode(ASTNode node) {
519         super.handleNextSelectedNode(node);
520         checkParent(node);
521     }
522     
523     protected boolean handleSelectionEndsIn(ASTNode node) {
524         invalidSelection(RefactoringCoreMessages.StatementAnalyzer_doesNotCover, JavaStatusContext.create(fCUnit, node));
525         return super.handleSelectionEndsIn(node);
526     }
527         
528     private void checkParent(ASTNode node) {
529         ASTNode firstParent= getFirstSelectedNode().getParent();
530         do {
531             node= node.getParent();
532             if (node == firstParent)
533                 return;
534         } while (node != null);
535         invalidSelection(RefactoringCoreMessages.ExtractMethodAnalyzer_parent_mismatch);
536     }
537     
538     public void endVisit(CompilationUnit node) {
539         RefactoringStatus status= getStatus();
540         superCall: {
541             if (status.hasFatalError())
542                 break superCall;
543             if (!hasSelectedNodes()) {
544                 ASTNode coveringNode= getLastCoveringNode();
545                 if (coveringNode instanceof Block && coveringNode.getParent() instanceof MethodDeclaration) {
546                     MethodDeclaration methodDecl= (MethodDeclaration)coveringNode.getParent();
547                     Message[] messages= ASTNodes.getMessages(methodDecl, ASTNodes.NODE_ONLY);
548                     if (messages.length > 0) {
549                         status.addFatalError(Messages.format(
550                             RefactoringCoreMessages.ExtractMethodAnalyzer_compile_errors,
551                             methodDecl.getName().getIdentifier()), JavaStatusContext.create(fCUnit, methodDecl));
552                         break superCall;
553                     }
554                 }
555                 status.addFatalError(RefactoringCoreMessages.ExtractMethodAnalyzer_only_method_body);
556                 break superCall;
557             }
558             fEnclosingBodyDeclaration= (BodyDeclaration)ASTNodes.getParent(getFirstSelectedNode(), BodyDeclaration.class);
559             if (fEnclosingBodyDeclaration == null ||
560                     (fEnclosingBodyDeclaration.getNodeType() != ASTNode.METHOD_DECLARATION &&
561                      fEnclosingBodyDeclaration.getNodeType() != ASTNode.INITIALIZER)) {
562                 status.addFatalError(RefactoringCoreMessages.ExtractMethodAnalyzer_only_method_body);
563                 break superCall;
564             } else if (ASTNodes.getEnclosingType(fEnclosingBodyDeclaration) == null) {
565                 status.addFatalError(RefactoringCoreMessages.ExtractMethodAnalyzer_compile_errors_no_parent_binding);
566                 break superCall;
567             } else if (fEnclosingBodyDeclaration.getNodeType() == ASTNode.METHOD_DECLARATION) {
568                 fEnclosingMethodBinding= ((MethodDeclaration)fEnclosingBodyDeclaration).resolveBinding();
569             }
570             if (!isSingleExpressionOrStatementSet()) {
571                 status.addFatalError(RefactoringCoreMessages.ExtractMethodAnalyzer_single_expression_or_set);
572                 break superCall;
573             }
574             if (isExpressionSelected()) {
575                 ASTNode expression= getFirstSelectedNode();
576                 if (expression instanceof Name) {
577                     Name name= (Name)expression;
578                     if (name.resolveBinding() instanceof ITypeBinding) {
579                         status.addFatalError(RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_type_reference);
580                         break superCall;
581                     }
582                     if (name.resolveBinding() instanceof IMethodBinding) {
583                         status.addFatalError(RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_method_name_reference);
584                     }
585                     if (name.isSimpleName() && ((SimpleName)name).isDeclaration()) {
586                         status.addFatalError(RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_name_in_declaration);
587                         break superCall;
588                     }
589                 }
590                 fForceStatic=
591                     ASTNodes.getParent(expression, ASTNode.SUPER_CONSTRUCTOR_INVOCATION) != null ||
592                     ASTNodes.getParent(expression, ASTNode.CONSTRUCTOR_INVOCATION) != null;
593             }
594             status.merge(LocalTypeAnalyzer.perform(fEnclosingBodyDeclaration, getSelection()));
595             computeLastStatementSelected();
596         }
597         super.endVisit(node);
598     }
599     
600     public boolean visit(AnonymousClassDeclaration node) {
601         boolean result= super.visit(node);
602         if (isFirstSelectedNode(node)) {
603             invalidSelection(RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_anonymous_type, JavaStatusContext.create(fCUnit, node));
604             return false;
605         }
606         return result;
607     }
608     
609     public boolean visit(Assignment node) {
610         boolean result= super.visit(node);
611         if (getSelection().getVisitSelectionMode(node.getLeftHandSide()) == Selection.SELECTED) {
612             invalidSelection(
613                 RefactoringCoreMessages.ExtractMethodAnalyzer_leftHandSideOfAssignment,
614                 JavaStatusContext.create(fCUnit, node));
615             return false;
616         }
617         return result;
618     }
619
620     public boolean visit(DoStatement node) {
621         boolean result= super.visit(node);
622         
623         try {
624             int actionStart= getTokenScanner().getTokenEndOffset(ITerminalSymbols.TokenNamedo, node.getStartPosition());
625             if (getSelection().getOffset() == actionStart) {
626                 invalidSelection(RefactoringCoreMessages.ExtractMethodAnalyzer_after_do_keyword, JavaStatusContext.create(fCUnit, getSelection()));
627                 return false;
628             }
629         } catch (CoreException e) {
630             // ignore
631
}
632         
633         return result;
634     }
635
636     public boolean visit(MethodDeclaration node) {
637         Block body= node.getBody();
638         if (body == null)
639             return false;
640         Selection selection= getSelection();
641         int nodeStart= body.getStartPosition();
642         int nodeExclusiveEnd= nodeStart + body.getLength();
643         // if selection node inside of the method body ignore method
644
if (!(nodeStart < selection.getOffset() && selection.getExclusiveEnd() < nodeExclusiveEnd))
645             return false;
646         return super.visit(node);
647     }
648     
649     public boolean visit(ConstructorInvocation node) {
650         return visitConstructorInvocation(node, super.visit(node));
651     }
652     
653     public boolean visit(SuperConstructorInvocation node) {
654         return visitConstructorInvocation(node, super.visit(node));
655     }
656     
657     private boolean visitConstructorInvocation(ASTNode node, boolean superResult) {
658         if (getSelection().getVisitSelectionMode(node) == Selection.SELECTED) {
659             invalidSelection(RefactoringCoreMessages.ExtractMethodAnalyzer_super_or_this, JavaStatusContext.create(fCUnit, node));
660             return false;
661         }
662         return superResult;
663     }
664     
665     public boolean visit(VariableDeclarationFragment node) {
666         boolean result= super.visit(node);
667         if (isFirstSelectedNode(node)) {
668             invalidSelection(RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_variable_declaration_fragment, JavaStatusContext.create(fCUnit, node));
669             return false;
670         }
671         return result;
672     }
673     
674     public void endVisit(ForStatement node) {
675         if (getSelection().getEndVisitSelectionMode(node) == Selection.AFTER) {
676             if (node.initializers().contains(getFirstSelectedNode())) {
677                 invalidSelection(RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_for_initializer, JavaStatusContext.create(fCUnit, getSelection()));
678             } else if (node.updaters().contains(getLastSelectedNode())) {
679                 invalidSelection(RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_for_updater, JavaStatusContext.create(fCUnit, getSelection()));
680             }
681         }
682         super.endVisit(node);
683     }
684     
685     public void endVisit(VariableDeclarationExpression node) {
686         checkTypeInDeclaration(node.getType());
687         super.endVisit(node);
688     }
689             
690     public void endVisit(VariableDeclarationStatement node) {
691         checkTypeInDeclaration(node.getType());
692         super.endVisit(node);
693     }
694             
695     private boolean isFirstSelectedNode(ASTNode node) {
696         return getSelection().getVisitSelectionMode(node) == Selection.SELECTED && getFirstSelectedNode() == node;
697     }
698     
699     private void checkTypeInDeclaration(Type node) {
700         if (getSelection().getEndVisitSelectionMode(node) == Selection.SELECTED && getFirstSelectedNode() == node) {
701             invalidSelection(RefactoringCoreMessages.ExtractMethodAnalyzer_cannot_extract_variable_declaration, JavaStatusContext.create(fCUnit, getSelection()));
702         }
703     }
704     
705     private boolean isSingleExpressionOrStatementSet() {
706         ASTNode first= getFirstSelectedNode();
707         if (first == null)
708             return true;
709         if (first instanceof Expression && getSelectedNodes().length != 1)
710             return false;
711         return true;
712     }
713 }
714
715
Popular Tags