blob: 4f50ea15851c5b40c6c5744b132a00ff59dd13ae [file] [log] [blame]
/*
* Copyright 2007-2011 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ig.migration;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Query;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.psiutils.PsiElementOrderComparator;
import com.siyeh.ig.psiutils.TypeUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class EnumerationCanBeIterationInspection extends EnumerationCanBeIterationInspectionBase {
@Override
@Nullable
protected InspectionGadgetsFix buildFix(Object... infos) {
return new EnumerationCanBeIterationFix();
}
private static class EnumerationCanBeIterationFix
extends InspectionGadgetsFix {
@Override
@NotNull
public String getFamilyName() {
return getName();
}
@Override
@NotNull
public String getName() {
return InspectionGadgetsBundle.message(
"enumeration.can.be.iteration.quickfix");
}
@Override
protected void doFix(Project project, ProblemDescriptor descriptor)
throws IncorrectOperationException {
final PsiElement element = descriptor.getPsiElement();
final PsiReferenceExpression methodExpression =
(PsiReferenceExpression)element.getParent();
final PsiMethodCallExpression methodCallExpression =
(PsiMethodCallExpression)methodExpression.getParent();
final PsiElement parent =
methodCallExpression.getParent();
final PsiVariable variable;
if (parent instanceof PsiVariable) {
variable = (PsiVariable)parent;
}
else if (parent instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression assignmentExpression =
(PsiAssignmentExpression)parent;
final PsiExpression lhs = assignmentExpression.getLExpression();
if (!(lhs instanceof PsiReferenceExpression)) {
return;
}
final PsiReferenceExpression referenceExpression =
(PsiReferenceExpression)lhs;
final PsiElement target = referenceExpression.resolve();
if (!(target instanceof PsiVariable)) {
return;
}
variable = (PsiVariable)target;
}
else {
return;
}
final String variableName = createVariableName(element);
final PsiStatement statement =
PsiTreeUtil.getParentOfType(element, PsiStatement.class);
if (statement == null) {
return;
}
final int result = replaceMethodCalls(variable,
statement.getTextOffset(), variableName);
final PsiType variableType = variable.getType();
if (!(variableType instanceof PsiClassType)) {
return;
}
final PsiClassType classType = (PsiClassType)variableType;
final PsiType[] parameterTypes = classType.getParameters();
final PsiType parameterType;
if (parameterTypes.length > 0) {
parameterType = parameterTypes[0];
}
else {
parameterType = null;
}
final PsiStatement newStatement =
createDeclaration(methodCallExpression, variableName,
parameterType);
if (newStatement == null) {
return;
}
if (parent.equals(variable)) {
if (result == KEEP_NOTHING) {
statement.replace(newStatement);
}
else {
insertNewStatement(statement, newStatement);
if (result != KEEP_INITIALIZATION) {
final PsiExpression initializer =
variable.getInitializer();
if (initializer != null) {
initializer.delete();
}
}
}
}
else {
if (result == KEEP_NOTHING || result == KEEP_DECLARATION) {
statement.replace(newStatement);
}
else {
insertNewStatement(statement, newStatement);
}
}
}
private static void insertNewStatement(PsiStatement anchor,
PsiStatement newStatement)
throws IncorrectOperationException {
final PsiElement statementParent = anchor.getParent();
if (statementParent instanceof PsiForStatement) {
final PsiElement statementGrandParent =
statementParent.getParent();
statementGrandParent.addBefore(newStatement,
statementParent);
}
else {
statementParent.addAfter(newStatement, anchor);
}
}
@Nullable
private static PsiStatement createDeclaration(
PsiMethodCallExpression methodCallExpression,
String variableName, PsiType parameterType)
throws IncorrectOperationException {
@NonNls final StringBuilder newStatementText = new StringBuilder();
final Project project = methodCallExpression.getProject();
final CodeStyleSettings codeStyleSettings =
CodeStyleSettingsManager.getSettings(project);
if (codeStyleSettings.GENERATE_FINAL_LOCALS) {
newStatementText.append("final ");
}
newStatementText.append(CommonClassNames.JAVA_UTIL_ITERATOR);
if (parameterType != null) {
final String typeText = parameterType.getCanonicalText();
newStatementText.append('<');
newStatementText.append(typeText);
newStatementText.append('>');
}
newStatementText.append(' ');
newStatementText.append(variableName);
newStatementText.append('=');
final PsiReferenceExpression methodExpression =
methodCallExpression.getMethodExpression();
final PsiExpression qualifier =
methodExpression.getQualifierExpression();
final String qualifierText;
if (qualifier == null) {
qualifierText = "";
}
else {
qualifierText = qualifier.getText() + '.';
}
newStatementText.append(qualifierText);
@NonNls final String methodName =
methodExpression.getReferenceName();
if ("elements".equals(methodName)) {
if (TypeUtils.expressionHasTypeOrSubtype(qualifier,
"java.util.Vector")) {
newStatementText.append(ITERATOR_TEXT);
}
else if (TypeUtils.expressionHasTypeOrSubtype(qualifier,
"java.util.Hashtable")) {
newStatementText.append(VALUES_ITERATOR_TEXT);
}
else {
return null;
}
}
else if ("keys".equals(methodName)) {
if (TypeUtils.expressionHasTypeOrSubtype(qualifier,
"java.util.Hashtable")) {
newStatementText.append(KEY_SET_ITERATOR_TEXT);
}
else {
return null;
}
}
else {
return null;
}
newStatementText.append(';');
final PsiElementFactory factory =
JavaPsiFacade.getElementFactory(project);
final PsiStatement statement =
factory.createStatementFromText(newStatementText.toString(),
methodExpression);
final JavaCodeStyleManager styleManager =
JavaCodeStyleManager.getInstance(project);
styleManager.shortenClassReferences(statement);
return statement;
}
/**
* @return true if the initialization of the Enumeration variable can
* be deleted.
*/
private static int replaceMethodCalls(
PsiVariable enumerationVariable,
int startOffset,
String newVariableName)
throws IncorrectOperationException {
final PsiManager manager = enumerationVariable.getManager();
final Project project = manager.getProject();
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
final PsiElementFactory factory = facade.getElementFactory();
final Query<PsiReference> query = ReferencesSearch.search(
enumerationVariable);
final List<PsiElement> referenceElements = new ArrayList();
for (PsiReference reference : query) {
final PsiElement referenceElement = reference.getElement();
referenceElements.add(referenceElement);
}
Collections.sort(referenceElements,
PsiElementOrderComparator.getInstance());
int result = 0;
for (PsiElement referenceElement : referenceElements) {
if (!(referenceElement instanceof PsiReferenceExpression)) {
result = KEEP_DECLARATION;
continue;
}
if (referenceElement.getTextOffset() <= startOffset) {
result = KEEP_DECLARATION;
continue;
}
final PsiReferenceExpression referenceExpression =
(PsiReferenceExpression)referenceElement;
final PsiElement referenceParent =
referenceExpression.getParent();
if (!(referenceParent instanceof PsiReferenceExpression)) {
if (referenceParent instanceof PsiAssignmentExpression) {
result = KEEP_DECLARATION;
break;
}
result = KEEP_INITIALIZATION;
continue;
}
final PsiElement referenceGrandParent =
referenceParent.getParent();
if (!(referenceGrandParent instanceof PsiMethodCallExpression)) {
result = KEEP_INITIALIZATION;
continue;
}
final PsiMethodCallExpression callExpression =
(PsiMethodCallExpression)referenceGrandParent;
final PsiReferenceExpression foundReferenceExpression =
callExpression.getMethodExpression();
@NonNls final String foundName =
foundReferenceExpression.getReferenceName();
@NonNls final String newExpressionText;
if ("hasMoreElements".equals(foundName)) {
newExpressionText = newVariableName + ".hasNext()";
}
else if ("nextElement".equals(foundName)) {
newExpressionText = newVariableName + ".next()";
}
else {
result = KEEP_INITIALIZATION;
continue;
}
final PsiExpression newExpression =
factory.createExpressionFromText(newExpressionText,
callExpression);
callExpression.replace(newExpression);
}
return result;
}
@NonNls
private static String createVariableName(PsiElement context) {
final Project project = context.getProject();
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
final PsiElementFactory factory = facade.getElementFactory();
final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
final PsiClass iteratorClass =
facade.findClass(CommonClassNames.JAVA_UTIL_ITERATOR, scope);
if (iteratorClass == null) {
return "iterator";
}
final JavaCodeStyleManager codeStyleManager =
JavaCodeStyleManager.getInstance(project);
final PsiType iteratorType = factory.createType(iteratorClass);
final SuggestedNameInfo baseNameInfo =
codeStyleManager.suggestVariableName(
VariableKind.LOCAL_VARIABLE, null, null,
iteratorType);
final SuggestedNameInfo nameInfo =
codeStyleManager.suggestUniqueVariableName(baseNameInfo,
context, true);
if (nameInfo.names.length <= 0) {
return "iterator";
}
return nameInfo.names[0];
}
}
}