From 52f49b5c5f5ba92f4b8efb6b888267c036cfb636 Mon Sep 17 00:00:00 2001 From: Artemiy Sartakov Date: Thu, 17 Jan 2019 20:26:42 +0700 Subject: [PATCH] ConvertToLocalInspection: inline created local variable if this variable is a copy of initializer (IDEA-33733) --- .../BaseConvertToLocalQuickFix.java | 59 ++++++++- .../FieldCanBeLocalInspection.java | 22 ++-- .../ParameterCanBeLocalInspection.java | 19 ++- .../intellij/refactoring/util/InlineUtil.java | 18 +++ .../convert2Local/afterFinalFieldIsCopy.java | 8 ++ .../afterMultipleMethodsMultipleFields.java | 1 - .../convert2Local/beforeFinalFieldIsCopy.java | 11 ++ .../afterFor.java | 3 +- .../ig/psiutils/VariableAccessUtils.java | 120 ++++++++++++++++++ .../UnnecessaryLocalVariableInspection.java | 115 +---------------- .../com/siyeh/ig/fixes/InlineVariableFix.java | 11 +- 11 files changed, 241 insertions(+), 146 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterFinalFieldIsCopy.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeFinalFieldIsCopy.java diff --git a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java index 90d5ee2ff6b2..374ded1f2d81 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java @@ -29,16 +29,23 @@ import com.intellij.psi.*; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.refactoring.util.InlineUtil; import com.intellij.util.IJSwingUtilities; import com.intellij.util.IncorrectOperationException; import com.intellij.util.NotNullFunction; import com.siyeh.ig.psiutils.CommentTracker; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import com.siyeh.ig.psiutils.VariableAccessUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; +import java.util.List; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; /** * refactored from {@link FieldCanBeLocalInspection} @@ -61,16 +68,54 @@ public abstract class BaseConvertToLocalQuickFix implemen final PsiFile myFile = variable.getContainingFile(); try { - final PsiElement newDeclaration = moveDeclaration(project, variable); - if (newDeclaration == null) return; + final List newDeclarations = moveDeclaration(project, variable).stream() + .map(declaration -> inlineRedundant(declaration)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); - positionCaretToDeclaration(project, myFile, newDeclaration); + if (newDeclarations.isEmpty()) return; + + positionCaretToDeclaration(project, myFile, newDeclarations.get(newDeclarations.size() - 1)); } catch (IncorrectOperationException e) { LOG.error(e); } } + @Nullable + private static PsiElement inlineRedundant(@Nullable PsiElement declaration) { + if (declaration == null) return null; + + final PsiLocalVariable newVariable = extractDeclared(declaration); + if (newVariable != null) { + final PsiExpression initializer = ParenthesesUtils.stripParentheses(newVariable.getInitializer()); + + if (VariableAccessUtils.localVariableIsCopy(newVariable, initializer)) { + WriteAction.run(() -> { + InlineUtil.inlineVariable(newVariable, initializer); + declaration.delete(); + }); + return null; + } + } + + return declaration; + } + + @Nullable + private static PsiLocalVariable extractDeclared(@NotNull PsiElement declaration) { + if (!(declaration instanceof PsiDeclarationStatement)) return null; + + final PsiElement[] declaredElements = ((PsiDeclarationStatement)declaration).getDeclaredElements(); + if (declaredElements.length != 1) return null; + + final PsiElement declared = declaredElements[0]; + + if (!(declared instanceof PsiLocalVariable)) return null; + + return (PsiLocalVariable)declared; + } + @Nullable protected abstract V getVariable(@NotNull ProblemDescriptor descriptor); @@ -88,12 +133,12 @@ public abstract class BaseConvertToLocalQuickFix implemen protected void beforeDelete(@NotNull Project project, @NotNull V variable, @NotNull PsiElement newDeclaration) { } - @Nullable - protected PsiElement moveDeclaration(@NotNull Project project, @NotNull V variable) { + @NotNull + protected List moveDeclaration(@NotNull Project project, @NotNull V variable) { final Collection references = ReferencesSearch.search(variable).findAll(); - if (references.isEmpty()) return null; + if (references.isEmpty()) return Collections.emptyList(); - return moveDeclaration(project, variable, references, true); + return Collections.singletonList(moveDeclaration(project, variable, references, true)); } protected PsiElement moveDeclaration(Project project, V variable, final Collection references, boolean delete) { diff --git a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java index 7af153a0a68f..f9789b2d4b61 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java @@ -323,20 +323,24 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo } private static class ConvertFieldToLocalQuickFix extends BaseConvertToLocalQuickFix { - @Nullable + @NotNull @Override - protected PsiElement moveDeclaration(@NotNull final Project project, @NotNull final PsiField variable) { + protected List moveDeclaration(@NotNull final Project project, @NotNull final PsiField variable) { final Map> refs = new HashMap<>(); - if (!groupByCodeBlocks(ReferencesSearch.search(variable).findAll(), refs)) return null; - PsiElement element = null; + final List newDeclarations = new ArrayList<>(); + if (!groupByCodeBlocks(ReferencesSearch.search(variable).findAll(), refs)) return newDeclarations; + + PsiElement declaration; for (Collection psiReferences : refs.values()) { - element = super.moveDeclaration(project, variable, psiReferences, false); + declaration = super.moveDeclaration(project, variable, psiReferences, false); + if (declaration != null) newDeclarations.add(declaration); } - if (element != null) { - final PsiElement finalElement = element; - ApplicationManager.getApplication().runWriteAction(() -> deleteSourceVariable(project, variable, finalElement)); + + if (!newDeclarations.isEmpty()) { + final PsiElement lastDeclaration = newDeclarations.get(newDeclarations.size() - 1); + ApplicationManager.getApplication().runWriteAction(() -> deleteSourceVariable(project, variable, lastDeclaration)); } - return element; + return newDeclarations; } private static boolean groupByCodeBlocks(final Collection allReferences, Map> refs) { diff --git a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java index 800587d5fbcb..9fc20b599abf 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java @@ -183,16 +183,25 @@ public class ParameterCanBeLocalInspection extends AbstractBaseJavaLocalInspecti final JavaChangeInfo changeInfo = new JavaChangeInfoImpl(visibilityModifier, method, method.getName(), returnType != null ? CanonicalTypes.createTypeWrapper(returnType) : null, newParams, null, false, ContainerUtil.newHashSet(), ContainerUtil.newHashSet()); - final ChangeSignatureProcessor cp = new ChangeSignatureProcessor(project, changeInfo) { + class ParameterToLocalProcessor extends ChangeSignatureProcessor { + private PsiElement newDeclaration; + + ParameterToLocalProcessor(Project project, JavaChangeInfo changeInfo) { + super(project, changeInfo); + } + @Override protected void performRefactoring(@NotNull UsageInfo[] usages) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); - final PsiElement newDeclaration = moveDeclaration(elementFactory, localName, parameter, initializer, action, references); + newDeclaration = moveDeclaration(elementFactory, localName, parameter, initializer, action, references); super.performRefactoring(usages); - positionCaretToDeclaration(project, newDeclaration.getContainingFile(), newDeclaration); } - }; - cp.run(); + } + + final ParameterToLocalProcessor processor = new ParameterToLocalProcessor(project, changeInfo); + processor.run(); + + return processor.newDeclaration; } return null; } diff --git a/java/java-impl/src/com/intellij/refactoring/util/InlineUtil.java b/java/java-impl/src/com/intellij/refactoring/util/InlineUtil.java index 19c45651b4d1..a20166fd7763 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/InlineUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/InlineUtil.java @@ -49,6 +49,24 @@ public class InlineUtil { private InlineUtil() {} + /** + * Replace variable with its initializer for every variable reference. + * + * @return references after replacement + */ + @NotNull + public static Collection inlineVariable(@NotNull PsiVariable variable, @NotNull PsiExpression initializer) { + final Collection replacedElements = new ArrayList<>(); + final Collection references = ReferencesSearch.search(variable).findAll(); + + for (PsiReference reference : references) { + final PsiExpression expression = inlineVariable(variable, initializer, (PsiJavaCodeReferenceElement)reference); + replacedElements.add(expression); + } + + return replacedElements; + } + @NotNull public static PsiExpression inlineVariable(PsiVariable variable, PsiExpression initializer, PsiJavaCodeReferenceElement ref) throws IncorrectOperationException { return inlineVariable(variable, initializer, ref, null); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterFinalFieldIsCopy.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterFinalFieldIsCopy.java new file mode 100644 index 000000000000..0ee8f3d8a8cc --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterFinalFieldIsCopy.java @@ -0,0 +1,8 @@ +// "Convert to local" "true" +class Test { + + public Test(String param) { + System.out.println(param == null ? "null" : param); + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethodsMultipleFields.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethodsMultipleFields.java index 9d1502b44bc0..32ed30f91211 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethodsMultipleFields.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethodsMultipleFields.java @@ -12,6 +12,5 @@ class MyClassTest { } public void setEditable1(final boolean editable1) { - boolean editable11 = editable1; } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeFinalFieldIsCopy.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeFinalFieldIsCopy.java new file mode 100644 index 000000000000..57e2e47b4917 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeFinalFieldIsCopy.java @@ -0,0 +1,11 @@ +// "Convert to local" "true" +class Test { + + private final String field; + + public Test(String param) { + field = param; + System.out.println(field == null ? "null" : field); + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterFor.java b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterFor.java index b0b1b428a968..86b345c1bf86 100644 --- a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterFor.java +++ b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterFor.java @@ -2,8 +2,7 @@ class Temp { public Temp() { for (int i = 0; i < 10; i++) { - int p = i; - System.out.print(p); + System.out.print(i); } } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java index 02c8fb76009d..4eda5e067537 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableAccessUtils.java @@ -15,11 +15,16 @@ */ package com.siyeh.ig.psiutils; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; +import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; +import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.RedundantCastUtil; +import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.Processor; import org.jetbrains.annotations.Contract; @@ -395,6 +400,121 @@ public class VariableAccessUtils { return visitor.isAssigned(); } + /** + * Check if local variable has the same behavior as its initializer. + */ + public static boolean localVariableIsCopy(@NotNull PsiLocalVariable variable) { + return localVariableIsCopy(variable, ParenthesesUtils.stripParentheses(variable.getInitializer())); + } + + /** + * Check if local variable has the same behavior as given expression. + */ + public static boolean localVariableIsCopy(@NotNull PsiLocalVariable variable, @Nullable PsiExpression expression) { + if (expression instanceof PsiTypeCastExpression) { + PsiExpression operand = ((PsiTypeCastExpression)expression).getOperand(); + if (operand instanceof PsiReferenceExpression && RedundantCastUtil.isCastRedundant((PsiTypeCastExpression)expression)) { + expression = operand; + } + } + if (!(expression instanceof PsiReferenceExpression)) { + return false; + } + final PsiReferenceExpression reference = (PsiReferenceExpression)expression; + final PsiVariable initialization = ObjectUtils.tryCast(reference.resolve(), PsiVariable.class); + if (initialization == null) { + return false; + } + if (!(initialization instanceof PsiResourceVariable) && variable instanceof PsiResourceVariable) { + return false; + } + if (!(initialization instanceof PsiLocalVariable || initialization instanceof PsiParameter)) { + if (!isFinalChain(reference) || ReferencesSearch.search(variable).findAll().size() != 1) { + // only warn when variable is referenced once, to avoid warning when a field is cached in local variable + // as in e.g. gnu.trove.TObjectHash#forEach() + return false; + } + } + final PsiCodeBlock containingScope = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (containingScope == null) { + return false; + } + if (variableMayChange(containingScope, null, variable)) { + return false; + } + if (variableMayChange(containingScope, PsiUtil.skipParenthesizedExprDown(reference.getQualifierExpression()), initialization)) { + return false; + } + + final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(containingScope.getProject()).getResolveHelper(); + final String initializationName = initialization.getName(); + if (initializationName == null) { + return false; + } + + final boolean finalVariableIntroduction = + !initialization.hasModifierProperty(PsiModifier.FINAL) && variable.hasModifierProperty(PsiModifier.FINAL) || + PsiUtil.isLanguageLevel8OrHigher(initialization) && + !HighlightControlFlowUtil.isEffectivelyFinal(initialization, containingScope, null) && + HighlightControlFlowUtil.isEffectivelyFinal(variable, containingScope, null); + + final PsiType variableType = variable.getType(); + final PsiType initializationType = initialization.getType(); + final boolean sameType = Comparing.equal(variableType, initializationType); + for (PsiReference ref : ReferencesSearch.search(variable, new LocalSearchScope(containingScope))) { + final PsiElement refElement = ref.getElement(); + if (finalVariableIntroduction) { + final PsiElement element = PsiTreeUtil.getParentOfType(refElement, PsiClass.class, PsiLambdaExpression.class); + if (element != null && PsiTreeUtil.isAncestor(containingScope, element, true)) { + return false; + } + } + + if (resolveHelper.resolveReferencedVariable(initializationName, refElement) != initialization) { + return false; + } + + if (!sameType) { + final PsiElement parent = refElement.getParent(); + if (parent instanceof PsiReferenceExpression) { + final PsiElement resolve = ((PsiReferenceExpression)parent).resolve(); + if (resolve instanceof PsiMember && + ((PsiMember)resolve).hasModifierProperty(PsiModifier.PRIVATE)) { + return false; + } + } + } + } + + return !TypeConversionUtil.boxingConversionApplicable(variableType, initializationType); + } + + private static boolean isFinalChain(PsiReferenceExpression reference) { + while (true) { + PsiElement element = reference.resolve(); + if (!(element instanceof PsiField)) return true; + if (!((PsiField)element).hasModifierProperty(PsiModifier.FINAL)) return false; + PsiExpression qualifier = PsiUtil.skipParenthesizedExprDown(reference.getQualifierExpression()); + if (qualifier == null || qualifier instanceof PsiThisExpression) return true; + if (!(qualifier instanceof PsiReferenceExpression)) return false; + reference = (PsiReferenceExpression)qualifier; + } + } + + private static boolean variableMayChange(PsiCodeBlock containingScope, PsiExpression qualifier, PsiVariable variable) { + while (variable != null) { + if (!variable.hasModifierProperty(PsiModifier.FINAL) && + variableIsAssigned(variable, containingScope, false)) { + return true; + } + if (!(qualifier instanceof PsiReferenceExpression)) break; + PsiReferenceExpression qualifierReference = (PsiReferenceExpression)qualifier; + qualifier = PsiUtil.skipParenthesizedExprDown(qualifierReference.getQualifierExpression()); + variable = ObjectUtils.tryCast(qualifierReference.resolve(), PsiVariable.class); + } + return false; + } + private static class VariableCollectingVisitor extends JavaRecursiveElementWalkingVisitor { private final Set usedVariables = new HashSet<>(); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/dataflow/UnnecessaryLocalVariableInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/dataflow/UnnecessaryLocalVariableInspection.java index e5fb4fe9419e..7db705c62d41 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/dataflow/UnnecessaryLocalVariableInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/dataflow/UnnecessaryLocalVariableInspection.java @@ -15,19 +15,12 @@ */ package com.siyeh.ig.dataflow; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.codeInspection.JavaSuppressionUtil; import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.*; -import com.intellij.psi.search.LocalSearchScope; -import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.RedundantCastUtil; -import com.intellij.psi.util.TypeConversionUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; @@ -118,7 +111,7 @@ public class UnnecessaryLocalVariableInspection extends BaseInspection { } } } - if (isCopyVariable(variable)) { + if (VariableAccessUtils.localVariableIsCopy(variable)) { registerVariableError(variable); } else if (!m_ignoreImmediatelyReturnedVariables && isImmediatelyReturned(variable)) { @@ -138,112 +131,6 @@ public class UnnecessaryLocalVariableInspection extends BaseInspection { } } - private boolean isCopyVariable(PsiVariable variable) { - PsiExpression initializer = ParenthesesUtils.stripParentheses(variable.getInitializer()); - if (initializer instanceof PsiTypeCastExpression) { - PsiExpression operand = ((PsiTypeCastExpression)initializer).getOperand(); - if (operand instanceof PsiReferenceExpression && RedundantCastUtil.isCastRedundant((PsiTypeCastExpression)initializer)) { - initializer = operand; - } - } - if (!(initializer instanceof PsiReferenceExpression)) { - return false; - } - final PsiReferenceExpression reference = (PsiReferenceExpression)initializer; - final PsiVariable initialization = tryCast(reference.resolve(), PsiVariable.class); - if (initialization == null) { - return false; - } - if (!(initialization instanceof PsiResourceVariable) && variable instanceof PsiResourceVariable) { - return false; - } - if (!(initialization instanceof PsiLocalVariable || initialization instanceof PsiParameter)) { - if (!isFinalChain(reference) || ReferencesSearch.search(variable).findAll().size() != 1) { - // only warn when variable is referenced once, to avoid warning when a field is cached in local variable - // as in e.g. gnu.trove.TObjectHash#forEach() - return false; - } - } - final PsiCodeBlock containingScope = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); - if (containingScope == null) { - return false; - } - if (variableMayChange(containingScope, null, variable)) { - return false; - } - if (variableMayChange(containingScope, PsiUtil.skipParenthesizedExprDown(reference.getQualifierExpression()), initialization)) { - return false; - } - - final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(containingScope.getProject()).getResolveHelper(); - final String initializationName = initialization.getName(); - if (initializationName == null) { - return false; - } - - final boolean finalVariableIntroduction = - !initialization.hasModifierProperty(PsiModifier.FINAL) && variable.hasModifierProperty(PsiModifier.FINAL) || - PsiUtil.isLanguageLevel8OrHigher(initialization) && - !HighlightControlFlowUtil.isEffectivelyFinal(initialization, containingScope, null) && - HighlightControlFlowUtil.isEffectivelyFinal(variable, containingScope, null); - - final PsiType variableType = variable.getType(); - final PsiType initializationType = initialization.getType(); - final boolean sameType = Comparing.equal(variableType, initializationType); - for (PsiReference ref : ReferencesSearch.search(variable, new LocalSearchScope(containingScope))) { - final PsiElement refElement = ref.getElement(); - if (finalVariableIntroduction) { - final PsiElement element = PsiTreeUtil.getParentOfType(refElement, PsiClass.class, PsiLambdaExpression.class); - if (element != null && PsiTreeUtil.isAncestor(containingScope, element, true)) { - return false; - } - } - - if (resolveHelper.resolveReferencedVariable(initializationName, refElement) != initialization) { - return false; - } - - if (!sameType) { - final PsiElement parent = refElement.getParent(); - if (parent instanceof PsiReferenceExpression) { - final PsiElement resolve = ((PsiReferenceExpression)parent).resolve(); - if (resolve instanceof PsiMember && - ((PsiMember)resolve).hasModifierProperty(PsiModifier.PRIVATE)) { - return false; - } - } - } - } - - return !TypeConversionUtil.boxingConversionApplicable(variableType, initializationType); - } - - private boolean isFinalChain(PsiReferenceExpression reference) { - while (true) { - PsiElement element = reference.resolve(); - if (!(element instanceof PsiField)) return true; - if (!((PsiField)element).hasModifierProperty(PsiModifier.FINAL)) return false; - PsiExpression qualifier = PsiUtil.skipParenthesizedExprDown(reference.getQualifierExpression()); - if (qualifier == null || qualifier instanceof PsiThisExpression) return true; - if (!(qualifier instanceof PsiReferenceExpression)) return false; - reference = (PsiReferenceExpression)qualifier; - } - } - - private boolean variableMayChange(PsiCodeBlock containingScope, PsiExpression qualifier, PsiVariable variable) { - while (variable != null) { - if (!variable.hasModifierProperty(PsiModifier.FINAL) && - VariableAccessUtils.variableIsAssigned(variable, containingScope, false)) { - return true; - } - if (!(qualifier instanceof PsiReferenceExpression)) break; - PsiReferenceExpression qualifierReference = (PsiReferenceExpression)qualifier; - qualifier = PsiUtil.skipParenthesizedExprDown(qualifierReference.getQualifierExpression()); - variable = tryCast(qualifierReference.resolve(), PsiVariable.class); - } - return false; - } - private boolean isImmediatelyReturned(PsiVariable variable) { final PsiCodeBlock containingScope = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class, true, PsiClass.class); if (containingScope == null) { diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/InlineVariableFix.java b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/InlineVariableFix.java index e2704e6f1487..68621bb0cae2 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/InlineVariableFix.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/InlineVariableFix.java @@ -18,14 +18,12 @@ package com.siyeh.ig.fixes; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.refactoring.util.InlineUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.HighlightUtils; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; import java.util.Collection; public class InlineVariableFix extends InspectionGadgetsFix { @@ -44,12 +42,9 @@ public class InlineVariableFix extends InspectionGadgetsFix { if (initializer == null) { return; } - final Collection references = ReferencesSearch.search(variable).findAll(); - final Collection replacedElements = new ArrayList<>(); - for (PsiReference reference : references) { - final PsiExpression expression = InlineUtil.inlineVariable(variable, initializer, (PsiJavaCodeReferenceElement)reference); - replacedElements.add(expression); - } + + final Collection replacedElements = InlineUtil.inlineVariable(variable, initializer); + if (isOnTheFly()) { HighlightUtils.highlightElements(replacedElements); }