From 69632b09da6ab296985671f11f195eaa8253a545 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Tue, 21 Mar 2017 12:14:55 +0700 Subject: [PATCH] StreamToLoopInspection: get rid of placeholder; instead pass a predicate to suggestUniqueVariableName to be able to reuse existing names --- .../streamToLoop/StreamToLoopInspection.java | 99 ++++++------ .../codeStyle/JavaCodeStyleManagerImpl.java | 142 +++++++++--------- .../psi/codeStyle/JavaCodeStyleManager.java | 15 +- .../core/CoreJavaCodeStyleManager.java | 20 ++- 4 files changed, 157 insertions(+), 119 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/streamToLoop/StreamToLoopInspection.java b/java/java-impl/src/com/intellij/codeInspection/streamToLoop/StreamToLoopInspection.java index 75deab9217f4..a71ba621c3d4 100644 --- a/java/java-impl/src/com/intellij/codeInspection/streamToLoop/StreamToLoopInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/streamToLoop/StreamToLoopInspection.java @@ -319,46 +319,50 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool { PsiStatement statement = PsiTreeUtil.getParentOfType(terminalCall, PsiStatement.class); LOG.assertTrue(statement != null); CommentTracker ct = new CommentTracker(); - PsiExpression temporaryStreamPlaceholder = - (PsiExpression)ct.replace(terminalCall, "((" + resultType.getCanonicalText() + ")$streamReplacement$)"); try { StreamToLoopReplacementContext context = - new StreamToLoopReplacementContext(statement, operations, temporaryStreamPlaceholder, ct); + new StreamToLoopReplacementContext(statement, operations, terminalCall, ct); registerVariables(operations, context); String replacement = ""; for (OperationRecord or : StreamEx.ofReversed(operations)) { replacement = or.myOperation.wrap(or.myInVar, or.myOutVar, replacement, context); } - ct.insertCommentsBefore(statement); + PsiElement firstAdded = null; for (PsiStatement addedStatement : ((PsiBlockStatement)factory.createStatementFromText("{" + replacement + "}", statement)) .getCodeBlock().getStatements()) { - addStatement(project, statement, addedStatement); + PsiElement res = addStatement(project, statement, addedStatement); + if (firstAdded == null) { + firstAdded = res; + } } PsiElement result = context.makeFinalReplacement(); if(result != null) { - normalize(project, result); + result = normalize(project, result); + if (firstAdded == null) { + firstAdded = result; + } + } + if (firstAdded != null) { + ct.insertCommentsBefore(firstAdded); } } catch (Exception ex) { String text = terminalCall.getText(); - if(temporaryStreamPlaceholder.isPhysical()) { - // Just in case if something went wrong: at least try to restore the original stream code - temporaryStreamPlaceholder.replace(factory.createExpressionFromText(text, temporaryStreamPlaceholder)); - } LOG.error(LogMessageEx.createEvent("Error converting Stream to loop", ExceptionUtil.getThrowableText(ex), new Attachment("Stream_code.txt", text))); } } - private static void addStatement(@NotNull Project project, PsiStatement statement, PsiStatement context) { + private static PsiElement addStatement(@NotNull Project project, PsiStatement statement, PsiStatement context) { PsiElement element = statement.getParent().addBefore(context, statement); - normalize(project, element); + return normalize(project, element); } - private static void normalize(@NotNull Project project, PsiElement element) { + private static PsiElement normalize(@NotNull Project project, PsiElement element) { element = JavaCodeStyleManager.getInstance(project).shortenClassReferences(element); PsiDiamondTypeUtil.removeRedundantTypeArguments(element); RedundantCastUtil.getRedundantCastsInside(element).forEach(RedundantCastUtil::removeCast); + return element; } private static StreamEx allOperations(List operations) { @@ -399,19 +403,19 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool { private final List myBeforeSteps = new ArrayList<>(); private final List myAfterSteps = new ArrayList<>(); private final CommentTracker myCommentTracker; - private PsiElement myPlaceholder; + private PsiElement myStreamExpression; private final PsiElementFactory myFactory; private String myLabel; private String myFinisher; StreamToLoopReplacementContext(PsiStatement statement, List records, - @NotNull PsiExpression placeholder, + @NotNull PsiExpression streamExpression, CommentTracker ct) { myStatement = statement; myFactory = JavaPsiFacade.getElementFactory(myStatement.getProject()); myHasNestedLoops = records.stream().anyMatch(or -> or.myOperation instanceof FlatMapOperation); - myPlaceholder = placeholder; + myStreamExpression = streamExpression; mySuffix = myHasNestedLoops ? "Outer" : ""; myCommentTracker = ct; myUsedNames = new HashSet<>(); @@ -422,7 +426,7 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool { StreamToLoopReplacementContext(StreamToLoopReplacementContext parentContext, List records) { myUsedNames = parentContext.myUsedNames; myUsedLabels = parentContext.myUsedLabels; - myPlaceholder = null; + myStreamExpression = parentContext.myStreamExpression; myStatement = parentContext.myStatement; myFactory = parentContext.myFactory; myCommentTracker = parentContext.myCommentTracker; @@ -480,7 +484,8 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool { private boolean isUsed(String varName) { return myUsedNames.contains(varName) || JavaLexer.isKeyword(varName, LanguageLevel.HIGHEST) || - !varName.equals(JavaCodeStyleManager.getInstance(myStatement.getProject()).suggestUniqueVariableName(varName, myStatement, true)); + !varName.equals(JavaCodeStyleManager.getInstance(myStatement.getProject()) + .suggestUniqueVariableName(varName, myStatement, v -> PsiTreeUtil.isAncestor(myStreamExpression, v, true))); } public String declare(String desiredName, String type, String initializer) { @@ -511,13 +516,13 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool { } public String declareResult(String desiredName, String type, String initializer, @NotNull ResultKind kind) { - if (kind != ResultKind.UNKNOWN && myPlaceholder.getParent() instanceof PsiVariable) { - PsiVariable var = (PsiVariable)myPlaceholder.getParent(); + if (kind != ResultKind.UNKNOWN && myStreamExpression.getParent() instanceof PsiVariable) { + PsiVariable var = (PsiVariable)myStreamExpression.getParent(); if(var.getType().equalsToText(type) && var.getParent() instanceof PsiDeclarationStatement && (kind == ResultKind.FINAL || canUseAsNonFinal(var))) { PsiDeclarationStatement declaration = (PsiDeclarationStatement)var.getParent(); if(declaration.getDeclaredElements().length == 1) { - myPlaceholder = declaration; + myStreamExpression = declaration; PsiVariable copy = (PsiVariable)var.copy(); if (kind == ResultKind.NON_FINAL) { PsiModifierList modifierList = copy.getModifierList(); @@ -553,18 +558,18 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool { } public PsiElement makeFinalReplacement() { - LOG.assertTrue(myPlaceholder != null); - if (myFinisher == null || myPlaceholder instanceof PsiStatement) { - myPlaceholder.delete(); + LOG.assertTrue(myStreamExpression != null); + if (myFinisher == null || myStreamExpression instanceof PsiStatement) { + myCommentTracker.delete(myStreamExpression); return null; } else { - PsiExpression expression = myFactory.createExpressionFromText(myFinisher, myPlaceholder); - PsiElement parent = myPlaceholder.getParent(); + PsiExpression expression = myFactory.createExpressionFromText(myFinisher, myStreamExpression); + PsiElement parent = myStreamExpression.getParent(); if (parent instanceof PsiExpression && ParenthesesUtils.areParenthesesNeeded(expression, (PsiExpression)parent, false)) { - expression = myFactory.createExpressionFromText("("+myFinisher+")", myPlaceholder); + expression = myFactory.createExpressionFromText("("+myFinisher+")", myStreamExpression); } - return myPlaceholder.replace(expression); + return myCommentTracker.replace(myStreamExpression, expression); } } @@ -580,7 +585,7 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool { } public String assignAndBreak(ConditionalExpression conditionalExpression) { - PsiStatement statement = PsiTreeUtil.getParentOfType(myPlaceholder, PsiStatement.class); + PsiStatement statement = PsiTreeUtil.getParentOfType(myStreamExpression, PsiStatement.class); boolean inReturn = statement instanceof PsiReturnStatement; if(conditionalExpression instanceof ConditionalExpression.Optional) { conditionalExpression = tryUnwrapOptional((ConditionalExpression.Optional)conditionalExpression, inReturn); @@ -591,38 +596,38 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool { if (inReturn) { setFinisher(conditionalExpression.getFalseBranch()); Object mark = new Object(); - PsiTreeUtil.mark(myPlaceholder, mark); + PsiTreeUtil.mark(myStreamExpression, mark); PsiElement returnCopy = statement.copy(); PsiElement placeHolderCopy = PsiTreeUtil.releaseMark(returnCopy, mark); LOG.assertTrue(placeHolderCopy != null); PsiElement replacement = placeHolderCopy.replace(createExpression(conditionalExpression.getTrueBranch())); return (placeHolderCopy == returnCopy ? replacement : returnCopy).getText(); } - PsiElement parent = PsiUtil.skipParenthesizedExprUp(myPlaceholder.getParent()); + PsiElement parent = PsiUtil.skipParenthesizedExprUp(myStreamExpression.getParent()); if(parent instanceof PsiIfStatement && conditionalExpression instanceof ConditionalExpression.Boolean && !((ConditionalExpression.Boolean)conditionalExpression).isInverted()) { PsiIfStatement ifStatement = (PsiIfStatement)parent; if(ifStatement.getElseBranch() == null) { PsiStatement thenStatement = ControlFlowUtils.stripBraces(ifStatement.getThenBranch()); if(thenStatement instanceof PsiReturnStatement || thenStatement instanceof PsiThrowStatement) { - myPlaceholder = parent; + myStreamExpression = parent; return thenStatement.getText(); } if(thenStatement instanceof PsiExpressionStatement) { - myPlaceholder = parent; + myStreamExpression = parent; return thenStatement.getText() + "\n" + getBreakStatement(); } } } - if(conditionalExpression instanceof ConditionalExpression.Optional && myPlaceholder instanceof PsiExpression) { - PsiMethodCallExpression call = ExpressionUtils.getCallForQualifier((PsiExpression)myPlaceholder); + if(conditionalExpression instanceof ConditionalExpression.Optional && myStreamExpression instanceof PsiExpression) { + PsiMethodCallExpression call = ExpressionUtils.getCallForQualifier((PsiExpression)myStreamExpression); if(call != null && call.getParent() instanceof PsiExpressionStatement) { PsiExpression[] args = call.getArgumentList().getExpressions(); if(args.length == 1 && "ifPresent".equals(call.getMethodExpression().getReferenceName())) { FunctionHelper fn = FunctionHelper.create(args[0], 1); if(fn != null) { fn.transform(this, ((ConditionalExpression.Optional)conditionalExpression).unwrap("").getTrueBranch()); - myPlaceholder = call.getParent(); + myStreamExpression = call.getParent(); return fn.getStatementText() + getBreakStatement(); } } @@ -635,19 +640,19 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool { } private ConditionalExpression tryUnwrapBoolean(ConditionalExpression.Boolean condition, boolean unwrapLazilyEvaluated) { - if (myPlaceholder instanceof PsiExpression) { - PsiExpression negation = BoolUtils.findNegation((PsiExpression)myPlaceholder); + if (myStreamExpression instanceof PsiExpression) { + PsiExpression negation = BoolUtils.findNegation((PsiExpression)myStreamExpression); if (negation != null) { - myPlaceholder = negation; + myStreamExpression = negation; condition = condition.negate(); } - PsiElement parent = PsiUtil.skipParenthesizedExprUp(myPlaceholder.getParent()); + PsiElement parent = PsiUtil.skipParenthesizedExprUp(myStreamExpression.getParent()); ConditionalExpression candidate = null; if (parent instanceof PsiPolyadicExpression) { PsiPolyadicExpression expression = (PsiPolyadicExpression)parent; PsiExpression[] operands = expression.getOperands(); - if (operands.length > 1 && PsiTreeUtil.isAncestor(operands[0], myPlaceholder, false)) { + if (operands.length > 1 && PsiTreeUtil.isAncestor(operands[0], myStreamExpression, false)) { IElementType type = expression.getOperationTokenType(); if (type.equals(JavaTokenType.ANDAND)) { candidate = condition @@ -659,7 +664,7 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool { } } else if (parent instanceof PsiConditionalExpression) { PsiConditionalExpression ternary = (PsiConditionalExpression)parent; - if (PsiTreeUtil.isAncestor(ternary.getCondition(), myPlaceholder, false)) { + if (PsiTreeUtil.isAncestor(ternary.getCondition(), myStreamExpression, false)) { PsiType type = ternary.getType(); PsiExpression thenExpression = ternary.getThenExpression(); PsiExpression elseExpression = ternary.getElseExpression(); @@ -670,7 +675,7 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool { } if (candidate != null && (unwrapLazilyEvaluated || ExpressionUtils.isSimpleExpression(createExpression(candidate.getFalseBranch())))) { - myPlaceholder = parent; + myStreamExpression = parent; return candidate; } } @@ -679,13 +684,13 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool { @NotNull private ConditionalExpression tryUnwrapOptional(ConditionalExpression.Optional condition, boolean unwrapLazilyEvaluated) { - if (myPlaceholder instanceof PsiExpression) { - PsiMethodCallExpression call = ExpressionUtils.getCallForQualifier((PsiExpression)myPlaceholder); + if (myStreamExpression instanceof PsiExpression) { + PsiMethodCallExpression call = ExpressionUtils.getCallForQualifier((PsiExpression)myStreamExpression); if (call != null && !(call.getParent() instanceof PsiExpressionStatement)) { String name = call.getMethodExpression().getReferenceName(); PsiExpression[] args = call.getArgumentList().getExpressions(); if (args.length == 0 && "isPresent".equals(name)) { - myPlaceholder = call; + myStreamExpression = call; return new ConditionalExpression.Boolean(condition.getCondition(), false); } if (args.length == 1) { @@ -701,7 +706,7 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool { } } if (absentExpression != null) { - myPlaceholder = call; + myStreamExpression = call; return condition.unwrap(absentExpression); } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java index 2dc856708c2c..2b4baed915e6 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/JavaCodeStyleManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,8 @@ import org.jetbrains.annotations.Nullable; import java.beans.Introspector; import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; /** * @author max @@ -677,12 +679,7 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager { @NotNull private static String constantValueToConstantName(@NotNull String[] names) { - final StringBuilder result = new StringBuilder(); - for (int i = 0; i < names.length; i++) { - if (i > 0) result.append("_"); - result.append(names[i]); - } - return result.toString(); + return Arrays.stream(names).collect(Collectors.joining("_")); } @NotNull @@ -749,13 +746,7 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager { method = (PsiMethod)navElement; } PsiExpression[] expressions = list.getExpressions(); - int index = -1; - for (int i = 0; i < expressions.length; i++) { - if (expressions[i] == expr) { - index = i; - break; - } - } + int index = ArrayUtil.indexOf(expressions, expr); PsiParameter[] parameters = method.getParameterList().getParameters(); if (index < parameters.length) { String name = parameters[index].getName(); @@ -899,62 +890,13 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager { @NotNull @Override public String suggestUniqueVariableName(@NotNull String baseName, PsiElement place, boolean lookForward) { - return suggestUniqueVariableName(baseName, place, lookForward, false); + return suggestUniqueVariableName(baseName, place, lookForward, false, v -> false); } - @NotNull - private static String suggestUniqueVariableName(@NotNull String baseName, PsiElement place, boolean lookForward, boolean allowShadowing) { - PsiElement scope = PsiTreeUtil.getNonStrictParentOfType(place, PsiStatement.class, PsiCodeBlock.class, PsiMethod.class); - for (int index = 0; ; index++) { - String name = index > 0 ? baseName + index : baseName; - if (hasConflictingVariable(place, name, allowShadowing) || lookForward && hasConflictingVariableAfterwards(scope, name)) { - continue; - } - return name; - } - } - - private static boolean hasConflictingVariableAfterwards(@Nullable PsiElement scope, @NotNull final String name) { - PsiElement run = scope; - while (run != null) { - class CancelException extends RuntimeException { - } - try { - run.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitClass(final PsiClass aClass) {} - - @Override public void visitVariable(PsiVariable variable) { - if (name.equals(variable.getName())) { - throw new CancelException(); - } - } - }); - } - catch (CancelException e) { - return true; - } - run = run.getNextSibling(); - if (scope instanceof PsiMethod || scope instanceof PsiForeachStatement) {//do not check next member for param name conflict - break; - } - } - return false; - } - - private static boolean hasConflictingVariable(@Nullable PsiElement place, @NotNull String name, boolean allowShadowing) { - if (place == null) { - return false; - } - PsiResolveHelper helper = JavaPsiFacade.getInstance(place.getProject()).getResolveHelper(); - PsiVariable existingVariable = helper.resolveAccessibleReferencedVariable(name, place); - if (existingVariable == null) return false; - - if (allowShadowing && existingVariable instanceof PsiField && PsiTreeUtil.getNonStrictParentOfType(place, PsiMethod.class) != null) { - return false; - } - - return true; + @NotNull + @Override + public String suggestUniqueVariableName(@NotNull String baseName, PsiElement place, Predicate canBeReused) { + return suggestUniqueVariableName(baseName, place, true, false, canBeReused); } @Override @@ -975,7 +917,7 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager { } String unique = suggestUniqueVariableName(name, place, lookForward); if (!unique.equals(name)) { - String withShadowing = suggestUniqueVariableName(name, place, lookForward, true); + String withShadowing = suggestUniqueVariableName(name, place, lookForward, true, v -> false); if (withShadowing.equals(name)) { uniqueNames.add(name); } @@ -991,6 +933,68 @@ public class JavaCodeStyleManagerImpl extends JavaCodeStyleManager { }; } + @NotNull + private static String suggestUniqueVariableName(@NotNull String baseName, + PsiElement place, + boolean lookForward, + boolean allowShadowing, + Predicate canBeReused) { + PsiElement scope = PsiTreeUtil.getNonStrictParentOfType(place, PsiStatement.class, PsiCodeBlock.class, PsiMethod.class); + for (int index = 0; ; index++) { + String name = index > 0 ? baseName + index : baseName; + if (hasConflictingVariable(place, name, allowShadowing) || + lookForward && hasConflictingVariableAfterwards(scope, name, canBeReused)) { + continue; + } + return name; + } + } + + private static boolean hasConflictingVariable(@Nullable PsiElement place, @NotNull String name, boolean allowShadowing) { + if (place == null) { + return false; + } + PsiResolveHelper helper = JavaPsiFacade.getInstance(place.getProject()).getResolveHelper(); + PsiVariable existingVariable = helper.resolveAccessibleReferencedVariable(name, place); + if (existingVariable == null) return false; + + if (allowShadowing && existingVariable instanceof PsiField && PsiTreeUtil.getNonStrictParentOfType(place, PsiMethod.class) != null) { + return false; + } + + return true; + } + + private static boolean hasConflictingVariableAfterwards(@Nullable PsiElement scope, + @NotNull final String name, + @NotNull Predicate canBeReused) { + PsiElement run = scope; + while (run != null) { + class CancelException extends RuntimeException { + } + try { + run.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitClass(final PsiClass aClass) {} + + @Override public void visitVariable(PsiVariable variable) { + if (name.equals(variable.getName()) && !canBeReused.test(variable)) { + throw new CancelException(); + } + } + }); + } + catch (CancelException e) { + return true; + } + run = run.getNextSibling(); + if (scope instanceof PsiMethod || scope instanceof PsiForeachStatement) {//do not check next member for param name conflict + break; + } + } + return false; + } + private static void sortVariableNameSuggestions(@NotNull String[] names, @NotNull final VariableKind variableKind, @Nullable final String propertyName, diff --git a/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java b/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java index 8c22db6ecbd2..8f9d1b9664b7 100644 --- a/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java +++ b/java/java-psi-api/src/com/intellij/psi/codeStyle/JavaCodeStyleManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; +import java.util.function.Predicate; /** * @author max @@ -203,6 +204,18 @@ public abstract class JavaCodeStyleManager { return suggestUniqueVariableName(baseNameInfo, place, false, lookForward); } + /** + * Suggests a unique name for the variable used at the specified location looking forward with possible filtering. + * + * @param baseName the base name info for the variable. + * @param place the location where the variable will be used. + * @param canBeReused a predicate which returns true for variables which names still could be reused (e.g. a variable will be deleted + * during the ongoing refactoring) + * @return the generated unique name + */ + @NotNull + public abstract String suggestUniqueVariableName(@NotNull String baseName, PsiElement place, Predicate canBeReused); + /** * Suggests a unique name for the variable used at the specified location. * diff --git a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java index f670f2466afe..e8f38590cf21 100644 --- a/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java +++ b/java/java-psi-impl/src/com/intellij/core/CoreJavaCodeStyleManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.LinkedHashSet; +import java.util.function.Predicate; public class CoreJavaCodeStyleManager extends JavaCodeStyleManager { @Override @@ -63,6 +64,7 @@ public class CoreJavaCodeStyleManager extends JavaCodeStyleManager { return 0; } + @NotNull @Override public PsiElement shortenClassReferences(@NotNull PsiElement element) throws IncorrectOperationException { return element; @@ -106,6 +108,14 @@ public class CoreJavaCodeStyleManager extends JavaCodeStyleManager { @NotNull @Override public String suggestUniqueVariableName(@NotNull @NonNls String baseName, PsiElement place, boolean lookForward) { + return suggestUniqueVariableName(baseName, place, lookForward, v -> false); + } + + @NotNull + private static String suggestUniqueVariableName(@NotNull @NonNls String baseName, + PsiElement place, + boolean lookForward, + Predicate canBeReused) { int index = 0; PsiElement scope = PsiTreeUtil.getNonStrictParentOfType(place, PsiStatement.class, PsiCodeBlock.class, PsiMethod.class); NextName: @@ -129,7 +139,7 @@ public class CoreJavaCodeStyleManager extends JavaCodeStyleManager { } @Override public void visitVariable(PsiVariable variable) { - if (name1.equals(variable.getName())) { + if (name1.equals(variable.getName()) && !canBeReused.test(variable)) { throw new CancelException(); } } @@ -150,6 +160,12 @@ public class CoreJavaCodeStyleManager extends JavaCodeStyleManager { } } + @NotNull + @Override + public String suggestUniqueVariableName(@NotNull String baseName, PsiElement place, Predicate canBeReused) { + return suggestUniqueVariableName(baseName, place, true, canBeReused); + } + @NotNull @Override public SuggestedNameInfo suggestUniqueVariableName(@NotNull final SuggestedNameInfo baseNameInfo,