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 6dd3558b6817..1862d7edc0ef 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java @@ -46,7 +46,7 @@ import java.util.Set; * @author Danila Ponomarenko */ public abstract class BaseConvertToLocalQuickFix implements LocalQuickFix { - private static final Logger LOG = Logger.getInstance(BaseConvertToLocalQuickFix.class); + protected static final Logger LOG = Logger.getInstance(BaseConvertToLocalQuickFix.class); @Override @NotNull @@ -89,10 +89,14 @@ public abstract class BaseConvertToLocalQuickFix implemen } @Nullable - private PsiElement moveDeclaration(@NotNull Project project, @NotNull V variable) { + protected PsiElement moveDeclaration(@NotNull Project project, @NotNull V variable) { final Collection references = ReferencesSearch.search(variable).findAll(); if (references.isEmpty()) return null; + return moveDeclaration(project, variable, references, true); + } + + protected PsiElement moveDeclaration(Project project, V variable, final Collection references, boolean delete) { final PsiCodeBlock anchorBlock = findAnchorBlock(references); if (anchorBlock == null) return null; //was assert, but need to fix the case when obsolete inspection highlighting is left if (!CodeInsightUtil.preparePsiElementsForWrite(anchorBlock)) return null; @@ -113,6 +117,7 @@ public abstract class BaseConvertToLocalQuickFix implemen anchorAssignmentExpression.getRExpression(), variable, refsSet, + delete, new NotNullFunction() { @NotNull @Override @@ -132,6 +137,7 @@ public abstract class BaseConvertToLocalQuickFix implemen variable.getInitializer(), variable, references, + delete, new NotNullFunction() { @NotNull @Override @@ -147,7 +153,7 @@ public abstract class BaseConvertToLocalQuickFix implemen @Nullable final PsiExpression initializer, @NotNull final V variable, @NotNull final Collection references, - @NotNull final NotNullFunction action) { + final boolean delete, @NotNull final NotNullFunction action) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); return ApplicationManager.getApplication().runWriteAction( @@ -155,9 +161,11 @@ public abstract class BaseConvertToLocalQuickFix implemen @Override public PsiElement compute() { final PsiElement newDeclaration = moveDeclaration(elementFactory, localName, variable, initializer, action, references); - beforeDelete(project, variable, newDeclaration); - variable.normalizeDeclaration(); - variable.delete(); + if (delete) { + beforeDelete(project, variable, newDeclaration); + variable.normalizeDeclaration(); + variable.delete(); + } return newDeclaration; } } 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 8eb519864e91..c82e779e84e1 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java @@ -25,6 +25,7 @@ import com.intellij.codeInspection.ex.BaseLocalInspectionTool; import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.codeInspection.util.SpecialAnnotationsUtil; import com.intellij.lang.java.JavaCommenter; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; @@ -36,6 +37,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.controlFlow.*; import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.util.RefactoringUtil; @@ -47,10 +49,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.util.Collection; -import java.util.LinkedHashSet; +import java.util.*; import java.util.List; -import java.util.Set; /** * @author ven @@ -271,6 +271,63 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { private static class ConvertFieldToLocalQuickFix extends BaseConvertToLocalQuickFix { + @Nullable + @Override + protected PsiElement moveDeclaration(@NotNull final Project project, @NotNull final PsiField variable) { + final Map> refs = new HashMap>(); + groupByCodeBlocks(ReferencesSearch.search(variable).findAll(), refs); + PsiElement element = null; + for (Collection psiReferences : refs.values()) { + element = super.moveDeclaration(project, variable, psiReferences, false); + } + if (element != null) { + final PsiElement finalElement = element; + Runnable runnable = new Runnable() { + public void run() { + beforeDelete(project, variable, finalElement); + variable.normalizeDeclaration(); + variable.delete(); + } + }; + ApplicationManager.getApplication().runWriteAction(runnable); + } + return element; + } + + private static void groupByCodeBlocks(final Collection allReferences, Map> refs) { + for (PsiReference psiReference : allReferences) { + final PsiElement element = psiReference.getElement(); + final PsiCodeBlock block = PsiTreeUtil.getParentOfType(element, PsiCodeBlock.class); + LOG.assertTrue(block != null); + Collection references = refs.get(block); + if (references == null) { + references = new ArrayList(); + if (findExistentBlock(refs, psiReference, block, references)) continue; + refs.put(block, references); + } + references.add(psiReference); + } + } + + private static boolean findExistentBlock(Map> refs, + PsiReference psiReference, + PsiCodeBlock block, + Collection references) { + for (Iterator iterator = refs.keySet().iterator(); iterator.hasNext(); ) { + PsiCodeBlock codeBlock = iterator.next(); + if (PsiTreeUtil.isAncestor(codeBlock, block, false)) { + refs.get(codeBlock).add(psiReference); + return true; + } + else if (PsiTreeUtil.isAncestor(block, codeBlock, false)) { + references.addAll(refs.get(codeBlock)); + iterator.remove(); + break; + } + } + return false; + } + @Override @Nullable protected PsiField getVariable(@NotNull ProblemDescriptor descriptor) { 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 66980e986cc2..a0fb322bd5c4 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java @@ -153,11 +153,12 @@ public class ParameterCanBeLocalInspection extends BaseJavaLocalInspectionTool { @Override protected PsiElement applyChanges(@NotNull final Project project, - @NotNull final String localName, - @Nullable final PsiExpression initializer, - @NotNull final PsiParameter parameter, - @NotNull final Collection references, - @NotNull final NotNullFunction action) { + @NotNull final String localName, + @Nullable final PsiExpression initializer, + @NotNull final PsiParameter parameter, + @NotNull final Collection references, + boolean delete, + @NotNull final NotNullFunction action) { final PsiElement scope = parameter.getDeclarationScope(); if (scope instanceof PsiMethod) { final PsiMethod method = (PsiMethod)scope; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethods.java new file mode 100644 index 000000000000..d5d911a4067e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/afterMultipleMethods.java @@ -0,0 +1,13 @@ +// "Convert to local" "true" +class Test { + + int getFoo1() { + int myFoo = 1; + return myFoo; + } + + int getFoo2() { + int myFoo = 2; + return myFoo; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethods.java new file mode 100644 index 000000000000..f4afcf9b448a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local/beforeMultipleMethods.java @@ -0,0 +1,14 @@ +// "Convert to local" "true" +class Test { + private int myFoo; + + int getFoo1() { + myFoo = 1; + return myFoo; + } + + int getFoo2() { + myFoo = 2; + return myFoo; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertFieldToLocalTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertFieldToLocalTest.java new file mode 100644 index 000000000000..d74b67fe3e91 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ConvertFieldToLocalTest.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2013 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon.quickFix; + +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.varScopeCanBeNarrowed.FieldCanBeLocalInspection; +import org.jetbrains.annotations.NotNull; + + +public class ConvertFieldToLocalTest extends LightQuickFixTestCase { + @NotNull + @Override + protected LocalInspectionTool[] configureLocalInspectionTools() { + final FieldCanBeLocalInspection inspection = new FieldCanBeLocalInspection(); + inspection.IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS = false; + return new LocalInspectionTool[] { inspection }; + } + + public void test() throws Exception { doAllTests(); } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/convert2Local"; + } + +} \ No newline at end of file