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 4e6f592e2d53..149beec691dc 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java @@ -19,17 +19,20 @@ import com.intellij.codeInsight.CodeInsightUtil; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; 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.util.IJSwingUtilities; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.NotNullFunction; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -42,7 +45,7 @@ import java.util.Set; * * @author Danila Ponomarenko */ -public abstract class BaseConvertToLocalQuickFix implements LocalQuickFix { +public abstract class BaseConvertToLocalQuickFix implements LocalQuickFix { private static final Logger LOG = Logger.getInstance(BaseConvertToLocalQuickFix.class); @NotNull @@ -51,12 +54,12 @@ public abstract class BaseConvertToLocalQuickFix implemen } public final void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - final T myVariable = getVariable(descriptor); - final PsiFile myFile = myVariable.getContainingFile(); - if (myVariable == null || !myVariable.isValid()) return; //weird. should not get here when field becomes invalid + final V variable = getVariable(descriptor); + final PsiFile myFile = variable.getContainingFile(); + if (variable == null || !variable.isValid()) return; //weird. should not get here when field becomes invalid try { - final PsiElement newDeclaration = moveDeclaration(project, myVariable); + final PsiElement newDeclaration = moveDeclaration(project, variable); if (newDeclaration == null) return; positionCaretToDeclaration(project, myFile, newDeclaration); @@ -67,11 +70,11 @@ public abstract class BaseConvertToLocalQuickFix implemen } @Nullable - protected abstract T getVariable(@NotNull ProblemDescriptor descriptor); + protected abstract V getVariable(@NotNull ProblemDescriptor descriptor); private static void positionCaretToDeclaration(@NotNull Project project, @NotNull PsiFile psiFile, @NotNull PsiElement declaration) { final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); - if (editor != null && IJSwingUtilities.hasFocus(editor.getComponent())) { + if (editor != null && (IJSwingUtilities.hasFocus(editor.getComponent()) || ApplicationManager.getApplication().isUnitTestMode())) { final PsiFile openedFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); if (openedFile == psiFile) { editor.getCaretModel().moveToOffset(declaration.getTextOffset()); @@ -80,57 +83,87 @@ public abstract class BaseConvertToLocalQuickFix implemen } } - @Nullable - private PsiElement moveDeclaration(@NotNull Project project, @NotNull T variable){ - final PsiElement newDeclaration = addDeclaration(project, variable); - if (newDeclaration == null) return null; - - beforeDelete(project,variable,newDeclaration); - - variable.normalizeDeclaration(); - variable.delete(); - - return newDeclaration; + protected void beforeDelete(@NotNull Project project, @NotNull V variable, @NotNull PsiElement newDeclaration) { } - protected void beforeDelete(@NotNull Project project, @NotNull T variable, @NotNull PsiElement newDeclaration){} - @Nullable - private PsiElement addDeclaration(@NotNull Project project, @NotNull T myVariable) { - final Collection refs = ReferencesSearch.search(myVariable).findAll(); - if (refs.isEmpty()) return null; + private PsiElement moveDeclaration(@NotNull Project project, @NotNull V variable) { + final Collection references = ReferencesSearch.search(variable).findAll(); + if (references.isEmpty()) return null; - final PsiCodeBlock anchorBlock = findAnchorBlock(refs); + 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; - final PsiElement firstElement = getLowestOffsetElement(refs); - final String localName = suggestLocalName(project, myVariable, anchorBlock); + final PsiElement firstElement = getLowestOffsetElement(references); + final String localName = suggestLocalName(project, variable, anchorBlock); final PsiElement anchor = getAnchorElement(anchorBlock, firstElement); - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); final PsiAssignmentExpression anchorAssignmentExpression = searchAssignmentExpression(anchor); - if (anchorAssignmentExpression != null && isVariableAssignment(anchorAssignmentExpression, myVariable)) { - final PsiExpression initializer = anchorAssignmentExpression.getRExpression(); - final PsiDeclarationStatement declaration = elementFactory.createVariableDeclarationStatement(localName, myVariable.getType(), initializer); - if (!mayBeFinal(firstElement, refs)) { - PsiUtil.setModifierProperty((PsiModifierListOwner)declaration.getDeclaredElements()[0], PsiModifier.FINAL, false); - } - final PsiElement newDeclaration = anchor.replace(declaration); - - final Set refsSet = new HashSet(refs); + if (anchorAssignmentExpression != null && isVariableAssignment(anchorAssignmentExpression, variable)) { + final Set refsSet = new HashSet(references); refsSet.remove(anchorAssignmentExpression.getLExpression()); - retargetReferences(elementFactory, localName, refsSet); - return newDeclaration; + return applyChanges( + project, + localName, + anchorAssignmentExpression.getRExpression(), + variable, + refsSet, + new NotNullFunction() { + @NotNull + @Override + public PsiElement fun(PsiDeclarationStatement declaration) { + if (!mayBeFinal(firstElement, references)) { + PsiUtil.setModifierProperty((PsiModifierListOwner)declaration.getDeclaredElements()[0], PsiModifier.FINAL, false); + } + return anchor.replace(declaration); + } + } + ); } - final PsiDeclarationStatement declaration = elementFactory.createVariableDeclarationStatement(localName, myVariable.getType(), myVariable.getInitializer()); - final PsiElement newDeclaration = anchorBlock.addBefore(declaration, anchor); + return applyChanges( + project, + localName, + variable.getInitializer(), + variable, + references, + new NotNullFunction() { + @NotNull + @Override + public PsiElement fun(PsiDeclarationStatement declaration) { + return anchorBlock.addBefore(declaration, anchor); + } + } + ); + } - retargetReferences(elementFactory, localName, refs); - return newDeclaration; + @NotNull + private PsiElement applyChanges(final @NotNull Project project, + final @NotNull String localName, + final @Nullable PsiExpression initializer, + final @NotNull V variable, + final @NotNull Collection references, + final @NotNull NotNullFunction action) { + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); + + return ApplicationManager.getApplication().runWriteAction( + new Computable() { + @Override + public PsiElement compute() { + final PsiDeclarationStatement declaration = + elementFactory.createVariableDeclarationStatement(localName, variable.getType(), initializer); + final PsiElement newDeclaration = action.fun(declaration); + retargetReferences(elementFactory, localName, references); + beforeDelete(project, variable, newDeclaration); + variable.normalizeDeclaration(); + variable.delete(); + return newDeclaration; + } + } + ); } @Nullable @@ -167,7 +200,7 @@ public abstract class BaseConvertToLocalQuickFix implemen } @NotNull - protected abstract String suggestLocalName(@NotNull Project project, @NotNull T variable, @NotNull PsiCodeBlock scope); + protected abstract String suggestLocalName(@NotNull Project project, @NotNull V variable, @NotNull PsiCodeBlock scope); private static boolean mayBeFinal(PsiElement firstElement, @NotNull Collection references) { for (PsiReference reference : references) { 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 52c4135e682d..f9e84420a033 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java @@ -16,21 +16,15 @@ package com.intellij.codeInspection.varScopeCanBeNarrowed; import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.codeInsight.CodeInsightUtil; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInsight.daemon.ImplicitUsageProvider; import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.ex.BaseLocalInspectionTool; import com.intellij.codeInspection.util.SpecialAnnotationsUtil; import com.intellij.lang.java.JavaCommenter; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.JDOMExternalizableStringList; @@ -41,13 +35,9 @@ 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; -import com.intellij.util.IJSwingUtilities; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.containers.HashSet; import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NonNls; 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 9d11afac789f..97b9855402fa 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java @@ -80,7 +80,9 @@ public class ParameterCanBeLocalInspection extends BaseJavaLocalInspectionTool { @NotNull - private static ProblemDescriptor createProblem(@NotNull InspectionManager manager, @NotNull PsiIdentifier identifier, boolean isOnTheFly) { + private static ProblemDescriptor createProblem(@NotNull InspectionManager manager, + @NotNull PsiIdentifier identifier, + boolean isOnTheFly) { return manager.createProblemDescriptor( identifier, InspectionsBundle.message("inspection.parameter.can.be.local.problem.descriptor"), @@ -126,7 +128,8 @@ public class ParameterCanBeLocalInspection extends BaseJavaLocalInspectionTool { @Nullable private static ControlFlow getControlFlow(final PsiElement context) { try { - return ControlFlowFactory.getInstance(context.getProject()).getControlFlow(context, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance()); + return ControlFlowFactory.getInstance(context.getProject()) + .getControlFlow(context, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance()); } catch (AnalysisCanceledException e) { return null; diff --git a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterFor.java b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterFor.java index 1635881830e0..ce8711eb6de5 100644 --- a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterFor.java +++ b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterFor.java @@ -2,7 +2,7 @@ class Temp { public Temp() { for (int i = 0; i < 10; i++) { - int p = i; + int p = i; System.out.print(p); } } diff --git a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterIf.java b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterIf.java index d5016105c40c..e6d8f7518700 100644 --- a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterIf.java +++ b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterIf.java @@ -3,8 +3,8 @@ class Temp { public boolean flag; void test() { - int p; - if (flag) { + int p; + if (flag) { p = 1; } else { diff --git a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterSimple.java b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterSimple.java index 1ace51e3ff57..f692ff1cafbc 100644 --- a/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterSimple.java +++ b/java/java-tests/testData/inspection/quickFix/ConvertParameterToLocalVariable/afterSimple.java @@ -2,7 +2,7 @@ class Temp { void test() { - int p = 1; + int p = 1; System.out.print(p); } } \ No newline at end of file