Index: core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java,v
retrieving revision 1.59
diff -u -r1.59 ASTNodes.java
--- core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java 22 Mar 2004 14:54:37 -0000 1.59
+++ core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java 22 Mar 2004 17:40:13 -0000
@@ -737,4 +737,36 @@
public static int changeVisibility(int modifiers, int visibility) {
return (modifiers & CLEAR_VISIBILITY) | visibility;
}
+
+
+ public static boolean isInvocation(Expression expression) {
+ int type= expression.getNodeType();
+ return type == ASTNode.METHOD_INVOCATION || type == ASTNode.SUPER_METHOD_INVOCATION;
+ }
+
+ public static boolean isLoopStatement(ASTNode node) {
+ int nodeType= node.getNodeType();
+ return nodeType == ASTNode.FOR_STATEMENT ||
+ nodeType == ASTNode.WHILE_STATEMENT || nodeType == ASTNode.DO_STATEMENT;
+ }
+
+ public static boolean isControlStatement(ASTNode node) {
+ int nodeType= node.getNodeType();
+ return nodeType == ASTNode.IF_STATEMENT || isLoopStatement(node);
+ }
+
+ public static Statement getLoopBody(ASTNode node) {
+ int nodeType= node.getNodeType();
+ switch(nodeType) {
+ case ASTNode.FOR_STATEMENT:
+ return ((ForStatement)node).getBody();
+ case ASTNode.WHILE_STATEMENT:
+ return ((WhileStatement)node).getBody();
+ case ASTNode.DO_STATEMENT:
+ return ((DoStatement)node).getBody();
+ default:
+ Assert.isTrue(false, "Should not happen"); //$NON-NLS-1$
+ }
+ return null;
+ }
}
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/refactoring.properties
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/refactoring.properties,v
retrieving revision 1.126
diff -u -r1.126 refactoring.properties
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/refactoring.properties 15 Mar 2004 17:10:43 -0000 1.126
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/refactoring.properties 22 Mar 2004 17:40:20 -0000
@@ -163,14 +163,14 @@
InlineMethodRefactoring.SourceAnalyzer.abstract_methods=Cannot inline abstract methods.
CallInliner.receiver_type=Can\'t determine receiver\'s type.
-CallInliner.execution_flow=Can\'t inline method. Return statement in method declaration interrupts execution flow.
-CallInliner.multiDeclaration=Can\'t inline method used as an initializer in a multi fragment variable declaration.
CallInliner.simple_functions=Inlining is only possible on simple functions (consisting of a single return statement), or functions used in an assignment.
CallInliner.field_initializer_simple=In field initializers inlining is only supported for simple functions (e.g. functions consisting of a single return statement).
-CallInliner.field_initialize_new_local=Can\'t inline field initializer because new local variable is required.
CallInliner.field_initialize_write_parameter=Can\'t inline field initializer because one of the method parameters is used as an assignment target and will require new local variable.
CallInliner.field_initialize_self_reference=Can\'t inline method. Method references the field to be initialized.
CallInliner.constructors=Can\'t inline a constructor invocation that is used as a class instance creation.
+CallInliner.return_in_loop=Can't inline a method that has a return statement inside a loop.
+CallInliner.return_in_switch=Can't inline a method having a return statement inside a switch.
+CallInliner.partial_return=Can't inline a method if not all execution paths have return statements.
#-- SEF ------------------------------------------------------
SelfEncapsulateField.AccessAnalyzer.encapsulate_read_access=Encapsulate read access
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallContext.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallContext.java,v
retrieving revision 1.8
diff -u -r1.8 CallContext.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallContext.java 10 Sep 2003 15:14:43 -0000 1.8
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallContext.java 22 Mar 2004 17:40:22 -0000
@@ -19,13 +19,11 @@
public String receiver;
public boolean receiverIsStatic;
public CodeScopeBuilder.Scope scope;
- public int callMode;
public ImportRewrite importer;
-
- public CallContext(CodeScopeBuilder.Scope s, int cm, ImportRewrite i) {
+
+ public CallContext(CodeScopeBuilder.Scope s, ImportRewrite i) {
super();
scope= s;
- callMode= cm;
importer= i;
}
}
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallInliner.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallInliner.java,v
retrieving revision 1.43
diff -u -r1.43 CallInliner.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallInliner.java 16 Mar 2004 08:52:41 -0000 1.43
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallInliner.java 22 Mar 2004 17:40:23 -0000
@@ -26,21 +26,24 @@
import java.util.List;
import org.eclipse.text.edits.MultiTextEdit;
-import org.eclipse.text.edits.TextEdit;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.resources.IFile;
import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ArrayCreation;
+import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.CastExpression;
+import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.DoStatement;
import org.eclipse.jdt.core.dom.Expression;
+import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.ForStatement;
@@ -54,11 +57,15 @@
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.ParenthesizedExpression;
+import org.eclipse.jdt.core.dom.PrimitiveType;
+import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.SuperFieldAccess;
+import org.eclipse.jdt.core.dom.SuperMethodInvocation;
+import org.eclipse.jdt.core.dom.SwitchStatement;
import org.eclipse.jdt.core.dom.ThisExpression;
-import org.eclipse.jdt.core.dom.VariableDeclaration;
+import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
import org.eclipse.jdt.core.dom.WhileStatement;
@@ -89,7 +96,7 @@
import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry;
public class CallInliner {
-
+
private ICompilationUnit fCUnit;
private ImportRewrite fImportEdit;
private TextBuffer fBuffer;
@@ -101,17 +108,18 @@
private ASTNode fInvocation;
private ASTRewrite fRewriter;
- private List fStatements;
- private int fInsertionIndex;
- private boolean fNeedsStatement;
- private ASTNode fTargetNode;
private FlowContext fFlowContext;
private FlowInfo fFlowInfo;
private CodeScopeBuilder.Scope fInvocationScope;
- private boolean fFieldInitializer;
- private List fLocals;
private CallContext fContext;
-
+
+ private List fStatementsBefore;
+ private List fStatementReplacement;
+ private List fStatementsAfter;
+ private Expression fInvocationReplacement;
+ private boolean fRemoveInvocation;
+ private Statement fInvocationStatement;
+
private class InlineEvaluator extends HierarchicalASTVisitor {
private ParameterData fFormalArgument;
private boolean fResult;
@@ -216,7 +224,7 @@
fBuffer= TextBuffer.acquire(getFile(fCUnit));
fSourceProvider= provider;
fImportEdit= new ImportRewrite(fCUnit, settings);
- fLocals= new ArrayList(3);
+ fStatementsBefore= new ArrayList();
}
public void dispose() {
@@ -231,10 +239,6 @@
return fImportEdit;
}
- public ASTNode getTargetNode() {
- return fTargetNode;
- }
-
public void initialize(BodyDeclaration declaration) {
fBodyDeclaration= declaration;
fRootScope= CodeScopeBuilder.perform(declaration, fSourceProvider.getDeclaration().resolveBinding());
@@ -250,17 +254,15 @@
public RefactoringStatus initialize(ASTNode invocation, int severity) {
RefactoringStatus result= new RefactoringStatus();
fInvocation= invocation;
- fLocals= new ArrayList(3);
checkMethodDeclaration(result, severity);
if (result.getSeverity() >= severity)
return result;
initializeRewriter();
- initializeTargetNode();
flowAnalysis();
- fContext= new CallContext(fInvocationScope, fTargetNode.getNodeType(), fImportEdit);
+ fContext= new CallContext(fInvocationScope, fImportEdit);
computeRealArguments();
computeReceiver();
@@ -277,7 +279,6 @@
ASTNode parentField= ASTNodes.getParent(fInvocation, ASTNode.FIELD_DECLARATION);
if(parentField != null) {
fRewriter= new ASTRewrite(parentField);
- fFieldInitializer= true;
}
else {
ASTNode parentBlock= ASTNodes.getParent(fInvocation, ASTNode.BLOCK);
@@ -286,16 +287,6 @@
}
}
- private void initializeTargetNode() {
- ASTNode parent= fInvocation.getParent();
- int nodeType= parent.getNodeType();
- if (nodeType == ASTNode.EXPRESSION_STATEMENT || nodeType == ASTNode.RETURN_STATEMENT) {
- fTargetNode= parent;
- } else {
- fTargetNode= fInvocation;
- }
- }
-
// the checks depend on invocation context and therefore can't be done in SourceAnalyzer
private void checkMethodDeclaration(RefactoringStatus result, int severity) {
MethodDeclaration methodDeclaration= fSourceProvider.getDeclaration();
@@ -304,20 +295,12 @@
if (fInvocation.getNodeType() != ASTNode.CONSTRUCTOR_INVOCATION && methodDeclaration.isConstructor()) {
result.addEntry(new RefactoringStatusEntry(
severity, //$NON-NLS-1$
- RefactoringCoreMessages.getString("CallInliner.constructors"), JavaStatusContext.create(fCUnit, fInvocation)));
+ RefactoringCoreMessages.getString("CallInliner.constructors"), JavaStatusContext.create(fCUnit, fInvocation))); //$NON-NLS-1$
}
}
private void checkInvocationContext(RefactoringStatus result, int severity) {
if (ASTNodes.getParent(fInvocation, FieldDeclaration.class) != null) {
- // it is allowed to inline a method used for field initialization
- // if only it consists of single return statement
- if(fSourceProvider.getNumberOfStatements() > 1) {
- addEntry(result,
- RefactoringCoreMessages.getString("CallInliner.field_initializer_simple"), //$NON-NLS-1$
- RefactoringStatusCodes.INLINE_METHOD_FIELD_INITIALIZER, severity);
- return;
- }
int argumentsCount= fContext.arguments.length;
for (int i= 0; i < argumentsCount; i++) {
ParameterData parameter= fSourceProvider.getParameterData(i);
@@ -328,12 +311,6 @@
return;
}
}
- if(fLocals.size() > 0) {
- addEntry(result,
- RefactoringCoreMessages.getString("CallInliner.field_initialize_new_local"), //$NON-NLS-1$
- RefactoringStatusCodes.INLINE_METHOD_FIELD_INITIALIZER, severity);
- return;
- }
// verify that the field is not referenced by the initializer method
VariableDeclarationFragment variable= (VariableDeclarationFragment)ASTNodes.getParent(fInvocation, ASTNode.VARIABLE_DECLARATION_FRAGMENT);
if(fSourceProvider.isVariableReferenced(variable.resolveBinding())) {
@@ -343,14 +320,6 @@
return;
}
}
- if (fSourceProvider.isExecutionFlowInterrupted()) {
- VariableDeclaration vDecl= (VariableDeclaration)ASTNodes.getParent(fInvocation, VariableDeclaration.class);
- if (vDecl != null) {
- addEntry(result, RefactoringCoreMessages.getString("CallInliner.execution_flow"), //$NON-NLS-1$
- RefactoringStatusCodes.INLINE_METHOD_LOCAL_INITIALIZER, severity);
- return;
- }
- }
if (fInvocation.getNodeType() == ASTNode.METHOD_INVOCATION) {
Expression exp= ((MethodInvocation)fInvocation).getExpression();
if (exp != null && exp.resolveTypeBinding() == null) {
@@ -359,59 +328,6 @@
return;
}
}
- int nodeType= fTargetNode.getNodeType();
- if (nodeType == ASTNode.EXPRESSION_STATEMENT) {
- if (fSourceProvider.isExecutionFlowInterrupted()) {
- addEntry(result, RefactoringCoreMessages.getString("CallInliner.execution_flow"), //$NON-NLS-1$
- RefactoringStatusCodes.INLINE_METHOD_EXECUTION_FLOW, severity);
- return;
- }
- } else if (nodeType == ASTNode.METHOD_INVOCATION) {
- ASTNode parent= fTargetNode.getParent();
- if (parent.getNodeType() == ASTNode.ASSIGNMENT || isSingleDeclaration(parent)) {
- // this is ok
- } else if (isMultiDeclarationFragment(parent)) {
- if (!fSourceProvider.isSimpleFunction()) {
- addEntry(result, RefactoringCoreMessages.getString("CallInliner.multiDeclaration"), //$NON-NLS-1$
- RefactoringStatusCodes.INLINE_METHOD_INITIALIZER_IN_FRAGEMENT, severity);
- return;
- }
- } else if (fSourceProvider.getNumberOfStatements() > 1 ) {
- addEntry(result, RefactoringCoreMessages.getString("CallInliner.simple_functions"), //$NON-NLS-1$
- RefactoringStatusCodes.INLINE_METHOD_ONLY_SIMPLE_FUNCTIONS, severity);
- return;
- } else if (!fSourceProvider.isSimpleFunction()) {
- addEntry(result, RefactoringCoreMessages.getString("CallInliner.execution_flow"), //$NON-NLS-1$
- RefactoringStatusCodes.INLINE_METHOD_EXECUTION_FLOW, severity);
- return;
- }
- }
- }
-
- private static boolean isMultiDeclarationFragment(ASTNode node) {
- int nodeType= node.getNodeType();
- if (nodeType == ASTNode.VARIABLE_DECLARATION_FRAGMENT) {
- node= node.getParent();
- if (node.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT) {
- VariableDeclarationStatement vs= (VariableDeclarationStatement)node;
- return vs.fragments().size() > 1;
- }
- }
- return false;
- }
-
- private static boolean isSingleDeclaration(ASTNode node) {
- int type= node.getNodeType();
- if (type == ASTNode.SINGLE_VARIABLE_DECLARATION)
- return true;
- if (type == ASTNode.VARIABLE_DECLARATION_FRAGMENT) {
- node= node.getParent();
- if (node.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT) {
- VariableDeclarationStatement vs= (VariableDeclarationStatement)node;
- return vs.fragments().size() == 1;
- }
- }
- return false;
}
private void addEntry(RefactoringStatus result, String message, int code, int severity) {
@@ -423,8 +339,8 @@
}
private void flowAnalysis() {
- fInvocationScope= fRootScope.findScope(fTargetNode.getStartPosition(), fTargetNode.getLength());
- fInvocationScope.setCursor(fTargetNode.getStartPosition());
+ fInvocationScope= fRootScope.findScope(fInvocation.getStartPosition(), fInvocation.getLength());
+ fInvocationScope.setCursor(fInvocation.getStartPosition());
fFlowContext= new FlowContext(0, fNumberOfLocals + 1);
fFlowContext.setConsiderAccessMode(true);
fFlowContext.setComputeMode(FlowContext.ARGUMENTS);
@@ -440,20 +356,21 @@
}
}
- public TextEdit perform() throws CoreException {
+ public MultiTextEdit perform(RefactoringStatus status) throws CoreException {
- String[] blocks= fSourceProvider.getCodeBlocks(fContext);
- if(!fFieldInitializer) {
- initializeInsertionPoint(fSourceProvider.getNumberOfStatements() + fLocals.size());
- }
+ ASTRewrite sourceRewriter= fSourceProvider.prepareForInlining(fContext);
+ analyzeInvocationContext(sourceRewriter, status);
- addNewLocals();
- replaceCall(blocks);
+ MultiTextEdit edit= null;
+ if(!status.hasFatalError()) {
+ replaceCall();
+
+ edit= new MultiTextEdit();
+ fRewriter.rewriteNode(fBuffer, edit);
+ fRewriter.removeModifications();
+ }
- MultiTextEdit result= new MultiTextEdit();
- fRewriter.rewriteNode(fBuffer, result);
- fRewriter.removeModifications();
- return result;
+ return edit;
}
private void computeRealArguments() {
@@ -463,15 +380,15 @@
Expression expression= (Expression)arguments.get(i);
ParameterData parameter= fSourceProvider.getParameterData(i);
if (canInline(expression, parameter)) {
- realArguments[i] = getContent(expression);
+ realArguments[i]= getContent(expression, fBuffer);
// fixes bugs #35905, #38471
if(expression instanceof CastExpression || expression instanceof ArrayCreation) {
- realArguments[i] = "(" + realArguments[i] + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ realArguments[i]= "(" + realArguments[i] + ")"; //$NON-NLS-1$ //$NON-NLS-2$
}
} else {
String name= fInvocationScope.createName(parameter.getName(), true);
realArguments[i]= name;
- fLocals.add(createLocalDeclaration(
+ fStatementsBefore.add(createVariableDeclaration(
parameter.getTypeBinding(), name,
(Expression)fRewriter.createCopy(expression)));
}
@@ -494,7 +411,7 @@
case 0:
// Make sure we evaluate the current receiver. Best is to assign to
// local.
- fLocals.add(createLocalDeclaration(
+ fStatementsBefore.add(createVariableDeclaration(
receiver.resolveTypeBinding(),
fInvocationScope.createName("r", true), //$NON-NLS-1$
(Expression)fRewriter.createCopy(receiver)));
@@ -504,7 +421,7 @@
return;
default:
String local= fInvocationScope.createName("r", true); //$NON-NLS-1$
- fLocals.add(createLocalDeclaration(
+ fStatementsBefore.add(createVariableDeclaration(
receiver.resolveTypeBinding(),
local,
(Expression)fRewriter.createCopy(receiver)));
@@ -513,111 +430,707 @@
}
}
- private void addNewLocals() {
- for (Iterator iter= fLocals.iterator(); iter.hasNext();) {
- ASTNode element= (ASTNode)iter.next();
- fRewriter.markAsInserted(element);
- fStatements.add(fInsertionIndex++, element);
+ private boolean canInline(Expression actualParameter, ParameterData formalParameter) {
+ InlineEvaluator evaluator= new InlineEvaluator(formalParameter);
+ actualParameter.accept(evaluator);
+ return evaluator.getResult();
+ }
+
+ private void analyzeInvocationContext(ASTRewrite sourceRewriter, RefactoringStatus status) throws CoreException {
+
+ fInvocationStatement = (Statement)ASTNodes.getParent(fInvocation, Statement.class);
+ // direct invocation parent, not necessarily a statement
+ ASTNode invocationParent= fInvocation.getParent();
+ int invocationParentType= invocationParent.getNodeType();
+
+ // order of following if statements matters
+ if (invocationParentType == ASTNode.RETURN_STATEMENT) {
+ // if method invocation is used as a return expression it can be inlined always
+ List statements= new ArrayList(fSourceProvider.getDeclaration().getBody().statements());
+ List blocks= fSourceProvider.getSourceContent(statements);
+ fStatementReplacement= createPlaceholders(blocks, fRewriter, ASTRewrite.STATEMENT);
+ }
+ else {
+ if(verifySourceFlow(status));
+ else if(fInvocationStatement != null && fInvocationStatement.getNodeType() == ASTNode.FOR_STATEMENT) {
+ inlineInForStatement(status, sourceRewriter);
+ }
+ else if(fInvocationStatement != null && fInvocationStatement.getNodeType() == ASTNode.WHILE_STATEMENT) {
+ inlineInLoopCondition(status, sourceRewriter);
+ }
+ else if(fInvocationStatement != null && fInvocationStatement.getNodeType() == ASTNode.DO_STATEMENT) {
+ inlineInLoopCondition(status, sourceRewriter);
+ }
+ else if (!fSourceProvider.hasReturnValue()) {
+ inlineVoidMethod(sourceRewriter, invocationParentType);
+ }
+ else if (invocationParentType == ASTNode.EXPRESSION_STATEMENT) {
+ inlineInExpressionStatement(sourceRewriter);
+ }
+ else if(invocationParentType == ASTNode.VARIABLE_DECLARATION_FRAGMENT) {
+ inlineInVariableDeclaration(status, sourceRewriter);
+ }
+ else {
+ // covers not only expressions, but also all other statements except loops: if, assert etc.
+ inlineInExpression(sourceRewriter);
+ }
}
}
- private void replaceCall(String[] blocks) throws CoreException {
- // Inline empty body
- if (blocks.length == 0) {
- if (fNeedsStatement) {
- fRewriter.markAsReplaced(fTargetNode, fTargetNode.getAST().newEmptyStatement(), null);
- } else {
- fRewriter.markAsRemoved(fTargetNode, null);
- }
+ /**
+ * @param status refactoring status filled with detailed error information
+ * @return true
if problem was encoutered otherwise false
+ */
+ private boolean verifySourceFlow(RefactoringStatus status) {
+ FlowInfo sourceFlow= fSourceProvider.getFlowInfo();
+ if(sourceFlow.hasReturningControlStatement(FlowInfo.LOOP_STATEMENTS)) {
+ status.addFatalError(
+ RefactoringCoreMessages.getString("CallInliner.return_in_loop"), //$NON-NLS-1$
+ JavaStatusContext.create(fCUnit, fInvocation));
+ }
+ else if(sourceFlow.hasReturningControlStatement(FlowInfo.SWITCH_STATEMENT)) {
+ status.addFatalError(
+ RefactoringCoreMessages.getString("CallInliner.return_in_switch"), //$NON-NLS-1$
+ JavaStatusContext.create(fCUnit, fInvocation));
+ }
+ else if(sourceFlow.hasAnyPartialReturn()) {
+ status.addFatalError(
+ RefactoringCoreMessages.getString("CallInliner.partial_return"), //$NON-NLS-1$
+ JavaStatusContext.create(fCUnit, fInvocation));
+ }
+ return status.hasFatalError();
+ }
+
+ /**
+ * Inlines a method invoked from loop condition checking.
+ *
+ * Invocation examples: while(inlineMe()); while {} do(inlineMe() == 10); for(;
+ * inlineMe().size() < 10; );
+ *
+ * @param sourceRewriter source rewriter
+ * @throws CoreException
+ */
+ private void inlineInLoopCondition(RefactoringStatus result, ASTRewrite sourceRewriter) throws CoreException {
+
+ List statements= new ArrayList(fSourceProvider.getDeclaration().getBody().statements());
+
+ if (fSourceProvider.isSimpleFunction()) {
+ // if inlined function is simple - consists of a sinlge return statement,
+ // then it will be inlined directly into invocation place
+ List returnStatements= fSourceProvider.getReturnStatements();
+ ReturnStatement rs= (ReturnStatement)returnStatements.get(0);
+ statements.clear();
+ statements.add(rs.getExpression());
+ List blocks= fSourceProvider.getSourceContent(statements);
+ List placeholders= createPlaceholders(blocks, fRewriter, ASTRewrite.EXPRESSION);
+ fInvocationReplacement= (Expression)placeholders.get(0);
} else {
- ASTNode node= null;
- for (int i= 0; i < blocks.length - 1; i++) {
- node= fRewriter.createPlaceholder(blocks[i], ASTRewrite.STATEMENT);
- fRewriter.markAsInserted(node);
- fStatements.add(fInsertionIndex++, node);
- }
- String block= blocks[blocks.length - 1];
- // We can inline a call where the declaration is a function and the call itself
- // is a statement. In this case we have to create a temporary variable if the
- // returned expression must be evaluated.
- if (fContext.callMode == ASTNode.EXPRESSION_STATEMENT && fSourceProvider.hasReturnValue()) {
- if (fSourceProvider.mustEvaluateReturnedExpression()) {
- if (fSourceProvider.returnValueNeedsLocalVariable()) {
- node= createLocalDeclaration(
- fSourceProvider.getReturnType(),
- fInvocationScope.createName(fSourceProvider.getMethodName(), true),
- (Expression)fRewriter.createPlaceholder(block, ASTRewrite.EXPRESSION));
+ addEntry(result, RefactoringCoreMessages.getString("CallInliner.simple_functions"), //$NON-NLS-1$
+ RefactoringStatusCodes.INLINE_METHOD_ONLY_SIMPLE_FUNCTIONS, RefactoringStatus.FATAL);
+ }
+ }
+
+ /**
+ * Inlines methods invoked from for
statement.
+ *
+ * Invocation examples: for(; inlineMe().size() < 10; ); for(int i= inlineMe; true; );
+ * for(; true; inlineMe());
+ *
+ * @param result
+ * @param sourceRewriter
+ * @throws CoreException
+ */
+ private void inlineInForStatement(RefactoringStatus result, ASTRewrite sourceRewriter) throws CoreException {
+
+ ASTNode invocationParent= fInvocation.getParent();
+ ForStatement parentStatement= (ForStatement)fInvocationStatement;
+ if (isChild(fInvocation, parentStatement.initializers())) {
+ int invocationParentType= invocationParent.getNodeType();
+ if (invocationParent instanceof Expression) {
+ inlineInExpression(sourceRewriter);
+ } else if (invocationParentType == ASTNode.VARIABLE_DECLARATION_FRAGMENT) {
+ inlineInForLoopVariableDeclaration(sourceRewriter);
+ } else if (invocationParentType == ASTNode.FOR_STATEMENT) {
+ // copy statements because this list can be modified later in this method
+ List statements= new ArrayList(fSourceProvider.getDeclaration().getBody().statements());
+
+ VariableDeclarationStatement variableDeclaration= removeReturns(sourceRewriter, statements);
+ if (fSourceProvider.isSimpleFunction() && variableDeclaration == null) {
+ if (statements.size() == 1) {
+ statements.clear();
+ List returnStatements= fSourceProvider.getReturnStatements();
+ ReturnStatement returnStatement= (ReturnStatement)returnStatements.get(0);
+ statements.add(returnStatement.getExpression());
+ List blocks= fSourceProvider.getSourceContent(statements);
+ fInvocationReplacement= (Expression)createPlaceholders(blocks, fRewriter, ASTRewrite.EXPRESSION).get(0);
} else {
- node= fTargetNode.getAST().newExpressionStatement(
- (Expression)fRewriter.createPlaceholder(block, ASTRewrite.EXPRESSION));
+ fRemoveInvocation= true;
+ }
+ } else {
+ List blocks= fSourceProvider.getSourceContent(statements);
+ fStatementsBefore= createPlaceholders(blocks, fRewriter, ASTRewrite.STATEMENT);
+ if (variableDeclaration != null) {
+ fStatementsBefore.add(0, variableDeclaration);
}
+ fRemoveInvocation= true;
+ }
+ }
+ } else if (isChild(fInvocation, parentStatement.updaters())) {
+ int invocationParentType= invocationParent.getNodeType();
+ if (invocationParent instanceof Expression) {
+ if (fSourceProvider.isSimpleFunction()) {
+ inlineInExpression(sourceRewriter);
+ Assert.isTrue(fStatementsBefore.size() == 0);
} else {
- node= null;
+ List statements= fSourceProvider.getDeclaration().getBody().statements();
+
+ VariableDeclarationStatement variableDeclaration= createResultVariable(fInvocation.getAST());
+ VariableDeclarationFragment fragment= (VariableDeclarationFragment)variableDeclaration.fragments().get(0);
+ AST sourceAst= sourceRewriter.getAST();
+ SimpleName variableName= (SimpleName)ASTNode.copySubtree(sourceAst, fragment.getName());
+ replaceReturnsWithAssignments(sourceRewriter, variableName);
+ List blocks= fSourceProvider.getSourceContent(statements);
+ fStatementsAfter= createPlaceholders(blocks, fRewriter, ASTRewrite.STATEMENT);
+ fStatementsBefore.add(variableDeclaration);
}
- } else if (fTargetNode instanceof Expression) {
- node= fRewriter.createPlaceholder(block, ASTRewrite.EXPRESSION);
-
- // fixes bug #24941
- if(needsExplicitCast()) {
- AST ast= node.getAST();
- CastExpression castExpression= ast.newCastExpression();
- ITypeBinding returnType= fSourceProvider.getReturnType();
- fImportEdit.addImport(returnType);
- castExpression.setType(ASTNodeFactory.newType(ast, returnType, false));
- castExpression.setExpression((Expression)node);
- node= castExpression;
- }
-
- if (needsParenthesis()) {
- ParenthesizedExpression pExp= fTargetNode.getAST().newParenthesizedExpression();
- pExp.setExpression((Expression)node);
- node= pExp;
+ } else if (invocationParentType == ASTNode.FOR_STATEMENT) {
+ // copy statements because this list can be modified later in this method
+ List statements= new ArrayList(fSourceProvider.getDeclaration().getBody().statements());
+
+ VariableDeclarationStatement variableDeclaration= removeReturns(sourceRewriter, statements);
+ if (fSourceProvider.isSimpleFunction() && variableDeclaration == null) {
+ if (statements.size() == 1) {
+ statements.clear();
+ List returnStatements= fSourceProvider.getReturnStatements();
+ ReturnStatement returnStatement= (ReturnStatement)returnStatements.get(0);
+ statements.add(returnStatement.getExpression());
+ List blocks= fSourceProvider.getSourceContent(statements);
+ fInvocationReplacement= (Expression)createPlaceholders(blocks, fRewriter, ASTRewrite.EXPRESSION).get(0);
+ } else {
+ fRemoveInvocation= true;
+ }
+ } else {
+ List blocks= fSourceProvider.getSourceContent(statements);
+ fStatementsAfter= createPlaceholders(blocks, fRewriter, ASTRewrite.STATEMENT);
+ if (variableDeclaration != null) {
+ fStatementsBefore.add(0, variableDeclaration);
+ }
+ fRemoveInvocation= true;
}
- } else {
- node= fRewriter.createPlaceholder(block, ASTRewrite.STATEMENT);
}
-
- // Now replace the target node with the source node
+ } else {
+ inlineInLoopCondition(result, sourceRewriter);
+ }
+ }
+
+ private void inlineInForLoopVariableDeclaration(ASTRewrite sourceRewriter) throws CoreException {
+
+ List returnStatements= fSourceProvider.getReturnStatements();
+ List statements= new ArrayList(fSourceProvider.getDeclaration().getBody().statements());
+
+ if (returnStatements.size() == 1 && isLastReturn(statements)) {
+ inlineInVariableDeclaration(sourceRewriter, statements);
+ } else {
+ // method invocation in variable declaration fragment can only be used as an
+ // initializer
+ VariableDeclarationStatement declarationStatement= replaceReturnsWithAssignments(sourceRewriter);
+ VariableDeclarationFragment fragment= (VariableDeclarationFragment)(declarationStatement.fragments().get(0));
+ List blocks= fSourceProvider.getSourceContent(statements);
+ fStatementsBefore= createPlaceholders(blocks, fRewriter, ASTRewrite.STATEMENT);
+ fStatementsBefore.add(0, declarationStatement);
+ fInvocationReplacement= fragment.getName();
+ }
+ }
+
+ private void inlineInVariableDeclaration(RefactoringStatus result, ASTRewrite sourceRewriter) throws CoreException {
+
+ List statements= new ArrayList(fSourceProvider.getDeclaration().getBody().statements());
+ inlineInVariableDeclaration(sourceRewriter, statements);
+
+ if (ASTNodes.getParent(fInvocation, FieldDeclaration.class) != null) {
+ // for field declarations only invocation replacement is allowed
+ int numberOfStatements= 0;
+ if (fStatementsBefore != null) {
+ numberOfStatements+= fStatementsBefore.size();
+ }
+ if (fStatementsAfter != null) {
+ numberOfStatements+= fStatementsAfter.size();
+ }
+ if (fStatementReplacement != null) {
+ numberOfStatements+= fStatementReplacement.size();
+ }
+ if (numberOfStatements > 0) {
+ addEntry(result, RefactoringCoreMessages.getString("CallInliner.field_initializer_simple"), //$NON-NLS-1$
+ RefactoringStatusCodes.INLINE_METHOD_FIELD_INITIALIZER, RefactoringStatus.FATAL);
+ }
+ }
+ }
+
+ private void inlineInVariableDeclaration(ASTRewrite sourceRewriter, List statements) throws CoreException {
+
+ List returnStatements= fSourceProvider.getReturnStatements();
+
+ if (returnStatements.size() == 1 && isLastReturn(statements)) {
+ int numberOfStatements= statements.size();
+ List nodes= new ArrayList(statements);
+ ReturnStatement rs= (ReturnStatement)returnStatements.get(0);
+ int index= nodes.indexOf(rs);
+ if (index != -1) {
+ nodes.remove(index);
+ statements.remove(index);
+ --numberOfStatements;
+ }
+ nodes.add(rs.getExpression());
+ List blocks= fSourceProvider.getSourceContent(nodes);
+
+ fInvocationReplacement= (Expression)fRewriter.createPlaceholder(blocks.remove(numberOfStatements).toString(),
+ ASTRewrite.EXPRESSION);
+ fStatementsBefore= createPlaceholders(blocks, fRewriter, ASTRewrite.STATEMENT);
+ } else {
+ // method invocation in variable declaration fragment can only be used as an
+ // initializer
+ AST sourceAST= sourceRewriter.getAST();
+ ASTNode invocationParent= fInvocation.getParent();
+ VariableDeclarationFragment fragment= (VariableDeclarationFragment)invocationParent;
+ fInvocationReplacement= createDefaultInitializer(sourceAST, resolveInvocationTypeBinding());
+ SimpleName variable= fragment.getName();
+ replaceReturnsWithAssignments(sourceRewriter, variable);
+
+ List blocks= fSourceProvider.getSourceContent(statements);
+ fStatementsAfter= createPlaceholders(blocks, fRewriter, ASTRewrite.STATEMENT);
+ }
+ }
+
+ private void inlineInExpression(ASTRewrite sourceRewriter) throws CoreException {
+
+ List returnStatements= fSourceProvider.getReturnStatements();
+ List statements= fSourceProvider.getDeclaration().getBody().statements();
+
+ if (returnStatements.size() == 1 && isLastReturn(statements)) {
+ AST sourceAst= sourceRewriter.getAST();
+ ReturnStatement rs= (ReturnStatement)returnStatements.get(0);
+ Expression returnExpression= rs.getExpression();
+ Expression node= null;
+ // fixes bug #24941
+ if (needsExplicitCast(returnExpression)) {
+ CastExpression castExpression= sourceAst.newCastExpression();
+ Type returnType= fSourceProvider.getDeclaration().getReturnType();
+ Type type= createType(sourceAst, returnType.resolveBinding());
+ castExpression.setType(type);
+ castExpression.setExpression((Expression)sourceRewriter.createCopy(returnExpression));
+ node= castExpression;
+ }
+ if (needsParenthesis()) {
+ ParenthesizedExpression parenthesizedExpression= sourceAst.newParenthesizedExpression();
+ if (node != null) {
+ parenthesizedExpression.setExpression(node);
+ } else {
+ parenthesizedExpression.setExpression((Expression)sourceRewriter.createCopy(returnExpression));
+ }
+ node= parenthesizedExpression;
+ }
if (node != null) {
- if (fTargetNode == null) {
- fRewriter.markAsInserted(node);
- fStatements.add(fInsertionIndex++, node);
+ sourceRewriter.markAsReplaced(returnExpression, node, null);
+ }
+ // copying the list of statements to make a single call to getSourceContent
+ // method that will return source of all statements and return expression
+ List nodes= new ArrayList(statements);
+ // replace last return statement with its expression
+ nodes.set(nodes.size() - 1, returnExpression);
+ // get content of all statements and return expression in a single call
+ List blocks= fSourceProvider.getSourceContent(nodes);
+ // last string in the list corresponds to the only return expression
+ fInvocationReplacement= (Expression)fRewriter.createPlaceholder((String)blocks.remove(blocks.size() - 1),
+ ASTRewrite.EXPRESSION);
+ // all other strings are statements of the inlined method body
+ fStatementsBefore= createPlaceholders(blocks, fRewriter, ASTRewrite.STATEMENT);
+ } else {
+ VariableDeclarationStatement variableDeclaration= replaceReturnsWithAssignments(sourceRewriter);
+
+ List blocks= fSourceProvider.getSourceContent(statements);
+ fStatementsBefore= createPlaceholders(blocks, fRewriter, ASTRewrite.STATEMENT);
+ fStatementsBefore.add(0, variableDeclaration);
+
+ VariableDeclarationFragment fragment= (VariableDeclarationFragment)variableDeclaration.fragments().get(0);
+ fInvocationReplacement= fragment.getName();
+ }
+ }
+
+ private void inlineInExpressionStatement(ASTRewrite sourceRewriter) throws CoreException {
+
+ List statements= new ArrayList(fSourceProvider.getDeclaration().getBody().statements());
+
+ VariableDeclarationStatement variableDeclaration= removeReturns(sourceRewriter, statements);
+
+ List blocks= fSourceProvider.getSourceContent(statements);
+ fStatementReplacement= createPlaceholders(blocks, fRewriter, ASTRewrite.STATEMENT);
+ if (variableDeclaration != null) {
+ fStatementReplacement.add(0, variableDeclaration);
+ }
+ }
+
+ /**
+ * Inlines a method with no return value.
+ *
+ * @param sourceRewriter source method rewriter
+ * @param invocationParentType type of direct invocation parent
+ * @throws CoreException
+ */
+ private void inlineVoidMethod(ASTRewrite sourceRewriter, int invocationParentType) throws CoreException {
+
+ List returnStatements= fSourceProvider.getReturnStatements();
+ List statements= fSourceProvider.getDeclaration().getBody().statements();
+
+ for (Iterator it= returnStatements.iterator(); it.hasNext();) {
+ ReturnStatement rs= (ReturnStatement)it.next();
+ ASTNode parent= rs.getParent();
+ // if parent of return statement is a control statements(if, for, do, while)
+ // then empty statement is required in place of the return
+ if (parent != null && ASTNodes.isControlStatement(parent)) {
+ AST ast= fInvocation.getAST();
+ sourceRewriter.markAsReplaced(rs, ast.newEmptyStatement(), null);
+ } else {
+ // otheriwse it is safe to remove return statement completely
+ sourceRewriter.markAsRemoved(rs, null);
+ statements.remove(rs);
+ }
+ }
+
+ List blocks= fSourceProvider.getSourceContent(statements);
+ List placeholders= createPlaceholders(blocks, fRewriter, ASTRewrite.STATEMENT);
+ if (placeholders.size() > 0) {
+ if (invocationParentType == ASTNode.EXPRESSION_STATEMENT) {
+ fStatementReplacement= placeholders;
+ } else if (fInvocation.getNodeType() == ASTNode.CONSTRUCTOR_INVOCATION) {
+ fStatementReplacement= placeholders;
+ } else {
+ fStatementsBefore= placeholders;
+ fRemoveInvocation= true;
+ }
+ } else {
+ fRemoveInvocation= true;
+ }
+ }
+
+ private VariableDeclarationStatement removeReturns(ASTRewrite sourceRewriter, List statements) {
+
+ VariableDeclarationStatement variableDeclaration= null;
+ SimpleName variableName= null;
+ AST sourceAst= sourceRewriter.getAST();
+ List returnStatements= fSourceProvider.getReturnStatements();
+ for (Iterator it= returnStatements.iterator(); it.hasNext();) {
+ ReturnStatement returnStatement= (ReturnStatement)it.next();
+ Expression returnExpression= returnStatement.getExpression();
+ // check if return expression must be evaluated
+ if (ASTNodes.isLiteral(returnExpression) || returnExpression instanceof Name) {
+ ASTNode parent= returnStatement.getParent();
+ // if parent of return statement is a control statements(if, for, do,
+ // while)
+ // then empty statement is required in place of the return
+ if (parent != null && ASTNodes.isControlStatement(parent)) {
+ sourceRewriter.markAsReplaced(returnStatement, sourceAst.newEmptyStatement(), null);
} else {
- fRewriter.markAsReplaced(fTargetNode, node, null);
+ // otheriwse it is safe to remove return statement completely
+ sourceRewriter.markAsRemoved(returnStatement, null);
+ statements.remove(returnStatement);
}
} else {
- if (fTargetNode != null) {
- fRewriter.markAsRemoved(fTargetNode, null);
+ // check if return expression needs a local variable
+ if (ASTNodes.isInvocation(returnExpression) || returnExpression instanceof ClassInstanceCreation) {
+ ExpressionStatement statement= sourceAst.newExpressionStatement((Expression)sourceRewriter
+ .createCopy(returnExpression));
+ sourceRewriter.markAsReplaced(returnStatement, statement, null);
+ } else {
+ if (variableName == null) {
+ variableDeclaration= createResultVariable(fInvocation.getAST());
+ VariableDeclarationFragment variableFragment= (VariableDeclarationFragment)variableDeclaration
+ .fragments().get(0);
+ variableName= (SimpleName)ASTNode.copySubtree(sourceAst, variableFragment.getName());
+ }
+ replaceReturnWithAssignment(sourceRewriter, variableName, returnStatement);
+ }
+ }
+ }
+ return variableDeclaration;
+ }
+
+ /**
+ * The method replaces every return statement with assignment to local variable.
+ *
+ * @param sourceRewriter rewriter to be used for the replacement
+ * @return
+ */
+ private VariableDeclarationStatement replaceReturnsWithAssignments(ASTRewrite sourceRewriter) {
+ VariableDeclarationStatement variableDeclaration= createResultVariable(fInvocation.getAST());
+ VariableDeclarationFragment fragment= (VariableDeclarationFragment)variableDeclaration.fragments().get(0);
+ AST sourceAst= sourceRewriter.getRootNode().getAST();
+ SimpleName variableName= (SimpleName)ASTNode.copySubtree(sourceAst, fragment.getName());
+ replaceReturnsWithAssignments(sourceRewriter, variableName);
+ return variableDeclaration;
+ }
+
+ private void replaceReturnsWithAssignments(ASTRewrite sourceRewriter, SimpleName variable) {
+ List returnStatements= fSourceProvider.getReturnStatements();
+ for (Iterator it= returnStatements.iterator(); it.hasNext();) {
+ ReturnStatement returnStatement= (ReturnStatement)it.next();
+ // every return is substituted with an assignement to the variable.
+ // prior to that method initializeTarget has replaced variable
+ // initializer with a default value (0 or null).
+ replaceReturnWithAssignment(sourceRewriter, variable, returnStatement);
+ }
+ }
+
+ private void replaceReturnWithAssignment(ASTRewrite sourceRewriter, SimpleName variable, ReturnStatement returnStatement) {
+ AST ast= sourceRewriter.getAST();
+ Expression returnExpression= returnStatement.getExpression();
+ Assignment assignment= ast.newAssignment();
+ assignment.setLeftHandSide((Expression)ASTNode.copySubtree(ast, variable));
+ assignment.setRightHandSide((Expression)sourceRewriter.createCopy(returnExpression));
+ sourceRewriter.markAsReplaced(returnStatement, ast.newExpressionStatement(assignment), null);
+ }
+
+ private Expression createDefaultInitializer(AST ast, ITypeBinding typeBinding) {
+ if(typeBinding.isPrimitive()) {
+ if(typeBinding.getName().equals(PrimitiveType.BOOLEAN.toString())) {
+ return ast.newBooleanLiteral(false);
+ }
+ else {
+ return ast.newNumberLiteral();
+ }
+ }
+ return ast.newNullLiteral();
+ }
+
+ private List initializeInsertionPoint(Statement invocationStatement, boolean before, boolean replacement, boolean after) {
+ List statements= null;
+ ASTNode container= invocationStatement.getParent();
+ int type= container.getNodeType();
+ if (type == ASTNode.BLOCK) {
+ statements= ((Block)container).statements();
+ } else if (type == ASTNode.SWITCH_STATEMENT) {
+ statements= ((SwitchStatement)container).statements();
+ } else if (ASTNodes.isControlStatement(container)) {
+ int numberOfStatements= 0;
+ if(before && fStatementsBefore != null) {
+ numberOfStatements+= fStatementsBefore.size();
+ }
+ if(after && fStatementsAfter != null) {
+ numberOfStatements+= fStatementsAfter.size();
+ }
+ if(replacement) {
+ if(fStatementReplacement != null) {
+ numberOfStatements+= fStatementReplacement.size();
+ }
+ else {
+ ++numberOfStatements;
+ }
+ }
+ if (numberOfStatements > 1) {
+ Block block= fInvocation.getAST().newBlock();
+ statements= block.statements();
+ Statement currentStatement= null;
+ switch(type) {
+ case ASTNode.FOR_STATEMENT:
+ currentStatement= ((ForStatement)container).getBody();
+ break;
+ case ASTNode.WHILE_STATEMENT:
+ currentStatement= ((WhileStatement)container).getBody();
+ break;
+ case ASTNode.DO_STATEMENT:
+ currentStatement= ((DoStatement)container).getBody();
+ break;
+ case ASTNode.IF_STATEMENT:
+ IfStatement node= (IfStatement)container;
+ Statement thenPart= node.getThenStatement();
+ if (ASTNodes.isParent(fInvocation, thenPart)) {
+ currentStatement= thenPart;
+ } else {
+ currentStatement= node.getElseStatement();
+ }
+ break;
+ }
+ Assert.isNotNull(currentStatement);
+ if (replacement && fStatementReplacement == null) {
+ if (currentStatement == invocationStatement) {
+ if(invocationStatement.getNodeType() != ASTNode.EMPTY_STATEMENT) {
+ statements.add(fRewriter.createCopy(currentStatement));
+ }
+ }
+ }
+ fRewriter.markAsReplaced(currentStatement, block, null);
+ }
+ }
+ return statements;
+ }
+
+ private void replaceCall() {
+
+ List statements= null;
+ Statement invocationStatement= null;
+ if(fInvocation instanceof Statement) {
+ // the case of constructor invocation
+ invocationStatement= (Statement)fInvocation;
+ }
+ else {
+ invocationStatement= (Statement)ASTNodes.getParent(fInvocation, Statement.class);
+ }
+
+ int insertionIndex= 0;
+ if(invocationStatement != null) {
+ // 'after' statements are processed separately for loops
+ statements= initializeInsertionPoint(invocationStatement, true, true,
+ !ASTNodes.isLoopStatement(invocationStatement));
+ if(statements != null) {
+ insertionIndex= statements.indexOf(invocationStatement);
+ if(insertionIndex == -1) {
+ insertionIndex= 0;
+ }
+ }
+ }
+ if (fStatementsBefore != null) {
+ insertionIndex= insertStatements(statements,
+ fStatementsBefore, insertionIndex);
+ }
+ if (fStatementReplacement != null) {
+ if(fStatementReplacement.size() == 0) {
+ fStatementReplacement= null;
+ fRemoveInvocation= true;
+ }
+ }
+ if (fStatementReplacement != null) {
+ if(!fStatementReplacement.isEmpty()) {
+ if(statements == null || statements.contains(invocationStatement)) {
+ ASTNode node= (ASTNode)fStatementReplacement.remove(0);
+ fRewriter.markAsReplaced(invocationStatement, node, null);
+ ++insertionIndex;
+ }
+ insertionIndex= insertStatements(statements,
+ fStatementReplacement, insertionIndex);
+ }
+ }
+ else if (fInvocationReplacement != null) {
+ fRewriter.markAsReplaced(fInvocation, fInvocationReplacement, null);
+ fInvocationReplacement= null;
+ insertionIndex++;
+ }
+ else if(fRemoveInvocation) {
+ ASTNode parent= fInvocation.getParent();
+ if(parent.getNodeType() == ASTNode.EXPRESSION_STATEMENT) {
+ ASTNode parentParent= parent.getParent();
+ if (ASTNodes.isControlStatement(parentParent)) {
+ // if parent of return statement is a control statements(if, for, do, while)
+ // then empty statement is required in place of the return
+ AST ast= fInvocation.getAST();
+ fRewriter.markAsReplaced(parent, ast.newEmptyStatement(), null);
+ } else {
+ // otheriwse it is safe to remove return statement completely
+ fRewriter.markAsRemoved(parent, null);
+ }
+ }
+ else {
+ fRewriter.markAsRemoved(fInvocation, null);
+ }
+ }
+ if (fStatementsAfter != null) {
+ ASTNode replaceNode= null;
+ if(invocationStatement != null && ASTNodes.isLoopStatement(invocationStatement)) {
+ // 'after' statements for loops are processed separately;
+ // they are appended to the end of loop's body
+ Statement body= ASTNodes.getLoopBody(invocationStatement);
+ if(body.getNodeType() == ASTNode.BLOCK) {
+ Block block= (Block)body;
+ statements= block.statements();
+ insertionIndex= statements.size();
+ }
+ else {
+ statements= initializeInsertionPoint(body, false, false, true);
+ if(statements != null) {
+ insertionIndex= statements.size();
+ }
+ else {
+ replaceNode= body;
+ }
}
}
+ if(statements != null) {
+ insertionIndex= insertStatements(statements,
+ fStatementsAfter, insertionIndex);
+ }
+ else {
+ fRewriter.markAsReplaced(replaceNode, (ASTNode)fStatementsAfter.get(0), null);
+ }
+ }
+ }
+
+ private int insertStatements(List statements, List statementsToInsert, int index) {
+ for (Iterator it= statementsToInsert.iterator(); it.hasNext();) {
+ ASTNode node= (ASTNode)it.next();
+ fRewriter.markAsInserted(node);
+ statements.add(index++, node);
}
+ return index;
+ }
+
+ private Type createType(AST ast, ITypeBinding typeBinding) {
+ String typeName= fImportEdit.addImport(typeBinding);
+ return ASTNodeFactory.newType(ast, typeName);
+ }
+
+ /**
+ * Creates a local variable to keep result of the method invocation.
+ *
+ * @param ast
+ * @return
+ */
+ private VariableDeclarationStatement createResultVariable(AST ast) {
+ return createResultVariable(createDefaultInitializer(
+ ast, fSourceProvider.getReturnType()));
+ }
+
+ /**
+ * Creates a local variable to keep result of the method invocation.
+ *
+ * @param initializer variable initializer
+ * @return
+ */
+ private VariableDeclarationStatement createResultVariable(Expression initializer) {
+ return createVariableDeclaration(
+ fSourceProvider.getReturnType(),
+ fRootScope.createName(fSourceProvider.getMethodName(), true),
+ initializer);
+ }
+
+ private VariableDeclarationStatement createVariableDeclaration(ITypeBinding typeBinding, String name, Expression initializer) {
+ AST ast= initializer.getAST();
+ Type type= createType(ast, typeBinding);
+ VariableDeclarationFragment fragment= ast.newVariableDeclarationFragment();
+ fragment.setName(ast.newSimpleName(name));
+ fragment.setInitializer(initializer);
+ VariableDeclarationStatement statement= ast.newVariableDeclarationStatement(fragment);
+ statement.setType(type);
+ return statement;
}
/**
* @return true
if explicit cast is needed otherwise false
* @throws JavaModelException
*/
- private boolean needsExplicitCast() {
+ private boolean needsExplicitCast(Expression returnExpression) {
// if the return type of the method is the same as the type of the
// returned expression then we don't need an explicit cast.
- if (fSourceProvider.returnTypeMatchesReturnExpressions())
- return false;
- ASTNode parent= fTargetNode.getParent();
+ ITypeBinding returnType= fSourceProvider.getReturnType();
+ if (Bindings.equals(returnType, returnExpression.resolveTypeBinding()))
+ return false;
+ ASTNode parent= fInvocation.getParent();
int nodeType= parent.getNodeType();
if (nodeType == ASTNode.METHOD_INVOCATION) {
MethodInvocation methodInvocation= (MethodInvocation)parent;
- if(methodInvocation.getExpression() == fTargetNode)
+ if(methodInvocation.getExpression() == fInvocation)
return false;
IMethodBinding method= methodInvocation.resolveMethodBinding();
ITypeBinding[] parameters= method.getParameterTypes();
int argumentIndex= methodInvocation.arguments().indexOf(fInvocation);
- List returnExprs= fSourceProvider.getReturnExpressions();
- // it is infered that only methods consisting of a single
- // return statement can be inlined as parameters in other
- // method invocations
- if (returnExprs.size() != 1)
- return false;
- parameters[argumentIndex]= ((Expression)returnExprs.get(0)).resolveTypeBinding();
+ parameters[argumentIndex]= returnExpression.resolveTypeBinding();
ITypeBinding type= ASTNodes.getReceiverTypeBinding(methodInvocation);
TypeBindingVisitor visitor= new AmbiguousMethodAnalyzer(method, parameters);
@@ -641,90 +1154,51 @@
private boolean needsParenthesis() {
if (!fSourceProvider.needsReturnedExpressionParenthesis())
return false;
- ASTNode parent= fTargetNode.getParent();
+ ASTNode parent= fInvocation.getParent();
int type= parent.getNodeType();
- return type == ASTNode.METHOD_INVOCATION || (parent instanceof Expression && type != ASTNode.ASSIGNMENT);
- }
-
- private VariableDeclarationStatement createLocalDeclaration(ITypeBinding type, String name, Expression initializer) {
- String typeName= fImportEdit.addImport(type);
- VariableDeclarationStatement decl= (VariableDeclarationStatement)ASTNodeFactory.newStatement(
- fInvocation.getAST(), typeName + " " + name + ";"); //$NON-NLS-1$ //$NON-NLS-2$
- ((VariableDeclarationFragment)decl.fragments().get(0)).setInitializer(initializer);
- return decl;
+ return type == ASTNode.METHOD_INVOCATION ||
+ (parent instanceof Expression && type != ASTNode.ASSIGNMENT);
}
- private boolean canInline(Expression actualParameter, ParameterData formalParameter) {
- InlineEvaluator evaluator= new InlineEvaluator(formalParameter);
- actualParameter.accept(evaluator);
- return evaluator.getResult();
- }
-
- private void initializeInsertionPoint(int nos) {
- fStatements= null;
- fInsertionIndex= -1;
- fNeedsStatement= false;
- ASTNode parentStatement= ASTNodes.getParent(fInvocation, Statement.class);
- ASTNode container= parentStatement.getParent();
- int type= container.getNodeType();
- if (type == ASTNode.BLOCK) {
- fStatements= ((Block)container).statements();
- fInsertionIndex= fStatements.indexOf(parentStatement);
- } else if (isControlStatement(container)) {
- fNeedsStatement= true;
- if (nos > 1) {
- Block block= fInvocation.getAST().newBlock();
- fStatements= block.statements();
- fInsertionIndex= 0;
- Statement currentStatement= null;
- switch(type) {
- case ASTNode.FOR_STATEMENT:
- currentStatement= ((ForStatement)container).getBody();
- break;
- case ASTNode.WHILE_STATEMENT:
- currentStatement= ((WhileStatement)container).getBody();
- break;
- case ASTNode.DO_STATEMENT:
- currentStatement= ((DoStatement)container).getBody();
- break;
- case ASTNode.IF_STATEMENT:
- IfStatement node= (IfStatement)container;
- Statement thenPart= node.getThenStatement();
- if (fTargetNode == thenPart || ASTNodes.isParent(fTargetNode, thenPart)) {
- currentStatement= thenPart;
- } else {
- currentStatement= node.getElseStatement();
- }
- break;
- }
- Assert.isNotNull(currentStatement);
- // The method to be inlined is not the body of the control statement.
- if (currentStatement != fTargetNode) {
- ASTNode copy= fRewriter.createCopy(currentStatement);
- fStatements.add(copy);
- } else {
- // We can't replace a copy with something else. So we
- // have to insert all statements to be inlined.
- fTargetNode= null;
- }
- fRewriter.markAsReplaced(currentStatement, block, null);
+ private static List createPlaceholders(List blocks, ASTRewrite rewriter, int nodeType) {
+ for (int i= 0; i < blocks.size(); i++) {
+ String block= blocks.get(i).toString();
+ if(block != null) {
+ blocks.set(i, rewriter.createPlaceholder(block, nodeType));
}
}
- // We only insert one new statement or we delete the existing call.
- // So there is no need to have an insertion index.
+ return blocks;
+ }
+
+ private static String getContent(ASTNode node, TextBuffer buffer) {
+ return InlineMethodRefactoring.getContent(node.getStartPosition(), node.getLength(), buffer);
}
- private String getContent(ASTNode node) {
- return fBuffer.getContent(node.getStartPosition(), node.getLength());
+ private ITypeBinding resolveInvocationTypeBinding() {
+ if(fInvocation instanceof MethodInvocation) {
+ return ((MethodInvocation)fInvocation).resolveTypeBinding();
+ }
+ else if(fInvocation instanceof SuperMethodInvocation) {
+ return ((SuperMethodInvocation)fInvocation).resolveTypeBinding();
+ }
+ return null;
}
- private static IFile getFile(ICompilationUnit cu) throws CoreException {
+ private static IFile getFile(ICompilationUnit cu) {
return (IFile)WorkingCopyUtil.getOriginal(cu).getResource();
}
-
- private boolean isControlStatement(ASTNode node) {
- int type= node.getNodeType();
- return type == ASTNode.IF_STATEMENT || type == ASTNode.FOR_STATEMENT ||
- type == ASTNode.WHILE_STATEMENT || type == ASTNode.DO_STATEMENT;
+
+ private static boolean isLastReturn(List statements) {
+ return statements.get(statements.size() - 1) instanceof ReturnStatement;
+ }
+
+ private static boolean isChild(ASTNode node, List parents) {
+ for (Iterator iter = parents.iterator(); iter.hasNext();) {
+ ASTNode parent= (ASTNode) iter.next();
+ if(parent == node || ASTNodes.isParent(node, parent)) {
+ return true;
+ }
+ }
+ return false;
}
}
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/InlineMethodRefactoring.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/InlineMethodRefactoring.java,v
retrieving revision 1.49
diff -u -r1.49 InlineMethodRefactoring.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/InlineMethodRefactoring.java 19 Mar 2004 20:52:54 -0000 1.49
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/InlineMethodRefactoring.java 22 Mar 2004 17:40:24 -0000
@@ -57,8 +57,12 @@
import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange;
import org.eclipse.jdt.internal.corext.refactoring.changes.ValidationStateChange;
+import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
+import org.eclipse.jdt.internal.corext.textmanipulation.TextBuffer;
+import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
+import org.eclipse.jdt.internal.corext.util.Strings;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
@@ -218,8 +222,10 @@
if (result.hasFatalError())
break;
if (result.getSeverity() < fTargetProvider.getStatusSeverity()) {
+ MultiTextEdit edit= inliner.perform(result);
+ if (result.hasFatalError())
+ break;
added= true;
- TextEdit edit= inliner.perform();
change.addTextEditGroup(
new TextEditGroup(RefactoringCoreMessages.getString("InlineMethodRefactoring.edit.inline"), new TextEdit[] { edit })); //$NON-NLS-1$
root.addChild(edit);
@@ -282,20 +288,6 @@
return null;
}
- source= JavaModelUtil.toWorkingCopy(source);
-
- /*if (!source.isWorkingCopy()) {
- // try to find a working copy if exists.
- // XXX: This is a layer breaker - should not access jdt.ui
- IWorkingCopy[] workingCopies= JavaUI.getSharedWorkingCopiesOnClasspath();
- for (int i= 0; i < workingCopies.length; i++) {
- IWorkingCopy wcopy= workingCopies[i];
- if (source.equals(wcopy.getOriginalElement())) {
- source= (ICompilationUnit)wcopy;
- break;
- }
- }
- }*/
declaration= (MethodDeclaration)JavaElementMapper.perform(method, MethodDeclaration.class);
if (declaration != null) {
return new SourceProvider(source, declaration);
@@ -306,7 +298,7 @@
}
private static ASTNode getTargetNode(ICompilationUnit unit, int offset, int length) {
- CompilationUnit root= AST.parseCompilationUnit(unit, true);
+ CompilationUnit root= new RefactoringASTParser(AST.LEVEL_2_0).parse(unit, true);
ASTNode node= null;
try {
node= checkNode(NodeFinder.perform(root, offset, length, unit));
@@ -395,6 +387,7 @@
"InlineMethodRefactoring.checking.implements.error", //$NON-NLS-1$
pm);
}
+
private void checkTypes(RefactoringStatus result, IMethod method, IType[] types, String key, IProgressMonitor pm) {
pm.beginTask("", types.length); //$NON-NLS-1$
for (int i= 0; i < types.length; i++) {
@@ -407,4 +400,11 @@
}
}
}
+
+ /* package*/ static String getContent(int offset, int length, TextBuffer buffer) {
+ String content= buffer.getContent(offset, length);
+ String lines[]= Strings.convertIntoLines(content);
+ Strings.trimIndentation(lines, CodeFormatterUtil.getTabWidth(), false);
+ return Strings.concatenate(lines, buffer.getLineDelimiter());
+ }
}
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceAnalyzer.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceAnalyzer.java,v
retrieving revision 1.20
diff -u -r1.20 SourceAnalyzer.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceAnalyzer.java 16 Mar 2004 08:52:41 -0000 1.20
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceAnalyzer.java 22 Mar 2004 17:40:25 -0000
@@ -39,13 +39,11 @@
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.QualifiedName;
-import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.ThisExpression;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
-
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.dom.LocalVariableIndex;
import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
@@ -77,14 +75,7 @@
private class ActivationAnalyzer extends ASTVisitor {
public RefactoringStatus status= new RefactoringStatus();
- private ASTNode fLastNode= getLastNode();
private IMethodBinding fBinding= getBinding();
- public boolean visit(ReturnStatement node) {
- if (node != fLastNode) {
- fInterruptedExecutionFlow= true;
- }
- return true;
- }
public boolean visit(TypeDeclaration node) {
return false;
}
@@ -120,12 +111,6 @@
}
return true;
}
- private ASTNode getLastNode() {
- List statements= fDeclaration.getBody().statements();
- if (statements.size() == 0)
- return null;
- return (ASTNode)statements.get(statements.size() - 1);
- }
private IMethodBinding getBinding() {
return fDeclaration.resolveBinding();
}
@@ -244,8 +229,8 @@
private Map fNames;
private List fImplicitReceivers;
private List fTypes;
- private boolean fInterruptedExecutionFlow;
-
+ private FlowInfo fFlowInfo;
+
public SourceAnalyzer(ICompilationUnit unit, MethodDeclaration declaration) {
super();
fCUnit= unit;
@@ -261,10 +246,6 @@
fTypes= new ArrayList(2);
}
- public boolean isExecutionFlowInterrupted() {
- return fInterruptedExecutionFlow;
- }
-
public RefactoringStatus checkActivation() throws JavaModelException {
RefactoringStatus result= new RefactoringStatus();
if (!fCUnit.isStructureKnown()) {
@@ -289,9 +270,6 @@
ActivationAnalyzer analyzer= new ActivationAnalyzer();
fDeclaration.accept(analyzer);
result.merge(analyzer.status);
- if (!result.hasFatalError()) {
-
- }
return result;
}
@@ -304,16 +282,20 @@
context.setConsiderAccessMode(true);
context.setComputeMode(FlowContext.MERGE);
InOutFlowAnalyzer flowAnalyzer= new InOutFlowAnalyzer(context);
- FlowInfo info= flowAnalyzer.perform(getStatements());
+ fFlowInfo= flowAnalyzer.perform(getStatements());
for (Iterator iter= fDeclaration.parameters().iterator(); iter.hasNext();) {
SingleVariableDeclaration element= (SingleVariableDeclaration) iter.next();
IVariableBinding binding= element.resolveBinding();
ParameterData data= (ParameterData)element.getProperty(ParameterData.PROPERTY);
- data.setAccessMode(info.getAccessMode(context, binding));
+ data.setAccessMode(fFlowInfo.getAccessMode(context, binding));
}
}
+ public FlowInfo getFlowInfo() {
+ return fFlowInfo;
+ }
+
public Collection getUsedNames() {
return fNames.values();
}
@@ -325,6 +307,7 @@
public List getUsedTypes() {
return fTypes;
}
+
private ASTNode[] getStatements() {
List statements= fDeclaration.getBody().statements();
return (ASTNode[]) statements.toArray(new ASTNode[statements.size()]);
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceProvider.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceProvider.java,v
retrieving revision 1.33
diff -u -r1.33 SourceProvider.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceProvider.java 16 Mar 2004 08:52:41 -0000 1.33
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceProvider.java 22 Mar 2004 17:40:25 -0000
@@ -22,6 +22,7 @@
import java.util.Iterator;
import java.util.List;
+import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.RangeMarker;
import org.eclipse.text.edits.TextEdit;
@@ -33,6 +34,8 @@
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
+import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.IMethodBinding;
@@ -45,46 +48,47 @@
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
-
-import org.eclipse.jface.text.IRegion;
-import org.eclipse.jface.text.Region;
+import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.internal.corext.codemanipulation.ImportRewrite;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.dom.ASTRewrite;
import org.eclipse.jdt.internal.corext.dom.Bindings;
import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder;
+import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowInfo;
import org.eclipse.jdt.internal.corext.textmanipulation.TextBuffer;
import org.eclipse.jdt.internal.corext.textmanipulation.TextBufferEditor;
-import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
-import org.eclipse.jdt.internal.corext.util.Strings;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
public class SourceProvider {
+ private static class ReturnCollector extends ASTVisitor {
+ private List fNodes;
+ public ReturnCollector() {
+ fNodes= new ArrayList();
+ }
+ public List getNodes() {
+ return fNodes;
+ }
+ public boolean visit(ReturnStatement node) {
+ fNodes.add(node);
+ return false;
+ }
+ public boolean visit(AnonymousClassDeclaration node) {
+ return false;
+ }
+ public boolean visit(TypeDeclaration node) {
+ return false;
+ }
+ }
+
private ICompilationUnit fCUnit;
private TextBuffer fBuffer;
private MethodDeclaration fDeclaration;
private ASTRewrite fRewriter;
private SourceAnalyzer fAnalyzer;
- private boolean fMustEvalReturnedExpression;
- private boolean fReturnValueNeedsLocalVariable;
- private List fReturnExpressions;
+ private List fReturnStatements;
- private class ReturnAnalyzer extends ASTVisitor {
- public boolean visit(ReturnStatement node) {
- Expression expression= node.getExpression();
- if (!(ASTNodes.isLiteral(expression) || expression instanceof Name)) {
- fMustEvalReturnedExpression= true;
- }
- if (Invocations.isInvocation(expression) || expression instanceof ClassInstanceCreation) {
- fReturnValueNeedsLocalVariable= false;
- }
- fReturnExpressions.add(expression);
- return false;
- }
- }
-
public SourceProvider(ICompilationUnit unit, MethodDeclaration declaration) {
super();
fCUnit= unit;
@@ -97,8 +101,6 @@
}
fRewriter= new ASTRewrite(fDeclaration);
fAnalyzer= new SourceAnalyzer(fCUnit, fDeclaration);
- fReturnValueNeedsLocalVariable= true;
- fReturnExpressions= new ArrayList();
}
public RefactoringStatus checkActivation() throws JavaModelException {
@@ -108,17 +110,11 @@
public void initialize() throws JavaModelException {
fBuffer= TextBuffer.create(fCUnit.getBuffer().getContents());
fAnalyzer.analyzeParameters();
- if (hasReturnValue()) {
- ASTNode last= getLastStatement();
- if (last != null) {
- ReturnAnalyzer analyzer= new ReturnAnalyzer();
- last.accept(analyzer);
- }
- }
- }
-
- public boolean isExecutionFlowInterrupted() {
- return fAnalyzer.isExecutionFlowInterrupted();
+
+ Block methodBody= fDeclaration.getBody();
+ ReturnCollector returnCollector = new ReturnCollector();
+ methodBody.accept(returnCollector);
+ fReturnStatements= returnCollector.getNodes();
}
static class VariableReferenceFinder extends ASTVisitor {
@@ -155,14 +151,6 @@
return binding.getReturnType() != fDeclaration.getAST().resolveWellKnownType("void"); //$NON-NLS-1$
}
- public boolean mustEvaluateReturnedExpression() {
- return fMustEvalReturnedExpression;
- }
-
- public boolean returnValueNeedsLocalVariable() {
- return fReturnValueNeedsLocalVariable;
- }
-
public int getNumberOfStatements() {
return fDeclaration.getBody().statements().size();
}
@@ -182,24 +170,18 @@
return fDeclaration.getName().getIdentifier();
}
+ public FlowInfo getFlowInfo() {
+ return fAnalyzer.getFlowInfo();
+ }
+
public ITypeBinding getReturnType() {
return fDeclaration.resolveBinding().getReturnType();
}
- public List getReturnExpressions() {
- return fReturnExpressions;
+ public List getReturnStatements() {
+ return fReturnStatements;
}
-
- public boolean returnTypeMatchesReturnExpressions() {
- ITypeBinding returnType= getReturnType();
- for (Iterator iter= fReturnExpressions.iterator(); iter.hasNext();) {
- Expression expression= (Expression)iter.next();
- if (!Bindings.equals(returnType, expression.resolveTypeBinding()))
- return false;
- }
- return true;
- }
-
+
public ParameterData getParameterData(int index) {
SingleVariableDeclaration decl= (SingleVariableDeclaration)fDeclaration.parameters().get(index);
return (ParameterData)decl.getProperty(ParameterData.PROPERTY);
@@ -229,63 +211,14 @@
rewriter.removeModifications();
return result;
}
-
- public String[] getCodeBlocks(CallContext context) throws CoreException {
+
+ public ASTRewrite prepareForInlining(CallContext context) {
replaceParameterWithExpression(context.arguments);
updateImplicitReceivers(context);
makeNamesUnique(context.scope);
updateTypes(context);
- List ranges= null;
- if (hasReturnValue()) {
- if (context.callMode == ASTNode.RETURN_STATEMENT) {
- ranges= getStatementRanges();
- } else {
- ranges= getExpressionRanges();
- }
- } else {
- ASTNode last= getLastStatement();
- if (last != null && last.getNodeType() == ASTNode.RETURN_STATEMENT) {
- ranges= getReturnStatementRanges();
- } else {
- ranges= getStatementRanges();
- }
- }
-
- MultiTextEdit dummy= new MultiTextEdit();
- fRewriter.rewriteNode(fBuffer, dummy);
-
- int size= ranges.size();
- RangeMarker[] markers= new RangeMarker[size];
- for (int i= 0; i < markers.length; i++) {
- IRegion range= (IRegion)ranges.get(i);
- markers[i]= new RangeMarker(range.getOffset(), range.getLength());
- }
- int split;
- if (size <= 1) {
- split= Integer.MAX_VALUE;
- } else {
- IRegion region= (IRegion)ranges.get(0);
- split= region.getOffset() + region.getLength();
- }
- TextEdit[] edits= dummy.removeChildren();
- for (int i= 0; i < edits.length; i++) {
- TextEdit edit= edits[i];
- int pos= edit.getOffset() >= split ? 1 : 0;
- markers[pos].addChild(edit);
- }
- MultiTextEdit root= new MultiTextEdit();
- root.addChildren(markers);
- TextBufferEditor editor= new TextBufferEditor(fBuffer);
- editor.add(root);
- UndoEdit undo= editor.performEdits(null);
- String[] result= getBlocks(markers);
- // It is faster to undo the changes than coping the buffer over and over again.
- TextBufferEditor undoEditor= new TextBufferEditor(fBuffer);
- undoEditor.add(undo);
- undoEditor.performEdits(null);
- fRewriter.removeModifications();
- return result;
+ return fRewriter;
}
private void replaceParameterWithExpression(String[] expressions) {
@@ -366,78 +299,75 @@
return (ASTNode)statements.get(statements.size() - 1);
}
- private List getReturnStatementRanges() {
- List result= new ArrayList(1);
- List statements= fDeclaration.getBody().statements();
- int size= statements.size();
- if (size <= 1)
- return result;
- result.add(createRange(statements, size - 2));
- return result;
+ public TextBuffer getBuffer() {
+ return fBuffer;
}
- private List getStatementRanges() {
- List result= new ArrayList(1);
- List statements= fDeclaration.getBody().statements();
- int size= statements.size();
- if (size == 0)
- return result;
- result.add(createRange(statements, size - 1));
- return result;
- }
-
- private List getExpressionRanges() {
- List result= new ArrayList(2);
- List statements= fDeclaration.getBody().statements();
- ReturnStatement rs= null;
- int size= statements.size();
- ASTNode node;
- switch (size) {
- case 0:
- return result;
- case 1:
- node= (ASTNode)statements.get(0);
- if (node.getNodeType() == ASTNode.RETURN_STATEMENT) {
- rs= (ReturnStatement)node;
- } else {
- result.add(new Region(node.getStartPosition(), node.getLength()));
- }
- break;
- default: {
- node= (ASTNode)statements.get(size - 1);
- if (node.getNodeType() == ASTNode.RETURN_STATEMENT) {
- result.add(createRange(statements, size - 2));
- rs= (ReturnStatement)node;
- } else {
- result.add(createRange(statements, size - 1));
- }
- break;
+ public List getSourceContent(List nodes) throws CoreException {
+
+ int size= nodes.size();
+ // the same list is used for markers and then for strings
+ List result= new ArrayList(size);
+
+ TextBuffer buffer= getBuffer();
+ MultiTextEdit dummy= new MultiTextEdit();
+ fRewriter.rewriteNode(buffer, dummy);
+ TextEdit[] edits= dummy.removeChildren();
+
+ MultiTextEdit root= new MultiTextEdit();
+ for (Iterator it= nodes.iterator(); it.hasNext();) {
+ ASTNode node= (ASTNode)it.next();
+ RangeMarker marker= createMarker(node);
+ mergeEdits(marker, edits);
+ try {
+ root.addChild(marker);
+ } catch (MalformedTreeException e) {
+ // ignore
}
+ // add marker to resulting list
+ result.add(marker);
}
- if (rs != null) {
- Expression exp= rs.getExpression();
- result.add(new Region(exp.getStartPosition(), exp.getLength()));
+
+ UndoEdit undo= performEdit(buffer, root);
+
+ for (int i= 0; i < size; i++) {
+ RangeMarker marker= (RangeMarker)result.get(i);
+ // replace marker with node's new content
+ result.set(i, getContent(marker, buffer));
}
+
+ // it is faster to undo the changes than coping the buffer over and over again
+ performEdit(buffer, undo);
+ fRewriter.removeModifications();
return result;
}
- private IRegion createRange(List statements, int end) {
- int start= ((ASTNode)statements.get(0)).getStartPosition();
- ASTNode last= (ASTNode)statements.get(end);
- int length = last.getStartPosition() - start + last.getLength();
- IRegion range= new Region(start, length);
- return range;
- }
-
- private String[] getBlocks(RangeMarker[] markers) {
- String[] result= new String[markers.length];
- for (int i= 0; i < markers.length; i++) {
- RangeMarker marker= markers[i];
- String content= fBuffer.getContent(marker.getOffset(), marker.getLength());
- String lines[]= Strings.convertIntoLines(content);
- Strings.trimIndentation(lines, CodeFormatterUtil.getTabWidth(), false);
- result[i]= Strings.concatenate(lines, fBuffer.getLineDelimiter());
+ private static UndoEdit performEdit(TextBuffer buffer, TextEdit edit) throws CoreException {
+ TextBufferEditor editor= new TextBufferEditor(buffer);
+ editor.add(edit);
+ return editor.performEdits(null);
+ }
+
+ private static UndoEdit performEdit(TextBuffer buffer, UndoEdit edit) throws CoreException {
+ TextBufferEditor editor= new TextBufferEditor(buffer);
+ editor.add(edit);
+ return editor.performEdits(null);
+ }
+
+ private static RangeMarker createMarker(ASTNode node) {
+ return new RangeMarker(node.getStartPosition(), node.getLength());
+ }
+
+ private static void mergeEdits(TextEdit dest, TextEdit[] edits) {
+ for (int j= 0; j < edits.length; j++) {
+ TextEdit edit= edits[j];
+ if(dest.covers(edit)) {
+ dest.addChild(edit);
+ }
}
- return result;
}
+
+ private static String getContent(RangeMarker marker, TextBuffer buffer) {
+ return InlineMethodRefactoring.getContent(marker.getOffset(), marker.getLength(), buffer);
+ }
}
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/TargetProvider.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/TargetProvider.java,v
retrieving revision 1.13
diff -u -r1.13 TargetProvider.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/TargetProvider.java 16 Mar 2004 08:52:41 -0000 1.13
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/TargetProvider.java 22 Mar 2004 17:40:25 -0000
@@ -45,6 +45,7 @@
import org.eclipse.jdt.internal.corext.dom.Bindings;
import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine;
import org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringScopeFactory;
+import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
abstract class TargetProvider {
@@ -65,7 +66,7 @@
// constructor invocation is not an expression but a statement
public abstract ASTNode[] getInvocations(BodyDeclaration declaration, IProgressMonitor pm);
- public abstract RefactoringStatus checkActivation() throws JavaModelException;
+ public abstract RefactoringStatus checkActivation();
public abstract int getStatusSeverity();
@@ -131,7 +132,7 @@
fIterated= true;
return new ASTNode[] { fInvocation };
}
- public RefactoringStatus checkActivation() throws JavaModelException {
+ public RefactoringStatus checkActivation() {
return new RefactoringStatus();
}
public int getStatusSeverity() {
@@ -273,7 +274,7 @@
return data.getInvocations();
}
- public RefactoringStatus checkActivation() throws JavaModelException {
+ public RefactoringStatus checkActivation() {
return new RefactoringStatus();
}
@@ -305,7 +306,7 @@
}
public BodyDeclaration[] getAffectedBodyDeclarations(ICompilationUnit unit, IProgressMonitor pm) {
- ASTNode root= AST.parseCompilationUnit(unit, true);
+ ASTNode root= new RefactoringASTParser(AST.LEVEL_2_0).parse(unit, true);
InvocationFinder finder= new InvocationFinder(fMethod.resolveBinding());
root.accept(finder);
fCurrentBodies= finder.result;
@@ -321,7 +322,7 @@
return data.getInvocations();
}
- public RefactoringStatus checkActivation() throws JavaModelException {
+ public RefactoringStatus checkActivation() {
return new RefactoringStatus();
}
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/DoWhileFlowInfo.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/DoWhileFlowInfo.java,v
retrieving revision 1.3
diff -u -r1.3 DoWhileFlowInfo.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/DoWhileFlowInfo.java 10 Mar 2003 23:27:15 -0000 1.3
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/DoWhileFlowInfo.java 22 Mar 2004 17:40:25 -0000
@@ -17,11 +17,15 @@
public void mergeAction(FlowInfo info, FlowContext context) {
if (info == null)
return;
-
+
fActionBranches= info.branches();
-
+
assign(info);
-
+
+ if(info.hasAnyReturn()) {
+ setReturningControlStatements(DO_STATEMENT);
+ }
+
if (fActionBranches && fReturnKind == VALUE_RETURN) {
fReturnKind= PARTIAL_RETURN;
}
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/FlowInfo.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/FlowInfo.java,v
retrieving revision 1.11
diff -u -r1.11 FlowInfo.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/FlowInfo.java 27 May 2003 14:41:50 -0000 1.11
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/FlowInfo.java 22 Mar 2004 17:40:26 -0000
@@ -23,6 +23,15 @@
public abstract class FlowInfo {
+ // Flags to specify control statements containing return statements
+ public static final int IF_STATEMENT= 1 << 0;
+ public static final int FOR_STATEMENT= 1 << 1;
+ public static final int WHILE_STATEMENT= 1 << 2;
+ public static final int DO_STATEMENT= 1 << 3;
+ public static final int TRY_STATEMENT= 1 << 4;
+ public static final int SWITCH_STATEMENT= 1 << 5;
+ public static final int LOOP_STATEMENTS= FOR_STATEMENT | WHILE_STATEMENT | DO_STATEMENT;
+
// Return statement handling.
protected static final int NOT_POSSIBLE= 0;
protected static final int UNDEFINED= 1;
@@ -37,7 +46,7 @@
public static final int READ= 1 << 1;
public static final int READ_POTENTIAL= 1 << 2;
public static final int WRITE= 1 << 3;
- public static final int WRITE_POTENTIAL= 1 << 4;
+ public static final int WRITE_POTENTIAL= 1 << 4;
public static final int UNKNOWN= 1 << 5;
// Table to merge access modes for condition statements (e.g branch[x] || branch[y]).
@@ -85,6 +94,9 @@
protected static final IVariableBinding[] EMPTY_ARRAY= new IVariableBinding[0];
protected int fReturnKind;
+ protected int fReturningControlStatements;
+ // 'true' if there is at least one particial return in the examined execution flow
+ protected boolean fHasAnyPartialReturn;
protected int[] fAccessModes;
protected HashSet fBranches;
protected HashSet fExceptions;
@@ -99,8 +111,15 @@
//---- General Helpers ----------------------------------------------------------
+ protected void assign(FlowInfo right) {
+ assignExecutionFlow(right);
+ assignAccessMode(right);
+ }
+
protected void assignExecutionFlow(FlowInfo right) {
fReturnKind= right.fReturnKind;
+ fReturningControlStatements= right.fReturningControlStatements;
+ fHasAnyPartialReturn= right.fHasAnyPartialReturn;
fBranches= right.fBranches;
fExceptions= right.fExceptions;
}
@@ -109,11 +128,6 @@
fAccessModes= right.fAccessModes;
}
- protected void assign(FlowInfo right) {
- assignExecutionFlow(right);
- assignAccessMode(right);
- }
-
protected void mergeConditional(FlowInfo info, FlowContext context) {
mergeAccessModeConditional(info, context);
mergeExecutionFlowConditional(info, context);
@@ -158,6 +172,22 @@
return fReturnKind == VOID_RETURN || fReturnKind == VALUE_RETURN;
}
+ public boolean hasAnyPartialReturn() {
+ return fHasAnyPartialReturn;
+ }
+
+ public boolean hasAnyReturn() {
+ return fReturnKind == VOID_RETURN || fReturnKind == VALUE_RETURN || fHasAnyPartialReturn;
+ }
+
+ public boolean hasReturningControlStatement(int statementMask) {
+ return (fReturningControlStatements & statementMask) != 0;
+ }
+
+ public void setReturningControlStatements(int statementMask) {
+ fReturningControlStatements= fReturningControlStatements | statementMask;
+ }
+
//---- Branches -------------------------------------------------------------------------
public boolean branches() {
@@ -240,12 +270,19 @@
if (branches() && other == VALUE_RETURN)
other= PARTIAL_RETURN;
fReturnKind= RETURN_KIND_SEQUENTIAL_TABLE[fReturnKind][other];
+ fReturningControlStatements= fReturningControlStatements | otherInfo.fReturningControlStatements;
+ fHasAnyPartialReturn= fHasAnyPartialReturn ||
+ fReturnKind == PARTIAL_RETURN || other == PARTIAL_RETURN;
mergeBranches(otherInfo, context);
mergeExceptions(otherInfo, context);
}
private void mergeExecutionFlowConditional(FlowInfo otherInfo, FlowContext context) {
- fReturnKind= RETURN_KIND_CONDITIONAL_TABLE[fReturnKind][otherInfo.fReturnKind];
+ int other= otherInfo.fReturnKind;
+ fReturnKind= RETURN_KIND_CONDITIONAL_TABLE[fReturnKind][other];
+ fReturningControlStatements= fReturningControlStatements | otherInfo.fReturningControlStatements;
+ fHasAnyPartialReturn= fHasAnyPartialReturn ||
+ fReturnKind == PARTIAL_RETURN || other == PARTIAL_RETURN;
mergeBranches(otherInfo, context);
mergeExceptions(otherInfo, context);
}
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/ForFlowInfo.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/ForFlowInfo.java,v
retrieving revision 1.3
diff -u -r1.3 ForFlowInfo.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/ForFlowInfo.java 10 Mar 2003 23:27:14 -0000 1.3
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/ForFlowInfo.java 22 Mar 2004 17:40:26 -0000
@@ -36,6 +36,10 @@
if (info == null)
return;
+ if(info.hasAnyReturn()) {
+ setReturningControlStatements(FOR_STATEMENT);
+ }
+
if (!context.isLoopReentranceMode())
info.mergeEmptyCondition(context);
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/IfFlowInfo.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/IfFlowInfo.java,v
retrieving revision 1.3
diff -u -r1.3 IfFlowInfo.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/IfFlowInfo.java 10 Mar 2003 23:27:15 -0000 1.3
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/IfFlowInfo.java 22 Mar 2004 17:40:26 -0000
@@ -23,11 +23,19 @@
return;
GenericConditionalFlowInfo cond= new GenericConditionalFlowInfo();
- if (thenPart != null)
+ if (thenPart != null) {
cond.merge(thenPart, context);
+ if(thenPart.hasAnyReturn()) {
+ setReturningControlStatements(IF_STATEMENT);
+ }
+ }
- if (elsePart != null)
+ if (elsePart != null) {
cond.merge(elsePart, context);
+ if(elsePart.hasAnyReturn()) {
+ setReturningControlStatements(IF_STATEMENT);
+ }
+ }
if (thenPart == null || elsePart == null)
cond.mergeEmptyCondition(context);
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/InOutFlowAnalyzer.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/InOutFlowAnalyzer.java,v
retrieving revision 1.10
diff -u -r1.10 InOutFlowAnalyzer.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/InOutFlowAnalyzer.java 10 Mar 2003 23:27:15 -0000 1.10
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/InOutFlowAnalyzer.java 22 Mar 2004 17:40:26 -0000
@@ -31,6 +31,14 @@
super(context);
}
+ public FlowInfo perform(ASTNode node) {
+ FlowContext context= getFlowContext();
+ GenericSequentialFlowInfo result= createSequential();
+ node.accept(this);
+ result.merge(getFlowInfo(node), context);
+ return result;
+ }
+
public FlowInfo perform(ASTNode[] selectedNodes) {
FlowContext context= getFlowContext();
GenericSequentialFlowInfo result= createSequential();
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/InputFlowAnalyzer.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/InputFlowAnalyzer.java,v
retrieving revision 1.11
diff -u -r1.11 InputFlowAnalyzer.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/InputFlowAnalyzer.java 3 Oct 2003 16:14:32 -0000 1.11
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/InputFlowAnalyzer.java 22 Mar 2004 17:40:26 -0000
@@ -78,7 +78,6 @@
forInfo.mergeIncrement(incrementInfo, fFlowContext);
forInfo.mergeCondition(conditionInfo, fFlowContext);
forInfo.mergeAction(actionInfo, fFlowContext);
- forInfo.removeLabel(null);
} else {
// we have to merge two different cases. One if we reenter the for statement
// immediatelly (that means we have to consider increments, condition and action
@@ -106,7 +105,20 @@
Assert.isNotNull(fSelection);
}
- public FlowInfo perform(BodyDeclaration node) {
+ /**
+ * Performs the actual analysis. Accepted nodes are: all body declarations
+ * except type declarations and all nodes that a children of an excepted
+ * body declaration.
+ *
+ * @param node the node to analyze
+ * @return the computed flow information
+ */
+ public FlowInfo perform(ASTNode node) {
+ ASTNode bodyDecl= node;
+ while (!(bodyDecl instanceof BodyDeclaration) && bodyDecl != null) {
+ bodyDecl= bodyDecl.getParent();
+ }
+ Assert.isTrue(bodyDecl != null);
Assert.isTrue(!(node instanceof TypeDeclaration));
node.accept(this);
return getFlowInfo(node);
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/SwitchFlowInfo.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/SwitchFlowInfo.java,v
retrieving revision 1.4
diff -u -r1.4 SwitchFlowInfo.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/SwitchFlowInfo.java 10 Mar 2003 23:27:15 -0000 1.4
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/SwitchFlowInfo.java 22 Mar 2004 17:40:26 -0000
@@ -29,6 +29,11 @@
fHasNullCaseInfo= true;
return;
}
+
+ if(info.hasAnyReturn()) {
+ setReturningControlStatements(SWITCH_STATEMENT);
+ }
+
fCases.mergeConditional(info, context);
}
Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/WhileFlowInfo.java
===================================================================
RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/WhileFlowInfo.java,v
retrieving revision 1.3
diff -u -r1.3 WhileFlowInfo.java
--- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/WhileFlowInfo.java 10 Mar 2003 23:27:15 -0000 1.3
+++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/flow/WhileFlowInfo.java 22 Mar 2004 17:40:26 -0000
@@ -22,7 +22,11 @@
public void mergeAction(FlowInfo info, FlowContext context) {
if (info == null)
return;
-
+
+ if(info.hasAnyReturn()) {
+ setReturningControlStatements(WHILE_STATEMENT);
+ }
+
if (!context.isLoopReentranceMode())
info.mergeEmptyCondition(context);