1 22 package org.eclipse.jdt.internal.corext.refactoring.code; 23 24 import java.util.ArrayList ; 25 import java.util.HashSet ; 26 import java.util.Iterator ; 27 import java.util.List ; 28 import java.util.Set ; 29 30 import org.eclipse.text.edits.TextEdit; 31 import org.eclipse.text.edits.TextEditGroup; 32 33 import org.eclipse.core.runtime.Assert; 34 import org.eclipse.core.runtime.CoreException; 35 36 import org.eclipse.core.filebuffers.ITextFileBuffer; 37 38 import org.eclipse.jface.text.BadLocationException; 39 40 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 41 import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry; 42 43 import org.eclipse.jdt.core.ICompilationUnit; 44 import org.eclipse.jdt.core.dom.AST; 45 import org.eclipse.jdt.core.dom.ASTNode; 46 import org.eclipse.jdt.core.dom.ASTVisitor; 47 import org.eclipse.jdt.core.dom.ArrayCreation; 48 import org.eclipse.jdt.core.dom.ArrayInitializer; 49 import org.eclipse.jdt.core.dom.Assignment; 50 import org.eclipse.jdt.core.dom.Block; 51 import org.eclipse.jdt.core.dom.BodyDeclaration; 52 import org.eclipse.jdt.core.dom.CastExpression; 53 import org.eclipse.jdt.core.dom.CompilationUnit; 54 import org.eclipse.jdt.core.dom.DoStatement; 55 import org.eclipse.jdt.core.dom.EnhancedForStatement; 56 import org.eclipse.jdt.core.dom.Expression; 57 import org.eclipse.jdt.core.dom.FieldAccess; 58 import org.eclipse.jdt.core.dom.FieldDeclaration; 59 import org.eclipse.jdt.core.dom.ForStatement; 60 import org.eclipse.jdt.core.dom.IBinding; 61 import org.eclipse.jdt.core.dom.IMethodBinding; 62 import org.eclipse.jdt.core.dom.ITypeBinding; 63 import org.eclipse.jdt.core.dom.IVariableBinding; 64 import org.eclipse.jdt.core.dom.IfStatement; 65 import org.eclipse.jdt.core.dom.LabeledStatement; 66 import org.eclipse.jdt.core.dom.MethodDeclaration; 67 import org.eclipse.jdt.core.dom.MethodInvocation; 68 import org.eclipse.jdt.core.dom.Modifier; 69 import org.eclipse.jdt.core.dom.Name; 70 import org.eclipse.jdt.core.dom.ParenthesizedExpression; 71 import org.eclipse.jdt.core.dom.ReturnStatement; 72 import org.eclipse.jdt.core.dom.SimpleName; 73 import org.eclipse.jdt.core.dom.Statement; 74 import org.eclipse.jdt.core.dom.SuperFieldAccess; 75 import org.eclipse.jdt.core.dom.SwitchStatement; 76 import org.eclipse.jdt.core.dom.ThisExpression; 77 import org.eclipse.jdt.core.dom.Type; 78 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 79 import org.eclipse.jdt.core.dom.VariableDeclarationStatement; 80 import org.eclipse.jdt.core.dom.WhileStatement; 81 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 82 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; 83 import org.eclipse.jdt.core.dom.rewrite.ListRewrite; 84 85 import org.eclipse.jdt.internal.corext.Corext; 86 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; 87 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; 88 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 89 import org.eclipse.jdt.internal.corext.dom.Bindings; 90 import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder; 91 import org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor; 92 import org.eclipse.jdt.internal.corext.dom.LocalVariableIndex; 93 import org.eclipse.jdt.internal.corext.dom.Selection; 94 import org.eclipse.jdt.internal.corext.dom.TypeBindingVisitor; 95 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 96 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; 97 import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatusCodes; 98 import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowContext; 99 import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowInfo; 100 import org.eclipse.jdt.internal.corext.refactoring.code.flow.InputFlowAnalyzer; 101 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType; 102 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TypeEnvironment; 103 import org.eclipse.jdt.internal.corext.refactoring.util.NoCommentSourceRangeComputer; 104 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringFileBuffers; 105 106 import org.eclipse.jdt.internal.ui.JavaPlugin; 107 108 public class CallInliner { 109 110 private ICompilationUnit fCUnit; 111 private ASTRewrite fRewrite; 112 private ImportRewrite fImportRewrite; 113 private ITextFileBuffer fBuffer; 114 private SourceProvider fSourceProvider; 115 private TypeEnvironment fTypeEnvironment; 116 117 private BodyDeclaration fBodyDeclaration; 118 private CodeScopeBuilder.Scope fRootScope; 119 private int fNumberOfLocals; 120 121 private ASTNode fInvocation; 122 123 private int fInsertionIndex; 124 private ListRewrite fListRewrite; 125 126 private boolean fNeedsStatement; 127 private ASTNode fTargetNode; 128 private FlowContext fFlowContext; 129 private FlowInfo fFlowInfo; 130 private CodeScopeBuilder.Scope fInvocationScope; 131 private boolean fFieldInitializer; 132 private List fLocals; 133 private CallContext fContext; 134 135 private class InlineEvaluator extends HierarchicalASTVisitor { 136 private ParameterData fFormalArgument; 137 private boolean fResult; 138 public InlineEvaluator(ParameterData argument) { 139 fFormalArgument= argument; 140 } 141 public boolean getResult() { 142 return fResult; 143 } 144 private boolean setResult(boolean result) { 145 fResult= result; 146 return false; 147 } 148 public boolean visit(Expression node) { 149 int accessMode= fFormalArgument.getSimplifiedAccessMode(); 150 if (accessMode == FlowInfo.WRITE) 151 return setResult(false); 152 if (accessMode == FlowInfo.UNUSED) 153 return setResult(true); 154 if (ASTNodes.isLiteral(node)) 155 return setResult(true); 156 return setResult(fFormalArgument.getNumberOfAccesses() <= 1); 157 } 158 public boolean visit(SimpleName node) { 159 IBinding binding= node.resolveBinding(); 160 if (binding instanceof IVariableBinding) { 161 int accessMode = fFormalArgument.getSimplifiedAccessMode(); 162 if (accessMode == FlowInfo.READ || accessMode == FlowInfo.UNUSED) 163 return setResult(true); 164 IVariableBinding vb= (IVariableBinding)binding; 166 if (vb.isField()) 167 return setResult(false); 168 return setResult(fFlowInfo.hasAccessMode(fFlowContext, vb, FlowInfo.UNUSED | FlowInfo.WRITE)); 169 } 170 return setResult(false); 171 } 172 public boolean visit(FieldAccess node) { 173 return visit(node.getName()); 174 } 175 public boolean visit(SuperFieldAccess node) { 176 return visit(node.getName()); 177 } 178 public boolean visit(ThisExpression node) { 179 int accessMode= fFormalArgument.getSimplifiedAccessMode(); 180 if (accessMode == FlowInfo.READ || accessMode == FlowInfo.UNUSED) 181 return setResult(true); 182 return setResult(false); 183 } 184 } 185 186 private static class AmbiguousMethodAnalyzer implements TypeBindingVisitor { 187 private TypeEnvironment fTypeEnvironment; 188 private TType[] fTypes; 189 private IMethodBinding fOriginal; 190 191 public AmbiguousMethodAnalyzer(TypeEnvironment typeEnvironment, IMethodBinding original, TType[] types) { 192 fTypeEnvironment= typeEnvironment; 193 fOriginal= original; 194 fTypes= types; 195 } 196 public boolean visit(ITypeBinding node) { 197 IMethodBinding[] methods= node.getDeclaredMethods(); 198 for (int i= 0; i < methods.length; i++) { 199 IMethodBinding candidate= methods[i]; 200 if (candidate == fOriginal) { 201 continue; 202 } 203 if (fOriginal.getName().equals(candidate.getName())) { 204 if (canImplicitlyCall(candidate)) { 205 return false; 206 } 207 } 208 } 209 return true; 210 } 211 215 private boolean canImplicitlyCall(IMethodBinding candidate) { 216 ITypeBinding[] parameters= candidate.getParameterTypes(); 217 if (parameters.length != fTypes.length) { 218 return false; 219 } 220 for (int i= 0; i < parameters.length; i++) { 221 if (!fTypes[i].canAssignTo(fTypeEnvironment.create(parameters[i]))) { 222 return false; 223 } 224 } 225 return true; 226 } 227 } 228 229 public CallInliner(ICompilationUnit unit, CompilationUnit targetAstRoot, SourceProvider provider) throws CoreException { 230 super(); 231 fCUnit= unit; 232 fBuffer= RefactoringFileBuffers.acquire(fCUnit); 233 fSourceProvider= provider; 234 fImportRewrite= StubUtility.createImportRewrite(targetAstRoot, true); 235 fLocals= new ArrayList (3); 236 fRewrite= ASTRewrite.create(targetAstRoot.getAST()); 237 fRewrite.setTargetSourceRangeComputer(new NoCommentSourceRangeComputer()); 238 fTypeEnvironment= new TypeEnvironment(); 239 } 240 241 public void dispose() { 242 try { 243 RefactoringFileBuffers.release(fCUnit); 244 } catch (CoreException exception) { 245 JavaPlugin.log(exception); 246 } 247 } 248 249 250 public ImportRewrite getImportEdit() { 251 return fImportRewrite; 252 } 253 254 public ASTNode getTargetNode() { 255 return fTargetNode; 256 } 257 258 public void initialize(BodyDeclaration declaration) { 259 fBodyDeclaration= declaration; 260 fRootScope= CodeScopeBuilder.perform(declaration, fSourceProvider.getDeclaration().resolveBinding()); 261 fNumberOfLocals= 0; 262 switch (declaration.getNodeType()) { 263 case ASTNode.METHOD_DECLARATION: 264 case ASTNode.INITIALIZER: 265 fNumberOfLocals= LocalVariableIndex.perform(declaration); 266 break; 267 } 268 } 269 270 public RefactoringStatus initialize(ASTNode invocation, int severity) { 271 RefactoringStatus result= new RefactoringStatus(); 272 fInvocation= invocation; 273 fLocals= new ArrayList (3); 274 275 checkMethodDeclaration(result, severity); 276 if (result.getSeverity() >= severity) 277 return result; 278 279 initializeRewriteState(); 280 initializeTargetNode(); 281 flowAnalysis(); 282 283 fContext= new CallContext(fInvocation, fInvocationScope, fTargetNode.getNodeType(), fImportRewrite); 284 285 try { 286 computeRealArguments(); 287 computeReceiver(); 288 } catch (BadLocationException exception) { 289 JavaPlugin.log(exception); 290 } 291 checkInvocationContext(result, severity); 292 293 return result; 294 } 295 296 private void initializeRewriteState() { 297 if(ASTNodes.getParent(fInvocation, ASTNode.FIELD_DECLARATION) != null) { 300 fFieldInitializer= true; 301 } 302 } 303 304 private void initializeTargetNode() { 305 ASTNode parent= fInvocation.getParent(); 306 int nodeType= parent.getNodeType(); 307 if (nodeType == ASTNode.EXPRESSION_STATEMENT || nodeType == ASTNode.RETURN_STATEMENT) { 308 fTargetNode= parent; 309 } else { 310 fTargetNode= fInvocation; 311 } 312 } 313 314 private void checkMethodDeclaration(RefactoringStatus result, int severity) { 316 MethodDeclaration methodDeclaration= fSourceProvider.getDeclaration(); 317 if (fInvocation.getNodeType() != ASTNode.CONSTRUCTOR_INVOCATION && methodDeclaration.isConstructor()) { 320 result.addEntry(new RefactoringStatusEntry( 321 severity, 322 RefactoringCoreMessages.CallInliner_constructors, 323 JavaStatusContext.create(fCUnit, fInvocation))); 324 } 325 if (fSourceProvider.hasSuperMethodInvocation() && fInvocation.getNodeType() == ASTNode.METHOD_INVOCATION) { 326 Expression receiver= ((MethodInvocation)fInvocation).getExpression(); 327 if (receiver instanceof ThisExpression) { 328 result.addEntry(new RefactoringStatusEntry( 329 severity, 330 RefactoringCoreMessages.CallInliner_super_into_this_expression, 331 JavaStatusContext.create(fCUnit, fInvocation))); 332 } 333 } 334 } 335 336 private void checkInvocationContext(RefactoringStatus result, int severity) { 337 if (fInvocation.getNodeType() == ASTNode.METHOD_INVOCATION) { 338 Expression exp= ((MethodInvocation)fInvocation).getExpression(); 339 if (exp != null && exp.resolveTypeBinding() == null) { 340 addEntry(result, RefactoringCoreMessages.CallInliner_receiver_type, 341 RefactoringStatusCodes.INLINE_METHOD_NULL_BINDING, severity); 342 return; 343 } 344 } 345 int nodeType= fTargetNode.getNodeType(); 346 if (nodeType == ASTNode.EXPRESSION_STATEMENT) { 347 if (fSourceProvider.isExecutionFlowInterrupted()) { 348 addEntry(result, RefactoringCoreMessages.CallInliner_execution_flow, 349 RefactoringStatusCodes.INLINE_METHOD_EXECUTION_FLOW, severity); 350 return; 351 } 352 } else if (nodeType == ASTNode.METHOD_INVOCATION) { 353 ASTNode parent= fTargetNode.getParent(); 354 if (isReturnStatement(parent)) { 355 return; 357 } 358 if (fSourceProvider.isExecutionFlowInterrupted()) { 359 addEntry(result, RefactoringCoreMessages.CallInliner_execution_flow, 360 RefactoringStatusCodes.INLINE_METHOD_EXECUTION_FLOW, severity); 361 return; 362 } 363 if (isAssignment(parent) || isSingleDeclaration(parent)) { 364 return; 367 } else { 368 boolean isFieldDeclaration= ASTNodes.getParent(fInvocation, FieldDeclaration.class) != null; 369 if (!fSourceProvider.isSimpleFunction()) { 370 if (isMultiDeclarationFragment(parent)) { 371 addEntry(result, RefactoringCoreMessages.CallInliner_multiDeclaration, 372 RefactoringStatusCodes.INLINE_METHOD_INITIALIZER_IN_FRAGEMENT, severity); 373 } else if (isFieldDeclaration) { 374 addEntry(result, 375 RefactoringCoreMessages.CallInliner_field_initializer_simple, 376 RefactoringStatusCodes.INLINE_METHOD_FIELD_INITIALIZER, severity); 377 } else { 378 addEntry(result, RefactoringCoreMessages.CallInliner_simple_functions, 379 RefactoringStatusCodes.INLINE_METHOD_ONLY_SIMPLE_FUNCTIONS, severity); 380 } 381 return; 382 } 383 if (isFieldDeclaration) { 384 int argumentsCount= fContext.arguments.length; 385 for (int i= 0; i < argumentsCount; i++) { 386 ParameterData parameter= fSourceProvider.getParameterData(i); 387 if(parameter.isWrite()) { 388 addEntry(result, 389 RefactoringCoreMessages.CallInliner_field_initialize_write_parameter, 390 RefactoringStatusCodes.INLINE_METHOD_FIELD_INITIALIZER, severity); 391 return; 392 } 393 } 394 if(fLocals.size() > 0) { 395 addEntry(result, 396 RefactoringCoreMessages.CallInliner_field_initialize_new_local, 397 RefactoringStatusCodes.INLINE_METHOD_FIELD_INITIALIZER, severity); 398 return; 399 } 400 VariableDeclarationFragment variable= (VariableDeclarationFragment)ASTNodes.getParent(fInvocation, ASTNode.VARIABLE_DECLARATION_FRAGMENT); 402 if(fSourceProvider.isVariableReferenced(variable.resolveBinding())) { 403 addEntry(result, 404 RefactoringCoreMessages.CallInliner_field_initialize_self_reference, 405 RefactoringStatusCodes.INLINE_METHOD_FIELD_INITIALIZER, severity); 406 return; 407 } 408 } 409 } 410 } 411 } 412 413 private static boolean isAssignment(ASTNode node) { 414 return node instanceof Assignment; 415 } 416 417 private static boolean isReturnStatement(ASTNode node) { 418 return node instanceof ReturnStatement; 419 } 420 421 private static boolean isSingleDeclaration(ASTNode node) { 422 int type= node.getNodeType(); 423 if (type == ASTNode.SINGLE_VARIABLE_DECLARATION) 424 return true; 425 if (type == ASTNode.VARIABLE_DECLARATION_FRAGMENT) { 426 node= node.getParent(); 427 if (node.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT) { 428 VariableDeclarationStatement vs= (VariableDeclarationStatement)node; 429 return vs.fragments().size() == 1; 430 } 431 } 432 return false; 433 } 434 435 private static boolean isMultiDeclarationFragment(ASTNode node) { 436 int nodeType= node.getNodeType(); 437 if (nodeType == ASTNode.VARIABLE_DECLARATION_FRAGMENT) { 438 node= node.getParent(); 439 if (node.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT) { 440 VariableDeclarationStatement vs= (VariableDeclarationStatement)node; 441 return vs.fragments().size() > 1; 442 } 443 } 444 return false; 445 } 446 447 private void addEntry(RefactoringStatus result, String message, int code, int severity) { 448 result.addEntry(new RefactoringStatusEntry( 449 severity, message, 450 JavaStatusContext.create(fCUnit, fInvocation), 451 Corext.getPluginId(), 452 code, null)); 453 } 454 455 private void flowAnalysis() { 456 fInvocationScope= fRootScope.findScope(fTargetNode.getStartPosition(), fTargetNode.getLength()); 457 fInvocationScope.setCursor(fTargetNode.getStartPosition()); 458 fFlowContext= new FlowContext(0, fNumberOfLocals + 1); 459 fFlowContext.setConsiderAccessMode(true); 460 fFlowContext.setComputeMode(FlowContext.ARGUMENTS); 461 Selection selection= Selection.createFromStartLength(fInvocation.getStartPosition(), fInvocation.getLength()); 462 switch (fBodyDeclaration.getNodeType()) { 463 case ASTNode.INITIALIZER: 464 case ASTNode.FIELD_DECLARATION: 465 case ASTNode.METHOD_DECLARATION: 466 fFlowInfo= new InputFlowAnalyzer(fFlowContext, selection, true).perform(fBodyDeclaration); 467 break; 468 default: 469 Assert.isTrue(false, "Should not happen"); } 471 } 472 473 public RefactoringStatus perform(TextEditGroup textEditGroup) throws CoreException { 474 RefactoringStatus result= new RefactoringStatus(); 475 String [] blocks= fSourceProvider.getCodeBlocks(fContext); 476 if(!fFieldInitializer) { 477 initializeInsertionPoint(fSourceProvider.getNumberOfStatements() + fLocals.size()); 478 } 479 480 addNewLocals(textEditGroup); 481 replaceCall(result, blocks, textEditGroup); 482 return result; 483 } 484 485 public TextEdit getModifications() { 486 return fRewrite.rewriteAST(fBuffer.getDocument(), fCUnit.getJavaProject().getOptions(true)); 487 } 488 489 private void computeRealArguments() throws BadLocationException { 490 List arguments= Invocations.getArguments(fInvocation); 491 Set canNotInline= crossCheckArguments(arguments); 492 boolean needsVarargBoxing= needsVarargBoxing(arguments); 493 int varargIndex= fSourceProvider.getVarargIndex(); 494 String [] realArguments= new String [needsVarargBoxing ? varargIndex + 1 : arguments.size()]; 495 for (int i= 0; i < (needsVarargBoxing ? varargIndex : arguments.size()); i++) { 496 Expression expression= (Expression)arguments.get(i); 497 ParameterData parameter= fSourceProvider.getParameterData(i); 498 if (canInline(expression, parameter) && !canNotInline.contains(expression)) { 499 realArguments[i] = getContent(expression); 500 if (argumentNeedsParenthesis(expression, parameter)) { 502 realArguments[i] = "(" + realArguments[i] + ")"; } 504 } else { 505 String name= fInvocationScope.createName(parameter.getName(), true); 506 realArguments[i]= name; 507 fLocals.add(createLocalDeclaration( 508 parameter.getTypeBinding(), name, 509 (Expression)fRewrite.createCopyTarget(expression))); 510 } 511 } 512 if (needsVarargBoxing) { 513 ParameterData parameter= fSourceProvider.getParameterData(varargIndex); 514 String name= fInvocationScope.createName(parameter.getName(), true); 515 realArguments[varargIndex]= name; 516 AST ast= fInvocation.getAST(); 517 Type type= fImportRewrite.addImport(parameter.getTypeBinding(), ast); 518 VariableDeclarationFragment fragment= ast.newVariableDeclarationFragment(); 519 fragment.setName(ast.newSimpleName(name)); 520 ArrayInitializer initializer= ast.newArrayInitializer(); 521 for (int i= varargIndex; i < arguments.size(); i++) { 522 initializer.expressions().add(fRewrite.createCopyTarget((ASTNode)arguments.get(i))); 523 } 524 fragment.setInitializer(initializer); 525 VariableDeclarationStatement decl= ast.newVariableDeclarationStatement(fragment); 526 decl.setType(type); 527 fLocals.add(decl); 528 } 529 fContext.arguments= realArguments; 530 } 531 532 private boolean needsVarargBoxing(List arguments) { 533 if (!fSourceProvider.isVarargs()) 534 return false; 535 539 int index= fSourceProvider.getVarargIndex(); 540 if (index >= arguments.size()) 542 return true; 543 if (index == arguments.size() - 1) { 546 ITypeBinding argument= ((Expression)arguments.get(index)).resolveTypeBinding(); 547 if (argument == null) 548 return false; 549 ITypeBinding parameter= fSourceProvider.getParameterData(index).getTypeBinding(); 550 return !fTypeEnvironment.create(argument).canAssignTo(fTypeEnvironment.create(parameter)); 551 } 552 return true; 553 } 554 555 private boolean argumentNeedsParenthesis(Expression expression, ParameterData param) { 556 if (expression instanceof CastExpression || expression instanceof ArrayCreation) 557 return true; 558 int argPrecedence= OperatorPrecedence.getValue(expression); 559 int paramPrecedence= param.getOperatorPrecedence(); 560 if (argPrecedence != -1 && paramPrecedence != -1) 561 return argPrecedence < paramPrecedence; 562 563 return false; 564 } 565 566 private void computeReceiver() throws BadLocationException { 567 Expression receiver= Invocations.getExpression(fInvocation); 568 if (receiver == null) 569 return; 570 final boolean isName= receiver instanceof Name; 571 if (isName) 572 fContext.receiverIsStatic= ((Name)receiver).resolveBinding() instanceof ITypeBinding; 573 if (ASTNodes.isLiteral(receiver) || isName || receiver instanceof ThisExpression) { 574 fContext.receiver= fBuffer.getDocument().get(receiver.getStartPosition(), receiver.getLength()); 575 return; 576 } 577 switch(fSourceProvider.getReceiversToBeUpdated()) { 578 case 0: 579 fLocals.add(createLocalDeclaration( 582 receiver.resolveTypeBinding(), 583 fInvocationScope.createName("r", true), (Expression)fRewrite.createCopyTarget(receiver))); 585 return; 586 case 1: 587 fContext.receiver= fBuffer.getDocument().get(receiver.getStartPosition(), receiver.getLength()); 588 return; 589 default: 590 String local= fInvocationScope.createName("r", true); fLocals.add(createLocalDeclaration( 592 receiver.resolveTypeBinding(), 593 local, 594 (Expression)fRewrite.createCopyTarget(receiver))); 595 fContext.receiver= local; 596 return; 597 } 598 } 599 600 private void addNewLocals(TextEditGroup textEditGroup) { 601 if (fLocals.isEmpty()) 602 return; 603 for (Iterator iter= fLocals.iterator(); iter.hasNext();) { 604 ASTNode element= (ASTNode)iter.next(); 605 fListRewrite.insertAt(element, fInsertionIndex++, textEditGroup); 606 } 607 } 608 609 private void replaceCall(RefactoringStatus status, String [] blocks, TextEditGroup textEditGroup) { 610 if (blocks.length == 0) { 612 if (fNeedsStatement) { 613 fRewrite.replace(fTargetNode, fTargetNode.getAST().newEmptyStatement(), textEditGroup); 614 } else { 615 fRewrite.remove(fTargetNode, textEditGroup); 616 } 617 } else { 618 ASTNode node= null; 619 for (int i= 0; i < blocks.length - 1; i++) { 620 node= fRewrite.createStringPlaceholder(blocks[i], ASTNode.RETURN_STATEMENT); 621 fListRewrite.insertAt(node, fInsertionIndex++, textEditGroup); 622 } 623 String block= blocks[blocks.length - 1]; 624 if (fContext.callMode == ASTNode.EXPRESSION_STATEMENT && fSourceProvider.hasReturnValue()) { 628 if (fSourceProvider.mustEvaluateReturnedExpression()) { 629 if (fSourceProvider.returnValueNeedsLocalVariable()) { 630 IMethodBinding invocation= Invocations.resolveBinding(fInvocation); 631 node= createLocalDeclaration( 632 invocation.getReturnType(), 633 fInvocationScope.createName(fSourceProvider.getMethodName(), true), 634 (Expression)fRewrite.createStringPlaceholder(block, ASTNode.METHOD_INVOCATION)); 635 } else { 636 node= fTargetNode.getAST().newExpressionStatement( 637 (Expression)fRewrite.createStringPlaceholder(block, ASTNode.METHOD_INVOCATION)); 638 } 639 } else { 640 node= null; 641 } 642 } else if (fTargetNode instanceof Expression) { 643 node= fRewrite.createStringPlaceholder(block, ASTNode.METHOD_INVOCATION); 644 645 if(needsExplicitCast(status)) { 647 AST ast= node.getAST(); 648 CastExpression castExpression= ast.newCastExpression(); 649 Type returnType= fImportRewrite.addImport(fSourceProvider.getReturnType(), ast); 650 castExpression.setType(returnType); 651 castExpression.setExpression((Expression)node); 652 node= castExpression; 653 } 654 655 if (needsParenthesis()) { 656 ParenthesizedExpression pExp= fTargetNode.getAST().newParenthesizedExpression(); 657 pExp.setExpression((Expression)node); 658 node= pExp; 659 } 660 } else { 661 node= fRewrite.createStringPlaceholder(block, ASTNode.RETURN_STATEMENT); 662 } 663 664 if (node != null) { 666 if (fTargetNode == null) { 667 fListRewrite.insertAt(node, fInsertionIndex++, textEditGroup); 668 } else { 669 fRewrite.replace(fTargetNode, node, textEditGroup); 670 } 671 } else { 672 if (fTargetNode != null) { 673 fRewrite.remove(fTargetNode, textEditGroup); 674 } 675 } 676 } 677 } 678 679 682 private boolean needsExplicitCast(RefactoringStatus status) { 683 if (fSourceProvider.returnTypeMatchesReturnExpressions()) 686 return false; 687 ASTNode parent= fTargetNode.getParent(); 688 int nodeType= parent.getNodeType(); 689 if (nodeType == ASTNode.METHOD_INVOCATION) { 690 MethodInvocation methodInvocation= (MethodInvocation)parent; 691 if(methodInvocation.getExpression() == fTargetNode) 692 return false; 693 IMethodBinding method= methodInvocation.resolveMethodBinding(); 694 if (method == null) { 695 status.addError(RefactoringCoreMessages.CallInliner_cast_analysis_error, 696 JavaStatusContext.create(fCUnit, methodInvocation)); 697 return false; 698 } 699 ITypeBinding[] parameters= method.getParameterTypes(); 700 int argumentIndex= methodInvocation.arguments().indexOf(fInvocation); 701 List returnExprs= fSourceProvider.getReturnExpressions(); 702 if (returnExprs.size() != 1) 706 return false; 707 parameters[argumentIndex]= ((Expression)returnExprs.get(0)).resolveTypeBinding(); 708 709 ITypeBinding type= ASTNodes.getReceiverTypeBinding(methodInvocation); 710 TypeBindingVisitor visitor= new AmbiguousMethodAnalyzer( 711 fTypeEnvironment, method, fTypeEnvironment.create(parameters)); 712 if(!visitor.visit(type)) { 713 return true; 714 } 715 else if(type.isInterface()) { 716 return !Bindings.visitInterfaces(type, visitor); 717 } 718 else if(Modifier.isAbstract(type.getModifiers())) { 719 return !Bindings.visitHierarchy(type, visitor); 720 } 721 else { 722 return !Bindings.visitSuperclasses(type, visitor); 724 } 725 } 726 return false; 727 } 728 729 private boolean needsParenthesis() { 730 if (!fSourceProvider.needsReturnedExpressionParenthesis()) 731 return false; 732 ASTNode parent= fTargetNode.getParent(); 733 int type= parent.getNodeType(); 734 return 735 type == ASTNode.METHOD_INVOCATION || 736 (parent instanceof Expression && type != ASTNode.ASSIGNMENT) || 737 (fSourceProvider.returnsConditionalExpression() && 738 type == ASTNode.VARIABLE_DECLARATION_FRAGMENT && 739 ((VariableDeclarationFragment)parent).getInitializer() == fTargetNode); 740 } 741 742 private VariableDeclarationStatement createLocalDeclaration(ITypeBinding type, String name, Expression initializer) { 743 String typeName= fImportRewrite.addImport(type); 744 VariableDeclarationStatement decl= (VariableDeclarationStatement)ASTNodeFactory.newStatement( 745 fInvocation.getAST(), typeName + " " + name + ";"); ((VariableDeclarationFragment)decl.fragments().get(0)).setInitializer(initializer); 747 return decl; 748 } 749 750 760 private Set crossCheckArguments(List arguments) { 761 final Set assigned= new HashSet (); 762 final Set result= new HashSet (); 763 for (Iterator iter= arguments.iterator(); iter.hasNext();) { 764 final Expression expression= (Expression) iter.next(); 765 expression.accept(new ASTVisitor() { 766 public boolean visit(Assignment node) { 767 Expression lhs= node.getLeftHandSide(); 768 if (lhs instanceof Name) { 769 IBinding binding= ((Name)lhs).resolveBinding(); 770 if (binding instanceof IVariableBinding) { 771 assigned.add(binding); 772 result.add(expression); 773 } 774 } 775 return true; 776 } 777 }); 778 } 779 for (Iterator iter= arguments.iterator(); iter.hasNext();) { 780 final Expression expression= (Expression) iter.next(); 781 if (!result.contains(expression)) { 782 expression.accept(new HierarchicalASTVisitor() { 783 public boolean visit(Name node) { 784 IBinding binding= node.resolveBinding(); 785 if (binding != null && assigned.contains(binding)) 786 result.add(expression); 787 return false; 788 } 789 }); 790 } 791 } 792 return result; 793 } 794 795 private boolean canInline(Expression actualParameter, ParameterData formalParameter) { 796 InlineEvaluator evaluator= new InlineEvaluator(formalParameter); 797 actualParameter.accept(evaluator); 798 return evaluator.getResult(); 799 } 800 801 private void initializeInsertionPoint(int nos) { 802 fInsertionIndex= -1; 803 fNeedsStatement= false; 804 ASTNode parentStatement= fInvocation instanceof Statement 806 ? fInvocation 807 : ASTNodes.getParent(fInvocation, Statement.class); 808 ASTNode container= parentStatement.getParent(); 809 int type= container.getNodeType(); 810 if (type == ASTNode.BLOCK) { 811 Block block= (Block)container; 812 fListRewrite= fRewrite.getListRewrite(block, Block.STATEMENTS_PROPERTY); 813 fInsertionIndex= fListRewrite.getRewrittenList().indexOf(parentStatement); 814 } else if (type == ASTNode.SWITCH_STATEMENT) { 815 SwitchStatement switchStatement= (SwitchStatement)container; 816 fListRewrite= fRewrite.getListRewrite(switchStatement, SwitchStatement.STATEMENTS_PROPERTY); 817 fInsertionIndex= fListRewrite.getRewrittenList().indexOf(parentStatement); 818 } else if (isControlStatement(container) || type == ASTNode.LABELED_STATEMENT) { 819 fNeedsStatement= true; 820 if (nos > 1 || needsBlockAroundDanglingIf()) { 821 Block block= fInvocation.getAST().newBlock(); 822 fInsertionIndex= 0; 823 Statement currentStatement= null; 824 switch(type) { 825 case ASTNode.LABELED_STATEMENT: 826 currentStatement= ((LabeledStatement)container).getBody(); 827 break; 828 case ASTNode.FOR_STATEMENT: 829 currentStatement= ((ForStatement)container).getBody(); 830 break; 831 case ASTNode.ENHANCED_FOR_STATEMENT: 832 currentStatement= ((EnhancedForStatement)container).getBody(); 833 break; 834 case ASTNode.WHILE_STATEMENT: 835 currentStatement= ((WhileStatement)container).getBody(); 836 break; 837 case ASTNode.DO_STATEMENT: 838 currentStatement= ((DoStatement)container).getBody(); 839 break; 840 case ASTNode.IF_STATEMENT: 841 IfStatement node= (IfStatement)container; 842 Statement thenPart= node.getThenStatement(); 843 if (fTargetNode == thenPart || ASTNodes.isParent(fTargetNode, thenPart)) { 844 currentStatement= thenPart; 845 } else { 846 currentStatement= node.getElseStatement(); 847 } 848 break; 849 } 850 Assert.isNotNull(currentStatement); 851 fRewrite.replace(currentStatement, block, null); 852 fListRewrite= fRewrite.getListRewrite(block, Block.STATEMENTS_PROPERTY); 853 if (currentStatement != fTargetNode) { 855 fListRewrite.insertLast(fRewrite.createCopyTarget(currentStatement), null); 856 } else { 857 fTargetNode= null; 860 } 861 } 862 } 863 } 866 867 private boolean needsBlockAroundDanglingIf() { 868 884 return fTargetNode.getLocationInParent() == IfStatement.THEN_STATEMENT_PROPERTY 885 && fTargetNode.getParent().getStructuralProperty(IfStatement.ELSE_STATEMENT_PROPERTY) != null 886 && fSourceProvider.isDangligIf(); 887 } 888 889 private String getContent(ASTNode node) throws BadLocationException { 890 return fBuffer.getDocument().get(node.getStartPosition(), node.getLength()); 891 } 892 893 private boolean isControlStatement(ASTNode node) { 894 int type= node.getNodeType(); 895 return type == ASTNode.IF_STATEMENT || type == ASTNode.FOR_STATEMENT || type == ASTNode.ENHANCED_FOR_STATEMENT || 896 type == ASTNode.WHILE_STATEMENT || type == ASTNode.DO_STATEMENT; 897 } 898 } 899 | Popular Tags |