View | Details | Raw Unified | Return to bug 36049 | Differences between
and this patch

Collapse All | Expand All

(-)core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java (-2 / +675 lines)
Lines 18-24 Link Here
18
import java.util.List;
18
import java.util.List;
19
19
20
import org.eclipse.core.runtime.CoreException;
20
import org.eclipse.core.runtime.CoreException;
21
22
import org.eclipse.jdt.core.ISourceRange;
21
import org.eclipse.jdt.core.ISourceRange;
23
import org.eclipse.jdt.core.ToolFactory;
22
import org.eclipse.jdt.core.ToolFactory;
24
import org.eclipse.jdt.core.compiler.IProblem;
23
import org.eclipse.jdt.core.compiler.IProblem;
Lines 27-69 Link Here
27
import org.eclipse.jdt.core.dom.ASTNode;
26
import org.eclipse.jdt.core.dom.ASTNode;
28
import org.eclipse.jdt.core.dom.ASTVisitor;
27
import org.eclipse.jdt.core.dom.ASTVisitor;
29
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
28
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
29
import org.eclipse.jdt.core.dom.ArrayAccess;
30
import org.eclipse.jdt.core.dom.ArrayCreation;
30
import org.eclipse.jdt.core.dom.ArrayCreation;
31
import org.eclipse.jdt.core.dom.ArrayInitializer;
31
import org.eclipse.jdt.core.dom.ArrayInitializer;
32
import org.eclipse.jdt.core.dom.ArrayType;
32
import org.eclipse.jdt.core.dom.ArrayType;
33
import org.eclipse.jdt.core.dom.AssertStatement;
33
import org.eclipse.jdt.core.dom.Assignment;
34
import org.eclipse.jdt.core.dom.Assignment;
34
import org.eclipse.jdt.core.dom.Block;
35
import org.eclipse.jdt.core.dom.Block;
35
import org.eclipse.jdt.core.dom.BodyDeclaration;
36
import org.eclipse.jdt.core.dom.BodyDeclaration;
37
import org.eclipse.jdt.core.dom.BooleanLiteral;
38
import org.eclipse.jdt.core.dom.BreakStatement;
39
import org.eclipse.jdt.core.dom.CastExpression;
40
import org.eclipse.jdt.core.dom.CatchClause;
41
import org.eclipse.jdt.core.dom.CharacterLiteral;
36
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
42
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
37
import org.eclipse.jdt.core.dom.CompilationUnit;
43
import org.eclipse.jdt.core.dom.CompilationUnit;
44
import org.eclipse.jdt.core.dom.ConditionalExpression;
38
import org.eclipse.jdt.core.dom.ConstructorInvocation;
45
import org.eclipse.jdt.core.dom.ConstructorInvocation;
46
import org.eclipse.jdt.core.dom.ContinueStatement;
47
import org.eclipse.jdt.core.dom.DoStatement;
48
import org.eclipse.jdt.core.dom.EmptyStatement;
39
import org.eclipse.jdt.core.dom.Expression;
49
import org.eclipse.jdt.core.dom.Expression;
50
import org.eclipse.jdt.core.dom.ExpressionStatement;
51
import org.eclipse.jdt.core.dom.FieldAccess;
40
import org.eclipse.jdt.core.dom.FieldDeclaration;
52
import org.eclipse.jdt.core.dom.FieldDeclaration;
41
import org.eclipse.jdt.core.dom.ForStatement;
53
import org.eclipse.jdt.core.dom.ForStatement;
42
import org.eclipse.jdt.core.dom.IBinding;
54
import org.eclipse.jdt.core.dom.IBinding;
43
import org.eclipse.jdt.core.dom.IMethodBinding;
55
import org.eclipse.jdt.core.dom.IMethodBinding;
44
import org.eclipse.jdt.core.dom.ITypeBinding;
56
import org.eclipse.jdt.core.dom.ITypeBinding;
45
import org.eclipse.jdt.core.dom.IVariableBinding;
57
import org.eclipse.jdt.core.dom.IVariableBinding;
58
import org.eclipse.jdt.core.dom.IfStatement;
59
import org.eclipse.jdt.core.dom.ImportDeclaration;
46
import org.eclipse.jdt.core.dom.InfixExpression;
60
import org.eclipse.jdt.core.dom.InfixExpression;
61
import org.eclipse.jdt.core.dom.Initializer;
62
import org.eclipse.jdt.core.dom.InstanceofExpression;
63
import org.eclipse.jdt.core.dom.Javadoc;
64
import org.eclipse.jdt.core.dom.LabeledStatement;
47
import org.eclipse.jdt.core.dom.Message;
65
import org.eclipse.jdt.core.dom.Message;
48
import org.eclipse.jdt.core.dom.MethodDeclaration;
66
import org.eclipse.jdt.core.dom.MethodDeclaration;
49
import org.eclipse.jdt.core.dom.MethodInvocation;
67
import org.eclipse.jdt.core.dom.MethodInvocation;
50
import org.eclipse.jdt.core.dom.Name;
68
import org.eclipse.jdt.core.dom.Name;
69
import org.eclipse.jdt.core.dom.NullLiteral;
70
import org.eclipse.jdt.core.dom.NumberLiteral;
71
import org.eclipse.jdt.core.dom.PackageDeclaration;
72
import org.eclipse.jdt.core.dom.ParenthesizedExpression;
73
import org.eclipse.jdt.core.dom.PostfixExpression;
74
import org.eclipse.jdt.core.dom.PrefixExpression;
51
import org.eclipse.jdt.core.dom.PrimitiveType;
75
import org.eclipse.jdt.core.dom.PrimitiveType;
52
import org.eclipse.jdt.core.dom.QualifiedName;
76
import org.eclipse.jdt.core.dom.QualifiedName;
53
import org.eclipse.jdt.core.dom.ReturnStatement;
77
import org.eclipse.jdt.core.dom.ReturnStatement;
54
import org.eclipse.jdt.core.dom.SimpleName;
78
import org.eclipse.jdt.core.dom.SimpleName;
79
import org.eclipse.jdt.core.dom.SimpleType;
55
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
80
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
81
import org.eclipse.jdt.core.dom.Statement;
82
import org.eclipse.jdt.core.dom.StringLiteral;
56
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
83
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
84
import org.eclipse.jdt.core.dom.SuperFieldAccess;
57
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
85
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
86
import org.eclipse.jdt.core.dom.SwitchCase;
58
import org.eclipse.jdt.core.dom.SwitchStatement;
87
import org.eclipse.jdt.core.dom.SwitchStatement;
88
import org.eclipse.jdt.core.dom.SynchronizedStatement;
89
import org.eclipse.jdt.core.dom.ThisExpression;
90
import org.eclipse.jdt.core.dom.ThrowStatement;
59
import org.eclipse.jdt.core.dom.TryStatement;
91
import org.eclipse.jdt.core.dom.TryStatement;
60
import org.eclipse.jdt.core.dom.Type;
92
import org.eclipse.jdt.core.dom.Type;
61
import org.eclipse.jdt.core.dom.TypeDeclaration;
93
import org.eclipse.jdt.core.dom.TypeDeclaration;
94
import org.eclipse.jdt.core.dom.TypeDeclarationStatement;
95
import org.eclipse.jdt.core.dom.TypeLiteral;
62
import org.eclipse.jdt.core.dom.VariableDeclaration;
96
import org.eclipse.jdt.core.dom.VariableDeclaration;
63
import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
97
import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
64
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
98
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
65
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
99
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
66
100
import org.eclipse.jdt.core.dom.WhileStatement;
67
import org.eclipse.jdt.internal.corext.Assert;
101
import org.eclipse.jdt.internal.corext.Assert;
68
import org.eclipse.jdt.internal.corext.SourceRange;
102
import org.eclipse.jdt.internal.corext.SourceRange;
69
import org.eclipse.jdt.internal.corext.textmanipulation.TextBuffer;
103
import org.eclipse.jdt.internal.corext.textmanipulation.TextBuffer;
Lines 321-326 Link Here
321
			type == ASTNode.NUMBER_LITERAL || type == ASTNode.STRING_LITERAL || type == ASTNode.TYPE_LITERAL;
355
			type == ASTNode.NUMBER_LITERAL || type == ASTNode.STRING_LITERAL || type == ASTNode.TYPE_LITERAL;
322
	}
356
	}
323
	
357
	
358
	public static boolean isInvocation(Expression expression) {
359
		int type= expression.getNodeType();
360
		return type == ASTNode.METHOD_INVOCATION || type == ASTNode.SUPER_METHOD_INVOCATION;
361
	}
362
	
