IDEADEV-41135 (forearch -> indexed for intention is broken)
[fedora-idea.git] / plugins / IntentionPowerPak / src / com / siyeh / ipp / forloop / ReplaceForEachLoopWithIndexedForLoopIntention.java
blob8f94088b031c07f5881b708330d1bf9b6f1607ca
1 /*
2 * Copyright 2003-2009 Dave Griffith, Bas Leijdekkers
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.siyeh.ipp.forloop;
18 import com.intellij.openapi.project.Project;
19 import com.intellij.openapi.util.text.StringUtil;
20 import com.intellij.psi.*;
21 import com.intellij.psi.codeStyle.CodeStyleSettings;
22 import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
23 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
24 import com.intellij.util.IncorrectOperationException;
25 import com.siyeh.ipp.base.Intention;
26 import com.siyeh.ipp.base.PsiElementPredicate;
27 import org.jetbrains.annotations.NonNls;
28 import org.jetbrains.annotations.NotNull;
30 public class ReplaceForEachLoopWithIndexedForLoopIntention extends Intention {
32 @Override
33 @NotNull
34 public PsiElementPredicate getElementPredicate() {
35 return new IndexedForEachLoopPredicate();
38 @Override
39 public void processIntention(@NotNull PsiElement element)
40 throws IncorrectOperationException {
41 final PsiForeachStatement statement =
42 (PsiForeachStatement)element.getParent();
43 if (statement == null) {
44 return;
46 final PsiExpression iteratedValue = statement.getIteratedValue();
47 if (iteratedValue == null) {
48 return;
50 final PsiParameter iterationParameter =
51 statement.getIterationParameter();
52 final PsiType type = iterationParameter.getType();
53 final PsiType iteratedValueType = iteratedValue.getType();
54 if (iteratedValueType == null) {
55 return;
57 final boolean isArray = iteratedValueType instanceof PsiArrayType;
58 final Project project = statement.getProject();
59 final JavaCodeStyleManager codeStyleManager =
60 JavaCodeStyleManager.getInstance(project);
61 final String indexText =
62 codeStyleManager.suggestUniqueVariableName("i", statement, true);
63 final String variableNameRoot;
64 if (iteratedValue instanceof PsiMethodCallExpression) {
65 final PsiMethodCallExpression methodCallExpression =
66 (PsiMethodCallExpression)iteratedValue;
67 final PsiReferenceExpression methodExpression =
68 methodCallExpression.getMethodExpression();
69 final String name = methodExpression.getReferenceName();
70 if (name == null) {
71 return;
73 if (name.startsWith("to") && name.length() > 2) {
74 variableNameRoot = StringUtil.decapitalize(name.substring(2));
75 } else if (name.startsWith("get") && name.length() > 3) {
76 variableNameRoot = StringUtil.decapitalize(name.substring(3));
77 } else {
78 variableNameRoot = name;
80 } else if (iteratedValue instanceof PsiTypeCastExpression) {
81 final PsiTypeCastExpression castExpression =
82 (PsiTypeCastExpression) iteratedValue;
83 final PsiExpression operand = castExpression.getOperand();
84 if (operand == null) {
85 variableNameRoot = "";
86 } else {
87 variableNameRoot = operand.getText();
89 } else {
90 variableNameRoot = iteratedValue.getText();
92 final String lengthText;
93 if (isArray) {
94 lengthText = codeStyleManager.suggestUniqueVariableName(
95 variableNameRoot + "Length", statement, true);
96 } else {
97 lengthText = codeStyleManager.suggestUniqueVariableName(
98 variableNameRoot + "Size", statement, true);
100 final CodeStyleSettings codeStyleSettings =
101 CodeStyleSettingsManager.getSettings(project);
102 if (iteratedValue instanceof PsiMethodCallExpression) {
103 final String variableName =
104 codeStyleManager.suggestUniqueVariableName(
105 variableNameRoot, statement, true);
106 final StringBuilder declaration = new StringBuilder();
107 if (codeStyleSettings.GENERATE_FINAL_LOCALS) {
108 declaration.append("final ");
110 declaration.append(iteratedValueType.getCanonicalText());
111 declaration.append(' ');
112 declaration.append(variableName);
113 declaration.append('=');
114 declaration.append(iteratedValue.getText());
115 declaration.append(';');
116 final PsiElementFactory elementFactory =
117 JavaPsiFacade.getElementFactory(project);
118 final PsiStatement declarationStatement =
119 elementFactory.createStatementFromText(
120 declaration.toString(), statement);
121 statement.getParent().addBefore(declarationStatement, statement);
123 @NonNls final StringBuilder newStatement = new StringBuilder();
124 newStatement.append("for(int ");
125 newStatement.append(indexText);
126 newStatement.append(" = 0, ");
128 newStatement.append(lengthText);
129 newStatement.append(" = ");
130 if (iteratedValue instanceof PsiTypeCastExpression) {
131 newStatement.append('(');
132 newStatement.append(iteratedValue.getText());
133 newStatement.append(')');
134 } else {
135 newStatement.append(variableNameRoot);
137 if (isArray) {
138 newStatement.append(".length;");
139 } else {
140 newStatement.append(".size();");
142 newStatement.append(indexText);
143 newStatement.append('<');
144 newStatement.append(lengthText);
145 newStatement.append(';');
146 newStatement.append(indexText);
147 newStatement.append("++)");
148 newStatement.append("{ ");
149 if (codeStyleSettings.GENERATE_FINAL_LOCALS) {
150 newStatement.append("final ");
152 newStatement.append(type.getCanonicalText());
153 newStatement.append(' ');
154 newStatement.append(iterationParameter.getName());
155 newStatement.append(" = ");
156 if (iteratedValue instanceof PsiTypeCastExpression) {
157 newStatement.append('(');
158 newStatement.append(iteratedValue.getText());
159 newStatement.append(')');
160 } else {
161 newStatement.append(variableNameRoot);
163 if (isArray) {
164 newStatement.append('[');
165 newStatement.append(indexText);
166 newStatement.append("];");
167 } else {
168 newStatement.append(".get(");
169 newStatement.append(indexText);
170 newStatement.append(");");
172 final PsiStatement body = statement.getBody();
173 if (body == null) {
174 return;
176 if (body instanceof PsiBlockStatement) {
177 final PsiCodeBlock block = ((PsiBlockStatement)body).getCodeBlock();
178 final PsiElement[] children = block.getChildren();
179 for (int i = 1; i < children.length - 1; i++) {
180 //skip the braces
181 newStatement.append(children[i].getText());
183 } else {
184 newStatement.append(body.getText());
186 newStatement.append('}');
187 replaceStatementAndShorten(newStatement.toString(), statement);