1 11 package org.eclipse.jdt.internal.corext.refactoring.code; 12 13 import java.util.ArrayList ; 14 import java.util.HashSet ; 15 import java.util.List ; 16 import java.util.Set ; 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 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 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 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 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 273 public void checkInput(RefactoringStatus status, String 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 (fEnclosingMethodBinding == null) 327 return true; 328 ITypeBinding binding= fEnclosingMethodBinding.getReturnType(); 329 if (fEnclosingBodyDeclaration.getAST().resolveWellKnownType("void").equals(binding)) 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 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 result= new ArrayList (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 result= new HashSet (); 377 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 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 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 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 callerLocals= new ArrayList (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 if (fInputFlowInfo.hasAccessMode(fInputFlowContext, argument, FlowInfo.WRITE_POTENTIAL)) { 455 if (argument != fReturnValue) 456 fArguments[i]= null; 457 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 494 public void aboutToCreateChange() { 495 } 496 497 499 public ITypeBinding[] getExceptions(boolean includeRuntimeExceptions, AST ast) { 500 if (includeRuntimeExceptions) 501 return fAllExceptions; 502 List result= new ArrayList (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 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 } 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 (!(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 |