324
	public static String getTypeName(Type type) {
363
	public static String getTypeName(Type type) {
325
		final StringBuffer buffer= new StringBuffer();
364
		final StringBuffer buffer= new StringBuffer();
326
		ASTVisitor visitor= new ASTVisitor() {
365
		ASTVisitor visitor= new ASTVisitor() {
Lines 697-700 Link Here
697
		name.accept(visitor);
736
		name.accept(visitor);
698
		return result[0];
737
		return result[0];
699
	}	
738
	}	
739
740
	public static void acceptNodes(List nodes, ASTVisitor visitor) {
741
		for (Iterator iter = nodes.iterator(); iter.hasNext();) {
742
			ASTNode element = (ASTNode) iter.next();
743
			element.accept(visitor);
744
		}
745
	}
746
747
	private static class ChildSubstituteVisitor extends ASTVisitor {
748
		private ASTNode fSource;
749
		private ASTNode fReplacement;
750
		public ChildSubstituteVisitor(ASTNode source, ASTNode replacement) {
751
			fSource= source;
752
			fReplacement= replacement;
753
		}
754
		public boolean visit(AnonymousClassDeclaration node) {
755
			List bodies= node.bodyDeclarations();
756
			int index= bodies.indexOf(fSource);
757
			if(index != -1) {
758
				if(fReplacement != null) {
759
					bodies.set(index, (BodyDeclaration)fReplacement);
760
				}
761
				else {
762
					bodies.remove(index);
763
				}
764
			}
765
			return false;
766
		}
767
		public boolean visit(ArrayAccess node) {
768
			if(node.getArray() == fSource) {
769
				node.setArray((Expression)fReplacement);
770
			}
771
			else if(node.getIndex() == fSource) {
772
				node.setIndex((Expression)fReplacement);
773
			}
774
			return false;
775
		}
776
		public boolean visit(ArrayCreation node) {
777
			if(node.getType() == fSource) {
778
				node.setType((ArrayType)fReplacement);
779
			}
780
			else if(node.getInitializer() == fSource) {
781
				node.setInitializer((ArrayInitializer)fReplacement);
782
			}
783
			return false;
784
		}
785
		public boolean visit(ArrayInitializer node) {
786
			List expressions= node.expressions();
787
			int index= expressions.indexOf(fSource);
788
			if(index != -1) {
789
				if(fReplacement != null) {
790
					expressions.set(index, (Expression)fReplacement);
791
				}
792
				else {
793
					expressions.remove(index);
794
				}
795
			}
796
			return false;
797
		}
798
		public boolean visit(ArrayType node) {
799
			if(node.getComponentType() == fSource) {
800
				node.setComponentType((Type)fReplacement);
801
			}
802
			return false;
803
		}
804
		public boolean visit(AssertStatement node) {
805
			if(node.getExpression() == fSource) {
806
				node.setExpression((Expression)fReplacement);
807
			}
808
			else if(node.getMessage() == fSource) {
809
				node.setMessage((Expression)fReplacement);
810
			}
811
			return false;
812
		}
813
		public boolean visit(Assignment node) {
814
			if(node.getLeftHandSide() == fSource) {
815
				node.setLeftHandSide((Expression)fReplacement);
816
			}
817
			else if(node.getRightHandSide() == fSource) {
818
				node.setRightHandSide((Expression)fReplacement);
819
			}
820
			return false;
821
		}
822
		public boolean visit(Block node) {
823
			List statements= node.statements();
824
			int index= statements.indexOf(fSource);
825
			if(index != -1) {
826
				if(fReplacement != null) {
827
					statements.set(index, (Statement)fReplacement);
828
				}
829
				else {
830
					statements.remove(index);
831
				}
832
			}
833
			return false;
834
		}
835
		public boolean visit(BooleanLiteral node) {
836
			return false;
837
		}
838
		public boolean visit(BreakStatement node) {
839
			if(node.getLabel() == fSource) {
840
				node.setLabel((SimpleName)fReplacement);
841
			}
842
			return false;
843
		}
844
		public boolean visit(CastExpression node) {
845
			if(node.getExpression() == fSource) {
846
				node.setExpression((Expression)fReplacement);
847
			}
848
			else if(node.getType() == fSource) {
849
				node.setType((Type)fReplacement);
850
			}
851
			return false;
852
		}
853
		public boolean visit(CatchClause node) {
854
			if(node.getBody() == fSource) {
855
				node.setBody((Block)fReplacement);
856
			}
857
			else if(node.getException() == fSource) {
858
				node.setException((SingleVariableDeclaration)fReplacement);
859
			}
860
			return false;
861
		}
862
		public boolean visit(CharacterLiteral node) {
863
			return false;
864
		}
865
		public boolean visit(ClassInstanceCreation node) {
866
			if(node.getAnonymousClassDeclaration() == fSource) {
867
				node.setAnonymousClassDeclaration((AnonymousClassDeclaration)fReplacement);
868
			}
869
			else if(node.getExpression() == fSource) {
870
				node.setExpression((Expression)fReplacement);
871
			}
872
			else if(node.getName() == fSource) {
873
				node.setName((Name)fReplacement);
874
			}
875
			return false;
876
		}
877
		public boolean visit(CompilationUnit node) {
878
			return false;
879
		}
880
		public boolean visit(ConditionalExpression node) {
881
			if(node.getExpression() == fSource) {
882
				node.setExpression((Expression)fReplacement);
883
			}
884
			else if(node.getThenExpression() == fSource) {
885
				node.setThenExpression((Expression)fReplacement);
886
			}
887
			else if(node.getElseExpression() == fSource) {
888
				node.setElseExpression((Expression)fReplacement);
889
			}
890
			return false;
891
		}
892
		public boolean visit(ConstructorInvocation node) {
893
			List arguments= node.arguments();
894
			int index= arguments.indexOf(fSource);
895
			if(index != -1) {
896
				if(fReplacement != null) {
897
					arguments.set(index, (Expression)fReplacement);
898
				}
899
				else {
900
					arguments.remove(index);
901
				}
902
			}
903
			return false;
904
		}
905
		public boolean visit(ContinueStatement node) {
906
			if(node.getLabel() == fSource) {
907
				node.setLabel((SimpleName)fReplacement);
908
			}
909
			return false;
910
		}
911
		public boolean visit(DoStatement node) {
912
			if(node.getBody() == fSource) {
913
				node.setBody((Statement)fReplacement);
914
			}
915
			else if(node.getExpression() == fSource) {
916
				node.setExpression((Expression)fReplacement);
917
			}
918
			return false;
919
		}
920
		public boolean visit(EmptyStatement node) {
921
			return false;
922
		}
923
		public boolean visit(ExpressionStatement node) {
924
			if(node.getExpression() == fSource) {
925
				node.setExpression((Expression)fReplacement);
926
			}
927
			return false;
928
		}
929
		public boolean visit(FieldAccess node) {
930
			if(node.getName() == fSource) {
931
				node.setName((SimpleName)fReplacement);
932
			}
933
			else if(node.getExpression() == fSource) {
934
				node.setExpression((Expression)fReplacement);
935
			}
936
			return false;
937
		}
938
		public boolean visit(FieldDeclaration node) {
939
			if(node.getType() == fSource) {
940
				node.setType((Type)fReplacement);
941
			}
942
			else {
943
				List fragments= node.fragments();
944
				int index= fragments.indexOf(fSource);
945
				if(index != -1) {
946
					if(fReplacement != null) {
947
						fragments.set(index, (VariableDeclarationFragment)fReplacement);
948
					}
949
					else {
950
						fragments.remove(index);
951
					}
952
				}
953
			}
954
			return false;
955
		}
956
		public boolean visit(ForStatement node) {
957
			if(node.getExpression() == fSource) {
958
				node.setExpression((Expression)fReplacement);
959
			}
960
			else if(node.getBody() == fSource) {
961
				node.setBody((Statement)fReplacement);
962
			}
963
			else {
964
				List initializers= node.initializers();
965
				int index= initializers.indexOf(fSource);
966
				if(index != -1) {
967
					if(fReplacement != null) {
968
						initializers.set(index, (Expression)fReplacement);
969
					}
970
					else {
971
						initializers.remove(index);
972
					}
973
				}
974
				else {
975
					List updaters= node.updaters();
976
					index= updaters.indexOf(fSource);
977
					if(index != -1) {
978
						if(fReplacement != null) {
979
							updaters.set(index, (Expression)fReplacement);
980
						}
981
						else {
982
							updaters.remove(index);
983
						}
984
					}
985
				}
986
			}
987
			return false;
988
		}
989
		public boolean visit(IfStatement node) {
990
			if(node.getExpression() == fSource) {
991
				node.setExpression((Expression)fReplacement);
992
			}
993
			else if(node.getThenStatement() == fSource) {
994
				node.setThenStatement((Statement)fReplacement);
995
			}
996
			else if(node.getElseStatement() == fSource) {
997
				node.setElseStatement((Statement)fReplacement);
998
			}
999
			return false;
1000
		}
1001
		public boolean visit(ImportDeclaration node) {
1002
			if(node.getName() == fSource) {
1003
				node.setName((Name)fReplacement);
1004
			}
1005
			return false;
1006
		}
1007
		public boolean visit(InfixExpression node) {
1008
			if(node.getLeftOperand() == fSource) {
1009
				node.setLeftOperand((Expression)fReplacement);
1010
			}
1011
			else if(node.getRightOperand() == fSource) {
1012
				node.setRightOperand((Expression)fReplacement);
1013
			}
1014
			else if(node.hasExtendedOperands()) {
1015
				List extendedOperands= node.extendedOperands();
1016
				int index= extendedOperands.indexOf(fSource);
1017
				if(index != -1) {
1018
					if(fReplacement != null) {
1019
						extendedOperands.set(index, (Expression)fReplacement);
1020
					}
1021
					else {
1022
						extendedOperands.remove(index);
1023
					}
1024
				}
1025
			}
1026
			return false;
1027
		}
1028
		public boolean visit(Initializer node) {
1029
			if(node.getBody() == fSource) {
1030
				node.setBody((Block)fReplacement);
1031
			}
1032
			return false;
1033
		}
1034
		public boolean visit(Javadoc node) {
1035
			return false;
1036
		}
1037
		public boolean visit(LabeledStatement node) {
1038
			if(node.getLabel() == fSource) {
1039
				node.setLabel((SimpleName)fReplacement);
1040
			}
1041
			else if(node.getBody() == fSource) {
1042
				node.setBody((Block)fReplacement);
1043
			}
1044
			return false;
1045
		}
1046
		public boolean visit(MethodDeclaration node) {
1047
			if(node.getName() == fSource) {
1048
				node.setName((SimpleName)fReplacement);
1049
			}
1050
			else if(node.getReturnType() == fSource) {
1051
				node.setReturnType((Type)fReplacement);
1052
			}
1053
			else if(node.getBody() == fSource) {
1054
				node.setBody((Block)fReplacement);
1055
			}
1056
			else {
1057
				List parameters= node.parameters();
1058
				int index= parameters.indexOf(fSource);
1059
				if(index != -1) {
1060
					if(fReplacement != null) {
1061
						parameters.set(index, (SingleVariableDeclaration)fReplacement);
1062
					}
1063
					else {
1064
						parameters.remove(index);
1065
					}
1066
				}
1067
			}
1068
			return false;
1069
		}
1070
		public boolean visit(MethodInvocation node) {
1071
			if(node.getName() == fSource) {
1072
				node.setName((SimpleName)fReplacement);
1073
			}
1074
			else if(node.getExpression() == fSource) {
1075
				node.setExpression((Expression)fReplacement);
1076
			}
1077
			else {
1078
				List arguments= node.arguments();
1079
				int index= arguments.indexOf(fSource);
1080
				if(index != -1) {
1081
					if(fReplacement != null) {
1082
						arguments.set(index, (Expression)fReplacement);
1083
					}
1084
					else {
1085
						arguments.remove(index);
1086
					}
1087
				}
1088
			}
1089
			return false;
1090
		}
1091
		public boolean visit(NullLiteral node) {
1092
			return false;
1093
		}
1094
		public boolean visit(NumberLiteral node) {
1095
			return false;
1096
		}
1097
		public boolean visit(PackageDeclaration node) {
1098
			if(node.getName() == fSource) {
1099
				node.setName((SimpleName)fReplacement);
1100
			}
1101
			return false;
1102
		}
1103
		public boolean visit(ParenthesizedExpression node) {
1104
			if(node.getExpression() == fSource) {
1105
				node.setExpression((Expression)fReplacement);
1106
			}
1107
			return false;
1108
		}
1109
		public boolean visit(PostfixExpression node) {
1110
			if(node.getOperand() == fSource) {
1111
				node.setOperand((Expression)fReplacement);
1112
			}
1113
			return false;
1114
		}
1115
		public boolean visit(PrefixExpression node) {
1116
			if(node.getOperand() == fSource) {
1117
				node.setOperand((Expression)fReplacement);
1118
			}
1119
			return false;
1120
		}
1121
		public boolean visit(PrimitiveType node) {
1122
			return false;
1123
		}
1124
		public boolean visit(QualifiedName node) {
1125
			if(node.getName() == fSource) {
1126
				node.setName((SimpleName)fReplacement);
1127
			}
1128
			return false;
1129
		}
1130
		public boolean visit(ReturnStatement node) {
1131
			if(node.getExpression() == fSource) {
1132
				node.setExpression((Expression)fReplacement);
1133
			}
1134
			return false;
1135
		}
1136
		public boolean visit(SimpleName node) {
1137
			return false;
1138
		}
1139
		public boolean visit(SimpleType node) {
1140
			if(node.getName() == fSource) {
1141
				node.setName((Name)fReplacement);
1142
			}
1143
			return false;
1144
		}
1145
		public boolean visit(SingleVariableDeclaration node) {
1146
			if(node.getInitializer() == fSource) {
1147
				node.setInitializer((Expression)fReplacement);
1148
			}
1149
			else if(node.getName() == fSource) {
1150
				node.setName((SimpleName)fReplacement);
1151
			}
1152
			else if(node.getType() == fSource) {
1153
				node.setType((Type)fReplacement);
1154
			}
1155
			return false;
1156
		}
1157
		public boolean visit(StringLiteral node) {
1158
			return false;
1159
		}
1160
		public boolean visit(SuperConstructorInvocation node) {
1161
			if(node.getExpression() == fSource) {
1162
				node.setExpression((Expression)fReplacement);
1163
			}
1164
			else {
1165
				List arguments= node.arguments();
1166
				int index= arguments.indexOf(fSource);
1167
				if(index != -1) {
1168
					if(fReplacement != null) {
1169
						arguments.set(index, (Expression)fReplacement);
1170
					}
1171
					else {
1172
						arguments.remove(index);
1173
					}
1174
				}
1175
			}
1176
			return false;
1177
		}
1178
		public boolean visit(SuperFieldAccess node) {
1179
			if(node.getName() == fSource) {
1180
				node.setName((SimpleName)fReplacement);
1181
			}
1182
			else if(node.getQualifier() == fSource) {
1183
				node.setQualifier((Name)fReplacement);
1184
			}
1185
			return false;
1186
		}
1187
		public boolean visit(SuperMethodInvocation node) {
1188
			if(node.getName() == fSource) {
1189
				node.setName((SimpleName)fReplacement);
1190
			}
1191
			else if(node.getQualifier() == fSource) {
1192
				node.setQualifier((Name)fReplacement);
1193
			}
1194
			else {
1195
				List arguments= node.arguments();
1196
				int index= arguments.indexOf(fSource);
1197
				if(index != -1) {
1198
					if(fReplacement != null) {
1199
						arguments.set(index, (Expression)fReplacement);
1200
					}
1201
					else {
1202
						arguments.remove(index);
1203
					}
1204
				}
1205
			}
1206
			return false;
1207
		}
1208
		public boolean visit(SwitchCase node) {
1209
			if(node.getExpression() == fSource) {
1210
				node.setExpression((Expression)fReplacement);
1211
			}
1212
			return false;
1213
		}
1214
		public boolean visit(SwitchStatement node) {
1215
			if(node.getExpression() == fSource) {
1216
				node.setExpression((Expression)fReplacement);
1217
			}
1218
			return false;
1219
		}
1220
		public boolean visit(SynchronizedStatement node) {
1221
			if(node.getExpression() == fSource) {
1222
				node.setExpression((Expression)fReplacement);
1223
			}
1224
			else if(node.getBody() == fSource) {
1225
				node.setBody((Block)fReplacement);
1226
			}
1227
			return false;
1228
		}
1229
		public boolean visit(ThisExpression node) {
1230
			return false;
1231
		}
1232
		public boolean visit(ThrowStatement node) {
1233
			if(node.getExpression() == fSource) {
1234
				node.setExpression((Expression)fReplacement);
1235
			}
1236
			return false;
1237
		}
1238
		public boolean visit(TryStatement node) {
1239
			if(node.getBody() == fSource) {
1240
				node.setBody((Block)fReplacement);
1241
			}
1242
			else if(node.getFinally() == fSource) {
1243
				node.setFinally((Block)fReplacement);
1244
			}
1245
			else {
1246
				List catchClauses= node.catchClauses();
1247
				int index= catchClauses.indexOf(fSource);
1248
				if(index != -1) {
1249
					if(fReplacement != null) {
1250
						catchClauses.set(index, (CatchClause)fReplacement);
1251
					}
1252
					else {
1253
						catchClauses.remove(index);
1254
					}
1255
				}
1256
			}
1257
			return false;
1258
		}
1259
		public boolean visit(TypeDeclaration node) {
1260
			if(node.getName() == fSource) {
1261
				node.setName((SimpleName)fReplacement);
1262
			}
1263
			else if(node.getSuperclass() == fSource) {
1264
				node.setSuperclass((Name)fReplacement);
1265
			}
1266
			else {
1267
				List bodyDeclarations= node.bodyDeclarations();
1268
				int index= bodyDeclarations.indexOf(fSource);
1269
				if(index != -1) {
1270
					if(fReplacement != null) {
1271
						bodyDeclarations.set(index, (BodyDeclaration)fReplacement);
1272
					}
1273
					else {
1274
						bodyDeclarations.remove(index);
1275
					}
1276
				}
1277
				else {
1278
					List superInterfaces= node.superInterfaces();
1279
					index= superInterfaces.indexOf(fSource);
1280
					if(index != -1) {
1281
						if(fReplacement != null) {
1282
							superInterfaces.set(index, (Name)fReplacement);
1283
						}
1284
						else {
1285
							superInterfaces.remove(index);
1286
						}
1287
					}
1288
				}
1289
			}
1290
			return false;
1291
		}
1292
		public boolean visit(TypeDeclarationStatement node) {
1293
			if(node.getTypeDeclaration() == fSource) {
1294
				node.setTypeDeclaration((TypeDeclaration)fReplacement);
1295
			}
1296
			return false;
1297
		}
1298
		public boolean visit(TypeLiteral node) {
1299
			if(node.getType() == fSource) {
1300
				node.setType((Type)fReplacement);
1301
			}
1302
			return false;
1303
		}
1304
		public boolean visit(VariableDeclarationExpression node) {
1305
			if(node.getType() == fSource) {
1306
				node.setType((Type)fReplacement);
1307
			}
1308
			else {
1309
				List fragments= node.fragments();
1310
				int index= fragments.indexOf(fSource);
1311
				if(index != -1) {
1312
					if(fReplacement != null) {
1313
						fragments.set(index, (VariableDeclarationFragment)fReplacement);
1314
					}
1315
					else {
1316
						fragments.remove(index);
1317
					}
1318
				}
1319
			}
1320
			return false;
1321
		}
1322
		public boolean visit(VariableDeclarationFragment node) {
1323
			if(node.getName() == fSource) {
1324
				node.setName((SimpleName)fReplacement);
1325
			}
1326
			else if(node.getInitializer() == fSource) {
1327
				node.setInitializer((Expression)fReplacement);
1328
			}
1329
			return false;
1330
		}
1331
		public boolean visit(VariableDeclarationStatement node) {
1332
			if(node.getType() == fSource) {
1333
				node.setType((Type)fReplacement);
1334
			}
1335
			else {
1336
				List fragments= node.fragments();
1337
				int index= fragments.indexOf(fSource);
1338
				if(index != -1) {
1339
					if(fReplacement != null) {
1340
						fragments.set(index, (VariableDeclarationFragment)fReplacement);
1341
					}
1342
					else {
1343
						fragments.remove(index);
1344
					}
1345
				}
1346
			}
1347
			return false;
1348
		}
1349
		public boolean visit(WhileStatement node) {
1350
			if(node.getExpression() == fSource) {
1351
				node.setExpression((Expression)fReplacement);
1352
			}
1353
			else if(node.getBody() == fSource) {
1354
				node.setBody((Statement)fReplacement);
1355
			}
1356
			return false;
1357
		}
1358
		public boolean visit(InstanceofExpression node) {
1359
			if(node.getLeftOperand() == fSource) {
1360
				node.setLeftOperand((Expression)fReplacement);
1361
			}
1362
			else if(node.getRightOperand() == fSource) {
1363
				node.setRightOperand((Type)fReplacement);
1364
			}
1365
			return false;
1366
		}
1367
	}
1368
1369
	public static void substitute(ASTNode source, ASTNode replacement) {
1370
		ASTNode parent= source.getParent();
1371
		parent.accept(new ChildSubstituteVisitor(source, replacement));
1372
	}
700
}
1373
}
(-)core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallContext.java (-5 / +4 lines)
Lines 10-31 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.corext.refactoring.code;
11
package org.eclipse.jdt.internal.corext.refactoring.code;
12
12
13
import org.eclipse.jdt.core.dom.ASTNode;
13
import org.eclipse.jdt.internal.corext.codemanipulation.ImportEdit;
14
import org.eclipse.jdt.internal.corext.codemanipulation.ImportEdit;
14
import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder;
15
import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder;
15
16
16
public class CallContext {
17
public class CallContext {
17
18
18
	public String[] arguments;
19
	public ASTNode[] arguments;
19
	public String receiver; 
20
	public ASTNode receiver; 
20
	public boolean receiverIsStatic;
21
	public boolean receiverIsStatic;
21
	public CodeScopeBuilder.Scope scope;
22
	public CodeScopeBuilder.Scope scope;
22
	public int callMode;
23
	public ImportEdit importer;
23
	public ImportEdit importer;
24
24
25
	public CallContext(CodeScopeBuilder.Scope s, int cm, ImportEdit i) {
25
	public CallContext(CodeScopeBuilder.Scope s, ImportEdit i) {
26
		super();
26
		super();
27
		scope= s;
27
		scope= s;
28
		callMode= cm;
29
		importer= i;
28
		importer= i;
30
	}
29
	}
31
}
30
}
(-)core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/CallInliner.java (-211 / +462 lines)
Lines 17-67 Link Here
17
import java.util.Iterator;
17
import java.util.Iterator;
18
import java.util.List;
18
import java.util.List;
19
19
20
import org.eclipse.core.runtime.CoreException;
21
22
import org.eclipse.core.resources.IFile;
20
import org.eclipse.core.resources.IFile;
23
21
import org.eclipse.core.runtime.CoreException;
24
import org.eclipse.jdt.core.ICompilationUnit;
22
import org.eclipse.jdt.core.ICompilationUnit;
25
import org.eclipse.jdt.core.dom.AST;
23
import org.eclipse.jdt.core.dom.AST;
26
import org.eclipse.jdt.core.dom.ASTNode;
24
import org.eclipse.jdt.core.dom.ASTNode;
25
import org.eclipse.jdt.core.dom.ASTVisitor;
26
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
27
import org.eclipse.jdt.core.dom.Assignment;
27
import org.eclipse.jdt.core.dom.Block;
28
import org.eclipse.jdt.core.dom.Block;
28
import org.eclipse.jdt.core.dom.BodyDeclaration;
29
import org.eclipse.jdt.core.dom.BodyDeclaration;
29
import org.eclipse.jdt.core.dom.CastExpression;
30
import org.eclipse.jdt.core.dom.CastExpression;
30
import org.eclipse.jdt.core.dom.DoStatement;
31
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
31
import org.eclipse.jdt.core.dom.Expression;
32
import org.eclipse.jdt.core.dom.Expression;
32
import org.eclipse.jdt.core.dom.FieldAccess;
33
import org.eclipse.jdt.core.dom.FieldAccess;
33
import org.eclipse.jdt.core.dom.ForStatement;
34
import org.eclipse.jdt.core.dom.IBinding;
34
import org.eclipse.jdt.core.dom.IBinding;
35
import org.eclipse.jdt.core.dom.IMethodBinding;
35
import org.eclipse.jdt.core.dom.IMethodBinding;
36
import org.eclipse.jdt.core.dom.ITypeBinding;
36
import org.eclipse.jdt.core.dom.ITypeBinding;
37
import org.eclipse.jdt.core.dom.IVariableBinding;
37
import org.eclipse.jdt.core.dom.IVariableBinding;
38
import org.eclipse.jdt.core.dom.IfStatement;
39
import org.eclipse.jdt.core.dom.Initializer;
38
import org.eclipse.jdt.core.dom.Initializer;
40
import org.eclipse.jdt.core.dom.MethodDeclaration;
39
import org.eclipse.jdt.core.dom.MethodDeclaration;
41
import org.eclipse.jdt.core.dom.MethodInvocation;
40
import org.eclipse.jdt.core.dom.MethodInvocation;
42
import org.eclipse.jdt.core.dom.Modifier;
41
import org.eclipse.jdt.core.dom.Modifier;
43
import org.eclipse.jdt.core.dom.Name;
42
import org.eclipse.jdt.core.dom.Name;
44
import org.eclipse.jdt.core.dom.ParenthesizedExpression;
43
import org.eclipse.jdt.core.dom.ParenthesizedExpression;
44
import org.eclipse.jdt.core.dom.PrimitiveType;
45
import org.eclipse.jdt.core.dom.ReturnStatement;
45
import org.eclipse.jdt.core.dom.SimpleName;
46
import org.eclipse.jdt.core.dom.SimpleName;
46
import org.eclipse.jdt.core.dom.Statement;
47
import org.eclipse.jdt.core.dom.Statement;
47
import org.eclipse.jdt.core.dom.SuperFieldAccess;
48
import org.eclipse.jdt.core.dom.SuperFieldAccess;
49
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
50
import org.eclipse.jdt.core.dom.SwitchStatement;
48
import org.eclipse.jdt.core.dom.ThisExpression;
51
import org.eclipse.jdt.core.dom.ThisExpression;
52
import org.eclipse.jdt.core.dom.Type;
53
import org.eclipse.jdt.core.dom.TypeDeclaration;
49
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
54
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
50
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
55
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
51
import org.eclipse.jdt.core.dom.WhileStatement;
52
53
import org.eclipse.jdt.internal.corext.Assert;
56
import org.eclipse.jdt.internal.corext.Assert;
54
import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
57
import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
55
import org.eclipse.jdt.internal.corext.codemanipulation.ImportEdit;
58
import org.eclipse.jdt.internal.corext.codemanipulation.ImportEdit;
56
import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
59
import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
57
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
60
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
58
import org.eclipse.jdt.internal.corext.dom.ASTRewrite;
61
import org.eclipse.jdt.internal.corext.dom.ASTRewrite;
59
import org.eclipse.jdt.internal.corext.dom.TypeBindingVisitor;
60
import org.eclipse.jdt.internal.corext.dom.Bindings;
62
import org.eclipse.jdt.internal.corext.dom.Bindings;
61
import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder;
63
import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder;
64
import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
62
import org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor;
65
import org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor;
63
import org.eclipse.jdt.internal.corext.dom.LocalVariableIndex;
66
import org.eclipse.jdt.internal.corext.dom.LocalVariableIndex;
64
import org.eclipse.jdt.internal.corext.dom.Selection;
67
import org.eclipse.jdt.internal.corext.dom.Selection;
68
import org.eclipse.jdt.internal.corext.dom.TypeBindingVisitor;
65
import org.eclipse.jdt.internal.corext.dom.TypeRules;
69
import org.eclipse.jdt.internal.corext.dom.TypeRules;
66
import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatus;
70
import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatus;
67
import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowContext;
71
import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowContext;
Lines 85-98 Link Here
85
	
