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.43 diff -u -r1.43 ASTNodes.java --- core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java 20 Aug 2003 15:46:51 -0000 1.43 +++ core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java 24 Aug 2003 16:18:06 -0000 @@ -18,7 +18,6 @@ import java.util.List; import org.eclipse.core.runtime.CoreException; - import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.ToolFactory; import org.eclipse.jdt.core.compiler.IProblem; @@ -27,43 +26,78 @@ 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.ArrayAccess; import org.eclipse.jdt.core.dom.ArrayCreation; import org.eclipse.jdt.core.dom.ArrayInitializer; import org.eclipse.jdt.core.dom.ArrayType; +import org.eclipse.jdt.core.dom.AssertStatement; 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.BooleanLiteral; +import org.eclipse.jdt.core.dom.BreakStatement; +import org.eclipse.jdt.core.dom.CastExpression; +import org.eclipse.jdt.core.dom.CatchClause; +import org.eclipse.jdt.core.dom.CharacterLiteral; import org.eclipse.jdt.core.dom.ClassInstanceCreation; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ConditionalExpression; import org.eclipse.jdt.core.dom.ConstructorInvocation; +import org.eclipse.jdt.core.dom.ContinueStatement; +import org.eclipse.jdt.core.dom.DoStatement; +import org.eclipse.jdt.core.dom.EmptyStatement; 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; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; +import org.eclipse.jdt.core.dom.IfStatement; +import org.eclipse.jdt.core.dom.ImportDeclaration; import org.eclipse.jdt.core.dom.InfixExpression; +import org.eclipse.jdt.core.dom.Initializer; +import org.eclipse.jdt.core.dom.InstanceofExpression; +import org.eclipse.jdt.core.dom.Javadoc; +import org.eclipse.jdt.core.dom.LabeledStatement; import org.eclipse.jdt.core.dom.Message; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.Name; +import org.eclipse.jdt.core.dom.NullLiteral; +import org.eclipse.jdt.core.dom.NumberLiteral; +import org.eclipse.jdt.core.dom.PackageDeclaration; +import org.eclipse.jdt.core.dom.ParenthesizedExpression; +import org.eclipse.jdt.core.dom.PostfixExpression; +import org.eclipse.jdt.core.dom.PrefixExpression; import org.eclipse.jdt.core.dom.PrimitiveType; 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.SimpleType; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.Statement; +import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.jdt.core.dom.SuperConstructorInvocation; +import org.eclipse.jdt.core.dom.SuperFieldAccess; import org.eclipse.jdt.core.dom.SuperMethodInvocation; +import org.eclipse.jdt.core.dom.SwitchCase; import org.eclipse.jdt.core.dom.SwitchStatement; +import org.eclipse.jdt.core.dom.SynchronizedStatement; +import org.eclipse.jdt.core.dom.ThisExpression; +import org.eclipse.jdt.core.dom.ThrowStatement; import org.eclipse.jdt.core.dom.TryStatement; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.TypeDeclarationStatement; +import org.eclipse.jdt.core.dom.TypeLiteral; import org.eclipse.jdt.core.dom.VariableDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationExpression; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; - +import org.eclipse.jdt.core.dom.WhileStatement; import org.eclipse.jdt.internal.corext.Assert; import org.eclipse.jdt.internal.corext.SourceRange; import org.eclipse.jdt.internal.corext.textmanipulation.TextBuffer; @@ -321,6 +355,11 @@ type == ASTNode.NUMBER_LITERAL || type == ASTNode.STRING_LITERAL || type == ASTNode.TYPE_LITERAL; } + public static boolean isInvocation(Expression expression) { + int type= expression.getNodeType(); + return type == ASTNode.METHOD_INVOCATION || type == ASTNode.SUPER_METHOD_INVOCATION; + } + public static String getTypeName(Type type) { final StringBuffer buffer= new StringBuffer(); ASTVisitor visitor= new ASTVisitor() { @@ -697,4 +736,638 @@ name.accept(visitor); return result[0]; } + + public static void acceptNodes(List nodes, ASTVisitor visitor) { + for (Iterator iter = nodes.iterator(); iter.hasNext();) { + ASTNode element = (ASTNode) iter.next(); + element.accept(visitor); + } + } + + private static class ChildSubstituteVisitor extends ASTVisitor { + private ASTNode fSource; + private ASTNode fReplacement; + public ChildSubstituteVisitor(ASTNode source, ASTNode replacement) { + fSource= source; + fReplacement= replacement; + } + public boolean visit(AnonymousClassDeclaration node) { + List bodies= node.bodyDeclarations(); + int index= bodies.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + bodies.set(index, (BodyDeclaration)fReplacement); + } + else { + bodies.remove(index); + } + } + return false; + } + public boolean visit(ArrayAccess node) { + if(node.getArray() == fSource) { + node.setArray((Expression)fReplacement); + } + else if(node.getIndex() == fSource) { + node.setIndex((Expression)fReplacement); + } + return false; + } + public boolean visit(ArrayCreation node) { + if(node.getType() == fSource) { + node.setType((ArrayType)fReplacement); + } + else if(node.getInitializer() == fSource) { + node.setInitializer((ArrayInitializer)fReplacement); + } + return false; + } + public boolean visit(ArrayInitializer node) { + List expressions= node.expressions(); + int index= expressions.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + expressions.set(index, (Expression)fReplacement); + } + else { + expressions.remove(index); + } + } + return false; + } + public boolean visit(ArrayType node) { + if(node.getComponentType() == fSource) { + node.setComponentType((Type)fReplacement); + } + return false; + } + public boolean visit(AssertStatement node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + else if(node.getMessage() == fSource) { + node.setMessage((Expression)fReplacement); + } + return false; + } + public boolean visit(Assignment node) { + if(node.getLeftHandSide() == fSource) { + node.setLeftHandSide((Expression)fReplacement); + } + else if(node.getRightHandSide() == fSource) { + node.setRightHandSide((Expression)fReplacement); + } + return false; + } + public boolean visit(Block node) { + List statements= node.statements(); + int index= statements.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + statements.set(index, (Statement)fReplacement); + } + else { + statements.remove(index); + } + } + return false; + } + public boolean visit(BooleanLiteral node) { + return false; + } + public boolean visit(BreakStatement node) { + if(node.getLabel() == fSource) { + node.setLabel((SimpleName)fReplacement); + } + return false; + } + public boolean visit(CastExpression node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + else if(node.getType() == fSource) { + node.setType((Type)fReplacement); + } + return false; + } + public boolean visit(CatchClause node) { + if(node.getBody() == fSource) { + node.setBody((Block)fReplacement); + } + else if(node.getException() == fSource) { + node.setException((SingleVariableDeclaration)fReplacement); + } + return false; + } + public boolean visit(CharacterLiteral node) { + return false; + } + public boolean visit(ClassInstanceCreation node) { + if(node.getAnonymousClassDeclaration() == fSource) { + node.setAnonymousClassDeclaration((AnonymousClassDeclaration)fReplacement); + } + else if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + else if(node.getName() == fSource) { + node.setName((Name)fReplacement); + } + return false; + } + public boolean visit(CompilationUnit node) { + return false; + } + public boolean visit(ConditionalExpression node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + else if(node.getThenExpression() == fSource) { + node.setThenExpression((Expression)fReplacement); + } + else if(node.getElseExpression() == fSource) { + node.setElseExpression((Expression)fReplacement); + } + return false; + } + public boolean visit(ConstructorInvocation node) { + List arguments= node.arguments(); + int index= arguments.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + arguments.set(index, (Expression)fReplacement); + } + else { + arguments.remove(index); + } + } + return false; + } + public boolean visit(ContinueStatement node) { + if(node.getLabel() == fSource) { + node.setLabel((SimpleName)fReplacement); + } + return false; + } + public boolean visit(DoStatement node) { + if(node.getBody() == fSource) { + node.setBody((Statement)fReplacement); + } + else if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + return false; + } + public boolean visit(EmptyStatement node) { + return false; + } + public boolean visit(ExpressionStatement node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + return false; + } + public boolean visit(FieldAccess node) { + if(node.getName() == fSource) { + node.setName((SimpleName)fReplacement); + } + else if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + return false; + } + public boolean visit(FieldDeclaration node) { + if(node.getType() == fSource) { + node.setType((Type)fReplacement); + } + else { + List fragments= node.fragments(); + int index= fragments.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + fragments.set(index, (VariableDeclarationFragment)fReplacement); + } + else { + fragments.remove(index); + } + } + } + return false; + } + public boolean visit(ForStatement node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + else if(node.getBody() == fSource) { + node.setBody((Statement)fReplacement); + } + else { + List initializers= node.initializers(); + int index= initializers.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + initializers.set(index, (Expression)fReplacement); + } + else { + initializers.remove(index); + } + } + else { + List updaters= node.updaters(); + index= updaters.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + updaters.set(index, (Expression)fReplacement); + } + else { + updaters.remove(index); + } + } + } + } + return false; + } + public boolean visit(IfStatement node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + else if(node.getThenStatement() == fSource) { + node.setThenStatement((Statement)fReplacement); + } + else if(node.getElseStatement() == fSource) { + node.setElseStatement((Statement)fReplacement); + } + return false; + } + public boolean visit(ImportDeclaration node) { + if(node.getName() == fSource) { + node.setName((Name)fReplacement); + } + return false; + } + public boolean visit(InfixExpression node) { + if(node.getLeftOperand() == fSource) { + node.setLeftOperand((Expression)fReplacement); + } + else if(node.getRightOperand() == fSource) { + node.setRightOperand((Expression)fReplacement); + } + else if(node.hasExtendedOperands()) { + List extendedOperands= node.extendedOperands(); + int index= extendedOperands.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + extendedOperands.set(index, (Expression)fReplacement); + } + else { + extendedOperands.remove(index); + } + } + } + return false; + } + public boolean visit(Initializer node) { + if(node.getBody() == fSource) { + node.setBody((Block)fReplacement); + } + return false; + } + public boolean visit(Javadoc node) { + return false; + } + public boolean visit(LabeledStatement node) { + if(node.getLabel() == fSource) { + node.setLabel((SimpleName)fReplacement); + } + else if(node.getBody() == fSource) { + node.setBody((Block)fReplacement); + } + return false; + } + public boolean visit(MethodDeclaration node) { + if(node.getName() == fSource) { + node.setName((SimpleName)fReplacement); + } + else if(node.getReturnType() == fSource) { + node.setReturnType((Type)fReplacement); + } + else if(node.getBody() == fSource) { + node.setBody((Block)fReplacement); + } + else { + List parameters= node.parameters(); + int index= parameters.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + parameters.set(index, (SingleVariableDeclaration)fReplacement); + } + else { + parameters.remove(index); + } + } + } + return false; + } + public boolean visit(MethodInvocation node) { + if(node.getName() == fSource) { + node.setName((SimpleName)fReplacement); + } + else if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + else { + List arguments= node.arguments(); + int index= arguments.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + arguments.set(index, (Expression)fReplacement); + } + else { + arguments.remove(index); + } + } + } + return false; + } + public boolean visit(NullLiteral node) { + return false; + } + public boolean visit(NumberLiteral node) { + return false; + } + public boolean visit(PackageDeclaration node) { + if(node.getName() == fSource) { + node.setName((SimpleName)fReplacement); + } + return false; + } + public boolean visit(ParenthesizedExpression node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + return false; + } + public boolean visit(PostfixExpression node) { + if(node.getOperand() == fSource) { + node.setOperand((Expression)fReplacement); + } + return false; + } + public boolean visit(PrefixExpression node) { + if(node.getOperand() == fSource) { + node.setOperand((Expression)fReplacement); + } + return false; + } + public boolean visit(PrimitiveType node) { + return false; + } + public boolean visit(QualifiedName node) { + if(node.getName() == fSource) { + node.setName((SimpleName)fReplacement); + } + return false; + } + public boolean visit(ReturnStatement node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + return false; + } + public boolean visit(SimpleName node) { + return false; + } + public boolean visit(SimpleType node) { + if(node.getName() == fSource) { + node.setName((Name)fReplacement); + } + return false; + } + public boolean visit(SingleVariableDeclaration node) { + if(node.getInitializer() == fSource) { + node.setInitializer((Expression)fReplacement); + } + else if(node.getName() == fSource) { + node.setName((SimpleName)fReplacement); + } + else if(node.getType() == fSource) { + node.setType((Type)fReplacement); + } + return false; + } + public boolean visit(StringLiteral node) { + return false; + } + public boolean visit(SuperConstructorInvocation node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + else { + List arguments= node.arguments(); + int index= arguments.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + arguments.set(index, (Expression)fReplacement); + } + else { + arguments.remove(index); + } + } + } + return false; + } + public boolean visit(SuperFieldAccess node) { + if(node.getName() == fSource) { + node.setName((SimpleName)fReplacement); + } + else if(node.getQualifier() == fSource) { + node.setQualifier((Name)fReplacement); + } + return false; + } + public boolean visit(SuperMethodInvocation node) { + if(node.getName() == fSource) { + node.setName((SimpleName)fReplacement); + } + else if(node.getQualifier() == fSource) { + node.setQualifier((Name)fReplacement); + } + else { + List arguments= node.arguments(); + int index= arguments.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + arguments.set(index, (Expression)fReplacement); + } + else { + arguments.remove(index); + } + } + } + return false; + } + public boolean visit(SwitchCase node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + return false; + } + public boolean visit(SwitchStatement node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + return false; + } + public boolean visit(SynchronizedStatement node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + else if(node.getBody() == fSource) { + node.setBody((Block)fReplacement); + } + return false; + } + public boolean visit(ThisExpression node) { + return false; + } + public boolean visit(ThrowStatement node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + return false; + } + public boolean visit(TryStatement node) { + if(node.getBody() == fSource) { + node.setBody((Block)fReplacement); + } + else if(node.getFinally() == fSource) { + node.setFinally((Block)fReplacement); + } + else { + List catchClauses= node.catchClauses(); + int index= catchClauses.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + catchClauses.set(index, (CatchClause)fReplacement); + } + else { + catchClauses.remove(index); + } + } + } + return false; + } + public boolean visit(TypeDeclaration node) { + if(node.getName() == fSource) { + node.setName((SimpleName)fReplacement); + } + else if(node.getSuperclass() == fSource) { + node.setSuperclass((Name)fReplacement); + } + else { + List bodyDeclarations= node.bodyDeclarations(); + int index= bodyDeclarations.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + bodyDeclarations.set(index, (BodyDeclaration)fReplacement); + } + else { + bodyDeclarations.remove(index); + } + } + else { + List superInterfaces= node.superInterfaces(); + index= superInterfaces.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + superInterfaces.set(index, (Name)fReplacement); + } + else { + superInterfaces.remove(index); + } + } + } + } + return false; + } + public boolean visit(TypeDeclarationStatement node) { + if(node.getTypeDeclaration() == fSource) { + node.setTypeDeclaration((TypeDeclaration)fReplacement); + } + return false; + } + public boolean visit(TypeLiteral node) { + if(node.getType() == fSource) { + node.setType((Type)fReplacement); + } + return false; + } + public boolean visit(VariableDeclarationExpression node) { + if(node.getType() == fSource) { + node.setType((Type)fReplacement); + } + else { + List fragments= node.fragments(); + int index= fragments.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + fragments.set(index, (VariableDeclarationFragment)fReplacement); + } + else { + fragments.remove(index); + } + } + } + return false; + } + public boolean visit(VariableDeclarationFragment node) { + if(node.getName() == fSource) { + node.setName((SimpleName)fReplacement); + } + else if(node.getInitializer() == fSource) { + node.setInitializer((Expression)fReplacement); + } + return false; + } + public boolean visit(VariableDeclarationStatement node) { + if(node.getType() == fSource) { + node.setType((Type)fReplacement); + } + else { + List fragments= node.fragments(); + int index= fragments.indexOf(fSource); + if(index != -1) { + if(fReplacement != null) { + fragments.set(index, (VariableDeclarationFragment)fReplacement); + } + else { + fragments.remove(index); + } + } + } + return false; + } + public boolean visit(WhileStatement node) { + if(node.getExpression() == fSource) { + node.setExpression((Expression)fReplacement); + } + else if(node.getBody() == fSource) { + node.setBody((Statement)fReplacement); + } + return false; + } + public boolean visit(InstanceofExpression node) { + if(node.getLeftOperand() == fSource) { + node.setLeftOperand((Expression)fReplacement); + } + else if(node.getRightOperand() == fSource) { + node.setRightOperand((Type)fReplacement); + } + return false; + } + } + + public static void substitute(ASTNode source, ASTNode replacement) { + ASTNode parent= source.getParent(); + parent.accept(new ChildSubstituteVisitor(source, replacement)); + } } 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.7 diff -u -r1.7 CallContext.java --- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallContext.java 10 Mar 2003 21:56:47 -0000 1.7 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallContext.java 24 Aug 2003 16:18:08 -0000 @@ -10,22 +10,21 @@ *******************************************************************************/ package org.eclipse.jdt.internal.corext.refactoring.code; +import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.internal.corext.codemanipulation.ImportEdit; import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder; public class CallContext { - public String[] arguments; - public String receiver; + public ASTNode[] arguments; + public ASTNode receiver; public boolean receiverIsStatic; public CodeScopeBuilder.Scope scope; - public int callMode; public ImportEdit importer; - public CallContext(CodeScopeBuilder.Scope s, int cm, ImportEdit i) { + public CallContext(CodeScopeBuilder.Scope s, ImportEdit 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.30 diff -u -r1.30 CallInliner.java --- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallInliner.java 20 Aug 2003 15:46:51 -0000 1.30 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallInliner.java 24 Aug 2003 16:18:09 -0000 @@ -17,51 +17,55 @@ import java.util.Iterator; import java.util.List; -import org.eclipse.core.runtime.CoreException; - import org.eclipse.core.resources.IFile; - +import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.dom.AST; 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.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.DoStatement; +import org.eclipse.jdt.core.dom.ClassInstanceCreation; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.FieldAccess; -import org.eclipse.jdt.core.dom.ForStatement; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; -import org.eclipse.jdt.core.dom.IfStatement; import org.eclipse.jdt.core.dom.Initializer; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; 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.Type; +import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; -import org.eclipse.jdt.core.dom.WhileStatement; - import org.eclipse.jdt.internal.corext.Assert; import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings; import org.eclipse.jdt.internal.corext.codemanipulation.ImportEdit; import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; import org.eclipse.jdt.internal.corext.dom.ASTNodes; import org.eclipse.jdt.internal.corext.dom.ASTRewrite; -import org.eclipse.jdt.internal.corext.dom.TypeBindingVisitor; import org.eclipse.jdt.internal.corext.dom.Bindings; import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder; +import org.eclipse.jdt.internal.corext.dom.GenericVisitor; import org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor; import org.eclipse.jdt.internal.corext.dom.LocalVariableIndex; import org.eclipse.jdt.internal.corext.dom.Selection; +import org.eclipse.jdt.internal.corext.dom.TypeBindingVisitor; import org.eclipse.jdt.internal.corext.dom.TypeRules; import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatus; import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowContext; @@ -85,14 +89,28 @@ private Expression 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; - + + /** + * Statements inserted before inlined one. + */ + private List fStatementsBefore; + /** + * Statements inserted instead of inlined one. + */ + private List fStatementReplacement; + /** + * Statements inserted after inlined one. + */ + private List fStatementsAfter; + /** + * Expression inserted instead of method invocation. + */ + private Expression fInvocationReplacement; + private boolean fRemoveInvocation; + private class InlineEvaluator extends HierarchicalASTVisitor { private ParameterData fFormalArgument; private boolean fResult; @@ -206,10 +224,6 @@ return fImportEdit; } - public ASTNode getTargetNode() { - return fTargetNode; - } - public RefactoringStatus initialize(BodyDeclaration declaration) { fBodyDeclaration= declaration; RefactoringStatus result= new RefactoringStatus(); @@ -226,23 +240,14 @@ return result; } - public RefactoringStatus initialize(Expression invocation) { - RefactoringStatus result= new RefactoringStatus(); + public void initialize(Expression invocation) { fInvocation= invocation; fRewriter= new ASTRewrite(ASTNodes.getParent(fInvocation, ASTNode.BLOCK)); - ASTNode parent= fInvocation.getParent(); - int nodeType1= parent.getNodeType(); - if (nodeType1 == ASTNode.EXPRESSION_STATEMENT || nodeType1 == ASTNode.RETURN_STATEMENT) { - fTargetNode= parent; - } else { - fTargetNode= fInvocation; - } - return result; } 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); @@ -258,192 +263,483 @@ Assert.isTrue(false, "Should not happen"); //$NON-NLS-1$ } } - + + public static class ReturnCollector extends ASTVisitor { + private List fResult= new ArrayList(); + public ReturnCollector() { + } + public List getResult() { + return fResult; + } + public boolean visit(ReturnStatement node) { + fResult.add(node); + return false; + } + public boolean visit(AnonymousClassDeclaration node) { + return false; + } + public boolean visit(TypeDeclaration node) { + return false; + } + } + + /** + * The singleton class is used to reset code positions of visited nodes. + * + * This is a good candidate for moving into ASTNodes class. + */ + public static class PositionClearer extends GenericVisitor { + private static final PositionClearer instance= new PositionClearer(); + private PositionClearer() { + } + public static PositionClearer getInstance() { + return instance; + } + protected boolean visitNode(ASTNode node) { + node.setSourceRange(-1, 0); + return true; + } + } + public TextEdit perform() throws CoreException { flowAnalysis(); - int callType= fTargetNode.getNodeType(); - CallContext context= new CallContext(fInvocationScope, callType, fImportEdit); + CallContext context= new CallContext(fInvocationScope, fImportEdit); List locals= new ArrayList(3); - - computeRealArguments(context, locals); + context.arguments= computeRealArguments(locals); computeReceiver(context, locals); - - String[] blocks= fSourceProvider.getCodeBlocks(context); - initializeInsertionPoint(fSourceProvider.getNumberOfStatements() + locals.size()); - addNewLocals(locals); - replaceCall(callType, blocks); + List statements= fSourceProvider.getCodeStatements(context); + SourceProvider.replaceAST(fInvocation.getAST(), statements); + addNewLocals(statements, locals); + + processReturnStatements(statements); + replaceCall(); MultiTextEdit result= new MultiTextEdit(); - fRewriter.rewriteNode(fBuffer, result, null); + fRewriter.rewriteNode(fBuffer, result); fRewriter.removeModifications(); return result; } - private void computeRealArguments(CallContext context, List locals) { + /** + * Adds new locals to the top of statements list. + * + * @param statements list of statements + * @param locals list of new locals + */ + private void addNewLocals(List statements, List locals) { + int index= 0; + for (Iterator it= locals.iterator(); it.hasNext(); ) { + statements.add(index++, it.next()); + } + } + + private static ITypeBinding resolveInvocationTypeBinding(ASTNode invocation) { + if(invocation instanceof MethodInvocation) { + return ((MethodInvocation)invocation).resolveTypeBinding(); + } + else if(invocation instanceof SuperMethodInvocation) { + return ((SuperMethodInvocation)invocation).resolveTypeBinding(); + } + return null; + } + + private ASTNode[] computeRealArguments(List locals) { + AST ast= fInvocation.getAST(); List arguments= Invocations.getArguments(fInvocation); - String[] realArguments= new String[arguments.size()]; + ASTNode[] realArguments = new ASTNode[arguments.size()]; for (int i= 0; i < arguments.size(); i++) { Expression expression= (Expression)arguments.get(i); ParameterData parameter= fSourceProvider.getParameterData(i); if (canInline(expression, parameter)) { - realArguments[i] = getContent(expression); + realArguments[i]= ASTNode.copySubtree(expression.getAST(), expression); // fixes bug #35905 if(expression instanceof CastExpression) { - realArguments[i] = "(" + realArguments[i] + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + ParenthesizedExpression pe= ast.newParenthesizedExpression(); + pe.setExpression((Expression)realArguments[i]); + realArguments[i]= pe; } } else { String name= fInvocationScope.createName(parameter.getName(), true); - realArguments[i]= name; - locals.add(createLocalDeclaration( - parameter.getTypeBinding(), name, - (Expression)fRewriter.createCopy(expression))); + realArguments[i]= fInvocation.getAST().newSimpleName(name); + locals.add(createVariableDeclaration( + parameter.getType().resolveBinding(), name, + (Expression)ASTNode.copySubtree(expression.getAST(), expression))); } } - context.arguments= realArguments; + return realArguments; } - + private void computeReceiver(CallContext context, List locals) { Expression receiver= Invocations.getExpression(fInvocation); if (receiver == null) return; - final boolean isName= receiver instanceof Name; - if (isName) - context.receiverIsStatic= ((Name)receiver).resolveBinding() instanceof ITypeBinding; - if (ASTNodes.isLiteral(receiver) || isName) { - context.receiver= fBuffer.getContent(receiver.getStartPosition(), receiver.getLength()); + if (ASTNodes.isLiteral(receiver) || receiver instanceof Name) { + context.receiver= receiver; return; } switch(fSourceProvider.getReceiversToBeUpdated()) { case 0: - // Make sure we evaluate the current receiver. Best is to assign to - // local. - locals.add(createLocalDeclaration( + // Make sure we evaluate the current receiver. Best is to assign to local. + locals.add(createVariableDeclaration( receiver.resolveTypeBinding(), fInvocationScope.createName("r", true), //$NON-NLS-1$ (Expression)fRewriter.createCopy(receiver))); return; case 1: - context.receiver= fBuffer.getContent(receiver.getStartPosition(), receiver.getLength()); + context.receiver= receiver; return; default: String local= fInvocationScope.createName("r", true); //$NON-NLS-1$ - locals.add(createLocalDeclaration( - receiver.resolveTypeBinding(), - local, - (Expression)fRewriter.createCopy(receiver))); - context.receiver= local; + VariableDeclarationStatement receiverDeclaration= + createVariableDeclaration( + receiver.resolveTypeBinding(), + local, + (Expression)fRewriter.createCopy(receiver)); + locals.add(receiverDeclaration); + context.receiver= fInvocation.getAST().newSimpleName(local); return; } } - private void addNewLocals(List locals) { - for (Iterator iter= locals.iterator(); iter.hasNext();) { - ASTNode element= (ASTNode)iter.next(); - fRewriter.markAsInserted(element); - fStatements.add(fInsertionIndex++, element); - } - } - - private void replaceCall(int callType, String[] blocks) throws CoreException { - // Inline empty body - if (blocks.length == 0) { - if (fNeedsStatement) { - fRewriter.markAsReplaced(fTargetNode, fTargetNode.getAST().newEmptyStatement()); - } else { - fRewriter.markAsRemoved(fTargetNode); + /** + * The method analyses return statements and fills fStatementsAfter, + * fStatementsBefore, fStatementReplacement and fInvocationReplacement + * member variables with statements that will be used during inlining. + * + * @param statements list of method statements to process + */ + private void processReturnStatements(List statements) { + + List returnStatements= null; + ReturnCollector returnCollector= new ReturnCollector(); + ASTNodes.acceptNodes(statements, returnCollector); + returnStatements= returnCollector.getResult(); + + AST ast= fInvocation.getAST(); + ASTNode invocationParent= fInvocation.getParent(); + int invocationParentType= invocationParent.getNodeType(); + + if (!fSourceProvider.hasReturnValue()) { + // in case when inlined method returns void ... + for (Iterator iter= returnStatements.iterator(); iter.hasNext();) { + ReturnStatement rs= (ReturnStatement) iter.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 && isControlStatement(parent)) { + substitute(statements, rs, ast.newEmptyStatement()); + } else { + // otheriwse it is safe to remove return statement completely + substitute(statements, rs, null); + } } - } 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 (callType == 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)); + if(invocationParentType == ASTNode.EXPRESSION_STATEMENT) { + fStatementReplacement= statements; + } + else { + fStatementsBefore= statements; + fRemoveInvocation= true; + } + } else if(invocationParentType == ASTNode.RETURN_STATEMENT) { + fStatementReplacement= statements; + } else if (invocationParentType == ASTNode.EXPRESSION_STATEMENT) { + for (Iterator iter= returnStatements.iterator(); iter.hasNext();) { + ReturnStatement rs= (ReturnStatement) iter.next(); + Expression returnExpression= rs.getExpression(); + // check if return expression must be evaluated + if (ASTNodes.isLiteral(returnExpression) || returnExpression instanceof Name) { + // completely remove return and its expression + substitute(statements, rs, null); + } else { + // check if return expression needs a local variable + if (ASTNodes.isInvocation(returnExpression) || returnExpression instanceof ClassInstanceCreation) { + // substitute parent expression with return expression + substitute(statements, rs, + ast.newExpressionStatement((Expression)ASTNode.copySubtree(ast, rs.getExpression()))); } else { - node= fTargetNode.getAST().newExpressionStatement( - (Expression)fRewriter.createPlaceholder(block, ASTRewrite.EXPRESSION)); + // create a local variable to keep result of return expression + VariableDeclarationStatement node= createVariableDeclaration( + fSourceProvider.getReturnType().resolveBinding(), + fInvocationScope.createName(fSourceProvider.getMethodName(), true), + (Expression)ASTNode.copySubtree(ast, returnExpression)); + substitute(statements, rs, node); } - } else { - node= null; } - } else if (fTargetNode instanceof Expression) { - node= fRewriter.createPlaceholder(block, ASTRewrite.EXPRESSION); - + } + fStatementReplacement= statements; + } else if (invocationParent instanceof Expression) { + for (Iterator iter= returnStatements.iterator(); iter.hasNext();) { + ReturnStatement rs= (ReturnStatement) iter.next(); + Expression returnExpression= rs.getExpression(); + Expression node= (Expression)ASTNode.copySubtree(ast, returnExpression); // fixes bug #24941 - if(needsExplicitCast()) { - AST ast= node.getAST(); + if (needsExplicitCast(rs)) { CastExpression castExpression= ast.newCastExpression(); - ITypeBinding returnType= fSourceProvider.getReturnType(); - fImportEdit.addImport(returnType); - castExpression.setType(ASTNodeFactory.newType(ast, returnType, false)); - castExpression.setExpression((Expression)node); + Type returnType= fSourceProvider.getReturnType(); + fImportEdit.addImport(returnType.resolveBinding()); + castExpression.setType((Type)ASTNode.copySubtree(ast, returnType)); + castExpression.setExpression(node); node= castExpression; } - - if (needsParenthesis()) { - ParenthesizedExpression pExp= fTargetNode.getAST().newParenthesizedExpression(); - pExp.setExpression((Expression)node); - node= pExp; + if (needsParenthesis(rs)) { + ParenthesizedExpression pe= ast.newParenthesizedExpression(); + pe.setExpression(node); + node= pe; + } + if (returnStatements.size() == 1) { + fInvocationReplacement= node; + fStatementsBefore= statements; + statements.remove(rs); + } + else { + substitute(statements, rs, ast.newExpressionStatement(node)); + } + } + } else if(invocationParentType == ASTNode.VARIABLE_DECLARATION_FRAGMENT) { + if(returnStatements.size() > 1) { + // method invocation in variable declaration fragment can be used only as initializer + VariableDeclarationFragment fragment= (VariableDeclarationFragment)invocationParent; + fInvocationReplacement= createDefaultInitializer(invocationParent.getAST(), + resolveInvocationTypeBinding(fInvocation)); + Expression variable= fragment.getName(); + substituteReturnsWithAssignments(variable, returnStatements, statements); + fStatementsAfter= statements; + } + else { // returnStatements.size() == 1 + ReturnStatement rs= (ReturnStatement) returnStatements.get(0); + Expression returnExpression= rs.getExpression(); + fInvocationReplacement= (Expression)ASTNode.copySubtree(ast, returnExpression); + substitute(statements, rs, null); + fStatementsBefore= statements; + } + } else { + // case example: + // for(inlineMe(); i < 10; i++); + if(returnStatements.size() > 1) { + // if method has multiple returns then temporary variable will be created and all + // returns will be substituted with assignments to it. + VariableDeclarationStatement variableStatement= createVariableDeclaration( + fSourceProvider.getReturnType().resolveBinding(), + fInvocationScope.createName("temp", true), //$NON-NLS-1$ + createDefaultInitializer(ast, fSourceProvider.getReturnType().resolveBinding())); + statements.add(0, variableStatement); + VariableDeclarationFragment fragment= (VariableDeclarationFragment)variableStatement.fragments().get(0); + Expression variable= fragment.getName(); + substituteReturnsWithAssignments(variable, returnStatements, statements); + fStatementsBefore= statements; + fRemoveInvocation= true; + } + else { // returnStatements.size() == 1 + ReturnStatement rs= (ReturnStatement) returnStatements.get(0); + Expression returnExpression= rs.getExpression(); + // check if return expression must be evaluated + if (ASTNodes.isLiteral(returnExpression) || returnExpression instanceof Name) { + substitute(statements, rs, null); + fStatementsBefore= statements; + fRemoveInvocation= true; + } + else { + fInvocationReplacement= (Expression)ASTNode.copySubtree(ast, returnExpression); + substitute(statements, rs, null); + fStatementsBefore= statements; } - } else { - node= fRewriter.createPlaceholder(block, ASTRewrite.STATEMENT); } - - // Now replace the target node with the source node - if (node != null) { - if (fTargetNode == null) { - fRewriter.markAsInserted(node); - fStatements.add(fInsertionIndex++, node); - } else { - fRewriter.markAsReplaced(fTargetNode, node); + } + } + + /** + * The helper method substitutes return statements with assignments + * expressions wrapped inside expression statements. + * + * @param variable AST node representing variable to assign to + * @param returnStatements list of return statements + * @param statements list of original statements + */ + private void substituteReturnsWithAssignments(Expression variable, List returnStatements, List statements) { + AST ast= variable.getAST(); + for (Iterator iter= returnStatements.iterator(); iter.hasNext();) { + ReturnStatement rs= (ReturnStatement) iter.next(); + Expression returnExpression= rs.getExpression(); + ASTNode parent= rs.getParent(); + // 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). + Assignment assignment= ast.newAssignment(); + assignment.setLeftHandSide((Expression)ASTNode.copySubtree(ast, variable)); + assignment.setRightHandSide((Expression)ASTNode.copySubtree(ast, returnExpression)); + substitute(statements, rs, ast.newExpressionStatement(assignment)); + } + } + + /** + * @param ast + * @param variableBinding + * @return + */ + 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(); + } + + /** + * Helper method for substitution of one node with another in a list of statements. + * + * Special processing is required for top level nodes since their parents are null. + * + * @param statements list of original statements + * @param source source node, must exist in the hierarchy of statements + * @param replacement node replacing the source one + */ + private static void substitute(List statements, ASTNode source, ASTNode replacement) { + if(source.getParent() == null) { + if(replacement == null) { + statements.remove(source); + } + else { + int index= statements.indexOf(source); + statements.set(index, replacement); + } + } + else { + ASTNodes.substitute(source, replacement); + } + } + + /** + * The method does actual code modificiations. + * + * It uses only fStatementsBefore, fStatementsAfter, fStatementReplacement + * and fInvocationReplacement member variables prepared by other methods. + * + * The method adds empty statements and blocks where it is needed. + */ + private void replaceCall() throws CoreException { + + AST ast= fInvocation.getAST(); + Statement invocationStatement= (Statement)ASTNodes.getParent(fInvocation, Statement.class); + Statement parentStatement= (Statement)invocationStatement.getParent(); + + int numberOfStatements= 0; + if (fStatementsBefore != null) { + numberOfStatements+= fStatementsBefore.size(); + ASTNodes.acceptNodes(fStatementsBefore, PositionClearer.getInstance()); + } + if (fStatementsAfter != null) { + numberOfStatements+= fStatementsAfter.size(); + ASTNodes.acceptNodes(fStatementsAfter, PositionClearer.getInstance()); + } + if (fStatementReplacement != null) { + numberOfStatements+= fStatementReplacement.size(); + ASTNodes.acceptNodes(fStatementReplacement, PositionClearer.getInstance()); + } + else { + numberOfStatements++; + } + if(fInvocationReplacement != null) { + fInvocationReplacement.accept(PositionClearer.getInstance()); + } + + List parentStatements= null; + if (parentStatement.getNodeType() == ASTNode.BLOCK) { + parentStatements= ((Block)parentStatement).statements(); + } + else if (parentStatement.getNodeType() == ASTNode.SWITCH_STATEMENT) { + parentStatements= ((SwitchStatement)parentStatement).statements(); + } + else if (numberOfStatements > 1) { + Block block= ast.newBlock(); + List blockStatements= block.statements(); + if (fStatementsBefore != null) { + blockStatements.addAll(fStatementsBefore); + } + if (fStatementReplacement != null) { + blockStatements.addAll(fStatementReplacement); + } + else if (fInvocationReplacement != null) { + // modifying original AST(not the copy!) + ASTNodes.substitute(fInvocation, fInvocationReplacement); + blockStatements.add(ASTNode.copySubtree(ast, invocationStatement)); + // restoring original AST + ASTNodes.substitute(fInvocationReplacement, fInvocation); + } + if (fStatementsAfter!= null) { + blockStatements.addAll(fStatementsAfter); + } + fStatementReplacement= new ArrayList(); + fStatementReplacement.add(block); + } + else if (numberOfStatements == 0) { + if (isControlStatement(parentStatement)/* && fInvocationReplacement == null*/) { + fStatementReplacement.add(ast.newEmptyStatement()); + } + } + if(fStatementReplacement == null) { + if (fInvocationReplacement != null) { + // statement replacement has higher priority over invocation replacement + // so if fStatementReplacement is not null it will be used instead of + // fInvocationReplacement. + fRewriter.markAsReplaced(fInvocation, fInvocationReplacement); + } + else if(fRemoveInvocation) { + fRewriter.markAsRemoved(fInvocation); + } + } + + if (parentStatements != null) { + int index= parentStatements.indexOf(invocationStatement); + if(fStatementsBefore != null) { + for (int i= 0; i < fStatementsBefore.size(); i++) { + parentStatements.add(index++, fStatementsBefore.get(i)); + fRewriter.markAsInserted((ASTNode)fStatementsBefore.get(i), true); } - } else { - if (fTargetNode != null) { - fRewriter.markAsRemoved(fTargetNode); + } + if(fStatementReplacement != null) { + fRewriter.markAsReplaced(invocationStatement, parentStatements, + (ASTNode[])fStatementReplacement.toArray(new ASTNode[fStatementReplacement.size()])); + } + if(fStatementsAfter != null) { + index++; + for (int i= 0; i < fStatementsAfter.size(); i++) { + parentStatements.add(index++, fStatementsAfter.get(i)); + fRewriter.markAsInserted((ASTNode)fStatementsAfter.get(i), true); } } } + else if(fStatementReplacement != null) { + fRewriter.markAsReplaced(invocationStatement, (ASTNode)fStatementReplacement.get(0)); + } } /** * @return true if explicit cast is needed otherwise false * @throws JavaModelException */ - private boolean needsExplicitCast() { + private boolean needsExplicitCast(ReturnStatement rs) { // 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(); + if (returnTypeMatchesReturnExpressions(rs)) + 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]= (ITypeBinding)fSourceProvider.resolveTypeBinding( + rs.getExpression().getStartPosition()); + ITypeBinding type= ASTNodes.getReceiverTypeBinding(methodInvocation); TypeBindingVisitor visitor= new AmbiguousMethodAnalyzer(method, parameters); if(!visitor.visit(type)) { @@ -463,20 +759,33 @@ return false; } - private boolean needsParenthesis() { - if (!fSourceProvider.needsReturnedExpressionParenthesis()) + public boolean returnTypeMatchesReturnExpressions(ReturnStatement returnStatement) { + ITypeBinding returnType= fSourceProvider.getReturnType().resolveBinding(); + Expression expression= returnStatement.getExpression(); + if (expression != null) { + if (!Bindings.equals(returnType, expression.resolveTypeBinding())) + return false; + } + return true; + } + + private boolean needsParenthesis(ReturnStatement rs) { + if (!ASTNodes.needsParentheses(rs.getExpression())) 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; + + private VariableDeclarationStatement createVariableDeclaration(ITypeBinding typeBinding, String name, Expression initializer) { + AST ast= initializer.getAST(); + String typeName= fImportEdit.addImport(typeBinding); + VariableDeclarationFragment fragment= ast.newVariableDeclarationFragment(); + fragment.setName(ast.newSimpleName(name)); + fragment.setInitializer(initializer); + VariableDeclarationStatement result= ast.newVariableDeclarationStatement(fragment); + result.setType(ASTNodeFactory.newType(ast, typeBinding.getName())); + return result; } private boolean canInline(Expression actualParameter, ParameterData formalParameter) { @@ -484,69 +793,11 @@ 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); - } - } - // We only insert one new statement or we delete the existing call. - // So there is no need to have an insertion index. - } - - private String getContent(ASTNode node) { - return fBuffer.getContent(node.getStartPosition(), node.getLength()); - } private static IFile getFile(ICompilationUnit cu) throws CoreException { return (IFile)WorkingCopyUtil.getOriginal(cu).getResource(); } - + private boolean isControlStatement(ASTNode node) { int type= node.getNodeType(); return type == ASTNode.IF_STATEMENT || type == ASTNode.FOR_STATEMENT || 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.33 diff -u -r1.33 InlineMethodRefactoring.java --- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/InlineMethodRefactoring.java 20 Aug 2003 15:46:51 -0000 1.33 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/InlineMethodRefactoring.java 24 Aug 2003 16:18:09 -0000 @@ -207,10 +207,10 @@ Expression[] invocations= fTargetProvider.getInvocations(body, new SubProgressMonitor(pm, 1)); for (int i= 0; i < invocations.length; i++) { Expression invocation= invocations[i]; - result.merge(inliner.initialize(invocation)); + inliner.initialize(invocation); if (result.hasFatalError()) break; - RefactoringStatus targetStatus= invocationAnalyzer.perform(unit, invocation, inliner.getTargetNode(), fTargetProvider.getStatusSeverity()); + RefactoringStatus targetStatus= invocationAnalyzer.perform(unit, invocation, fTargetProvider.getStatusSeverity()); result.merge(targetStatus); if (result.hasFatalError()) break; Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/InvocationAnalyzer.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/InvocationAnalyzer.java,v retrieving revision 1.5 diff -u -r1.5 InvocationAnalyzer.java --- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/InvocationAnalyzer.java 18 Jun 2003 15:24:47 -0000 1.5 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/InvocationAnalyzer.java 24 Aug 2003 16:18:10 -0000 @@ -10,14 +10,21 @@ *******************************************************************************/ package org.eclipse.jdt.internal.corext.refactoring.code; +import java.util.Iterator; +import java.util.List; + import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.BodyDeclaration; +import org.eclipse.jdt.core.dom.DoStatement; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.ForStatement; import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.Statement; import org.eclipse.jdt.core.dom.VariableDeclaration; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; +import org.eclipse.jdt.core.dom.WhileStatement; import org.eclipse.jdt.internal.corext.dom.ASTNodes; import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; @@ -41,12 +48,20 @@ fSourceProvider= sourceProvider; } - public RefactoringStatus perform(ICompilationUnit unit, ASTNode invocation, ASTNode targetNode, int severity) { + public RefactoringStatus perform(ICompilationUnit unit, ASTNode invocation, int severity) { RefactoringStatus result= new RefactoringStatus(); fCUnit= unit; fInvocation= invocation; fSeverity= severity; - fTargetNode= targetNode; + + ASTNode parent= fInvocation.getParent(); + int nodeType= parent.getNodeType(); + if (nodeType == ASTNode.EXPRESSION_STATEMENT || nodeType == ASTNode.RETURN_STATEMENT) { + fTargetNode= parent; + } else { + fTargetNode= fInvocation; + } + checkIfUsedInDeclaration(result); if (result.getSeverity() >= fSeverity) return result; @@ -73,28 +88,60 @@ JavaStatusContext.create(fSourceProvider.getCompilationUnit(), fSourceProvider.getDeclaration()), RefactoringStatusCodes.INLINE_METHOD_EXECUTION_FLOW); } - } 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("InvocationAnalyzer.multiDeclaration"), //$NON-NLS-1$ - RefactoringStatusCodes.INLINE_METHOD_INITIALIZER_IN_FRAGEMENT); - } - } else if (fSourceProvider.getNumberOfStatements() > 1 ) { + } else if (isUsedInLoop()) { + if (fSourceProvider.getNumberOfStatements() > 1 ) { + // TODO: The message is not correct for this situation addEntry(result, RefactoringCoreMessages.getString("CallInliner.simple_functions"), //$NON-NLS-1$ RefactoringStatusCodes.INLINE_METHOD_ONLY_SIMPLE_FUNCTIONS); - } else if (!fSourceProvider.isSimpleFunction()) { - addEntry(result, - RefactoringCoreMessages.getString("CallInliner.execution_flow"), //$NON-NLS-1$ - fSeverity, - JavaStatusContext.create(fSourceProvider.getCompilationUnit(), fSourceProvider.getDeclaration()), - RefactoringStatusCodes.INLINE_METHOD_EXECUTION_FLOW); } +// } 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("InvocationAnalyzer.multiDeclaration"), //$NON-NLS-1$ +// RefactoringStatusCodes.INLINE_METHOD_INITIALIZER_IN_FRAGEMENT); +// } +// } else if (fSourceProvider.getNumberOfStatements() > 1 ) { +// addEntry(result, +// RefactoringCoreMessages.getString("CallInliner.simple_functions"), //$NON-NLS-1$ +// RefactoringStatusCodes.INLINE_METHOD_ONLY_SIMPLE_FUNCTIONS); +// } else if (!fSourceProvider.isSimpleFunction()) { +// addEntry(result, +// RefactoringCoreMessages.getString("CallInliner.execution_flow"), //$NON-NLS-1$ +// fSeverity, +// JavaStatusContext.create(fSourceProvider.getCompilationUnit(), fSourceProvider.getDeclaration()), +// RefactoringStatusCodes.INLINE_METHOD_EXECUTION_FLOW); +// } } + } + + /** + * @return true is inlined invocation is used inside a one of loop statements. + */ + private boolean isUsedInLoop() { + ASTNode parentStatement= ASTNodes.getParent(fTargetNode, Statement.class); + if (parentStatement instanceof WhileStatement) { + return true; + } + else if (parentStatement instanceof DoStatement) { + return true; + } + else if (parentStatement instanceof ForStatement) { + ForStatement forStatement= (ForStatement)parentStatement; + List initializers= forStatement.initializers(); + for (Iterator iter= initializers.iterator(); iter.hasNext();) { + ASTNode initializer= (ASTNode) iter.next(); + if(fTargetNode == initializer || ASTNodes.isParent(fTargetNode, initializer)) { + return false; + } + } + return true; + } + return false; } private void checkIfUsedInDeclaration(RefactoringStatus result) { Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/ParameterData.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/ParameterData.java,v retrieving revision 1.5 diff -u -r1.5 ParameterData.java --- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/ParameterData.java 27 May 2003 14:41:50 -0000 1.5 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/ParameterData.java 24 Aug 2003 16:18:10 -0000 @@ -16,6 +16,7 @@ import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.internal.corext.dom.ASTNodes; import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowInfo; @@ -44,6 +45,10 @@ if (binding != null) return binding.getName(); return ASTNodes.asString(fDeclaration.getType()); + } + + public Type getType() { + return fDeclaration.getType(); } public ITypeBinding getTypeBinding() { Index: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceAnalyzer.java =================================================================== RCS file: core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceAnalyzer.java diff -N core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceAnalyzer.java --- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceAnalyzer.java 21 Jul 2003 10:18:13 -0000 1.17 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,330 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2003 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Common Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/cpl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.corext.refactoring.code; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.JavaModelException; -import org.eclipse.jdt.core.compiler.IProblem; -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.IBinding; -import org.eclipse.jdt.core.dom.IMethodBinding; -import org.eclipse.jdt.core.dom.ITypeBinding; -import org.eclipse.jdt.core.dom.IVariableBinding; -import org.eclipse.jdt.core.dom.MethodDeclaration; -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; -import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; -import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatus; -import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowContext; -import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowInfo; -import org.eclipse.jdt.internal.corext.refactoring.code.flow.InOutFlowAnalyzer; - -class SourceAnalyzer { - - public static class NameData { - private String fName; - private List fReferences; - public NameData(String n) { - fName= n; - fReferences= new ArrayList(2); - } - public String getName() { - return fName; - } - public void addReference(SimpleName ref) { - fReferences.add(ref); - } - public List references() { - return fReferences; - } - } - - 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; - } - public boolean visit(AnonymousClassDeclaration node) { - return false; - } - public boolean visit(MethodInvocation node) { - if (fBinding != null && fBinding == node.getName().resolveBinding() && !status.hasFatalError()) { - status.addFatalError(RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.recursive_call")); //$NON-NLS-1$ - return false; - } - return true; - } - public boolean visit(SimpleName node) { - IBinding binding= node.resolveBinding(); - if (binding == null && !status.hasFatalError()) { - status.addFatalError( - RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.declaration_has_errors"), //$NON-NLS-1$ - JavaStatusContext.create(fCUnit, fDeclaration)); - return false; - } - return true; - } - public boolean visit(ThisExpression node) { - if (node.getQualifier() != null) { - status.addFatalError( - RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.qualified_this_expressions"), //$NON-NLS-1$ - JavaStatusContext.create(fCUnit, node)); - return false; - } - 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(); - } - } - - private class UpdateCollector extends ASTVisitor { - private int fTypeCounter; - public boolean visit(TypeDeclaration node) { - if (fTypeCounter++ == 0) { - addNameData(node.getName()); - } - Name superclass= node.getSuperclass(); - if (superclass != null) { - ITypeBinding superBinding= ASTNodes.getTypeBinding(superclass); - if (superBinding != null) - fTypes.add(superclass); - } - List interfaces= node.superInterfaces(); - for (Iterator iter= interfaces.iterator(); iter.hasNext();) { - Name element= (Name)iter.next(); - ITypeBinding binding= ASTNodes.getTypeBinding(element); - if (binding != null) - fTypes.add(element); - } - return true; - } - public void endVisit(TypeDeclaration node) { - fTypeCounter--; - } - public boolean visit(AnonymousClassDeclaration node) { - fTypeCounter++; - return true; - } - public void endVisit(AnonymousClassDeclaration node) { - fTypeCounter--; - } - public boolean visit(MethodDeclaration node) { - if (node.isConstructor()) { - TypeDeclaration decl= (TypeDeclaration) ASTNodes.getParent(node, ASTNode.TYPE_DECLARATION); - NameData name= (NameData)fNames.get(decl.getName().resolveBinding()); - if (name != null) { - name.addReference(node.getName()); - } - } - return true; - } - public boolean visit(MethodInvocation node) { - if (fTypeCounter == 0) { - Expression receiver= node.getExpression(); - if (receiver == null) - fImplicitReceivers.add(node); - } - return true; - } - public boolean visit(ClassInstanceCreation node) { - if (fTypeCounter == 0) { - Expression receiver= node.getExpression(); - if (receiver == null) { - if (node.resolveTypeBinding().isLocal()) - fImplicitReceivers.add(node); - } - } - return true; - } - public boolean visit(SingleVariableDeclaration node) { - if (fTypeCounter == 0) - addNameData(node.getName()); - return true; - } - public boolean visit(VariableDeclarationFragment node) { - if (fTypeCounter == 0) - addNameData(node.getName()); - return true; - } - public boolean visit(SimpleName node) { - IBinding binding= node.resolveBinding(); - ParameterData data= (ParameterData)fParameters.get(binding); - if (data != null) - data.addReference(node); - - NameData name= (NameData)fNames.get(binding); - if (name != null) - name.addReference(node); - if (binding instanceof ITypeBinding) { - ITypeBinding tb= (ITypeBinding)binding; - Name qName= node; - QualifiedName parent; - while ((parent= (QualifiedName)ASTNodes.getParent(qName, ASTNode.QUALIFIED_NAME)) != null && - parent.getQualifier() != qName) { - qName= parent; - } - String typeName= null; - if (tb.isArray()) - typeName= tb.getElementType().getQualifiedName(); - else - typeName= tb.getQualifiedName(); - if (!ASTNodes.asString(qName).equals(typeName)) - fTypes.add(qName); - } - return true; - } - public boolean visit(ThisExpression node) { - if (fTypeCounter == 0) { - fImplicitReceivers.add(node); - } - return true; - } - private void addNameData(SimpleName name) { - fNames.put(name.resolveBinding(), new NameData(name.getIdentifier())); - } - } - - private ICompilationUnit fCUnit; - private MethodDeclaration fDeclaration; - private Map fParameters; - private Map fNames; - private List fImplicitReceivers; - private List fTypes; - private boolean fInterruptedExecutionFlow; - - public SourceAnalyzer(ICompilationUnit unit, MethodDeclaration declaration) { - super(); - fCUnit= unit; - fDeclaration= declaration; - List parameters= fDeclaration.parameters(); - fParameters= new HashMap(parameters.size() * 2); - for (Iterator iter= parameters.iterator(); iter.hasNext();) { - SingleVariableDeclaration element= (SingleVariableDeclaration) iter.next(); - fParameters.put(element.resolveBinding(), element.getProperty(ParameterData.PROPERTY)); - } - fNames= new HashMap(); - fImplicitReceivers= new ArrayList(2); - fTypes= new ArrayList(2); - } - - public boolean isExecutionFlowInterrupted() { - return fInterruptedExecutionFlow; - } - - public RefactoringStatus checkActivation() throws JavaModelException { - RefactoringStatus result= new RefactoringStatus(); - if (!fCUnit.isStructureKnown()) { - result.addFatalError( - RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.syntax_errors"), //$NON-NLS-1$ - JavaStatusContext.create(fCUnit)); - return result; - } - IProblem[] problems= ASTNodes.getProblems(fDeclaration, ASTNodes.NODE_ONLY, ASTNodes.ERROR); - if (problems.length > 0) { - result.addFatalError( - RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.declaration_has_errors"), //$NON-NLS-1$ - JavaStatusContext.create(fCUnit, fDeclaration)); - return result; - } - if (fDeclaration.getBody() == null) { - result.addFatalError( - RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.abstract_methods"), //$NON-NLS-1$ - JavaStatusContext.create(fCUnit, fDeclaration)); - return result; - } - if (fDeclaration.isConstructor()) { - result.addFatalError( - RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.constructors"), //$NON-NLS-1$ - JavaStatusContext.create(fCUnit, fDeclaration)); - return result; - } - ActivationAnalyzer analyzer= new ActivationAnalyzer(); - fDeclaration.accept(analyzer); - result.merge(analyzer.status); - if (!result.hasFatalError()) { - - } - return result; - } - - public void analyzeParameters() { - Block body= fDeclaration.getBody(); - body.accept(new UpdateCollector()); - - int numberOfLocals= LocalVariableIndex.perform(fDeclaration); - FlowContext context= new FlowContext(0, numberOfLocals + 1); - context.setConsiderAccessMode(true); - context.setComputeMode(FlowContext.MERGE); - InOutFlowAnalyzer flowAnalyzer= new InOutFlowAnalyzer(context); - FlowInfo info= 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)); - } - } - - public Collection getUsedNames() { - return fNames.values(); - } - - public List getImplicitReceivers() { - return fImplicitReceivers; - } - - 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.21 diff -u -r1.21 SourceProvider.java --- core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceProvider.java 22 Aug 2003 12:00:25 -0000 1.21 +++ core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceProvider.java 24 Aug 2003 16:18:11 -0000 @@ -15,69 +15,303 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; - import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.core.dom.AST; 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.ClassInstanceCreation; import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; +import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.core.dom.Name; +import org.eclipse.jdt.core.dom.PrimitiveType; +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.Type; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.internal.corext.codemanipulation.ImportEdit; 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.dom.LocalVariableIndex; +import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; +import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatus; +import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowContext; +import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowInfo; +import org.eclipse.jdt.internal.corext.refactoring.code.flow.InOutFlowAnalyzer; import org.eclipse.jdt.internal.corext.textmanipulation.MultiTextEdit; -import org.eclipse.jdt.internal.corext.textmanipulation.RangeMarker; import org.eclipse.jdt.internal.corext.textmanipulation.TextBuffer; -import org.eclipse.jdt.internal.corext.textmanipulation.TextBufferEditor; import org.eclipse.jdt.internal.corext.textmanipulation.TextEdit; -import org.eclipse.jdt.internal.corext.textmanipulation.TextRange; -import org.eclipse.jdt.internal.corext.textmanipulation.UndoMemento; -import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil; -import org.eclipse.jdt.internal.corext.util.Strings; public class SourceProvider { + private Map fNames; + private List fImplicitReceivers; + private List fTypes; + private Map fParameters; private ICompilationUnit fCUnit; private TextBuffer fBuffer; + private List fStatements; private MethodDeclaration fDeclaration; - private ASTRewrite fRewriter; - private SourceAnalyzer fAnalyzer; - private boolean fMustEvalReturnedExpression; - private boolean fReturnValueNeedsLocalVariable; - private List fReturnExpressions; + private boolean fInterruptedExecutionFlow; + + private Map fBindings; + private Map fTypeBindings; + private Map fMethodBindings; + + public static class NameData { + private String fName; + private List fReferences; + public NameData(String n) { + fName= n; + fReferences= new ArrayList(2); + } + public String getName() { + return fName; + } + public void addReference(SimpleName ref) { + fReferences.add(ref); + } + public List references() { + return fReferences; + } + } + + 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; + } + public boolean visit(AnonymousClassDeclaration node) { + return false; + } + public boolean visit(MethodInvocation node) { + if (fBinding != null && fBinding == resolveMethodBinding(node.getName()) && !status.hasFatalError()) { + status.addFatalError(RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.recursive_call")); //$NON-NLS-1$ + return false; + } + return true; + } + public boolean visit(SimpleName node) { + IBinding binding= resolveBinding(node); + if (binding == null && !status.hasFatalError()) { + status.addFatalError( + RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.declaration_has_errors"), //$NON-NLS-1$ + JavaStatusContext.create(fCUnit, fDeclaration)); + return false; + } + return true; + } + public boolean visit(ThisExpression node) { + if (node.getQualifier() != null) { + status.addFatalError( + RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.qualified_this_expressions"), //$NON-NLS-1$ + JavaStatusContext.create(fCUnit, node)); + return false; + } + return true; + } + private ASTNode getLastNode() { + if (fStatements.size() == 0) + return null; + return (ASTNode)fStatements.get(fStatements.size() - 1); + } + private IMethodBinding getBinding() { + return fDeclaration.resolveBinding(); + } + } - private class ReturnAnalyzer extends ASTVisitor { + private class UpdateCollector extends ASTVisitor { + private int fTypeCounter; + public boolean visit(TypeDeclaration node) { + if (fTypeCounter++ == 0) { + addNameData(node.getName()); + } + Name superclass= node.getSuperclass(); + if (superclass != null) { + ITypeBinding superBinding= resolveTypeBinding(superclass); + if (superBinding != null) + fTypes.add(superclass); + } + List interfaces= node.superInterfaces(); + for (Iterator iter= interfaces.iterator(); iter.hasNext();) { + Name element= (Name)iter.next(); + ITypeBinding superBinding= resolveTypeBinding(superclass); + if (superBinding != null) + fTypes.add(superclass); + } + return true; + } + public void endVisit(TypeDeclaration node) { + fTypeCounter--; + } + public boolean visit(AnonymousClassDeclaration node) { + fTypeCounter++; + return true; + } + public void endVisit(AnonymousClassDeclaration node) { + fTypeCounter--; + } + public boolean visit(MethodDeclaration node) { + if (node.isConstructor()) { + TypeDeclaration decl= (TypeDeclaration) ASTNodes.getParent(node, ASTNode.TYPE_DECLARATION); + NameData name= (NameData)fNames.get(resolveTypeBinding(decl.getName())); + if (name != null) { + name.addReference(node.getName()); + } + } + return true; + } + public boolean visit(MethodInvocation node) { + if (fTypeCounter == 0) { + Expression receiver= node.getExpression(); + if (receiver == null) + fImplicitReceivers.add(node); + } + return true; + } + public boolean visit(ClassInstanceCreation node) { + if (fTypeCounter == 0) { + Expression receiver= node.getExpression(); + if (receiver == null) { + IMethodBinding methodBinding= resolveMethodBinding(node); + ITypeBinding typeBinding= methodBinding.getDeclaringClass(); + if (typeBinding.isLocal()) { + fImplicitReceivers.add(node); + } + } + } + return true; + } + public boolean visit(SingleVariableDeclaration node) { + if (fTypeCounter == 0) + addNameData(node.getName()); + return true; + } + public boolean visit(VariableDeclarationFragment node) { + if (fTypeCounter == 0) + addNameData(node.getName()); + return true; + } + public boolean visit(SimpleName node) { + IBinding binding= resolveBinding(node); + ParameterData data= (ParameterData)fParameters.get(binding); + if (data != null) + data.addReference(node); + + NameData name= (NameData)fNames.get(binding); + if (name != null) + name.addReference(node); + if (binding instanceof ITypeBinding) { + ITypeBinding tb= (ITypeBinding)binding; + Name qName= node; + QualifiedName parent; + while ((parent= (QualifiedName)ASTNodes.getParent(qName, ASTNode.QUALIFIED_NAME)) != null && + parent.getQualifier() != qName) { + qName= parent; + } + String typeName= null; + if (tb.isArray()) + typeName= tb.getElementType().getQualifiedName(); + else + typeName= tb.getQualifiedName(); + if (!ASTNodes.asString(qName).equals(typeName)) + fTypes.add(qName); + } + return true; + } + public boolean visit(ThisExpression node) { + if (fTypeCounter == 0) { + fImplicitReceivers.add(node); + } + return true; + } + private void addNameData(SimpleName name) { + IBinding binding= (IBinding)fBindings.get(new Integer(name.getStartPosition())); + fNames.put(binding, new NameData(name.getIdentifier())); + } + } + + private class BindingCollector extends ASTVisitor { + public boolean visit(SimpleName node) { + fBindings.put(new Integer(node.getStartPosition()), node.resolveBinding()); + fTypeBindings.put(new Integer(node.getStartPosition()), node.resolveTypeBinding()); + return true; + } + public boolean visit(MethodInvocation node) { + fMethodBindings.put(new Integer(node.getStartPosition()), node.resolveMethodBinding()); + return true; + } + public boolean visit(TypeDeclaration node) { + fTypeBindings.put(new Integer(node.getStartPosition()), node.resolveBinding()); + return true; + } + public boolean visit(ClassInstanceCreation node) { + fTypeBindings.put(new Integer(node.getStartPosition()), node.resolveTypeBinding()); + fMethodBindings.put(new Integer(node.getStartPosition()), node.resolveConstructorBinding()); + return true; + } 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; + if(expression != null) { + fTypeBindings.put(new Integer(expression.getStartPosition()), expression.resolveTypeBinding()); } - fReturnExpressions.add(expression); - return false; + return true; } } + public IBinding resolveBinding(ASTNode node) { + return resolveBinding(node.getStartPosition()); + } + + public IBinding resolveBinding(int startPosition) { + return (IBinding)fBindings.get(new Integer(startPosition)); + } + + public ITypeBinding resolveTypeBinding(ASTNode node) { + return resolveTypeBinding(node.getStartPosition()); + } + + public ITypeBinding resolveTypeBinding(int startPosition) { + return (ITypeBinding)fTypeBindings.get(new Integer(startPosition)); + } + + public IMethodBinding resolveMethodBinding(ASTNode node) { + return resolveMethodBinding(node.getStartPosition()); + } + + public IMethodBinding resolveMethodBinding(int startPosition) { + return (IMethodBinding)fMethodBindings.get(new Integer(startPosition)); + } + public SourceProvider(ICompilationUnit unit, MethodDeclaration declaration) { super(); fCUnit= unit; @@ -88,47 +322,90 @@ ParameterData data= new ParameterData(element); element.setProperty(ParameterData.PROPERTY, data); } - fRewriter= new ASTRewrite(fDeclaration); - fAnalyzer= new SourceAnalyzer(fCUnit, fDeclaration); - fReturnValueNeedsLocalVariable= true; - fReturnExpressions= new ArrayList(); + fStatements= ASTNode.copySubtrees(fDeclaration.getAST(), + fDeclaration.getBody().statements()); + + fBindings= new HashMap(); + fTypeBindings= new HashMap(); + fMethodBindings= new HashMap(); + fDeclaration.getBody().accept(new BindingCollector()); + fParameters= new HashMap(parameters.size()); + for (Iterator iter= parameters.iterator(); iter.hasNext();) { + SingleVariableDeclaration element= (SingleVariableDeclaration) iter.next(); + fParameters.put(element.resolveBinding(), element.getProperty(ParameterData.PROPERTY)); + } + fNames= new HashMap(); + fImplicitReceivers= new ArrayList(2); + fTypes= new ArrayList(2); } - + public RefactoringStatus checkActivation(IProgressMonitor pm) throws JavaModelException { - return fAnalyzer.checkActivation(); + RefactoringStatus result= new RefactoringStatus(); + if (!fCUnit.isStructureKnown()) { + result.addFatalError( + RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.syntax_errors"), //$NON-NLS-1$ + JavaStatusContext.create(fCUnit)); + return result; + } + IProblem[] problems= ASTNodes.getProblems(fDeclaration, ASTNodes.NODE_ONLY, ASTNodes.ERROR); + if (problems.length > 0) { + result.addFatalError( + RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.declaration_has_errors"), //$NON-NLS-1$ + JavaStatusContext.create(fCUnit, fDeclaration)); + return result; + } + if (fDeclaration.getBody() == null) { + result.addFatalError( + RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.abstract_methods"), //$NON-NLS-1$ + JavaStatusContext.create(fCUnit, fDeclaration)); + return result; + } + if (fDeclaration.isConstructor()) { + result.addFatalError( + RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.constructors"), //$NON-NLS-1$ + JavaStatusContext.create(fCUnit, fDeclaration)); + return result; + } + ActivationAnalyzer analyzer= new ActivationAnalyzer(); + ASTNodes.acceptNodes(fStatements, analyzer); + result.merge(analyzer.status); + return result; } 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); - } - } + + ASTNodes.acceptNodes(fStatements, new UpdateCollector()); + + int numberOfLocals= LocalVariableIndex.perform(fDeclaration); + FlowContext context= new FlowContext(0, numberOfLocals + 1); + context.setConsiderAccessMode(true); + context.setComputeMode(FlowContext.MERGE); + InOutFlowAnalyzer flowAnalyzer= new InOutFlowAnalyzer(context); + FlowInfo info= 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)); + } } public boolean isExecutionFlowInterrupted() { - return fAnalyzer.isExecutionFlowInterrupted(); + return fInterruptedExecutionFlow; } public boolean hasReturnValue() { - IMethodBinding binding= fDeclaration.resolveBinding(); - return binding.getReturnType() != fDeclaration.getAST().resolveWellKnownType("void"); //$NON-NLS-1$ - } - - public boolean mustEvaluateReturnedExpression() { - return fMustEvalReturnedExpression; - } - - public boolean returnValueNeedsLocalVariable() { - return fReturnValueNeedsLocalVariable; + Type returnType= fDeclaration.getReturnType(); + if(!returnType.isPrimitiveType()) { + return true; + } + return ((PrimitiveType)returnType).getPrimitiveTypeCode() != PrimitiveType.VOID; } public int getNumberOfStatements() { - return fDeclaration.getBody().statements().size(); + return fStatements.size(); } public boolean isSimpleFunction() { @@ -146,22 +423,8 @@ return fDeclaration.getName().getIdentifier(); } - public ITypeBinding getReturnType() { - return fDeclaration.resolveBinding().getReturnType(); - } - - public List getReturnExpressions() { - return fReturnExpressions; - } - - 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 Type getReturnType() { + return fDeclaration.getReturnType(); } public ParameterData getParameterData(int index) { @@ -172,229 +435,166 @@ public ICompilationUnit getCompilationUnit() { return fCUnit; } - - public boolean needsReturnedExpressionParenthesis() { - ASTNode last= getLastStatement(); - if (last instanceof ReturnStatement) { - return ASTNodes.needsParentheses(((ReturnStatement)last).getExpression()); - } - return false; - } - + public int getReceiversToBeUpdated() { - return fAnalyzer.getImplicitReceivers().size(); + return fImplicitReceivers.size(); } - + public TextEdit getDeleteEdit() { ASTRewrite rewriter= new ASTRewrite(fDeclaration.getParent()); rewriter.markAsRemoved(fDeclaration); MultiTextEdit result= new MultiTextEdit(); - rewriter.rewriteNode(fBuffer, result, null); + rewriter.rewriteNode(fBuffer, result); rewriter.removeModifications(); return result; } - - public String[] getCodeBlocks(CallContext context) throws CoreException { - replaceParameterWithExpression(context.arguments); - updateImplicitReceivers(context); - makeNamesUnique(context.scope); - updateTypes(context); + + /** + * @param context call context of method invocation. + * @return list of statements composing inlined method body. + * @throws CoreException + */ + public List getCodeStatements(CallContext context) throws CoreException { - 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(); - } - } + context.receiver= replaceAST(fDeclaration.getAST(), context.receiver); + replaceAST(fDeclaration.getAST(), context.arguments); - MultiTextEdit dummy= new MultiTextEdit(); - fRewriter.rewriteNode(fBuffer, dummy, null); + replaceParameterWithExpression(fStatements, context.arguments); + updateImplicitReceivers(context.importer, context.receiver); + makeNamesUnique(context.scope); + updateTypes(context.importer); + + return fStatements; + } - int size= ranges.size(); - RangeMarker[] markers= new RangeMarker[size]; - for (int i= 0; i < markers.length; i++) { - markers[i]= new RangeMarker((TextRange)ranges.get(i)); - } - int split= size <= 1 ? Integer.MAX_VALUE : ((TextRange)ranges.get(0)).getExclusiveEnd(); - TextEdit[] edits= dummy.removeAll(); - for (int i= 0; i < edits.length; i++) { - TextEdit edit= edits[i]; - int pos= edit.getTextRange().getOffset() >= split ? 1 : 0; - markers[pos].add(edit); - } - MultiTextEdit root= new MultiTextEdit(); - root.addAll(markers); - TextBufferEditor editor= new TextBufferEditor(fBuffer); - editor.add(root); - UndoMemento 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(); + public static ASTNode replaceAST(AST ast, ASTNode node) { + ASTNode result= node; + if(node != null && node.getAST() != ast) { + result= ASTNode.copySubtree(ast, node); + } return result; } - private void replaceParameterWithExpression(String[] expressions) { + public static void replaceAST(AST ast, ASTNode[] nodes) { + for (int i = 0; i < nodes.length; i++) { + nodes[i]= replaceAST(ast, nodes[i]); + } + } + + public static void replaceAST(AST ast, List nodes) { + for (int i = 0; i < nodes.size(); i++) { + nodes.set(i, replaceAST(ast, (ASTNode)nodes.get(i))); + } + } + + private class ParameterReferenceFinder extends ASTVisitor { + private HashMap parametersMap; + public ParameterReferenceFinder(HashMap parametersMap) { + this.parametersMap= parametersMap; + } + public boolean visit(SimpleName node) { + ArrayList list= (ArrayList)parametersMap.get(node.getIdentifier()); + if (list != null) { + list.add(node); + } + return true; + } + } + + private void replaceParameterWithExpression(List statements, ASTNode[] expressions) { + List parameters= fDeclaration.parameters(); + List[] referenceList= new ArrayList[parameters.size()]; + HashMap parametersMap= new HashMap(parameters.size()); + for (int i= 0; i < parameters.size(); i++) { + SingleVariableDeclaration element= (SingleVariableDeclaration) parameters.get(i); + parametersMap.put(element.getName().getIdentifier(), referenceList[i]= new ArrayList()); + } + ASTNodes.acceptNodes(fStatements, new ParameterReferenceFinder(parametersMap)); + for (int i= 0; i < expressions.length; i++) { - String expression= expressions[i]; - ParameterData parameter= getParameterData(i); - List references= parameter.references(); + ASTNode expression= expressions[i]; + List references= referenceList[i]; for (Iterator iter= references.iterator(); iter.hasNext();) { ASTNode element= (ASTNode) iter.next(); - ASTNode newNode= fRewriter.createPlaceholder(expression, ASTRewrite.getPlaceholderType(element)); - fRewriter.markAsReplaced(element, newNode); + if(expression.getParent() != null) { + expression= ASTNode.copySubtree( + expression.getAST(), expression); + } + ASTNodes.substitute(element, expression); } } } private void makeNamesUnique(CodeScopeBuilder.Scope scope) { - Collection usedCalleeNames= fAnalyzer.getUsedNames(); + Collection usedCalleeNames= fNames.values(); for (Iterator iter= usedCalleeNames.iterator(); iter.hasNext();) { - SourceAnalyzer.NameData nd= (SourceAnalyzer.NameData) iter.next(); + NameData nd= (NameData) iter.next(); if (scope.isInUse(nd.getName())) { String newName= scope.createName(nd.getName(), true); List references= nd.references(); for (Iterator refs= references.iterator(); refs.hasNext();) { SimpleName element= (SimpleName) refs.next(); - ASTNode newNode= fRewriter.createPlaceholder(newName, ASTRewrite.EXPRESSION); - fRewriter.markAsReplaced(element, newNode); + element.setIdentifier(newName); } } } } - private void updateImplicitReceivers(CallContext context) { - if (context.receiver == null) - return; - List implicitReceivers= fAnalyzer.getImplicitReceivers(); - for (Iterator iter= implicitReceivers.iterator(); iter.hasNext();) { - ASTNode node= (ASTNode)iter.next(); - if (node instanceof MethodInvocation) { - final MethodInvocation inv= (MethodInvocation)node; - inv.setExpression(createReceiver(context, (IMethodBinding)inv.getName().resolveBinding())); - } else if (node instanceof ClassInstanceCreation) { - final ClassInstanceCreation inst= (ClassInstanceCreation)node; - inst.setExpression(createReceiver(context, inst.resolveConstructorBinding())); - } else if (node instanceof Expression) { - fRewriter.markAsReplaced(node, fRewriter.createPlaceholder(context.receiver, ASTRewrite.EXPRESSION)); + private void updateImplicitReceivers(ImportEdit importer, ASTNode receiver) { + if (receiver != null) { + AST ast= receiver.getAST(); + for (Iterator iter= fImplicitReceivers.iterator(); iter.hasNext();) { + ASTNode node= (ASTNode)iter.next(); + if(receiver.getParent() != null) { + receiver= ASTNode.copySubtree(receiver.getAST(), receiver); + } + int nodeType= node.getNodeType(); + if (nodeType == ASTNode.METHOD_INVOCATION) { + MethodInvocation methodInvocation= (MethodInvocation)node; + IMethodBinding methodBinding= resolveMethodBinding(methodInvocation); + methodInvocation.setExpression(createReceiver(receiver, importer, methodBinding)); + } + else if (nodeType == ASTNode.CLASS_INSTANCE_CREATION) { + ClassInstanceCreation methodInvocation= (ClassInstanceCreation)node; + IMethodBinding methodBinding= resolveMethodBinding(methodInvocation); + methodInvocation.setExpression(createReceiver(receiver, importer, methodBinding)); + } + else { + ASTNodes.substitute(node, receiver); + } } } } - - private void updateTypes(CallContext context) { - ImportEdit importer= context.importer; - for (Iterator iter= fAnalyzer.getUsedTypes().iterator(); iter.hasNext();) { + + private Expression createReceiver(ASTNode receiver, ImportEdit importer, IMethodBinding methodBinding) { + if (Modifier.isStatic(methodBinding.getModifiers())) { + ITypeBinding typeBinding= methodBinding.getDeclaringClass(); + importer.addImport(typeBinding); + return receiver.getAST().newSimpleName(typeBinding.getName()); + } + else { + return (Expression)receiver; + } + } + + private void updateTypes(ImportEdit importer) { + for (Iterator iter= fTypes.iterator(); iter.hasNext();) { Name element= (Name)iter.next(); - ITypeBinding binding= ASTNodes.getTypeBinding(element); + ITypeBinding binding= resolveTypeBinding(element); if (binding != null && !binding.isLocal()) { String s= importer.addImport(binding); if (!ASTNodes.asString(element).equals(s)) { - fRewriter.markAsReplaced(element, fRewriter.createPlaceholder(s, ASTRewrite.EXPRESSION)); + if(element instanceof SimpleName) { + SimpleName simpleName= (SimpleName)element; + simpleName.setIdentifier(s); + } } } } } - private Expression createReceiver(CallContext context, IMethodBinding method) { - String receiver= context.receiver; - if (!context.receiverIsStatic && Modifier.isStatic(method.getModifiers())) { - receiver= context.importer.addImport(fDeclaration.resolveBinding().getDeclaringClass()); - } - Expression exp= (Expression)fRewriter.createPlaceholder(receiver, ASTRewrite.EXPRESSION); - fRewriter.markAsInserted(exp); - return exp; - } - - private ASTNode getLastStatement() { - List statements= fDeclaration.getBody().statements(); - if (statements.isEmpty()) - return null; - return (ASTNode)statements.get(statements.size() - 1); - } - - private List getReturnStatementRanges() { - List result= new ArrayList(1); + private ASTNode[] getStatements() { List statements= fDeclaration.getBody().statements(); - int size= statements.size(); - if (size <= 1) - return result; - result.add(createRange(statements, size - 2)); - return result; - } - - 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(TextRange.createFromStartAndLength(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; - } - } - if (rs != null) { - Expression exp= rs.getExpression(); - result.add(TextRange.createFromStartAndLength(exp.getStartPosition(), exp.getLength())); - } - return result; - } - - private TextRange 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(); - TextRange range= TextRange.createFromStartAndLength(start, length); - return range; - } - - private String[] getBlocks(RangeMarker[] markers) { - String[] result= new String[markers.length]; - for (int i= 0; i < markers.length; i++) { - TextRange range= markers[i].getTextRange(); - String content= fBuffer.getContent(range.getOffset(), range.getLength()); - String lines[]= Strings.convertIntoLines(content); - Strings.trimIndentation(lines, CodeFormatterUtil.getTabWidth(), false); - result[i]= Strings.concatenate(lines, fBuffer.getLineDelimiter()); - } - return result; - } + return (ASTNode[]) statements.toArray(new ASTNode[statements.size()]); + } }