From 56e7b3ec442e2fca521656e9a549c52bce035247 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 21 Dec 2018 12:27:34 +0700 Subject: [PATCH] VariableNameGenerator --- .../impl/quickfix/AddExceptionToCatchFix.java | 6 +- .../quickfix/ConvertSwitchToIfIntention.java | 16 +-- ...atorForEachLoopWithIteratorForLoopFix.java | 9 +- .../JavaWithTryCatchSurrounder.java | 4 +- .../OptionalIsPresentInspection.java | 8 +- ...SimplifyStreamApiCallChainsInspection.java | 18 +-- .../StreamFilterNotNullFix.java | 8 +- ...OptionalGetWithoutIsPresentInspection.java | 8 +- .../FoldExpressionIntoStreamInspection.java | 6 +- ...ntDecrementUsedAsExpressionInspection.java | 17 +-- .../ig/jdk/ForeachStatementInspection.java | 12 +- ...ySetIterationMayUseEntrySetInspection.java | 20 +-- .../ig/psiutils/VariableNameGenerator.java | 114 ++++++++++++++++++ .../migration/ForCanBeForeachInspection.java | 13 +- ...orEachLoopWithIndexedForLoopIntention.java | 36 ++---- ...rEachLoopWithIteratorForLoopIntention.java | 9 +- 16 files changed, 167 insertions(+), 137 deletions(-) create mode 100644 plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableNameGenerator.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java index 0c3bc289f40d..f6ea6df2407d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddExceptionToCatchFix.java @@ -32,6 +32,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.psiutils.VariableNameGenerator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -117,9 +118,8 @@ public class AddExceptionToCatchFix extends BaseIntentionAction { addTryBlock(tryStatement, factory); } - JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(tryStatement.getProject()); - String name = styleManager.suggestVariableName(VariableKind.PARAMETER, null, null, exceptionType).names[0]; - name = styleManager.suggestUniqueVariableName(name, tryStatement, false); + String name = new VariableNameGenerator(tryStatement, VariableKind.PARAMETER).byType(exceptionType) + .byName("e", "ex", "exception").generate(false); PsiCatchSection catchSection = factory.createCatchSection(exceptionType, name, file); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertSwitchToIfIntention.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertSwitchToIfIntention.java index e80cba436719..1ee8c1ed3567 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertSwitchToIfIntention.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ConvertSwitchToIfIntention.java @@ -8,6 +8,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; @@ -16,10 +17,7 @@ import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; -import com.siyeh.ig.psiutils.BreakConverter; -import com.siyeh.ig.psiutils.CommentTracker; -import com.siyeh.ig.psiutils.ControlFlowUtils; -import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.*; import one.util.streamex.StreamEx; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -120,14 +118,8 @@ public class ConvertSwitchToIfIntention implements IntentionAction { RemoveUnusedVariableUtil.checkSideEffects(switchExpression, null, new ArrayList<>())) { hadSideEffects = true; - final JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(project); - final String variableName; - if (isSwitchOnString) { - variableName = javaCodeStyleManager.suggestUniqueVariableName("s", switchExpression, true); - } - else { - variableName = javaCodeStyleManager.suggestUniqueVariableName("i", switchExpression, true); - } + final String variableName = new VariableNameGenerator(switchExpression, VariableKind.LOCAL_VARIABLE) + .byExpression(switchExpression).byType(switchExpressionType).byName(isSwitchOnString ? "s" : "i").generate(true); expressionText = variableName; declarationString = switchExpressionType.getCanonicalText() + ' ' + variableName + " = " + switchExpression.getText() + ';'; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceIteratorForEachLoopWithIteratorForLoopFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceIteratorForEachLoopWithIteratorForLoopFix.java index 481c94f4c569..6f73214cefdb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceIteratorForEachLoopWithIteratorForLoopFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceIteratorForEachLoopWithIteratorForLoopFix.java @@ -21,11 +21,9 @@ import com.intellij.codeInsight.intention.impl.BaseIntentionAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.codeStyle.CodeStyleSettings; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.JavaCodeStyleSettings; +import com.intellij.psi.codeStyle.*; import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.psiutils.VariableNameGenerator; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -82,7 +80,8 @@ public class ReplaceIteratorForEachLoopWithIteratorForLoopFix implements Intenti final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); final JavaCodeStyleManager javaStyleManager = JavaCodeStyleManager.getInstance(project); - final String name = javaStyleManager.suggestUniqueVariableName("it", myStatement, true); + final String name = new VariableNameGenerator(myStatement, VariableKind.LOCAL_VARIABLE) + .byName("it", "iter", "iterator").generate(true); PsiForStatement newForLoop = (PsiForStatement)elementFactory.createStatementFromText( "for (Iterator " + name + " = initializer; " + name + ".hasNext();) { Object next = " + name + ".next(); }", myStatement); diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryCatchSurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryCatchSurrounder.java index 38acd461b8c4..471bf4694315 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryCatchSurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryCatchSurrounder.java @@ -26,6 +26,7 @@ import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.psiutils.VariableNameGenerator; import org.jetbrains.annotations.NonNls; import java.util.Collections; @@ -81,8 +82,7 @@ public class JavaWithTryCatchSurrounder extends JavaStatementsSurrounder { for (int i = 0; i < exceptions.size(); i++) { PsiClassType exception = exceptions.get(i); - String[] nameSuggestions = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, exception).names; - String name = codeStyleManager.suggestUniqueVariableName(nameSuggestions[0], tryBlock, false); + String name = new VariableNameGenerator(tryBlock, VariableKind.PARAMETER).byType(exception).byName("e", "ex", "exc").generate(false); PsiCatchSection catchSection; try { catchSection = factory.createCatchSection(exception, name, tryBlock); diff --git a/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java b/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java index 1c37ca5fbd2b..c908fe0df0a8 100644 --- a/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java @@ -11,13 +11,10 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.ArrayUtil; import com.intellij.util.ObjectUtils; import com.siyeh.ig.psiutils.*; import org.jetbrains.annotations.Contract; @@ -207,10 +204,7 @@ public class OptionalIsPresentInspection extends AbstractBaseJavaLocalInspection PsiReferenceExpression optionalRef, PsiElement trueValue) { PsiType type = optionalRef.getType(); - JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(trueValue.getProject()); - SuggestedNameInfo info = javaCodeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, type); - String baseName = ObjectUtils.coalesce(ArrayUtil.getFirstElement(info.names), "value"); - String paramName = javaCodeStyleManager.suggestUniqueVariableName(baseName, trueValue, true); + String paramName = new VariableNameGenerator(trueValue, VariableKind.PARAMETER).byType(type).byName("value").generate(true); if(trueValue instanceof PsiExpressionStatement) { trueValue = ((PsiExpressionStatement)trueValue).getExpression(); } diff --git a/java/java-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java b/java/java-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java index 411c1addf0ee..5e005a8fa024 100644 --- a/java/java-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java @@ -11,11 +11,9 @@ import com.intellij.codeInspection.redundantCast.RemoveRedundantCastUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.impl.PsiDiamondTypeUtil; import com.intellij.psi.impl.source.tree.java.PsiEmptyExpressionImpl; @@ -1133,21 +1131,11 @@ public class SimplifyStreamApiCallChainsInspection extends AbstractBaseJavaLocal PsiParameter indexParameter = ArrayUtil.getFirstElement(lambda.getParameterList().getParameters()); PsiElement body = lambda.getBody(); if (body == null || indexParameter == null) return null; - String nameCandidate = null; + VariableNameGenerator generator = new VariableNameGenerator(mapToObjCall, VariableKind.PARAMETER); if (containerQualifier instanceof PsiReferenceExpression) { - String name = ((PsiReferenceExpression)containerQualifier).getReferenceName(); - if (name != null) { - nameCandidate = StringUtil.unpluralize(name); - if (name.equals(nameCandidate)) { - nameCandidate = null; - } - } + generator.byCollectionName(((PsiReferenceExpression)containerQualifier).getReferenceName()); } - JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(project); - SuggestedNameInfo info = - javaCodeStyleManager.suggestVariableName(VariableKind.PARAMETER, nameCandidate, null, elementType, true); - nameCandidate = ArrayUtil.getFirstElement(info.names); - String name = javaCodeStyleManager.suggestUniqueVariableName(nameCandidate == null ? "item" : nameCandidate, mapToObjCall, true); + String name = generator.byType(elementType).byName("item", "element").generate(true); Collection refs = ReferencesSearch.search(indexParameter, new LocalSearchScope(body)).findAll(); for (PsiReference ref : refs) { PsiExpression getExpression = container.extractGetExpressionFromIndex(tryCast(ref, PsiExpression.class)); diff --git a/java/java-impl/src/com/intellij/codeInspection/StreamFilterNotNullFix.java b/java/java-impl/src/com/intellij/codeInspection/StreamFilterNotNullFix.java index 6ed1c5b4a132..14865dc5b0ac 100644 --- a/java/java-impl/src/com/intellij/codeInspection/StreamFilterNotNullFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/StreamFilterNotNullFix.java @@ -18,14 +18,13 @@ package com.intellij.codeInspection; import com.intellij.codeInsight.intention.HighPriorityAction; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; import com.siyeh.ig.psiutils.StreamApiUtil; +import com.siyeh.ig.psiutils.VariableNameGenerator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -64,10 +63,7 @@ public class StreamFilterNotNullFix implements LocalQuickFix, HighPriorityAction } } PsiType type = StreamApiUtil.getStreamElementType(qualifier.getType()); - JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(function.getProject()); - SuggestedNameInfo info = javaCodeStyleManager.suggestVariableName(VariableKind.PARAMETER, name, null, type, true); - name = ArrayUtil.getFirstElement(info.names); - return javaCodeStyleManager.suggestUniqueVariableName(name == null ? "obj" : name, qualifier, false); + return new VariableNameGenerator(qualifier, VariableKind.PARAMETER).byName(name).byType(type).byName("obj").generate(false); } @Nullable diff --git a/java/java-impl/src/com/intellij/codeInspection/java18api/OptionalGetWithoutIsPresentInspection.java b/java/java-impl/src/com/intellij/codeInspection/java18api/OptionalGetWithoutIsPresentInspection.java index b54d506f2195..bfd9a19d03b1 100644 --- a/java/java-impl/src/com/intellij/codeInspection/java18api/OptionalGetWithoutIsPresentInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/java18api/OptionalGetWithoutIsPresentInspection.java @@ -10,14 +10,13 @@ import com.intellij.codeInspection.util.LambdaGenerationUtil; import com.intellij.codeInspection.util.OptionalUtil; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import com.siyeh.ig.psiutils.CommentTracker; import com.siyeh.ig.psiutils.ExpressionUtils; +import com.siyeh.ig.psiutils.VariableNameGenerator; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -120,10 +119,7 @@ public class OptionalGetWithoutIsPresentInspection extends AbstractBaseJavaLocal PsiType elementType = OptionalUtil.getOptionalElementType(qualifier.getType()); PsiMethodCallExpression nextCall = ExpressionUtils.getCallForQualifier(call); if (nextCall == null) return; - JavaCodeStyleManager manager = JavaCodeStyleManager.getInstance(project); - SuggestedNameInfo info = manager.suggestVariableName(VariableKind.PARAMETER, null, qualifier, elementType, true); - String name = info.names.length == 0 ? "value" : info.names[0]; - name = manager.suggestUniqueVariableName(name, call, true); + String name = new VariableNameGenerator(qualifier, VariableKind.PARAMETER).byType(elementType).byName("value").generate(true); CommentTracker ct = new CommentTracker(); PsiReferenceExpression methodExpression = nextCall.getMethodExpression(); ct.markRangeUnchanged(Objects.requireNonNull(methodExpression.getQualifierExpression()).getNextSibling(), diff --git a/java/java-impl/src/com/intellij/codeInspection/streamMigration/FoldExpressionIntoStreamInspection.java b/java/java-impl/src/com/intellij/codeInspection/streamMigration/FoldExpressionIntoStreamInspection.java index 76a56d41fca6..b608a3c0a07a 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamMigration/FoldExpressionIntoStreamInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamMigration/FoldExpressionIntoStreamInspection.java @@ -6,7 +6,6 @@ import com.intellij.codeInspection.util.LambdaGenerationUtil; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; @@ -208,11 +207,8 @@ public class FoldExpressionIntoStreamInspection extends AbstractBaseJavaLocalIns PsiExpression operandCopy = (PsiExpression)ct.markUnchanged(operands[0]).copy(); PsiElement expressionCopy = PsiTreeUtil.releaseMark(operandCopy, marker); if (expressionCopy == null) return; - JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); PsiType elementType = firstExpression.getType(); - SuggestedNameInfo info = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, elementType, true); - String name = info.names.length > 0 ? info.names[0] : "v"; - name = codeStyleManager.suggestUniqueVariableName(name, expression, true); + String name = new VariableNameGenerator(expression, VariableKind.PARAMETER).byType(elementType).byName("v").generate(true); PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); PsiExpression expressionCopyReplaced = (PsiExpression)expressionCopy.replace(factory.createExpressionFromText(name, expressionCopy)); if (operandCopy == expressionCopy) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/assignment/IncrementDecrementUsedAsExpressionInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/assignment/IncrementDecrementUsedAsExpressionInspection.java index e3fba3700420..f236142179fc 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/assignment/IncrementDecrementUsedAsExpressionInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/assignment/IncrementDecrementUsedAsExpressionInspection.java @@ -18,7 +18,7 @@ package com.siyeh.ig.assignment; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.tree.IElementType; @@ -29,6 +29,7 @@ import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.PsiReplacementUtil; import com.siyeh.ig.psiutils.ExpressionUtils; +import com.siyeh.ig.psiutils.VariableNameGenerator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -183,15 +184,12 @@ public class IncrementDecrementUsedAsExpressionInspection if (returnValue == null) { return; } - final JavaCodeStyleManager javaCodeStyleManager = - JavaCodeStyleManager.getInstance(project); - final String variableName = - javaCodeStyleManager.suggestUniqueVariableName( - "result", returnValue, true); final PsiType type = returnValue.getType(); if (type == null) { return; } + final String variableName = new VariableNameGenerator(returnValue, VariableKind.LOCAL_VARIABLE).byType(type) + .byExpression(returnValue).byName("result").generate(true); final String newReturnValueText = PsiReplacementUtil.getElementText( returnValue, element, operandText); final String declarationStatementText = @@ -223,11 +221,8 @@ public class IncrementDecrementUsedAsExpressionInspection if (exception == null) { return; } - final JavaCodeStyleManager javaCodeStyleManager = - JavaCodeStyleManager.getInstance(project); - final String variableName = - javaCodeStyleManager.suggestUniqueVariableName( - "e", exception, true); + final String variableName = new VariableNameGenerator(exception, VariableKind.LOCAL_VARIABLE) + .byName("e", "ex", "exc").generate(true); final PsiType type = exception.getType(); if (type == null) { return; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/ForeachStatementInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/ForeachStatementInspection.java index c7dfb9600634..bfb385f2d3d3 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/ForeachStatementInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/jdk/ForeachStatementInspection.java @@ -18,8 +18,8 @@ package com.siyeh.ig.jdk; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleSettingsFacade; +import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.util.InheritanceUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -28,6 +28,7 @@ import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.PsiReplacementUtil; import com.siyeh.ig.psiutils.CommentTracker; import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.VariableNameGenerator; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -62,7 +63,6 @@ public class ForeachStatementInspection extends BaseInspection { public void doFix(Project project, ProblemDescriptor descriptor) { final PsiElement element = descriptor.getPsiElement(); final PsiForeachStatement statement = (PsiForeachStatement)element.getParent(); - final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); assert statement != null; final PsiExpression iteratedValue = statement.getIteratedValue(); if (iteratedValue == null) { @@ -75,7 +75,8 @@ public class ForeachStatementInspection extends BaseInspection { tracker.markUnchanged(iteratedValue); if (iteratedValue.getType() instanceof PsiArrayType) { final PsiType type = iterationParameter.getType(); - final String index = codeStyleManager.suggestUniqueVariableName("i", statement, true); + final String index = new VariableNameGenerator(statement, VariableKind.LOCAL_VARIABLE) + .byType(PsiType.INT).byName("i", "j", "k").generate(true); newStatement.append("for(int ").append(index).append(" = 0;"); newStatement.append(index).append('<').append(iteratedValue.getText()).append(".length;"); newStatement.append(index).append("++)").append("{ "); @@ -94,7 +95,7 @@ public class ForeachStatementInspection extends BaseInspection { methodCall.append(iteratedValue.getText()); } methodCall.append(".iterator()"); - final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory(); + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); final PsiExpression iteratorCall = factory.createExpressionFromText(methodCall.toString(), iteratedValue); final PsiType variableType = GenericsUtil.getVariableTypeByExpressionType(iteratorCall.getType()); if (variableType == null) { @@ -103,7 +104,8 @@ public class ForeachStatementInspection extends BaseInspection { final PsiType parameterType = iterationParameter.getType(); final String typeText = parameterType.getCanonicalText(); newStatement.append("for(").append(variableType.getCanonicalText()).append(' '); - final String iterator = codeStyleManager.suggestUniqueVariableName("iterator", statement, true); + final String iterator = new VariableNameGenerator(statement, VariableKind.LOCAL_VARIABLE).byType(variableType) + .byName("iterator", "iter", "itr").generate(true); newStatement.append(iterator).append("=").append(iteratorCall.getText()).append(';'); newStatement.append(iterator).append(".hasNext();){"); if (generateFinalLocals) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/KeySetIterationMayUseEntrySetInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/KeySetIterationMayUseEntrySetInspection.java index f794516b2d00..4cb06d4c2e92 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/KeySetIterationMayUseEntrySetInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/KeySetIterationMayUseEntrySetInspection.java @@ -19,14 +19,11 @@ import com.intellij.codeInspection.CommonQuickFixBundle; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.RedundantCastUtil; -import com.intellij.util.ArrayUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; @@ -140,13 +137,8 @@ public class KeySetIterationMayUseEntrySetInspection extends BaseInspection { List accesses = ParameterAccessCollector.collectParameterAccesses(keyParameter, mapRef, lambdaBody); String valueName = tryReuseVariable(lambdaBody, accesses); if (valueName == null) { - JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); - SuggestedNameInfo nameInfo = codeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, valueType); - String name = ArrayUtil.getFirstElement(nameInfo.names); - if (name == null) { - name = "k".equals(keyParameter.getName()) ? "v" : "value"; - } - valueName = codeStyleManager.suggestUniqueVariableName(name, lambdaBody, false); + valueName = new VariableNameGenerator(lambdaBody, VariableKind.PARAMETER).byType(valueType) + .byName("k".equals(keyParameter.getName()) ? "v" : "value").generate(false); } for (PsiExpression access : accesses) { if (access instanceof PsiMethodCallExpression && access.isValid()) { @@ -236,13 +228,7 @@ public class KeySetIterationMayUseEntrySetInspection extends BaseInspection { } private static String createNewVariableName(@NotNull PsiElement scope, @NotNull PsiType type) { - final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(scope.getProject()); - final SuggestedNameInfo suggestions = codeStyleManager.suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, type); - @NonNls String baseName = suggestions.names.length > 0 ? suggestions.names[0] : "entry"; - if (baseName == null || baseName.isEmpty()) { - baseName = "entry"; - } - return codeStyleManager.suggestUniqueVariableName(baseName, scope, true); + return new VariableNameGenerator(scope, VariableKind.LOCAL_VARIABLE).byType(type).byName("entry", "e").generate(true); } private static class ParameterAccessCollector extends JavaRecursiveElementWalkingVisitor { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableNameGenerator.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableNameGenerator.java new file mode 100644 index 000000000000..f15bdb1f4c0c --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableNameGenerator.java @@ -0,0 +1,114 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.siyeh.ig.psiutils; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiExpression; +import com.intellij.psi.PsiType; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.SuggestedNameInfo; +import com.intellij.psi.codeStyle.VariableKind; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * A convenience helper class to generate unique name for new variable. To use it, call several by* methods in chain, then call + * the {@link #generate(boolean)} method. The order of by* method calls matters: candidates registered by earlier calls are preferred. + * It's recommended to have at least one {@link #byName(String...)} call with at least one non-null candidate as the last resort. + */ +public final class VariableNameGenerator { + private final @NotNull JavaCodeStyleManager myManager; + private final @NotNull PsiElement myContext; + private final @NotNull VariableKind myKind; + private final Set candidates = new LinkedHashSet<>(); + + /** + * Constructs a new generator + * @param context the place where new variable will be declared + * @param kind kind of variable to generate + */ + public VariableNameGenerator(@NotNull PsiElement context, @NotNull VariableKind kind) { + myManager = JavaCodeStyleManager.getInstance(context.getProject()); + myContext = context; + myKind = kind; + } + + /** + * Adds name candidates based on type + * @param type type of newly generated variable + * @return this generator + */ + public VariableNameGenerator byType(@Nullable PsiType type) { + if (type != null) { + SuggestedNameInfo info = myManager.suggestVariableName(myKind, null, null, type, true); + candidates.addAll(Arrays.asList(info.names)); + } + return this; + } + + /** + * Adds name candidates based on expression + * @param expression expression which value will be stored to the new variable + * @return this generator + */ + public VariableNameGenerator byExpression(@Nullable PsiExpression expression) { + if (expression != null) { + SuggestedNameInfo info = myManager.suggestVariableName(myKind, null, expression, null, true); + candidates.addAll(Arrays.asList(info.names)); + } + return this; + } + + /** + * Adds name candidates based on collection/array name + * @param name of the collection/array which element is represented by newly generated variable + * @return this generator + */ + public VariableNameGenerator byCollectionName(@Nullable String name) { + if (name != null) { + String nameCandidate = StringUtil.unpluralize(name); + if (nameCandidate != null && !name.equals(nameCandidate)) { + byName(nameCandidate); + } + } + return this; + } + + /** + * Adds name candidates based on property name + * @param names base names which could be used to generate variable name + * @return this generator + */ + public VariableNameGenerator byName(String... names) { + for (String name : names) { + if (name != null) { + SuggestedNameInfo info = myManager.suggestVariableName(myKind, name, null, null, true); + candidates.addAll(Arrays.asList(info.names)); + } + } + return this; + } + + /** + * Generates and returns the unique name + * @param lookForward whether further conflicting declarations should be considered + * @return a generated variable name + */ + @NotNull + public String generate(boolean lookForward) { + String suffixed = null; + for (String candidate : candidates.isEmpty() ? Collections.singleton("v") : candidates) { + String name = myManager.suggestUniqueVariableName(candidate, myContext, lookForward); + if (name.equals(candidate)) return name; + if (suffixed == null) { + suffixed = name; + } + } + return suffixed; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/migration/ForCanBeForeachInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/ForCanBeForeachInspection.java index 7ceafc26eb0a..648e862fb784 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/migration/ForCanBeForeachInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/migration/ForCanBeForeachInspection.java @@ -4,18 +4,14 @@ package com.siyeh.ig.migration; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleSettings; -import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.ArrayUtil; import com.siyeh.HardcodedMethodConstants; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -630,13 +626,8 @@ public class ForCanBeForeachInspection extends BaseInspection { } static String createNewVariableName(@NotNull PsiElement scope, PsiType type, @Nullable String containerName) { - final Project project = scope.getProject(); - final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); - final PsiExpression expr = - containerName != null ? JavaPsiFacade.getElementFactory(project).createExpressionFromText(containerName + "[0]", scope) : null; - final SuggestedNameInfo suggestions = codeStyleManager.suggestVariableName(VariableKind.LOCAL_VARIABLE, null, expr, type, true); - @NonNls String baseName = ArrayUtil.getFirstElement(suggestions.names); - return codeStyleManager.suggestUniqueVariableName(StringUtil.defaultIfEmpty(baseName, "value"), scope, true); + return new VariableNameGenerator(scope, VariableKind.PARAMETER).byCollectionName(containerName).byType(type) + .byName("value", "item", "element").generate(true); } @Nullable diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForEachLoopWithIndexedForLoopIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForEachLoopWithIndexedForLoopIntention.java index a296534d9fbd..7248815ff310 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForEachLoopWithIndexedForLoopIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForEachLoopWithIndexedForLoopIntention.java @@ -18,9 +18,12 @@ package com.siyeh.ipp.forloop; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.JavaCodeStyleSettings; +import com.intellij.psi.codeStyle.VariableKind; import com.siyeh.ig.PsiReplacementUtil; import com.siyeh.ig.psiutils.CommentTracker; +import com.siyeh.ig.psiutils.VariableNameGenerator; import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NonNls; @@ -237,37 +240,14 @@ public class ReplaceForEachLoopWithIndexedForLoopIntention extends Intention { return variableName; } - public static String createVariableName( - @Nullable String baseName, - @NotNull PsiExpression assignedExpression) { - final Project project = assignedExpression.getProject(); - final JavaCodeStyleManager codeStyleManager = - JavaCodeStyleManager.getInstance(project); - final SuggestedNameInfo names = - codeStyleManager.suggestVariableName(VariableKind.LOCAL_VARIABLE, - baseName, assignedExpression, null); - if (names.names.length == 0) { - return codeStyleManager.suggestUniqueVariableName(baseName, - assignedExpression, true); - } - return codeStyleManager.suggestUniqueVariableName(names.names[0], - assignedExpression, true); + public static String createVariableName(@Nullable String baseName, @NotNull PsiExpression assignedExpression) { + return new VariableNameGenerator(assignedExpression, VariableKind.LOCAL_VARIABLE).byName(baseName).byExpression(assignedExpression) + .byType(assignedExpression.getType()).generate(true); } public static String createVariableName(@Nullable String baseName, @NotNull PsiType type, @NotNull PsiElement context) { - final Project project = context.getProject(); - final JavaCodeStyleManager codeStyleManager = - JavaCodeStyleManager.getInstance(project); - final SuggestedNameInfo names = - codeStyleManager.suggestVariableName( - VariableKind.LOCAL_VARIABLE, baseName, null, type); - if (names.names.length == 0) { - return codeStyleManager.suggestUniqueVariableName(baseName, - context, true); - } - return codeStyleManager.suggestUniqueVariableName(names.names[0], - context, true); + return new VariableNameGenerator(context, VariableKind.LOCAL_VARIABLE).byName(baseName).byType(type).generate(true); } } \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForEachLoopWithIteratorForLoopIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForEachLoopWithIteratorForLoopIntention.java index c674c21ff84a..6208f4adefd8 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForEachLoopWithIteratorForLoopIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/forloop/ReplaceForEachLoopWithIteratorForLoopIntention.java @@ -17,11 +17,12 @@ package com.siyeh.ipp.forloop; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleSettings; +import com.intellij.psi.codeStyle.VariableKind; import com.siyeh.ig.PsiReplacementUtil; import com.siyeh.ig.psiutils.CommentTracker; import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.VariableNameGenerator; import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NonNls; @@ -52,7 +53,7 @@ public class ReplaceForEachLoopWithIteratorForLoopIntention extends Intention { CommentTracker tracker = new CommentTracker(); final String methodCall = tracker.text(iteratedValue, ParenthesesUtils.METHOD_CALL_PRECEDENCE) + ".iterator()"; final Project project = statement.getProject(); - final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory(); + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); final PsiExpression iteratorCall = factory.createExpressionFromText(methodCall, iteratedValue); final PsiType variableType = GenericsUtil.getVariableTypeByExpressionType(iteratorCall.getType()); if (variableType == null) { @@ -60,8 +61,8 @@ public class ReplaceForEachLoopWithIteratorForLoopIntention extends Intention { } @NonNls final StringBuilder newStatement = new StringBuilder(); newStatement.append("for(").append(variableType.getCanonicalText()).append(' '); - final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project); - final String iterator = codeStyleManager.suggestUniqueVariableName("iterator", statement, true); + final String iterator = new VariableNameGenerator(statement, VariableKind.LOCAL_VARIABLE).byType(variableType) + .byName("iterator", "iter", "it").generate(true); newStatement.append(iterator).append("=").append(iteratorCall.getText()).append(';'); newStatement.append(iterator).append(".hasNext();) {"); if (JavaCodeStyleSettings.getInstance(statement.getContainingFile()).GENERATE_FINAL_LOCALS) {