89
	
86
	private Expression fInvocation;
90
	private Expression fInvocation;
87
	private ASTRewrite fRewriter;
91
	private ASTRewrite fRewriter;
88
	private List fStatements;
89
	private int fInsertionIndex;
90
	private boolean fNeedsStatement;
91
	private ASTNode fTargetNode;
92
	private FlowContext fFlowContext;
92
	private FlowContext fFlowContext;
93
	private FlowInfo fFlowInfo;
93
	private FlowInfo fFlowInfo;
94
	private CodeScopeBuilder.Scope fInvocationScope;
94
	private CodeScopeBuilder.Scope fInvocationScope;
95
	
95
96
	/**
97
	 * Statements inserted before inlined one.
98
	 */
99
	private List fStatementsBefore;
100
	/**
101
	 * Statements inserted instead of inlined one.
102
	 */
103
	private List fStatementReplacement;
104
	/**
105
	 * Statements inserted after inlined one.
106
	 */
107
	private List fStatementsAfter;
108
	/**
109
	 * Expression inserted instead of method invocation.
110
	 */
111
	private Expression fInvocationReplacement;
112
	private boolean fRemoveInvocation;
113
96
	private class InlineEvaluator extends HierarchicalASTVisitor {
114
	private class InlineEvaluator extends HierarchicalASTVisitor {
97
		private ParameterData fFormalArgument;
115
		private ParameterData fFormalArgument;
98
		private boolean fResult;
116
		private boolean fResult;
Lines 206-215 Link Here
206
		return fImportEdit;
224
		return fImportEdit;
207
	}
225
	}
208
	
226
	
209
	public ASTNode getTargetNode() {
210
		return fTargetNode;
211
	}
212
	
213
	public RefactoringStatus initialize(BodyDeclaration declaration) {
227
	public RefactoringStatus initialize(BodyDeclaration declaration) {
214
		fBodyDeclaration= declaration;
228
		fBodyDeclaration= declaration;
215
		RefactoringStatus result= new RefactoringStatus();
229
		RefactoringStatus result= new RefactoringStatus();
Lines 226-248 Link Here
226
		return result;
240
		return result;
227
	}
241
	}
228
	
242
	
229
	public RefactoringStatus initialize(Expression invocation) {
243
	public void initialize(Expression invocation) {
230
		RefactoringStatus result= new RefactoringStatus();
231
		fInvocation= invocation;
244
		fInvocation= invocation;
232
		fRewriter= new ASTRewrite(ASTNodes.getParent(fInvocation, ASTNode.BLOCK));
245
		fRewriter= new ASTRewrite(ASTNodes.getParent(fInvocation, ASTNode.BLOCK));
233
		ASTNode parent= fInvocation.getParent();
234
		int nodeType1= parent.getNodeType();
235
		if (nodeType1 == ASTNode.EXPRESSION_STATEMENT || nodeType1 == ASTNode.RETURN_STATEMENT) {
236
			fTargetNode= parent;
237
		} else {
238
			fTargetNode= fInvocation;
239
		}
240
		return result;
241
	}
246
	}
242
	
247
	
243
	private void flowAnalysis() {
248
	private void flowAnalysis() {
244
		fInvocationScope= fRootScope.findScope(fTargetNode.getStartPosition(), fTargetNode.getLength());
249
		fInvocationScope= fRootScope.findScope(fInvocation.getStartPosition(), fInvocation.getLength());
245
		fInvocationScope.setCursor(fTargetNode.getStartPosition());
250
		fInvocationScope.setCursor(fInvocation.getStartPosition());
246
		fFlowContext= new FlowContext(0, fNumberOfLocals + 1);
251
		fFlowContext= new FlowContext(0, fNumberOfLocals + 1);
247
		fFlowContext.setConsiderAccessMode(true);
252
		fFlowContext.setConsiderAccessMode(true);
248
		fFlowContext.setComputeMode(FlowContext.ARGUMENTS);
253
		fFlowContext.setComputeMode(FlowContext.ARGUMENTS);
Lines 258-449 Link Here
258
				Assert.isTrue(false, "Should not happen");			 //$NON-NLS-1$
263
				Assert.isTrue(false, "Should not happen");			 //$NON-NLS-1$
259
		}
264
		}
260
	}
265
	}
261
	
266
267
	public static class ReturnCollector extends ASTVisitor {
268
		private List fResult= new ArrayList();
269
		public ReturnCollector() {
270
		}
271
		public List getResult() {
272
			return fResult;
273
		}
274
		public boolean visit(ReturnStatement node) {
275
			fResult.add(node);
276
			return false;
277
		}
278
		public boolean visit(AnonymousClassDeclaration node) {
279
			return false;
280
		}
281
		public boolean visit(TypeDeclaration node) {
282
			return false;
283
		}
284
	}
285
286
	/**
287
	 * The singleton class is used to reset code positions of visited nodes.
288
	 * 
289
	 * This is a good candidate for moving into ASTNodes class.
290
	 */
291
	public static class PositionClearer extends GenericVisitor {
292
		private static final PositionClearer instance= new PositionClearer();
293
		private PositionClearer() {
294
		}
295
		public static PositionClearer getInstance() {
296
			return instance;
297
		}
298
		protected boolean visitNode(ASTNode node) {
299
			node.setSourceRange(-1, 0);
300
			return true;
301
		}
302
	}
303
262
	public TextEdit perform() throws CoreException {
304
	public TextEdit perform() throws CoreException {
263
		flowAnalysis();
305
		flowAnalysis();
264
		int callType= fTargetNode.getNodeType();
306
		CallContext context= new CallContext(fInvocationScope, fImportEdit);
265
		CallContext context= new CallContext(fInvocationScope, callType, fImportEdit);
266
		
307
		
267
		List locals= new ArrayList(3);
308
		List locals= new ArrayList(3);
268
		
309
		context.arguments= computeRealArguments(locals);
269
		computeRealArguments(context, locals);
270
		computeReceiver(context, locals);
310
		computeReceiver(context, locals);
271
		 		
272
		String[] blocks= fSourceProvider.getCodeBlocks(context);
273
		initializeInsertionPoint(fSourceProvider.getNumberOfStatements() + locals.size());
274
		
311
		
275
		addNewLocals(locals);
312
		List statements= fSourceProvider.getCodeStatements(context);
276
		replaceCall(callType, blocks);
313
		SourceProvider.replaceAST(fInvocation.getAST(), statements);
314
		addNewLocals(statements, locals);
315
		
316
		processReturnStatements(statements);
317
		replaceCall();
277
		
318
		
278
		MultiTextEdit result= new MultiTextEdit();
319
		MultiTextEdit result= new MultiTextEdit();
279
		fRewriter.rewriteNode(fBuffer, result, null);
320
		fRewriter.rewriteNode(fBuffer, result);
280
		fRewriter.removeModifications();
321
		fRewriter.removeModifications();
281
		return result;
322
		return result;
282
	}
323
	}
283
324
284
	private void computeRealArguments(CallContext context, List locals) {
325
	/**
326
	 * Adds new locals to the top of statements list.
327
	 * 
328
	 * @param statements list of statements
329
	 * @param locals list of new locals
330
	 */
331
	private void addNewLocals(List statements, List locals) {
332
		int index= 0;
333
		for (Iterator it= locals.iterator(); it.hasNext(); ) {
334
			statements.add(index++, it.next());
335
		}
336
	}
337
338
	private static ITypeBinding resolveInvocationTypeBinding(ASTNode invocation) {
339
		if(invocation instanceof MethodInvocation) {
340
			return ((MethodInvocation)invocation).resolveTypeBinding();
341
		}
342
		else if(invocation instanceof SuperMethodInvocation) {
343
			return ((SuperMethodInvocation)invocation).resolveTypeBinding();
344
		}
345
		return null;
346
	}
347
348
	private ASTNode[] computeRealArguments(List locals) {
349
		AST ast= fInvocation.getAST();
285
		List arguments= Invocations.getArguments(fInvocation);
350
		List arguments= Invocations.getArguments(fInvocation);
286
		String[] realArguments= new String[arguments.size()];
351
		ASTNode[] realArguments = new ASTNode[arguments.size()];
287
		for (int i= 0; i < arguments.size(); i++) {
352
		for (int i= 0; i < arguments.size(); i++) {
288
			Expression expression= (Expression)arguments.get(i);
353
			Expression expression= (Expression)arguments.get(i);
289
			ParameterData parameter= fSourceProvider.getParameterData(i);
354
			ParameterData parameter= fSourceProvider.getParameterData(i);
290
			if (canInline(expression, parameter)) {
355
			if (canInline(expression, parameter)) {
291
				realArguments[i] = getContent(expression);
356
				realArguments[i]= ASTNode.copySubtree(expression.getAST(), expression);
292
				// fixes bug #35905
357
				// fixes bug #35905
293
				if(expression instanceof CastExpression) {
358
				if(expression instanceof CastExpression) {
294
					realArguments[i] = "(" + realArguments[i] + ")"; //$NON-NLS-1$ //$NON-NLS-2$
359
					ParenthesizedExpression pe= ast.newParenthesizedExpression();
360
					pe.setExpression((Expression)realArguments[i]);
361
					realArguments[i]= pe;
295
				}
362
				}
296
			} else {
363
			} else {
297
				String name= fInvocationScope.createName(parameter.getName(), true);
364
				String name= fInvocationScope.createName(parameter.getName(), true);
298
				realArguments[i]= name;
365
				realArguments[i]= fInvocation.getAST().newSimpleName(name);
299
				locals.add(createLocalDeclaration(
366
				locals.add(createVariableDeclaration(
300
					parameter.getTypeBinding(), name, 
367
					parameter.getType().resolveBinding(), name, 
301
					(Expression)fRewriter.createCopy(expression)));
368
					(Expression)ASTNode.copySubtree(expression.getAST(), expression)));
302
			}
369
			}
303
		}
370
		}
304
		context.arguments= realArguments;
371
		return realArguments;
305
	}
372
	}
306
	
373
307
	private void computeReceiver(CallContext context, List locals) {
374
	private void computeReceiver(CallContext context, List locals) {
308
		Expression receiver= Invocations.getExpression(fInvocation);
375
		Expression receiver= Invocations.getExpression(fInvocation);
309
		if (receiver == null)
376
		if (receiver == null)
310
			return;
377
			return;
311
		final boolean isName= receiver instanceof Name;
378
		if (ASTNodes.isLiteral(receiver) || receiver instanceof Name) {
312
		if (isName)
379
			context.receiver= receiver;
313
			context.receiverIsStatic= ((Name)receiver).resolveBinding() instanceof ITypeBinding;
314
		if (ASTNodes.isLiteral(receiver) || isName) {
315
			context.receiver= fBuffer.getContent(receiver.getStartPosition(), receiver.getLength());
316
			return;
380
			return;
317
		}
381
		}
318
		switch(fSourceProvider.getReceiversToBeUpdated()) {
382
		switch(fSourceProvider.getReceiversToBeUpdated()) {
319
			case 0:
383
			case 0:
320
				// Make sure we evaluate the current receiver. Best is to assign to
384
				// Make sure we evaluate the current receiver. Best is to assign to local.
321
				// local.
385
				locals.add(createVariableDeclaration(
322
				locals.add(createLocalDeclaration(
323
					receiver.resolveTypeBinding(), 
386
					receiver.resolveTypeBinding(), 
324
					fInvocationScope.createName("r", true),  //$NON-NLS-1$
387
					fInvocationScope.createName("r", true),  //$NON-NLS-1$
325
					(Expression)fRewriter.createCopy(receiver)));
388
					(Expression)fRewriter.createCopy(receiver)));
326
				return;
389
				return;
327
			case 1:
390
			case 1:
328
				context.receiver= fBuffer.getContent(receiver.getStartPosition(), receiver.getLength());
391
				context.receiver= receiver;
329
				return;
392
				return;
330
			default:
393
			default:
331
				String local= fInvocationScope.createName("r", true); //$NON-NLS-1$
394
				String local= fInvocationScope.createName("r", true); //$NON-NLS-1$
332
				locals.add(createLocalDeclaration(
395
				VariableDeclarationStatement receiverDeclaration= 
333
					receiver.resolveTypeBinding(), 
396
					createVariableDeclaration(
334
					local, 
397
						receiver.resolveTypeBinding(), 
335
					(Expression)fRewriter.createCopy(receiver)));
398
						local, 
336
				context.receiver= local;
399
						(Expression)fRewriter.createCopy(receiver));
400
				locals.add(receiverDeclaration);
401
				context.receiver= fInvocation.getAST().newSimpleName(local);
337
				return;
402
				return;
338
		}
403
		}
339
	}
404
	}
340
405
341
	private void addNewLocals(List locals) {
406
	/**
342
		for (Iterator iter= locals.iterator(); iter.hasNext();) {
407
	 * The method analyses return statements and fills fStatementsAfter, 
343
			ASTNode element= (ASTNode)iter.next();
408
	 * fStatementsBefore, fStatementReplacement and fInvocationReplacement 
344
			fRewriter.markAsInserted(element);
409
	 * member variables with statements that will be used during inlining.
345
			fStatements.add(fInsertionIndex++, element);
410
	 * 
346
		}
411
	 * @param statements list of method statements to process
347
	}
412
	 */
348
413
	private void processReturnStatements(List statements) {
349
	private void replaceCall(int callType, String[] blocks) throws CoreException {
414
		
350
		// Inline empty body
415
		List returnStatements= null;
351
		if (blocks.length == 0) {
416
		ReturnCollector returnCollector= new ReturnCollector();
352
			if (fNeedsStatement) {
417
		ASTNodes.acceptNodes(statements, returnCollector);
353
				fRewriter.markAsReplaced(fTargetNode, fTargetNode.getAST().newEmptyStatement());
418
		returnStatements= returnCollector.getResult();
354
			} else {
419
		
355
				fRewriter.markAsRemoved(fTargetNode);
420
		AST ast= fInvocation.getAST();
421
		ASTNode invocationParent= fInvocation.getParent();
422
		int invocationParentType= invocationParent.getNodeType();
423
		
424
		if (!fSourceProvider.hasReturnValue()) {
425
			// in case when inlined method returns void ...
426
			for (Iterator iter= returnStatements.iterator(); iter.hasNext();) {
427
				ReturnStatement rs= (ReturnStatement) iter.next();
428
				ASTNode parent= rs.getParent();
429
				// if parent of return statement is a control statements(if, for, do, while) 
430
				// then empty statement is required in place of the return
431
				if (parent != null && isControlStatement(parent)) {
432
					substitute(statements, rs, ast.newEmptyStatement());
433
				} else {
434
					// otheriwse it is safe to remove return statement completely
435
					substitute(statements, rs, null);
436
				}
356
			}
437
			}
357
		} else {
438
			if(invocationParentType == ASTNode.EXPRESSION_STATEMENT) {
358
			ASTNode node= null;
439
				fStatementReplacement= statements;
359
			for (int i= 0; i < blocks.length - 1; i++) {
440
			}
360
				node= fRewriter.createPlaceholder(blocks[i], ASTRewrite.STATEMENT);
441
			else {
361
				fRewriter.markAsInserted(node);
442
				fStatementsBefore= statements;
362
				fStatements.add(fInsertionIndex++, node);
443
				fRemoveInvocation= true;
363
			}
444
			}
364
			String block= blocks[blocks.length - 1];
445
		} else if(invocationParentType == ASTNode.RETURN_STATEMENT) {
365
			// We can inline a call where the declaration is a function and the call itself
446
			fStatementReplacement= statements;
366
			// is a statement. In this case we have to create a temporary variable if the
447
		} else if (invocationParentType == ASTNode.EXPRESSION_STATEMENT) {
367
			// returned expression must be evaluated.
448
			for (Iterator iter= returnStatements.iterator(); iter.hasNext();) {
368
			if (callType == ASTNode.EXPRESSION_STATEMENT && fSourceProvider.hasReturnValue()) {
449
				ReturnStatement rs= (ReturnStatement) iter.next();
369
				if (fSourceProvider.mustEvaluateReturnedExpression()) {
450
				Expression returnExpression= rs.getExpression();
370
					if (fSourceProvider.returnValueNeedsLocalVariable()) {
451
				// check if return expression must be evaluated 
371
						node= createLocalDeclaration(
452
				if (ASTNodes.isLiteral(returnExpression) || returnExpression instanceof Name) {
372
							fSourceProvider.getReturnType(), 
453
					// completely remove return and its expression 
373
							fInvocationScope.createName(fSourceProvider.getMethodName(), true), 
454
					substitute(statements, rs, null);
374
							(Expression)fRewriter.createPlaceholder(block, ASTRewrite.EXPRESSION));
455
				} else {
456
					// check if return expression needs a local variable
457
					if (ASTNodes.isInvocation(returnExpression) || returnExpression instanceof ClassInstanceCreation) {
458
						// substitute parent expression with return expression 
459
						substitute(statements, rs, 
460
							ast.newExpressionStatement((Expression)ASTNode.copySubtree(ast, rs.getExpression())));
375
					} else {
461
					} else {
376
						node= fTargetNode.getAST().newExpressionStatement(
462
						// create a local variable to keep result of return expression 
377
							(Expression)fRewriter.createPlaceholder(block, ASTRewrite.EXPRESSION));
463
						VariableDeclarationStatement node= createVariableDeclaration(
464
							fSourceProvider.getReturnType().resolveBinding(), 
465
							fInvocationScope.createName(fSourceProvider.getMethodName(), true),
466
							(Expression)ASTNode.copySubtree(ast, returnExpression));
467
						substitute(statements, rs, node);
378
					}
468
					}
379
				} else {
380
					node= null;
381
				}
469
				}
382
			} else if (fTargetNode instanceof Expression) {
470
			}
383
				node= fRewriter.createPlaceholder(block, ASTRewrite.EXPRESSION);
471
			fStatementReplacement= statements;
384
				
472
		} else if (invocationParent instanceof Expression) {
473
			for (Iterator iter= returnStatements.iterator(); iter.hasNext();) {
474
				ReturnStatement rs= (ReturnStatement) iter.next();
475
				Expression returnExpression= rs.getExpression();
476
				Expression node= (Expression)ASTNode.copySubtree(ast, returnExpression);
385
				// fixes bug #24941
477
				// fixes bug #24941
386
				if(needsExplicitCast()) {
478
				if (needsExplicitCast(rs)) {
387
					AST ast= node.getAST();
388
					CastExpression castExpression= ast.newCastExpression();
479
					CastExpression castExpression= ast.newCastExpression();
389
					ITypeBinding returnType= fSourceProvider.getReturnType();
480
					Type returnType= fSourceProvider.getReturnType();
390
					fImportEdit.addImport(returnType);
481
					fImportEdit.addImport(returnType.resolveBinding());
391
					castExpression.setType(ASTNodeFactory.newType(ast, returnType, false));
482
					castExpression.setType((Type)ASTNode.copySubtree(ast, returnType));
392
					castExpression.setExpression((Expression)node);
483
					castExpression.setExpression(node);
393
					node= castExpression;
484
					node= castExpression;
394
				}
485
				}
395
				
486
				if (needsParenthesis(rs)) {
396
				if (needsParenthesis()) {
487
					ParenthesizedExpression pe= ast.newParenthesizedExpression();
397
					ParenthesizedExpression pExp= fTargetNode.getAST().newParenthesizedExpression();
488
					pe.setExpression(node);
398
					pExp.setExpression((Expression)node);
489
					node= pe;
399
					node= pExp;
490
				}
491
				if (returnStatements.size() == 1) {
492
					fInvocationReplacement= node;
493
					fStatementsBefore= statements;
494
					statements.remove(rs);
495
				}
496
				else {
497
					substitute(statements, rs, ast.newExpressionStatement(node));
498
				}
499
			}
500
		} else if(invocationParentType == ASTNode.VARIABLE_DECLARATION_FRAGMENT) {
501
			if(returnStatements.size() > 1) {
502
				// method invocation in variable declaration fragment can be used only as initializer
503
				VariableDeclarationFragment fragment= (VariableDeclarationFragment)invocationParent;
504
				fInvocationReplacement= createDefaultInitializer(invocationParent.getAST(), 
505
					resolveInvocationTypeBinding(fInvocation));
506
				Expression variable= fragment.getName();
507
				substituteReturnsWithAssignments(variable, returnStatements, statements);
508
				fStatementsAfter= statements;
509
			}
510
			else { // returnStatements.size() == 1
511
				ReturnStatement rs= (ReturnStatement) returnStatements.get(0);
512
				Expression returnExpression= rs.getExpression();
513
				fInvocationReplacement= (Expression)ASTNode.copySubtree(ast, returnExpression);
514
				substitute(statements, rs, null);
515
				fStatementsBefore= statements;
516
			}
517
		} else {
518
			// case example:
519
			//   for(inlineMe(); i < 10; i++); 
520
			if(returnStatements.size() > 1) {
521
				// if method has multiple returns then temporary variable will be created and all 
522
				// returns will be substituted with assignments to it.
523
				VariableDeclarationStatement variableStatement= createVariableDeclaration(
524
					fSourceProvider.getReturnType().resolveBinding(), 
525
					fInvocationScope.createName("temp", true), //$NON-NLS-1$
526
					createDefaultInitializer(ast, fSourceProvider.getReturnType().resolveBinding()));
527
				statements.add(0, variableStatement);
528
				VariableDeclarationFragment fragment= (VariableDeclarationFragment)variableStatement.fragments().get(0);
529
				Expression variable= fragment.getName();
530
				substituteReturnsWithAssignments(variable, returnStatements, statements);
531
				fStatementsBefore= statements;
532
				fRemoveInvocation= true;
533
			}
534
			else { // returnStatements.size() == 1
535
				ReturnStatement rs= (ReturnStatement) returnStatements.get(0);
536
				Expression returnExpression= rs.getExpression();
537
				// check if return expression must be evaluated 
538
				if (ASTNodes.isLiteral(returnExpression) || returnExpression instanceof Name) {
539
					substitute(statements, rs, null);
540
					fStatementsBefore= statements;
541
					fRemoveInvocation= true;
542
				}
543
				else {
544
					fInvocationReplacement= (Expression)ASTNode.copySubtree(ast, returnExpression);
545
					substitute(statements, rs, null);
546
					fStatementsBefore= statements;
400
				}
547
				}
401
			} else {
402
				node= fRewriter.createPlaceholder(block, ASTRewrite.STATEMENT);
403
			}
548
			}
404
			
549
		}
405
			// Now replace the target node with the source node
550
	}
406
			if (node != null) {
551
407
				if (fTargetNode == null) {
552
	/**
408
					fRewriter.markAsInserted(node);
553
	 * The helper method substitutes return statements with assignments 
409
					fStatements.add(fInsertionIndex++, node);
554
	 * expressions wrapped inside expression statements.
410
				} else {
555
	 * 
411
					fRewriter.markAsReplaced(fTargetNode, node);
556
	 * @param variable AST node representing variable to assign to
557
	 * @param returnStatements list of return statements
558
	 * @param statements list of original statements
559
	 */
560
	private void substituteReturnsWithAssignments(Expression variable, List returnStatements, List statements) {
561
		AST ast= variable.getAST();
562
		for (Iterator iter= returnStatements.iterator(); iter.hasNext();) {
563
			ReturnStatement rs= (ReturnStatement) iter.next();
564
			Expression returnExpression= rs.getExpression();
565
			ASTNode parent= rs.getParent();
566
			// every return is substituted with an assignement to the variable.
567
			// prior to that method initializeTarget has replaced variable 
568
			// initializer with a default value (0 or null).
569
			Assignment assignment= ast.newAssignment();
570
			assignment.setLeftHandSide((Expression)ASTNode.copySubtree(ast, variable));
571
			assignment.setRightHandSide((Expression)ASTNode.copySubtree(ast, returnExpression));
572
			substitute(statements, rs, ast.newExpressionStatement(assignment));
573
		}
574
	}
575
576
	/**
577
	 * @param ast
578
	 * @param variableBinding
579
	 * @return
580
	 */
581
	private Expression createDefaultInitializer(AST ast, ITypeBinding typeBinding) {
582
		if(typeBinding.isPrimitive()) {
583
			if(typeBinding.getName().equals(PrimitiveType.BOOLEAN.toString())) {
584
				return ast.newBooleanLiteral(false);
585
			}
586
			else {
587
				return ast.newNumberLiteral();
588
			}
589
		}
590
		return ast.newNullLiteral();
591
	}
592
593
	/**
594
	 * Helper method for substitution of one node with another in a list of statements.
595
	 * 
596
	 * Special processing is required for top level nodes since their parents are null.
597
	 * 
598
	 * @param statements list of original statements
599
	 * @param source source node, must exist in the hierarchy of statements 
600
	 * @param replacement node replacing the source one
601
	 */
602
	private static void substitute(List statements, ASTNode source, ASTNode replacement) {
603
		if(source.getParent() == null) {
604
			if(replacement == null) {
605
				statements.remove(source);
606
			}
607
			else {
608
				int index= statements.indexOf(source);
609
				statements.set(index, replacement);
610
			}
611
		}
612
		else {
613
			ASTNodes.substitute(source, replacement);
614
		}
615
	}
616
617
	/**
618
	 * The method does actual code modificiations.
619
	 * 
620
	 * It uses only fStatementsBefore, fStatementsAfter, fStatementReplacement
621
	 * and fInvocationReplacement member variables prepared by other methods.
622
	 * 
623
	 * The method adds empty statements and blocks where it is needed.
624
	 */
625
	private void replaceCall() throws CoreException {
626
		
627
		AST ast= fInvocation.getAST();
628
		Statement invocationStatement= (Statement)ASTNodes.getParent(fInvocation, Statement.class);
629
		Statement parentStatement= (Statement)invocationStatement.getParent();
630
		
631
		int numberOfStatements= 0;
632
		if (fStatementsBefore != null) {
633
			numberOfStatements+= fStatementsBefore.size();
634
			ASTNodes.acceptNodes(fStatementsBefore, PositionClearer.getInstance());
635
		}
636
		if (fStatementsAfter != null) {
637
			numberOfStatements+= fStatementsAfter.size();
638
			ASTNodes.acceptNodes(fStatementsAfter, PositionClearer.getInstance());
639
		}
640
		if (fStatementReplacement != null) {
641
			numberOfStatements+= fStatementReplacement.size();
642
			ASTNodes.acceptNodes(fStatementReplacement, PositionClearer.getInstance());
643
		}
644
		else {
645
			numberOfStatements++;
646
		}
647
		if(fInvocationReplacement != null) {
648
			fInvocationReplacement.accept(PositionClearer.getInstance());
649
		}
650
		
651
		List parentStatements= null;
652
		if (parentStatement.getNodeType() == ASTNode.BLOCK) {
653
			parentStatements= ((Block)parentStatement).statements();
654
		}
655
		else if (parentStatement.getNodeType() == ASTNode.SWITCH_STATEMENT) {
656
			parentStatements= ((SwitchStatement)parentStatement).statements();
657
		}
658
		else if (numberOfStatements > 1) {
659
			Block block= ast.newBlock();
660
			List blockStatements= block.statements();
661
			if (fStatementsBefore != null) {
662
				blockStatements.addAll(fStatementsBefore);
663
			}
664
			if (fStatementReplacement != null) {
665
				blockStatements.addAll(fStatementReplacement);
666
			}
667
			else  if (fInvocationReplacement != null) {
668
				// modifying original AST(not the copy!)
669
				ASTNodes.substitute(fInvocation, fInvocationReplacement);
670
				blockStatements.add(ASTNode.copySubtree(ast, invocationStatement));
671
				// restoring original AST
672
				ASTNodes.substitute(fInvocationReplacement, fInvocation);
673
			}
674
			if (fStatementsAfter!= null) {
675
				blockStatements.addAll(fStatementsAfter);
676
			}
677
			fStatementReplacement= new ArrayList();
678
			fStatementReplacement.add(block);
679
		}
680
		else if (numberOfStatements == 0) {
681
			if (isControlStatement(parentStatement)/* && fInvocationReplacement == null*/) {
682
				fStatementReplacement.add(ast.newEmptyStatement());
683
			}
684
		}
685
		if(fStatementReplacement == null) {
686
			if (fInvocationReplacement != null) {
687
				// statement replacement has higher priority over invocation replacement
688
				// so if fStatementReplacement is not null it will be used instead of 
689
				// fInvocationReplacement.
690
				fRewriter.markAsReplaced(fInvocation, fInvocationReplacement);
691
			}
692
			else if(fRemoveInvocation) {
693
				fRewriter.markAsRemoved(fInvocation);
694
			}
695
		}
696
		
697
		if (parentStatements != null) {
698
			int index= parentStatements.indexOf(invocationStatement);
699
			if(fStatementsBefore != null) {
700
				for (int i= 0; i < fStatementsBefore.size(); i++) {
701
					parentStatements.add(index++, fStatementsBefore.get(i));
702
					fRewriter.markAsInserted((ASTNode)fStatementsBefore.get(i), true);
412
				}
703
				}
413
			} else {
704
			}
414
				if (fTargetNode != null) {
705
			if(fStatementReplacement != null) {
415
					fRewriter.markAsRemoved(fTargetNode);
706
				fRewriter.markAsReplaced(invocationStatement, parentStatements, 
707
					(ASTNode[])fStatementReplacement.toArray(new ASTNode[fStatementReplacement.size()]));
708
			}
709
			if(fStatementsAfter != null) {
710
				index++;
711
				for (int i= 0; i < fStatementsAfter.size(); i++) {
712
					parentStatements.add(index++, fStatementsAfter.get(i));
713
					fRewriter.markAsInserted((ASTNode)fStatementsAfter.get(i), true);
416
				}
714
				}
417
			}
715
			}
418
		}
716
		}
717
		else if(fStatementReplacement != null) {
718
			fRewriter.markAsReplaced(invocationStatement, (ASTNode)fStatementReplacement.get(0));
719
		}
419
	}
720
	}
420
721
421
	/**
722
	/**
422
	 * @return <code>true</code> if explicit cast is needed otherwise <code>false</code>
723
	 * @return <code>true</code> if explicit cast is needed otherwise <code>false</code>
423
	 * @throws JavaModelException
724
	 * @throws JavaModelException
424
	 */
725
	 */
425
	private boolean needsExplicitCast() {
726
	private boolean needsExplicitCast(ReturnStatement rs) {
426
		// if the return type of the method is the same as the type of the
727
		// if the return type of the method is the same as the type of the
427
		// returned expression then we don't need an explicit cast.
728
		// returned expression then we don't need an explicit cast.
428
		if (fSourceProvider.returnTypeMatchesReturnExpressions())
729
		if (returnTypeMatchesReturnExpressions(rs))
429
				return false;		 
730
			return false;		 
430
		ASTNode parent= fTargetNode.getParent();
731
		ASTNode parent= fInvocation.getParent();
431
		int nodeType= parent.getNodeType();
732
		int nodeType= parent.getNodeType();
432
		if (nodeType == ASTNode.METHOD_INVOCATION) {
733
		if (nodeType == ASTNode.METHOD_INVOCATION) {
433
			MethodInvocation methodInvocation= (MethodInvocation)parent;
734
			MethodInvocation methodInvocation= (MethodInvocation)parent;
434
			if(methodInvocation.getExpression() == fTargetNode)
735
			if(methodInvocation.getExpression() == fInvocation)
435
				return false;
736
				return false;
436
			IMethodBinding method= methodInvocation.resolveMethodBinding();
737
			IMethodBinding method= methodInvocation.resolveMethodBinding();
437
			ITypeBinding[] parameters= method.getParameterTypes();
738
			ITypeBinding[] parameters= method.getParameterTypes();
438
			int argumentIndex= methodInvocation.arguments().indexOf(fInvocation);
739
			int argumentIndex= methodInvocation.arguments().indexOf(fInvocation);
439
			List returnExprs= fSourceProvider.getReturnExpressions();
740
			parameters[argumentIndex]= (ITypeBinding)fSourceProvider.resolveTypeBinding(
440
			// it is infered that only methods consisting of a single 
741
				rs.getExpression().getStartPosition());
441
			// return statement can be inlined as parameters in other 
742
			
442
			// method invocations
443
			if (returnExprs.size() != 1)
444
				return false;
445
			parameters[argumentIndex]= ((Expression)returnExprs.get(0)).resolveTypeBinding();
446
447
			ITypeBinding type= ASTNodes.getReceiverTypeBinding(methodInvocation);
743
			ITypeBinding type= ASTNodes.getReceiverTypeBinding(methodInvocation);
448
			TypeBindingVisitor visitor= new AmbiguousMethodAnalyzer(method, parameters);
744
			TypeBindingVisitor visitor= new AmbiguousMethodAnalyzer(method, parameters);
449
			if(!visitor.visit(type)) {
745
			if(!visitor.visit(type)) {
Lines 463-482 Link Here
463
		return false;
759
		return false;
464
	}
760
	}
465
761
466
	private boolean needsParenthesis() {
762
	public boolean returnTypeMatchesReturnExpressions(ReturnStatement returnStatement) {
467
		if (!fSourceProvider.needsReturnedExpressionParenthesis())
763
		ITypeBinding returnType= fSourceProvider.getReturnType().resolveBinding();
764
		Expression expression= returnStatement.getExpression();
765
		if (expression != null) {
766
			if (!Bindings.equals(returnType, expression.resolveTypeBinding()))
767
				return false;
768
		}
769
		return true;
770
	}
771
772
	private boolean needsParenthesis(ReturnStatement rs) {
773
		if (!ASTNodes.needsParentheses(rs.getExpression()))
468
			return false;
774
			return false;
469
		ASTNode parent= fTargetNode.getParent();
775
		ASTNode parent= fInvocation.getParent();
470
		int type= parent.getNodeType();
776
		int type= parent.getNodeType();
471
		return type == ASTNode.METHOD_INVOCATION || (parent instanceof Expression && type != ASTNode.ASSIGNMENT);
777
		return type == ASTNode.METHOD_INVOCATION || (parent instanceof Expression && type != ASTNode.ASSIGNMENT);
472
	}
778
	}
473
	
779
474
	private VariableDeclarationStatement createLocalDeclaration(ITypeBinding type, String name, Expression initializer) {
780
	private VariableDeclarationStatement createVariableDeclaration(ITypeBinding typeBinding, String name, Expression initializer) {
475
		String typeName= fImportEdit.addImport(type);
781
		AST ast= initializer.getAST();
476
		VariableDeclarationStatement decl= (VariableDeclarationStatement)ASTNodeFactory.newStatement(
782
		String typeName= fImportEdit.addImport(typeBinding);
477
			fInvocation.getAST(), typeName + " " + name + ";"); //$NON-NLS-1$ //$NON-NLS-2$
783
		VariableDeclarationFragment fragment= ast.newVariableDeclarationFragment();
478
		((VariableDeclarationFragment)decl.fragments().get(0)).setInitializer(initializer);
784
		fragment.setName(ast.newSimpleName(name));
479
		return decl;
785
		fragment.setInitializer(initializer);
786
		VariableDeclarationStatement result= ast.newVariableDeclarationStatement(fragment);
787
		result.setType(ASTNodeFactory.newType(ast, typeBinding.getName()));
788
		return result;
480
	}
789
	}
481
790
482
	private boolean canInline(Expression actualParameter, ParameterData formalParameter) {
791
	private boolean canInline(Expression actualParameter, ParameterData formalParameter) {
Lines 484-552 Link Here
484
		actualParameter.accept(evaluator);
793
		actualParameter.accept(evaluator);
485
		return evaluator.getResult();
794
		return evaluator.getResult();
486
	}
795
	}
487
	
488
	private void initializeInsertionPoint(int nos) {
489
		fStatements= null;
490
		fInsertionIndex= -1;
491
		fNeedsStatement= false;
492
		ASTNode parentStatement= ASTNodes.getParent(fInvocation, Statement.class);
493
		ASTNode container= parentStatement.getParent();
494
		int type= container.getNodeType();
495
		if (type == ASTNode.BLOCK) {
496
			fStatements= ((Block)container).statements();
497
			fInsertionIndex= fStatements.indexOf(parentStatement);
498
		} else if (isControlStatement(container)) {
499
			fNeedsStatement= true;
500
			if (nos > 1) {
501
				Block block= fInvocation.getAST().newBlock();
502
				fStatements= block.statements();
503
				fInsertionIndex= 0;
504
				Statement currentStatement= null;
505
				switch(type) {
506
					case ASTNode.FOR_STATEMENT:
507
						currentStatement= ((ForStatement)container).getBody();
508
						break;
509
					case ASTNode.WHILE_STATEMENT:
510
						currentStatement= ((WhileStatement)container).getBody();
511
						break;
512
					case ASTNode.DO_STATEMENT:
513
						currentStatement= ((DoStatement)container).getBody();
514
						break;
515
					case ASTNode.IF_STATEMENT:
516
						IfStatement node= (IfStatement)container;
517
						Statement thenPart= node.getThenStatement();
518
						if (fTargetNode == thenPart || ASTNodes.isParent(fTargetNode, thenPart)) {
519
							currentStatement= thenPart;
520
						} else {
521
							currentStatement= node.getElseStatement();
522
						}
523
						break;
524
				}
525
				Assert.isNotNull(currentStatement);
526
				// The method to be inlined is not the body of the control statement.
527
				if (currentStatement != fTargetNode) {
528
					ASTNode copy= fRewriter.createCopy(currentStatement);
529
					fStatements.add(copy);
530
				} else {
531
					// We can't replace a copy with something else. So we
532
					// have to insert all statements to be inlined.
533
					fTargetNode= null;
534
				}
535
				fRewriter.markAsReplaced(currentStatement, block);
536
			}
537
		}
538
		// We only insert one new statement or we delete the existing call. 
539
		// So there is no need to have an insertion index.
540
	}
541
542
	private String getContent(ASTNode node) {
543
		return fBuffer.getContent(node.getStartPosition(), node.getLength());
544
	}
545
796
546
	private static IFile getFile(ICompilationUnit cu) throws CoreException {
797
	private static IFile getFile(ICompilationUnit cu) throws CoreException {
547
		return (IFile)WorkingCopyUtil.getOriginal(cu).getResource();
798
		return (IFile)WorkingCopyUtil.getOriginal(cu).getResource();
548
	}
799
	}
549
	
800
550
	private boolean isControlStatement(ASTNode node) {
801
	private boolean isControlStatement(ASTNode node) {
551
		int type= node.getNodeType();
802
		int type= node.getNodeType();
552
		return type == ASTNode.IF_STATEMENT || type == ASTNode.FOR_STATEMENT ||
803
		return type == ASTNode.IF_STATEMENT || type == ASTNode.FOR_STATEMENT ||
(-)core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/InlineMethodRefactoring.java (-2 / +2 lines)
Lines 207-216 Link Here
207
					Expression[] invocations= fTargetProvider.getInvocations(body, new SubProgressMonitor(pm, 1));
207
					Expression[] invocations= fTargetProvider.getInvocations(body, new SubProgressMonitor(pm, 1));
208
					for (int i= 0; i < invocations.length; i++) {
208
					for (int i= 0; i < invocations.length; i++) {
209
						Expression invocation= invocations[i];
209
						Expression invocation= invocations[i];
210
						result.merge(inliner.initialize(invocation));
210
						inliner.initialize(invocation);
211
						if (result.hasFatalError())
211
						if (result.hasFatalError())
212
							break;
212
							break;
213
						RefactoringStatus targetStatus= invocationAnalyzer.perform(unit, invocation, inliner.getTargetNode(), fTargetProvider.getStatusSeverity());
213
						RefactoringStatus targetStatus= invocationAnalyzer.perform(unit, invocation, fTargetProvider.getStatusSeverity());
214
						result.merge(targetStatus);
214
						result.merge(targetStatus);
215
						if (result.hasFatalError())
215
						if (result.hasFatalError())
216
							break;
216
							break;
(-)core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/InvocationAnalyzer.java (-19 / +66 lines)
Lines 10-23 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.corext.refactoring.code;
11
package org.eclipse.jdt.internal.corext.refactoring.code;
12
12
13
import java.util.Iterator;
14
import java.util.List;
15
13
import org.eclipse.jdt.core.ICompilationUnit;
16
import org.eclipse.jdt.core.ICompilationUnit;
14
import org.eclipse.jdt.core.dom.ASTNode;
17
import org.eclipse.jdt.core.dom.ASTNode;
15
import org.eclipse.jdt.core.dom.BodyDeclaration;
18
import org.eclipse.jdt.core.dom.BodyDeclaration;
19
import org.eclipse.jdt.core.dom.DoStatement;
16
import org.eclipse.jdt.core.dom.Expression;
20
import org.eclipse.jdt.core.dom.Expression;
17
import org.eclipse.jdt.core.dom.FieldDeclaration;
21
import org.eclipse.jdt.core.dom.FieldDeclaration;
22
import org.eclipse.jdt.core.dom.ForStatement;
18
import org.eclipse.jdt.core.dom.MethodInvocation;
23
import org.eclipse.jdt.core.dom.MethodInvocation;
24
import org.eclipse.jdt.core.dom.Statement;
19
import org.eclipse.jdt.core.dom.VariableDeclaration;
25
import org.eclipse.jdt.core.dom.VariableDeclaration;
20
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
26
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
27
import org.eclipse.jdt.core.dom.WhileStatement;
21
28
22
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
29
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
23
import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
30
import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
Lines 41-52 Link Here
41
		fSourceProvider= sourceProvider;
48
		fSourceProvider= sourceProvider;
42
	}
49
	}
43
	
50
	
44
	public RefactoringStatus perform(ICompilationUnit unit, ASTNode invocation, ASTNode targetNode, int severity) {
51
	public RefactoringStatus perform(ICompilationUnit unit, ASTNode invocation, int severity) {
45
		RefactoringStatus result= new RefactoringStatus();
52
		RefactoringStatus result= new RefactoringStatus();
46
		fCUnit= unit;
53
		fCUnit= unit;
47
		fInvocation= invocation;
54
		fInvocation= invocation;
48
		fSeverity= severity;
55
		fSeverity= severity;
49
		fTargetNode= targetNode;
56
		
57
		ASTNode parent= fInvocation.getParent();
58
		int nodeType= parent.getNodeType();
59
		if (nodeType == ASTNode.EXPRESSION_STATEMENT || nodeType == ASTNode.RETURN_STATEMENT) {
60
			fTargetNode= parent;
61
		} else {
62
			fTargetNode= fInvocation;
63
		}
64
		
50
		checkIfUsedInDeclaration(result);
65
		checkIfUsedInDeclaration(result);
51
		if (result.getSeverity() >= fSeverity)
66
		if (result.getSeverity() >= fSeverity)
52
			return result;
67
			return result;
Lines 73-100 Link Here
73
					JavaStatusContext.create(fSourceProvider.getCompilationUnit(), fSourceProvider.getDeclaration()),
88
					JavaStatusContext.create(fSourceProvider.getCompilationUnit(), fSourceProvider.getDeclaration()),
74
					RefactoringStatusCodes.INLINE_METHOD_EXECUTION_FLOW);
89
					RefactoringStatusCodes.INLINE_METHOD_EXECUTION_FLOW);
75
			}
90
			}
76
		} else if (nodeType == ASTNode.METHOD_INVOCATION) {
91
		} else if (isUsedInLoop()) {
77
			ASTNode parent= fTargetNode.getParent();
92
			if (fSourceProvider.getNumberOfStatements() > 1 ) {
78
			if (parent.getNodeType() == ASTNode.ASSIGNMENT || isSingleDeclaration(parent)) {
93
				// TODO: The message is not correct for this situation
79
				// this is ok
80
			} else if (isMultiDeclarationFragment(parent)) {
81
				if (!fSourceProvider.isSimpleFunction()) {
82
					addEntry(result,
83
						RefactoringCoreMessages.getString("InvocationAnalyzer.multiDeclaration"), //$NON-NLS-1$
84
						RefactoringStatusCodes.INLINE_METHOD_INITIALIZER_IN_FRAGEMENT);
85
				}
86
			} else if (fSourceProvider.getNumberOfStatements() > 1 ) {
87
				addEntry(result,
94
				addEntry(result,
88
					RefactoringCoreMessages.getString("CallInliner.simple_functions"), //$NON-NLS-1$
95
					RefactoringCoreMessages.getString("CallInliner.simple_functions"), //$NON-NLS-1$
89
					RefactoringStatusCodes.INLINE_METHOD_ONLY_SIMPLE_FUNCTIONS);
96
					RefactoringStatusCodes.INLINE_METHOD_ONLY_SIMPLE_FUNCTIONS);
90
			} else if (!fSourceProvider.isSimpleFunction()) {
91
				addEntry(result,
92
					RefactoringCoreMessages.getString("CallInliner.execution_flow"),  //$NON-NLS-1$
93
					fSeverity,
94
					JavaStatusContext.create(fSourceProvider.getCompilationUnit(), fSourceProvider.getDeclaration()),
95
					RefactoringStatusCodes.INLINE_METHOD_EXECUTION_FLOW);
96
			}
97
			}
98
//		} else if (nodeType == ASTNode.METHOD_INVOCATION) {
99
//			ASTNode parent= fTargetNode.getParent();
100
//			if (parent.getNodeType() == ASTNode.ASSIGNMENT || isSingleDeclaration(parent)) {
101
//				// this is ok
102
//			} else if (isMultiDeclarationFragment(parent)) {
103
//				if (!fSourceProvider.isSimpleFunction()) {
104
//					addEntry(result,
105
//						RefactoringCoreMessages.getString("InvocationAnalyzer.multiDeclaration"), //$NON-NLS-1$
106
//						RefactoringStatusCodes.INLINE_METHOD_INITIALIZER_IN_FRAGEMENT);
107
//				}
108
//			} else if (fSourceProvider.getNumberOfStatements() > 1 ) {
109
//				addEntry(result,
110
//					RefactoringCoreMessages.getString("CallInliner.simple_functions"), //$NON-NLS-1$
111
//					RefactoringStatusCodes.INLINE_METHOD_ONLY_SIMPLE_FUNCTIONS);
112
//			} else if (!fSourceProvider.isSimpleFunction()) {
113
//				addEntry(result,
114
//					RefactoringCoreMessages.getString("CallInliner.execution_flow"),  //$NON-NLS-1$
115
//					fSeverity,
116
//					JavaStatusContext.create(fSourceProvider.getCompilationUnit(), fSourceProvider.getDeclaration()),
117
//					RefactoringStatusCodes.INLINE_METHOD_EXECUTION_FLOW);
118
//			}
97
		}		
119
		}		
120
	}
121
122
	/**
123
	 * @return <code>true</code> is inlined invocation is used inside a one of loop statements.
124
	 */
125
	private boolean isUsedInLoop() {
126
		ASTNode parentStatement= ASTNodes.getParent(fTargetNode, Statement.class);
127
		if (parentStatement instanceof WhileStatement) {
128
			return true;
129
		}
130
		else if (parentStatement instanceof DoStatement) {
131
			return true;
132
		}
133
		else if (parentStatement instanceof ForStatement) {
134
			ForStatement forStatement= (ForStatement)parentStatement;
135
			List initializers= forStatement.initializers();
136
			for (Iterator iter= initializers.iterator(); iter.hasNext();) {
137
				ASTNode initializer= (ASTNode) iter.next();
138
				if(fTargetNode == initializer || ASTNodes.isParent(fTargetNode, initializer)) {
139
					return false;
140
				}
141
			}
142
			return true;
143
		}
144
		return false;
98
	}
145
	}
99
146
100
	private void checkIfUsedInDeclaration(RefactoringStatus result) {
147
	private void checkIfUsedInDeclaration(RefactoringStatus result) {
(-)core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/ParameterData.java (+5 lines)
Lines 16-21 Link Here
16
import org.eclipse.jdt.core.dom.ASTNode;
16
import org.eclipse.jdt.core.dom.ASTNode;
17
import org.eclipse.jdt.core.dom.ITypeBinding;
17
import org.eclipse.jdt.core.dom.ITypeBinding;
18
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
18
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
19
import org.eclipse.jdt.core.dom.Type;
19
20
20
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
21
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
21
import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowInfo;
22
import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowInfo;
Lines 44-49 Link Here
44
		if (binding != null)
45
		if (binding != null)
45
			return binding.getName();
46
			return binding.getName();
46
		return ASTNodes.asString(fDeclaration.getType());
47
		return ASTNodes.asString(fDeclaration.getType());
48
	}
49
	
50
	public Type getType() {
51
		return fDeclaration.getType();
47
	}
52
	}
48
	
53
	
49
	public ITypeBinding getTypeBinding() {
54
	public ITypeBinding getTypeBinding() {
(-)core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceAnalyzer.java (-330 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2003 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Common Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/cpl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.corext.refactoring.code;
12
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.HashMap;
16
import java.util.Iterator;
17
import java.util.List;
18
import java.util.Map;
19
20
import org.eclipse.jdt.core.ICompilationUnit;
21
import org.eclipse.jdt.core.JavaModelException;
22
import org.eclipse.jdt.core.compiler.IProblem;
23
import org.eclipse.jdt.core.dom.ASTNode;
24
import org.eclipse.jdt.core.dom.ASTVisitor;
25
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
26
import org.eclipse.jdt.core.dom.Block;
27
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
28
import org.eclipse.jdt.core.dom.Expression;
29
import org.eclipse.jdt.core.dom.IBinding;
30
import org.eclipse.jdt.core.dom.IMethodBinding;
31
import org.eclipse.jdt.core.dom.ITypeBinding;
32
import org.eclipse.jdt.core.dom.IVariableBinding;
33
import org.eclipse.jdt.core.dom.MethodDeclaration;
34
import org.eclipse.jdt.core.dom.MethodInvocation;
35
import org.eclipse.jdt.core.dom.Name;
36
import org.eclipse.jdt.core.dom.QualifiedName;
37
import org.eclipse.jdt.core.dom.ReturnStatement;
38
import org.eclipse.jdt.core.dom.SimpleName;
39
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
40
import org.eclipse.jdt.core.dom.ThisExpression;
41
import org.eclipse.jdt.core.dom.TypeDeclaration;
42
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
43
44
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
45
import org.eclipse.jdt.internal.corext.dom.LocalVariableIndex;
46
import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
47
import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
48
import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatus;
49
import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowContext;
50
import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowInfo;
51
import org.eclipse.jdt.internal.corext.refactoring.code.flow.InOutFlowAnalyzer;
52
53
class SourceAnalyzer  {
54
	
55
	public static class NameData {
56
		private String fName;
57
		private List fReferences;
58
		public NameData(String n) {
59
			fName= n;
60
			fReferences= new ArrayList(2);
61
		}
62
		public String getName() {
63
			return fName;
64
		}
65
		public void addReference(SimpleName ref) {
66
			fReferences.add(ref);
67
		}
68
		public List references() {
69
			return fReferences;
70
		}
71
	}
72
73
	private class ActivationAnalyzer extends ASTVisitor {
74
		public RefactoringStatus status= new RefactoringStatus();
75
		private ASTNode fLastNode= getLastNode();
76
		private IMethodBinding fBinding= getBinding();
77
		public boolean visit(ReturnStatement node) {
78
			if (node != fLastNode) {
79
				fInterruptedExecutionFlow= true;
80
			}
81
			return true;
82
		}
83
		public boolean visit(TypeDeclaration node) {
84
			return false;
85
		}
86
		public boolean visit(AnonymousClassDeclaration node) {
87
			return false;
88
		}
89
		public boolean visit(MethodInvocation node) {
90
			if (fBinding != null && fBinding == node.getName().resolveBinding() && !status.hasFatalError()) {
91
				status.addFatalError(RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.recursive_call")); //$NON-NLS-1$
92
				return false;
93
			}
94
			return true;
95
		}
96
		public boolean visit(SimpleName node) {
97
			IBinding binding= node.resolveBinding();
98
			if (binding == null && !status.hasFatalError()) {
99
				status.addFatalError(
100
					RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.declaration_has_errors"), //$NON-NLS-1$
101
					JavaStatusContext.create(fCUnit, fDeclaration));
102
				return false;
103
			}
104
			return true;
105
		}
106
		public boolean visit(ThisExpression node) {
107
			if (node.getQualifier() != null) {
108
				status.addFatalError(
109
					RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.qualified_this_expressions"), //$NON-NLS-1$
110
					JavaStatusContext.create(fCUnit, node));
111
				return false;
112
			}
113
			return true;
114
		}
115
		private ASTNode getLastNode() {
116
			List statements= fDeclaration.getBody().statements();
117
			if (statements.size() == 0)
118
				return null;
119
			return (ASTNode)statements.get(statements.size() - 1);
120
		}
121
		private IMethodBinding getBinding() {
122
			return fDeclaration.resolveBinding();
123
		}
124
	}
125
	
126
	private class UpdateCollector extends ASTVisitor {
127
		private int fTypeCounter;
128
		public boolean visit(TypeDeclaration node) {
129
			if (fTypeCounter++ == 0) {
130
				addNameData(node.getName());
131
			}
132
			Name superclass= node.getSuperclass();
133
			if (superclass != null) {
134
				ITypeBinding superBinding= ASTNodes.getTypeBinding(superclass);
135
				if (superBinding != null)
136
					fTypes.add(superclass);
137
			}
138
			List interfaces= node.superInterfaces();
139
			for (Iterator iter= interfaces.iterator(); iter.hasNext();) {
140
				Name element= (Name)iter.next();
141
				ITypeBinding binding= ASTNodes.getTypeBinding(element);
142
				if (binding != null)
143
					fTypes.add(element);
144
			}
145
			return true;
146
		}
147
		public void endVisit(TypeDeclaration node) {
148
			fTypeCounter--;
149
		}
150
		public boolean visit(AnonymousClassDeclaration node) {
151
			fTypeCounter++;
152
			return true;
153
		}
154
		public void endVisit(AnonymousClassDeclaration node) {
155
			fTypeCounter--;
156
		}
157
		public boolean visit(MethodDeclaration node) {
158
			if (node.isConstructor()) {
159
				TypeDeclaration decl= (TypeDeclaration) ASTNodes.getParent(node, ASTNode.TYPE_DECLARATION);
160
				NameData name= (NameData)fNames.get(decl.getName().resolveBinding());
161
				if (name != null) {
162
					name.addReference(node.getName());
163
				}
164
			}
165
			return true;
166
		}
167
		public boolean visit(MethodInvocation node) {
168
			if (fTypeCounter == 0) {
169
				Expression receiver= node.getExpression();
170
				if (receiver == null)
171
					fImplicitReceivers.add(node);
172
			}
173
			return true;
174
		}
175
		public boolean visit(ClassInstanceCreation node) {
176
			if (fTypeCounter == 0) {
177
				Expression receiver= node.getExpression();
178
				if (receiver == null) {
179
					if (node.resolveTypeBinding().isLocal())
180
						fImplicitReceivers.add(node);
181
				}
182
			}
183
			return true;
184
		}
185
		public boolean visit(SingleVariableDeclaration node) {
186
			if (fTypeCounter == 0)
187
				addNameData(node.getName());
188
			return true;
189
		}
190
		public boolean visit(VariableDeclarationFragment node) {
191
			if (fTypeCounter == 0)
192
				addNameData(node.getName());
193
			return true;
194
		}
195
		public boolean visit(SimpleName node) {
196
			IBinding binding= node.resolveBinding();
197
			ParameterData data= (ParameterData)fParameters.get(binding);
198
			if (data != null)
199
				data.addReference(node);
200
				
201
			NameData name= (NameData)fNames.get(binding);
202
			if (name != null)
203
				name.addReference(node);
204
			if (binding instanceof ITypeBinding) {
205
				ITypeBinding tb= (ITypeBinding)binding;
206
				Name qName= node;
207
				QualifiedName parent;
208
				while ((parent= (QualifiedName)ASTNodes.getParent(qName, ASTNode.QUALIFIED_NAME)) != null &&
209
						parent.getQualifier() != qName) {
210
					qName= parent; 
211
				}
212
				String typeName= null;
213
				if (tb.isArray())
214
					typeName= tb.getElementType().getQualifiedName();
215
				else
216
					typeName= tb.getQualifiedName();
217
				if (!ASTNodes.asString(qName).equals(typeName))
218
					fTypes.add(qName);
219
			}
220
			return true;
221
		}
222
		public boolean visit(ThisExpression node) {
223
			if (fTypeCounter == 0) {
224
				fImplicitReceivers.add(node);
225
			}
226
			return true;
227
		}
228
		private void addNameData(SimpleName name) {
229
			fNames.put(name.resolveBinding(), new NameData(name.getIdentifier()));
230
		}
231
	}
232
233
	private ICompilationUnit fCUnit;
234
	private MethodDeclaration fDeclaration;
235
	private Map fParameters;
236
	private Map fNames;
237
	private List fImplicitReceivers;
238
	private List fTypes;
239
	private boolean fInterruptedExecutionFlow;
240
241
	public SourceAnalyzer(ICompilationUnit unit, MethodDeclaration declaration) {
242
		super();
243
		fCUnit= unit;
244
		fDeclaration= declaration;
245
		List parameters= fDeclaration.parameters();
246
		fParameters= new HashMap(parameters.size() * 2);
247
		for (Iterator iter= parameters.iterator(); iter.hasNext();) {
248
			SingleVariableDeclaration element= (SingleVariableDeclaration) iter.next();
249
			fParameters.put(element.resolveBinding(), element.getProperty(ParameterData.PROPERTY));
250
		}
251
		fNames= new HashMap();
252
		fImplicitReceivers= new ArrayList(2);
253
		fTypes= new ArrayList(2);
254
	}
255
	
256
	public boolean isExecutionFlowInterrupted() {
257
		return fInterruptedExecutionFlow;
258
	}
259
	
260
	public RefactoringStatus checkActivation() throws JavaModelException {
261
		RefactoringStatus result= new RefactoringStatus();
262
		if (!fCUnit.isStructureKnown()) {
263
			result.addFatalError(		
264
				RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.syntax_errors"), //$NON-NLS-1$
265
				JavaStatusContext.create(fCUnit));		
266
			return result;
267
		}
268
		IProblem[] problems= ASTNodes.getProblems(fDeclaration, ASTNodes.NODE_ONLY, ASTNodes.ERROR);
269
		if (problems.length > 0) {
270
			result.addFatalError(		
271
				RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.declaration_has_errors"), //$NON-NLS-1$
272
				JavaStatusContext.create(fCUnit, fDeclaration));		
273
			return result;
274
		}
275
		if (fDeclaration.getBody() == null) {
276
			result.addFatalError(
277
				RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.abstract_methods"),  //$NON-NLS-1$
278
				JavaStatusContext.create(fCUnit, fDeclaration));
279
				return result;
280
		}
281
		if (fDeclaration.isConstructor()) {
282
			result.addFatalError(
283
				RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.constructors"),  //$NON-NLS-1$
284
				JavaStatusContext.create(fCUnit, fDeclaration));
285
			return result;
286
		}
287
		ActivationAnalyzer analyzer= new ActivationAnalyzer();
288
		fDeclaration.accept(analyzer);
289
		result.merge(analyzer.status);
290
		if (!result.hasFatalError()) {
291
			
292
		}
293
		return result;
294
	}
295
296
	public void analyzeParameters() {
297
		Block body= fDeclaration.getBody();
298
		body.accept(new UpdateCollector());
299
		
300
		int numberOfLocals= LocalVariableIndex.perform(fDeclaration);
301
		FlowContext context= new FlowContext(0, numberOfLocals + 1);
302
		context.setConsiderAccessMode(true);
303
		context.setComputeMode(FlowContext.MERGE);
304
		InOutFlowAnalyzer flowAnalyzer= new InOutFlowAnalyzer(context);
305
		FlowInfo info= flowAnalyzer.perform(getStatements());
306
		
307
		for (Iterator iter= fDeclaration.parameters().iterator(); iter.hasNext();) {
308
			SingleVariableDeclaration element= (SingleVariableDeclaration) iter.next();
309
			IVariableBinding binding= element.resolveBinding();
310
			ParameterData data= (ParameterData)element.getProperty(ParameterData.PROPERTY);
311
			data.setAccessMode(info.getAccessMode(context, binding));
312
		}		
313
	}
314
	
315
	public Collection getUsedNames() {
316
		return fNames.values();
317
	}
318
	
319
	public List getImplicitReceivers() {
320
		return fImplicitReceivers;
321
	}
322
	
323
	public List getUsedTypes() {
324
		return fTypes;
325
	}
326
	private ASTNode[] getStatements() {
327
		List statements= fDeclaration.getBody().statements();
328
		return (ASTNode[]) statements.toArray(new ASTNode[statements.size()]);
329
	}	
330
}
(-)core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/SourceProvider.java (-242 / +442 lines)
Lines 15-83 Link Here
15
15
16
import java.util.ArrayList;
16
import java.util.ArrayList;
17
import java.util.Collection;
17
import java.util.Collection;
18
import java.util.HashMap;
18
import java.util.Iterator;
19
import java.util.Iterator;
19
import java.util.List;
20
import java.util.List;
21
import java.util.Map;
20
22
21
import org.eclipse.core.runtime.CoreException;
23
import org.eclipse.core.runtime.CoreException;
22
import org.eclipse.core.runtime.IProgressMonitor;
24
import org.eclipse.core.runtime.IProgressMonitor;
23
24
import org.eclipse.jdt.core.ICompilationUnit;
25
import org.eclipse.jdt.core.ICompilationUnit;
25
import org.eclipse.jdt.core.JavaModelException;
26
import org.eclipse.jdt.core.JavaModelException;
27
import org.eclipse.jdt.core.compiler.IProblem;
28
import org.eclipse.jdt.core.dom.AST;
26
import org.eclipse.jdt.core.dom.ASTNode;
29
import org.eclipse.jdt.core.dom.ASTNode;
27
import org.eclipse.jdt.core.dom.ASTVisitor;
30
import org.eclipse.jdt.core.dom.ASTVisitor;
31
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
28
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
32
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
29
import org.eclipse.jdt.core.dom.Expression;
33
import org.eclipse.jdt.core.dom.Expression;
34
import org.eclipse.jdt.core.dom.IBinding;
30
import org.eclipse.jdt.core.dom.IMethodBinding;
35
import org.eclipse.jdt.core.dom.IMethodBinding;
31
import org.eclipse.jdt.core.dom.ITypeBinding;
36
import org.eclipse.jdt.core.dom.ITypeBinding;
37
import org.eclipse.jdt.core.dom.IVariableBinding;
32
import org.eclipse.jdt.core.dom.MethodDeclaration;
38
import org.eclipse.jdt.core.dom.MethodDeclaration;
33
import org.eclipse.jdt.core.dom.MethodInvocation;
39
import org.eclipse.jdt.core.dom.MethodInvocation;
34
import org.eclipse.jdt.core.dom.Modifier;
40
import org.eclipse.jdt.core.dom.Modifier;
35
import org.eclipse.jdt.core.dom.Name;
41
import org.eclipse.jdt.core.dom.Name;
42
import org.eclipse.jdt.core.dom.PrimitiveType;
43
import org.eclipse.jdt.core.dom.QualifiedName;
36
import org.eclipse.jdt.core.dom.ReturnStatement;
44
import org.eclipse.jdt.core.dom.ReturnStatement;
37
import org.eclipse.jdt.core.dom.SimpleName;
45
import org.eclipse.jdt.core.dom.SimpleName;
38
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
46
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
39
47
import org.eclipse.jdt.core.dom.ThisExpression;
48
import org.eclipse.jdt.core.dom.Type;
49
import org.eclipse.jdt.core.dom.TypeDeclaration;
50
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
40
import org.eclipse.jdt.internal.corext.codemanipulation.ImportEdit;
51
import org.eclipse.jdt.internal.corext.codemanipulation.ImportEdit;
41
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
52
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
42
import org.eclipse.jdt.internal.corext.dom.ASTRewrite;
53
import org.eclipse.jdt.internal.corext.dom.ASTRewrite;
43
import org.eclipse.jdt.internal.corext.dom.Bindings;
44
import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder;
54
import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder;
55
import org.eclipse.jdt.internal.corext.dom.LocalVariableIndex;
56
import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
57
import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
45
import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatus;
58
import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatus;
59
import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowContext;
60
import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowInfo;
61
import org.eclipse.jdt.internal.corext.refactoring.code.flow.InOutFlowAnalyzer;
46
import org.eclipse.jdt.internal.corext.textmanipulation.MultiTextEdit;
62
import org.eclipse.jdt.internal.corext.textmanipulation.MultiTextEdit;
47
import org.eclipse.jdt.internal.corext.textmanipulation.RangeMarker;
48
import org.eclipse.jdt.internal.corext.textmanipulation.TextBuffer;
63
import org.eclipse.jdt.internal.corext.textmanipulation.TextBuffer;
49
import org.eclipse.jdt.internal.corext.textmanipulation.TextBufferEditor;
50
import org.eclipse.jdt.internal.corext.textmanipulation.TextEdit;
64
import org.eclipse.jdt.internal.corext.textmanipulation.TextEdit;
51
import org.eclipse.jdt.internal.corext.textmanipulation.TextRange;
52
import org.eclipse.jdt.internal.corext.textmanipulation.UndoMemento;
53
import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
54
import org.eclipse.jdt.internal.corext.util.Strings;
55
65
56
public class SourceProvider {
66
public class SourceProvider {
57
67
68
	private Map fNames;
69
	private List fImplicitReceivers;
70
	private List fTypes;
71
	private Map fParameters;
58
	private ICompilationUnit fCUnit;
72
	private ICompilationUnit fCUnit;
59
	private TextBuffer fBuffer;
73
	private TextBuffer fBuffer;
74
	private List fStatements;
60
	private MethodDeclaration fDeclaration;
75
	private MethodDeclaration fDeclaration;
61
	private ASTRewrite fRewriter;
76
	private boolean fInterruptedExecutionFlow;
62
	private SourceAnalyzer fAnalyzer;
77
63
	private boolean fMustEvalReturnedExpression;
78
	private Map fBindings;
64
	private boolean fReturnValueNeedsLocalVariable;
79
	private Map fTypeBindings;
65
	private List fReturnExpressions;
80
	private Map fMethodBindings;
81
82
	public static class NameData {
83
		private String fName;
84
		private List fReferences;
85
		public NameData(String n) {
86
			fName= n;
87
			fReferences= new ArrayList(2);
88
		}
89
		public String getName() {
90
			return fName;
91
		}
92
		public void addReference(SimpleName ref) {
93
			fReferences.add(ref);
94
		}
95
		public List references() {
96
			return fReferences;
97
		}
98
	}
99
100
	private class ActivationAnalyzer extends ASTVisitor {
101
		public RefactoringStatus status= new RefactoringStatus();
102
		private ASTNode fLastNode= getLastNode();
103
		private IMethodBinding fBinding= getBinding();
104
		public boolean visit(ReturnStatement node) {
105
			if (node != fLastNode) {
106
				fInterruptedExecutionFlow= true;
107
			}
108
			return true;
109
		}
110
		public boolean visit(TypeDeclaration node) {
111
			return false;
112
		}
113
		public boolean visit(AnonymousClassDeclaration node) {
114
			return false;
115
		}
116
		public boolean visit(MethodInvocation node) {
117
			if (fBinding != null && fBinding == resolveMethodBinding(node.getName()) && !status.hasFatalError()) {
118
				status.addFatalError(RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.recursive_call")); //$NON-NLS-1$
119
				return false;
120
			}
121
			return true;
122
		}
123
		public boolean visit(SimpleName node) {
124
			IBinding binding= resolveBinding(node);
125
			if (binding == null && !status.hasFatalError()) {
126
				status.addFatalError(
127
					RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.declaration_has_errors"), //$NON-NLS-1$
128
					JavaStatusContext.create(fCUnit, fDeclaration));
129
				return false;
130
			}
131
			return true;
132
		}
133
		public boolean visit(ThisExpression node) {
134
			if (node.getQualifier() != null) {
135
				status.addFatalError(
136
					RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.qualified_this_expressions"), //$NON-NLS-1$
137
					JavaStatusContext.create(fCUnit, node));
138
				return false;
139
			}
140
			return true;
141
		}
142
		private ASTNode getLastNode() {
143
			if (fStatements.size() == 0)
144
				return null;
145
			return (ASTNode)fStatements.get(fStatements.size() - 1);
146
		}
147
		private IMethodBinding getBinding() {
148
			return fDeclaration.resolveBinding();
149
		}
150
	}
66
	
151
	
67
	private class ReturnAnalyzer extends ASTVisitor {
152
	private class UpdateCollector extends ASTVisitor {
153
		private int fTypeCounter;
154
		public boolean visit(TypeDeclaration node) {
155
			if (fTypeCounter++ == 0) {
156
				addNameData(node.getName());
157
			}
158
			Name superclass= node.getSuperclass();
159
			if (superclass != null) {
160
				ITypeBinding superBinding= resolveTypeBinding(superclass);
161
				if (superBinding != null)
162
					fTypes.add(superclass);
163
			}
164
			List interfaces= node.superInterfaces();
165
			for (Iterator iter= interfaces.iterator(); iter.hasNext();) {
166
				Name element= (Name)iter.next();
167
				ITypeBinding superBinding= resolveTypeBinding(superclass);
168
				if (superBinding != null)
169
					fTypes.add(superclass);
170
			}
171
			return true;
172
		}
173
		public void endVisit(TypeDeclaration node) {
174
			fTypeCounter--;
175
		}
176
		public boolean visit(AnonymousClassDeclaration node) {
177
			fTypeCounter++;
178
			return true;
179
		}
180
		public void endVisit(AnonymousClassDeclaration node) {
181
			fTypeCounter--;
182
		}
183
		public boolean visit(MethodDeclaration node) {
184
			if (node.isConstructor()) {
185
				TypeDeclaration decl= (TypeDeclaration) ASTNodes.getParent(node, ASTNode.TYPE_DECLARATION);
186
				NameData name= (NameData)fNames.get(resolveTypeBinding(decl.getName()));
187
				if (name != null) {
188
					name.addReference(node.getName());
189
				}
190
			}
191
			return true;
192
		}
193
		public boolean visit(MethodInvocation node) {
194
			if (fTypeCounter == 0) {
195
				Expression receiver= node.getExpression();
196
				if (receiver == null)
197
					fImplicitReceivers.add(node);
198
			}
199
			return true;
200
		}
201
		public boolean visit(ClassInstanceCreation node) {
202
			if (fTypeCounter == 0) {
203
				Expression receiver= node.getExpression();
204
				if (receiver == null) {
205
					IMethodBinding methodBinding= resolveMethodBinding(node);
206
					ITypeBinding typeBinding= methodBinding.getDeclaringClass();
207
					if (typeBinding.isLocal()) {
208
						fImplicitReceivers.add(node);
209
					}
210
				}
211
			}
212
			return true;
213
		}
214
		public boolean visit(SingleVariableDeclaration node) {
215
			if (fTypeCounter == 0)
216
				addNameData(node.getName());
217
			return true;
218
		}
219
		public boolean visit(VariableDeclarationFragment node) {
220
			if (fTypeCounter == 0)
221
				addNameData(node.getName());
222
			return true;
223
		}
224
		public boolean visit(SimpleName node) {
225
			IBinding binding= resolveBinding(node);
226
			ParameterData data= (ParameterData)fParameters.get(binding);
227
			if (data != null)
228
				data.addReference(node);
229
				
230
			NameData name= (NameData)fNames.get(binding);
231
			if (name != null)
232
				name.addReference(node);
233
			if (binding instanceof ITypeBinding) {
234
				ITypeBinding tb= (ITypeBinding)binding;
235
				Name qName= node;
236
				QualifiedName parent;
237
				while ((parent= (QualifiedName)ASTNodes.getParent(qName, ASTNode.QUALIFIED_NAME)) != null &&
238
						parent.getQualifier() != qName) {
239
					qName= parent; 
240
				}
241
				String typeName= null;
242
				if (tb.isArray())
243
					typeName= tb.getElementType().getQualifiedName();
244
				else
245
					typeName= tb.getQualifiedName();
246
				if (!ASTNodes.asString(qName).equals(typeName))
247
					fTypes.add(qName);
248
			}
249
			return true;
250
		}
251
		public boolean visit(ThisExpression node) {
252
			if (fTypeCounter == 0) {
253
				fImplicitReceivers.add(node);
254
			}
255
			return true;
256
		}
257
		private void addNameData(SimpleName name) {
258
			IBinding binding= (IBinding)fBindings.get(new Integer(name.getStartPosition()));
259
			fNames.put(binding, new NameData(name.getIdentifier()));
260
		}
261
	}
262
263
	private class BindingCollector extends ASTVisitor {
264
		public boolean visit(SimpleName node) {
265
			fBindings.put(new Integer(node.getStartPosition()), node.resolveBinding());
266
			fTypeBindings.put(new Integer(node.getStartPosition()), node.resolveTypeBinding());
267
			return true;
268
		}
269
		public boolean visit(MethodInvocation node) {
270
			fMethodBindings.put(new Integer(node.getStartPosition()), node.resolveMethodBinding());
271
			return true;
272
		}
273
		public boolean visit(TypeDeclaration node) {
274
			fTypeBindings.put(new Integer(node.getStartPosition()), node.resolveBinding());
275
			return true;
276
		}
277
		public boolean visit(ClassInstanceCreation node) {
278
			fTypeBindings.put(new Integer(node.getStartPosition()), node.resolveTypeBinding());
279
			fMethodBindings.put(new Integer(node.getStartPosition()), node.resolveConstructorBinding());
280
			return true;
281
		}
68
		public boolean visit(ReturnStatement node) {
282
		public boolean visit(ReturnStatement node) {
69
			Expression expression= node.getExpression();
283
			Expression expression= node.getExpression();
70
			if (!(ASTNodes.isLiteral(expression) || expression instanceof Name)) {
284
			if(expression != null) {
71
				fMustEvalReturnedExpression= true;
285
				fTypeBindings.put(new Integer(expression.getStartPosition()), expression.resolveTypeBinding());
72
			}
73
			if (Invocations.isInvocation(expression) || expression instanceof ClassInstanceCreation) {
74
				fReturnValueNeedsLocalVariable= false;
75
			}
286
			}
76
			fReturnExpressions.add(expression);
287
			return true;
77
			return false;
78
		}
288
		}
79
	}
289
	}
80
290
291
	public IBinding resolveBinding(ASTNode node) {
292
		return resolveBinding(node.getStartPosition());
293
	}
294
295
	public IBinding resolveBinding(int startPosition) {
296
		return (IBinding)fBindings.get(new Integer(startPosition));
297
	}
298
299
	public ITypeBinding resolveTypeBinding(ASTNode node) {
300
		return resolveTypeBinding(node.getStartPosition());
301
	}
302
303
	public ITypeBinding resolveTypeBinding(int startPosition) {
304
		return (ITypeBinding)fTypeBindings.get(new Integer(startPosition));
305
	}
306
307
	public IMethodBinding resolveMethodBinding(ASTNode node) {
308
		return resolveMethodBinding(node.getStartPosition());
309
	}
310
311
	public IMethodBinding resolveMethodBinding(int startPosition) {
312
		return (IMethodBinding)fMethodBindings.get(new Integer(startPosition));
313
	}
314
81
	public SourceProvider(ICompilationUnit unit, MethodDeclaration declaration) {
315
	public SourceProvider(ICompilationUnit unit, MethodDeclaration declaration) {
82
		super();
316
		super();
83
		fCUnit= unit;
317
		fCUnit= unit;
Lines 88-134 Link Here
88
			ParameterData data= new ParameterData(element);
322
			ParameterData data= new ParameterData(element);
89
			element.setProperty(ParameterData.PROPERTY, data);
323
			element.setProperty(ParameterData.PROPERTY, data);
90
		}
324
		}
91
		fRewriter= new ASTRewrite(fDeclaration);
325
		fStatements= ASTNode.copySubtrees(fDeclaration.getAST(), 
92
		fAnalyzer= new SourceAnalyzer(fCUnit, fDeclaration);
326
			fDeclaration.getBody().statements());
93
		fReturnValueNeedsLocalVariable= true;
327
		
94
		fReturnExpressions= new ArrayList();
328
		fBindings= new HashMap();
329
		fTypeBindings= new HashMap();
330
		fMethodBindings= new HashMap();
331
		fDeclaration.getBody().accept(new BindingCollector());
332
		fParameters= new HashMap(parameters.size());
333
		for (Iterator iter= parameters.iterator(); iter.hasNext();) {
334
			SingleVariableDeclaration element= (SingleVariableDeclaration) iter.next();
335
			fParameters.put(element.resolveBinding(), element.getProperty(ParameterData.PROPERTY));
336
		}
337
		fNames= new HashMap();
338
		fImplicitReceivers= new ArrayList(2);
339
		fTypes= new ArrayList(2);
95
	}
340
	}
96
	
341
97
	public RefactoringStatus checkActivation(IProgressMonitor pm) throws JavaModelException {
342
	public RefactoringStatus checkActivation(IProgressMonitor pm) throws JavaModelException {
98
		return fAnalyzer.checkActivation();
343
		RefactoringStatus result= new RefactoringStatus();
344
		if (!fCUnit.isStructureKnown()) {
345
			result.addFatalError(		
346
				RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.syntax_errors"), //$NON-NLS-1$
347
				JavaStatusContext.create(fCUnit));		
348
			return result;
349
		}
350
		IProblem[] problems= ASTNodes.getProblems(fDeclaration, ASTNodes.NODE_ONLY, ASTNodes.ERROR);
351
		if (problems.length > 0) {
352
			result.addFatalError(		
353
				RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.declaration_has_errors"), //$NON-NLS-1$
354
				JavaStatusContext.create(fCUnit, fDeclaration));		
355
			return result;
356
		}
357
		if (fDeclaration.getBody() == null) {
358
			result.addFatalError(
359
				RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.abstract_methods"),  //$NON-NLS-1$
360
				JavaStatusContext.create(fCUnit, fDeclaration));
361
				return result;
362
		}
363
		if (fDeclaration.isConstructor()) {
364
			result.addFatalError(
365
				RefactoringCoreMessages.getString("InlineMethodRefactoring.SourceAnalyzer.constructors"),  //$NON-NLS-1$
366
				JavaStatusContext.create(fCUnit, fDeclaration));
367
			return result;
368
		}
369
		ActivationAnalyzer analyzer= new ActivationAnalyzer();
370
		ASTNodes.acceptNodes(fStatements, analyzer);
371
		result.merge(analyzer.status);
372
		return result;
99
	}
373
	}
100
	
374
	
101
	public void initialize() throws JavaModelException {
375
	public void initialize() throws JavaModelException {
102
		fBuffer= TextBuffer.create(fCUnit.getBuffer().getContents());
376
		fBuffer= TextBuffer.create(fCUnit.getBuffer().getContents());
103
		fAnalyzer.analyzeParameters();
377
		
104
		if (hasReturnValue()) {
378
		ASTNodes.acceptNodes(fStatements, new UpdateCollector());
105
			ASTNode last= getLastStatement();
379
		
106
			if (last != null) {
380
		int numberOfLocals= LocalVariableIndex.perform(fDeclaration);
107
				ReturnAnalyzer analyzer= new ReturnAnalyzer();
381
		FlowContext context= new FlowContext(0, numberOfLocals + 1);
108
				last.accept(analyzer);
382
		context.setConsiderAccessMode(true);
109
			}
383
		context.setComputeMode(FlowContext.MERGE);
110
		}
384
		InOutFlowAnalyzer flowAnalyzer= new InOutFlowAnalyzer(context);
385
		FlowInfo info= flowAnalyzer.perform(getStatements());
386
		
387
		for (Iterator iter= fDeclaration.parameters().iterator(); iter.hasNext();) {
388
			SingleVariableDeclaration element= (SingleVariableDeclaration) iter.next();
389
			IVariableBinding binding= element.resolveBinding();
390
			ParameterData data= (ParameterData)element.getProperty(ParameterData.PROPERTY);
391
			data.setAccessMode(info.getAccessMode(context, binding));
392
		}		
111
	}
393
	}
112
394
113
	public boolean isExecutionFlowInterrupted() {
395
	public boolean isExecutionFlowInterrupted() {
114
		return fAnalyzer.isExecutionFlowInterrupted();
396
		return fInterruptedExecutionFlow;
115
	}
397
	}
116
	
398
	
117
	public boolean hasReturnValue() {
399
	public boolean hasReturnValue() {
118
		IMethodBinding binding= fDeclaration.resolveBinding();
400
		Type returnType= fDeclaration.getReturnType();
119
		return binding.getReturnType() != fDeclaration.getAST().resolveWellKnownType("void"); //$NON-NLS-1$
401
		if(!returnType.isPrimitiveType()) {
120
	}
402
			return true;
121
	
403
		}
122
	public boolean mustEvaluateReturnedExpression() {
404
		return ((PrimitiveType)returnType).getPrimitiveTypeCode() != PrimitiveType.VOID;
123
		return fMustEvalReturnedExpression;
124
	}
125
	
126
	public boolean returnValueNeedsLocalVariable() {
127
		return fReturnValueNeedsLocalVariable;
128
	}
405
	}
129
	
406
	
130
	public int getNumberOfStatements() {
407
	public int getNumberOfStatements() {
131
		return fDeclaration.getBody().statements().size();
408
		return fStatements.size();
132
	}
409
	}
133
	
410
	
134
	public boolean isSimpleFunction() {
411
	public boolean isSimpleFunction() {
Lines 146-167 Link Here
146
		return fDeclaration.getName().getIdentifier();
423
		return fDeclaration.getName().getIdentifier();
147
	}
424
	}
148
	
425
	
149
	public ITypeBinding getReturnType() {
426
	public Type getReturnType() {
150
		return fDeclaration.resolveBinding().getReturnType();
427
		return fDeclaration.getReturnType();
151
	}
152
	
153
	public List getReturnExpressions() {
154
		return fReturnExpressions;
155
	}
156
	
157
	public boolean returnTypeMatchesReturnExpressions() {
158
		ITypeBinding returnType= getReturnType();
159
		for (Iterator iter= fReturnExpressions.iterator(); iter.hasNext();) {
160
			Expression expression= (Expression)iter.next();
161
			if (!Bindings.equals(returnType, expression.resolveTypeBinding()))
162
				return false;
163
		}
164
		return true;
165
	}
428
	}
166
	
429
	
167
	public ParameterData getParameterData(int index) {
430
	public ParameterData getParameterData(int index) {
Lines 172-400 Link Here
172
	public ICompilationUnit getCompilationUnit() {
435
	public ICompilationUnit getCompilationUnit() {
173
		return fCUnit;
436
		return fCUnit;
174
	}
437
	}
175
	
438
176
	public boolean needsReturnedExpressionParenthesis() {
177
		ASTNode last= getLastStatement();
178
		if (last instanceof ReturnStatement) {
179
			return ASTNodes.needsParentheses(((ReturnStatement)last).getExpression());
180
		}
181
		return false;
182
	}
183
	
184
	public int getReceiversToBeUpdated() {
439
	public int getReceiversToBeUpdated() {
185
		return fAnalyzer.getImplicitReceivers().size();
440
		return fImplicitReceivers.size();
186
	}
441
	}
187
	
442
188
	public TextEdit getDeleteEdit() {
443
	public TextEdit getDeleteEdit() {
189
		ASTRewrite rewriter= new ASTRewrite(fDeclaration.getParent());
444
		ASTRewrite rewriter= new ASTRewrite(fDeclaration.getParent());
190
		rewriter.markAsRemoved(fDeclaration);
445
		rewriter.markAsRemoved(fDeclaration);
191
		MultiTextEdit result= new MultiTextEdit();
446
		MultiTextEdit result= new MultiTextEdit();
192
		rewriter.rewriteNode(fBuffer, result, null);
447
		rewriter.rewriteNode(fBuffer, result);
193
		rewriter.removeModifications();
448
		rewriter.removeModifications();
194
		return result;
449
		return result;
195
	}
450
	}
196
	
451
197
	public String[] getCodeBlocks(CallContext context) throws CoreException {
452
	/**
198
		replaceParameterWithExpression(context.arguments);
453
	 * @param context call context of method invocation.
199
		updateImplicitReceivers(context);
454
	 * @return list of statements composing inlined method body.
200
		makeNamesUnique(context.scope);
455
	 * @throws CoreException
201
		updateTypes(context);
456
	 */
457
	public List getCodeStatements(CallContext context) throws CoreException {
202
		
458
		
203
		List ranges= null;
459
		context.receiver= replaceAST(fDeclaration.getAST(), context.receiver);
204
		if (hasReturnValue()) {
460
		replaceAST(fDeclaration.getAST(), context.arguments);
205
			if (context.callMode == ASTNode.RETURN_STATEMENT) {
206
				ranges= getStatementRanges();
207
			} else {
208
				ranges= getExpressionRanges();
209
			}
210
		} else {
211
			ASTNode last= getLastStatement();
212
			if (last != null && last.getNodeType() == ASTNode.RETURN_STATEMENT) {
213
				ranges= getReturnStatementRanges();
214
			} else {
215
				ranges= getStatementRanges();
216
			}
217
		}
218
		
461
		
219
		MultiTextEdit dummy= new MultiTextEdit();
462
		replaceParameterWithExpression(fStatements, context.arguments);
220
		fRewriter.rewriteNode(fBuffer, dummy, null);
463
		updateImplicitReceivers(context.importer, context.receiver);
464
		makeNamesUnique(context.scope);
465
		updateTypes(context.importer);
466
		
467
		return fStatements;
468
	}
221
469
222
		int size= ranges.size();
470
	public static ASTNode replaceAST(AST ast, ASTNode node) {
223
		RangeMarker[] markers= new RangeMarker[size];
471
		ASTNode result= node;
224
		for (int i= 0; i < markers.length; i++) {
472
		if(node != null && node.getAST() != ast) {
225
			markers[i]= new RangeMarker((TextRange)ranges.get(i));
473
			result= ASTNode.copySubtree(ast, node);
226
		}
474
		}
227
		int split= size <= 1 ? Integer.MAX_VALUE : ((TextRange)ranges.get(0)).getExclusiveEnd();
228
		TextEdit[] edits= dummy.removeAll();
229
		for (int i= 0; i < edits.length; i++) {
230
			TextEdit edit= edits[i];
231
			int pos= edit.getTextRange().getOffset() >= split ? 1 : 0;
232
			markers[pos].add(edit);
233
		}
234
		MultiTextEdit root= new MultiTextEdit();
235
		root.addAll(markers);
236
		TextBufferEditor editor= new TextBufferEditor(fBuffer);
237
		editor.add(root);
238
		UndoMemento undo= editor.performEdits(null);
239
		String[] result= getBlocks(markers);
240
		// It is faster to undo the changes than coping the buffer over and over again.
241
		TextBufferEditor undoEditor= new TextBufferEditor(fBuffer);
242
		undoEditor.add(undo);
243
		undoEditor.performEdits(null);
244
		fRewriter.removeModifications();
245
		return result;
475
		return result;
246
	}
476
	}
247
477
248
	private void replaceParameterWithExpression(String[] expressions) {
478
	public static void replaceAST(AST ast, ASTNode[] nodes) {
479
		for (int i = 0; i < nodes.length; i++) {
480
			nodes[i]= replaceAST(ast, nodes[i]);
481
		}
482
	}
483
484
	public static void replaceAST(AST ast, List nodes) {
485
		for (int i = 0; i < nodes.size(); i++) {
486
			nodes.set(i, replaceAST(ast, (ASTNode)nodes.get(i)));
487
		}
488
	}
489
490
	private class ParameterReferenceFinder extends ASTVisitor {
491
		private HashMap parametersMap;
492
		public ParameterReferenceFinder(HashMap parametersMap) {
493
			this.parametersMap= parametersMap;
494
		}
495
		public boolean visit(SimpleName node) {
496
			ArrayList list= (ArrayList)parametersMap.get(node.getIdentifier());
497
			if (list != null) {
498
				list.add(node);
499
			}
500
			return true;
501
		}
502
	}
503
504
	private void replaceParameterWithExpression(List statements, ASTNode[] expressions) {
505
		List parameters= fDeclaration.parameters();
506
		List[] referenceList= new ArrayList[parameters.size()];
507
		HashMap parametersMap= new HashMap(parameters.size());
508
		for (int i= 0; i < parameters.size(); i++) {
509
			SingleVariableDeclaration element= (SingleVariableDeclaration) parameters.get(i);
510
			parametersMap.put(element.getName().getIdentifier(), referenceList[i]= new ArrayList());
511
		}
512
		ASTNodes.acceptNodes(fStatements, new ParameterReferenceFinder(parametersMap));
513
		
249
		for (int i= 0; i < expressions.length; i++) {
514
		for (int i= 0; i < expressions.length; i++) {
250
			String expression= expressions[i];
515
			ASTNode expression= expressions[i];
251
			ParameterData parameter= getParameterData(i);
516
			List references= referenceList[i];
252
			List references= parameter.references();
253
			for (Iterator iter= references.iterator(); iter.hasNext();) {
517
			for (Iterator iter= references.iterator(); iter.hasNext();) {
254
				ASTNode element= (ASTNode) iter.next();
518
				ASTNode element= (ASTNode) iter.next();
255
				ASTNode newNode= fRewriter.createPlaceholder(expression, ASTRewrite.getPlaceholderType(element));
519
				if(expression.getParent() != null) {
256
				fRewriter.markAsReplaced(element, newNode);
520
					expression= ASTNode.copySubtree(
521
						expression.getAST(), expression);
522
				}
523
				ASTNodes.substitute(element, expression);
257
			}
524
			}
258
		}
525
		}
259
	}
526
	}
260
527
261
	private void makeNamesUnique(CodeScopeBuilder.Scope scope) {
528
	private void makeNamesUnique(CodeScopeBuilder.Scope scope) {
262
		Collection usedCalleeNames= fAnalyzer.getUsedNames();
529
		Collection usedCalleeNames= fNames.values();
263
		for (Iterator iter= usedCalleeNames.iterator(); iter.hasNext();) {
530
		for (Iterator iter= usedCalleeNames.iterator(); iter.hasNext();) {
264
			SourceAnalyzer.NameData nd= (SourceAnalyzer.NameData) iter.next();
531
			NameData nd= (NameData) iter.next();
265
			if (scope.isInUse(nd.getName())) {
532
			if (scope.isInUse(nd.getName())) {
266
				String newName= scope.createName(nd.getName(), true);
533
				String newName= scope.createName(nd.getName(), true);
267
				List references= nd.references();
534
				List references= nd.references();
268
				for (Iterator refs= references.iterator(); refs.hasNext();) {
535
				for (Iterator refs= references.iterator(); refs.hasNext();) {
269
					SimpleName element= (SimpleName) refs.next();
536
					SimpleName element= (SimpleName) refs.next();
270
					ASTNode newNode= fRewriter.createPlaceholder(newName, ASTRewrite.EXPRESSION);
537
					element.setIdentifier(newName);
271
					fRewriter.markAsReplaced(element, newNode);
272
				}
538
				}
273
			}
539
			}
274
		}
540
		}
275
	}
541
	}
276
	
542
	
277
	private void updateImplicitReceivers(CallContext context) {
543
	private void updateImplicitReceivers(ImportEdit importer, ASTNode receiver) {
278
		if (context.receiver == null)
544
		if (receiver != null) {
279
			return;
545
			AST ast= receiver.getAST();
280
		List implicitReceivers= fAnalyzer.getImplicitReceivers();
546
			for (Iterator iter= fImplicitReceivers.iterator(); iter.hasNext();) {
281
		for (Iterator iter= implicitReceivers.iterator(); iter.hasNext();) {
547
				ASTNode node= (ASTNode)iter.next();
282
			ASTNode node= (ASTNode)iter.next();
548
				if(receiver.getParent() != null) {
283
			if (node instanceof MethodInvocation) {
549
					receiver= ASTNode.copySubtree(receiver.getAST(), receiver);
284
				final MethodInvocation inv= (MethodInvocation)node;
550
				}
285
				inv.setExpression(createReceiver(context, (IMethodBinding)inv.getName().resolveBinding()));
551
				int nodeType= node.getNodeType();
286
			} else if (node instanceof ClassInstanceCreation) {
552
				if (nodeType == ASTNode.METHOD_INVOCATION) {
287
				final ClassInstanceCreation inst= (ClassInstanceCreation)node;
553
					MethodInvocation methodInvocation= (MethodInvocation)node;
288
				inst.setExpression(createReceiver(context, inst.resolveConstructorBinding()));
554
					IMethodBinding methodBinding= resolveMethodBinding(methodInvocation);
289
			} else if (node instanceof Expression) {
555
					methodInvocation.setExpression(createReceiver(receiver, importer, methodBinding));
290
				fRewriter.markAsReplaced(node, fRewriter.createPlaceholder(context.receiver, ASTRewrite.EXPRESSION));
556
				}
557
				else if (nodeType == ASTNode.CLASS_INSTANCE_CREATION) {
558
					ClassInstanceCreation methodInvocation= (ClassInstanceCreation)node;
559
					IMethodBinding methodBinding= resolveMethodBinding(methodInvocation);
560
					methodInvocation.setExpression(createReceiver(receiver, importer, methodBinding));
561
				}
562
				else {
563
					ASTNodes.substitute(node, receiver);
564
				}
291
			}
565
			}
292
		}
566
		}
293
	}
567
	}
294
	
568
295
	private void updateTypes(CallContext context) {
569
	private Expression createReceiver(ASTNode receiver, ImportEdit importer, IMethodBinding methodBinding) {
296
		ImportEdit importer= context.importer;
570
		if (Modifier.isStatic(methodBinding.getModifiers())) {
297
		for (Iterator iter= fAnalyzer.getUsedTypes().iterator(); iter.hasNext();) {
571
			ITypeBinding typeBinding= methodBinding.getDeclaringClass();
572
			importer.addImport(typeBinding);
573
			return receiver.getAST().newSimpleName(typeBinding.getName());
574
		}
575
		else {
576
			return (Expression)receiver;
577
		}
578
	}
579
580
	private void updateTypes(ImportEdit importer) {
581
		for (Iterator iter= fTypes.iterator(); iter.hasNext();) {
298
			Name element= (Name)iter.next();
582
			Name element= (Name)iter.next();
299
			ITypeBinding binding= ASTNodes.getTypeBinding(element);
583
			ITypeBinding binding= resolveTypeBinding(element);
300
			if (binding != null && !binding.isLocal()) {
584
			if (binding != null && !binding.isLocal()) {
301
				String s= importer.addImport(binding);
585
				String s= importer.addImport(binding);
302
				if (!ASTNodes.asString(element).equals(s)) {
586
				if (!ASTNodes.asString(element).equals(s)) {
303
					fRewriter.markAsReplaced(element, fRewriter.createPlaceholder(s, ASTRewrite.EXPRESSION));
587
					if(element instanceof SimpleName) {
588
						SimpleName simpleName= (SimpleName)element;
589
						simpleName.setIdentifier(s);
590
					}
304
				}
591
				}
305
			}
592
			}
306
		}
593
		}
307
	}
594
	}
308
595
309
	private Expression createReceiver(CallContext context, IMethodBinding method) {
596
	private ASTNode[] getStatements() {
310
		String receiver= context.receiver;
311
		if (!context.receiverIsStatic && Modifier.isStatic(method.getModifiers())) {
312
			receiver= context.importer.addImport(fDeclaration.resolveBinding().getDeclaringClass()); 
313
		}
314
		Expression exp= (Expression)fRewriter.createPlaceholder(receiver, ASTRewrite.EXPRESSION);
315
		fRewriter.markAsInserted(exp);
316
		return exp;
317
	}
318
	
319
	private ASTNode getLastStatement() {
320
		List statements= fDeclaration.getBody().statements();
321
		if (statements.isEmpty())
322
			return null;
323
		return (ASTNode)statements.get(statements.size() - 1);
324
	}
325
326
	private List getReturnStatementRanges() {
327
		List result= new ArrayList(1);
328
		List statements= fDeclaration.getBody().statements();
597
		List statements= fDeclaration.getBody().statements();
329
		int size= statements.size();
598
		return (ASTNode[]) statements.toArray(new ASTNode[statements.size()]);
330
		if (size <= 1)
599
	}	
331
			return result;
332
		result.add(createRange(statements, size - 2));
333
		return result;
334
	}
335
336
	private List getStatementRanges() {
337
		List result= new ArrayList(1);
338
		List statements= fDeclaration.getBody().statements();
339
		int size= statements.size();
340
		if (size == 0)
341
			return result;
342
		result.add(createRange(statements, size - 1));
343
		return result;
344
	}
345
346
	private List getExpressionRanges() {
347
		List result= new ArrayList(2);
348
		List statements= fDeclaration.getBody().statements();
349
		ReturnStatement rs= null;
350
		int size= statements.size();
351
		ASTNode node;
352
		switch (size) {
353
			case 0:
354
				return result;
355
			case 1:
356
				node= (ASTNode)statements.get(0);
357
				if (node.getNodeType() == ASTNode.RETURN_STATEMENT) {
358
					rs= (ReturnStatement)node;
359
				} else {
360
					result.add(TextRange.createFromStartAndLength(node.getStartPosition(), node.getLength()));
361
				}
362
				break;
363
			default: {
364
				node= (ASTNode)statements.get(size - 1);
365
				if (node.getNodeType() == ASTNode.RETURN_STATEMENT) {
366
					result.add(createRange(statements, size - 2));
367
					rs= (ReturnStatement)node;
368
				} else {
369
					result.add(createRange(statements, size - 1));
370
				}
371
				break;
372
			}
373
		}
374
		if (rs != null) {
375
			Expression exp= rs.getExpression();
376
			result.add(TextRange.createFromStartAndLength(exp.getStartPosition(), exp.getLength()));
377
		}
378
		return result;
379
	}
380
	
381
	private TextRange createRange(List statements, int end) {
382
		int start= ((ASTNode)statements.get(0)).getStartPosition();
383
		ASTNode last= (ASTNode)statements.get(end);
384
		int length = last.getStartPosition() - start + last.getLength();
385
		TextRange range= TextRange.createFromStartAndLength(start, length);
386
		return range;
387
	}
388
	
389
	private String[] getBlocks(RangeMarker[] markers) {
390
		String[] result= new String[markers.length];
391
		for (int i= 0; i < markers.length; i++) {
392
			TextRange range= markers[i].getTextRange();
393
			String content= fBuffer.getContent(range.getOffset(), range.getLength());
394
			String lines[]= Strings.convertIntoLines(content);
395
			Strings.trimIndentation(lines, CodeFormatterUtil.getTabWidth(), false);
396
			result[i]= Strings.concatenate(lines, fBuffer.getLineDelimiter());
397
		}
398
		return result;
399
	}
400
}
600
}

Return to bug 36049