diff --git a/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java b/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java index 35aeedc78c66..8b5e73576ed6 100644 --- a/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java @@ -21,8 +21,6 @@ import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.codeInspection.*; -import com.intellij.codeInspection.ex.InspectionTool; -import com.intellij.codeInspection.ex.QuickFixAction; import com.intellij.codeInspection.reference.*; import com.intellij.codeInspection.util.SpecialAnnotationsUtil; import com.intellij.openapi.application.ApplicationManager; @@ -33,7 +31,7 @@ import com.intellij.openapi.util.*; import com.intellij.psi.*; import com.intellij.psi.search.searches.AllOverridingMethodsSearch; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtilBase; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.refactoring.safeDelete.SafeDeleteHandler; import com.intellij.util.Processor; import com.intellij.util.Query; @@ -319,7 +317,7 @@ public class EmptyMethodInspection extends GlobalJavaInspectionTool { ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { - SafeDeleteHandler.invoke(project, PsiUtilBase.toPsiElementArray(psiElements), false); + SafeDeleteHandler.invoke(project, PsiUtilCore.toPsiElementArray(psiElements), false); } }); } @@ -327,13 +325,13 @@ public class EmptyMethodInspection extends GlobalJavaInspectionTool { } - private class DeleteMethodQuickFix implements LocalQuickFix { + private class DeleteMethodQuickFix implements LocalQuickFix, BatchQuickFix { private final ProblemDescriptionsProcessor myProcessor; - private final boolean myNeedToDEleteHierarchy; + private final boolean myNeedToDeleteHierarchy; public DeleteMethodQuickFix(final ProblemDescriptionsProcessor processor, final boolean needToDeleteHierarchy) { myProcessor = processor; - myNeedToDEleteHierarchy = needToDeleteHierarchy; + myNeedToDeleteHierarchy = needToDeleteHierarchy; } @NotNull @@ -342,28 +340,7 @@ public class EmptyMethodInspection extends GlobalJavaInspectionTool { } public void applyFix(final @NotNull Project project, @NotNull ProblemDescriptor descriptor) { - RefElement refElement = (RefElement)myProcessor.getElement(descriptor); - if (refElement.isValid() && refElement instanceof RefMethod) { - final List refElements = new ArrayList(1); - RefMethod refMethod = (RefMethod)refElement; - final List psiElements = new ArrayList(); - if (myNeedToDEleteHierarchy) { - deleteHierarchy(refMethod, psiElements, refElements); - } else { - deleteMethod(refMethod, psiElements, refElements); - } - - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - SafeDeleteHandler.invoke(project, PsiUtilBase.toPsiElementArray(psiElements), false, new Runnable() { - public void run() { - QuickFixAction - .removeElements(refElements.toArray(new RefElement[refElements.size()]), project, (InspectionTool)myProcessor); - } - }); - } - }); - } + applyFix(project, new ProblemDescriptor[]{descriptor}, new ArrayList(), null); } @NotNull @@ -371,20 +348,43 @@ public class EmptyMethodInspection extends GlobalJavaInspectionTool { return getName(); } - private void deleteHierarchy(RefMethod refMethod, List result, List refElements) { + private void deleteHierarchy(RefMethod refMethod, List result) { Collection derivedMethods = refMethod.getDerivedMethods(); RefMethod[] refMethods = derivedMethods.toArray(new RefMethod[derivedMethods.size()]); for (RefMethod refDerived : refMethods) { - deleteMethod(refDerived, result, refElements); + deleteMethod(refDerived, result); } - deleteMethod(refMethod, result, refElements); + deleteMethod(refMethod, result); } - private void deleteMethod(RefMethod refMethod, List result, List refElements) { - refElements.add(refMethod); + private void deleteMethod(RefMethod refMethod, List result) { PsiElement psiElement = refMethod.getElement(); if (psiElement == null) return; if (!result.contains(psiElement)) result.add(psiElement); } + + @Override + public void applyFix(@NotNull final Project project, + @NotNull final CommonProblemDescriptor[] descriptors, + final List psiElementsToIgnore, + final Runnable refreshViews) { + for (CommonProblemDescriptor descriptor : descriptors) { + RefElement refElement = (RefElement)myProcessor.getElement(descriptor); + if (refElement.isValid() && refElement instanceof RefMethod) { + RefMethod refMethod = (RefMethod)refElement; + if (myNeedToDeleteHierarchy) { + deleteHierarchy(refMethod, psiElementsToIgnore); + } + else { + deleteMethod(refMethod, psiElementsToIgnore); + } + } + } + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + SafeDeleteHandler.invoke(project, PsiUtilCore.toPsiElementArray(psiElementsToIgnore), false, refreshViews); + } + }); + } } } diff --git a/platform/lang-api/src/com/intellij/codeInspection/BatchQuickFix.java b/platform/lang-api/src/com/intellij/codeInspection/BatchQuickFix.java new file mode 100644 index 000000000000..99a3b7be5575 --- /dev/null +++ b/platform/lang-api/src/com/intellij/codeInspection/BatchQuickFix.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2011 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.codeInspection; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * User: anna + * Date: 10/27/11 + */ +public interface BatchQuickFix { + /** + * Called to apply the cumulative fix. Is invoked in WriteAction + * + * @param project {@link com.intellij.openapi.project.Project} + * @param descriptors problem reported by the tool on which fix should work + * @param psiElementsToIgnore elements to be excluded from view during post-refresh + * @param refreshViews post-refresh inspection results view; would remove collected elements from the view + */ + void applyFix(@NotNull final Project project, + @NotNull final D[] descriptors, + final List psiElementsToIgnore, + final Runnable refreshViews); +} diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/LocalQuickFixWrapper.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/LocalQuickFixWrapper.java index deb4f0cede61..5cd924dfd42b 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/LocalQuickFixWrapper.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/LocalQuickFixWrapper.java @@ -16,10 +16,20 @@ package com.intellij.codeInspection.ex; -import com.intellij.codeInspection.QuickFix; +import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; +import com.intellij.codeInspection.*; import com.intellij.codeInspection.reference.RefElement; import com.intellij.codeInspection.reference.RefEntity; +import com.intellij.codeInspection.reference.RefManager; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiManager; +import com.intellij.psi.util.PsiModificationTracker; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Set; /** * @author max @@ -27,6 +37,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; public class LocalQuickFixWrapper extends QuickFixAction { private final QuickFix myFix; private String myText; + public LocalQuickFixWrapper(QuickFix fix, DescriptorProviderInspection tool) { super(fix.getName(), tool); myTool = tool; @@ -48,26 +59,6 @@ public class LocalQuickFixWrapper extends QuickFixAction { myText = text; } - protected boolean applyFix(RefElement[] refElements) { - /* dead code ?! - for (RefElement refElement : refElements) { - ProblemDescriptor[] problems = myTool.getDescriptions(refElement); - if (problems != null) { - PsiElement psiElement = refElement.getElement(); - if (psiElement != null) { - for (ProblemDescriptor problem : problems) { - LocalQuickFix fix = problem.getFix(); - if (fix != null) { - fix.applyFix(psiElement.getProject(), problem); - myTool.ignoreProblem(refElement, problem); - } - } - } - } - }*/ - - return true; - } protected boolean isProblemDescriptorsAcceptable() { return true; @@ -76,4 +67,79 @@ public class LocalQuickFixWrapper extends QuickFixAction { public QuickFix getFix() { return myFix; } -} + + @Nullable + protected QuickFix getWorkingQuickFix(QuickFix[] fixes) { + for (QuickFix fix : fixes) { + if (!myFix.getClass().isInstance(fix)) continue; + if (myFix instanceof IntentionWrapper && fix instanceof IntentionWrapper && + !(((IntentionWrapper)myFix).getAction().getClass().isInstance(((IntentionWrapper)fix).getAction()))) { + continue; + } + return fix; + } + return null; + } + + protected boolean applyFix(RefElement[] refElements) { + throw new UnsupportedOperationException(""); + } + + @Override + protected void applyFix(final Project project, final CommonProblemDescriptor[] descriptors, final Set ignoredElements) { + final PsiModificationTracker tracker = PsiManager.getInstance(project).getModificationTracker(); + if (myFix instanceof BatchQuickFix) { + final ArrayList collectedElementsToIgnore = new ArrayList(); + final Runnable refreshViews = new Runnable() { + @Override + public void run() { + DaemonCodeAnalyzer.getInstance(project).restart(); + for (CommonProblemDescriptor descriptor : descriptors) { + ignore(ignoredElements, descriptor, getWorkingQuickFix(descriptor.getFixes())); + } + + final RefManager refManager = myTool.getContext().getRefManager(); + final RefElement[] refElements = new RefElement[collectedElementsToIgnore.size()]; + for (int i = 0, collectedElementsToIgnoreSize = collectedElementsToIgnore.size(); i < collectedElementsToIgnoreSize; i++) { + refElements[i] = refManager.getReference(collectedElementsToIgnore.get(i)); + } + + removeElements(refElements, project, myTool); + } + }; + + ((BatchQuickFix)myFix).applyFix(project, descriptors, collectedElementsToIgnore, refreshViews); + return; + } + + boolean restart = false; + for (CommonProblemDescriptor descriptor : descriptors) { + if (descriptor == null) continue; + final QuickFix[] fixes = descriptor.getFixes(); + if (fixes != null) { + final QuickFix fix = getWorkingQuickFix(fixes); + if (fix != null) { + final long startCount = tracker.getModificationCount(); + //CCE here means QuickFix was incorrectly inherited, is there a way to signal (plugin) it is wrong? + fix.applyFix(project, descriptor); + if (startCount != tracker.getModificationCount()) { + restart = true; + ignore(ignoredElements, descriptor, fix); + } + } + } + } + if (restart) { + DaemonCodeAnalyzer.getInstance(project).restart(); + } + } + + private void ignore(Set ignoredElements, CommonProblemDescriptor descriptor, QuickFix fix) { + if (fix != null) { + ((DescriptorProviderInspection)myTool).ignoreProblem(descriptor, fix); + } + if (descriptor instanceof ProblemDescriptor) { + ignoredElements.add(((ProblemDescriptor)descriptor).getPsiElement()); + } + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java index 9a48c53d8254..a6602265bd26 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java @@ -16,8 +16,9 @@ package com.intellij.codeInspection.ex; -import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; -import com.intellij.codeInspection.*; +import com.intellij.codeInspection.CommonProblemDescriptor; +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.reference.RefElement; import com.intellij.codeInspection.reference.RefEntity; import com.intellij.codeInspection.reference.RefManagerImpl; @@ -36,8 +37,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; -import com.intellij.psi.util.PsiModificationTracker; import gnu.trove.THashSet; import javax.swing.*; @@ -110,6 +109,7 @@ public class QuickFixAction extends AnAction { } + protected void applyFix(Project project, CommonProblemDescriptor[] descriptors, Set ignoredElements) {} private void doApplyFix(final Project project, final CommonProblemDescriptor[] descriptors) { final Set readOnlyFiles = new THashSet(); @@ -139,38 +139,7 @@ public class QuickFixAction extends AnAction { CommandProcessor.getInstance().markCurrentCommandAsGlobal(project); ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { - final PsiModificationTracker tracker = PsiManager.getInstance(project).getModificationTracker(); - for (CommonProblemDescriptor descriptor : descriptors) { - if (descriptor == null) continue; - final QuickFix[] fixes = descriptor.getFixes(); - if (fixes != null) { - for (QuickFix fix : fixes) { - if (fix != null) { - final QuickFixAction quickFixAction = QuickFixAction.this; - if (quickFixAction instanceof LocalQuickFixWrapper) { - QuickFix unwrapped = ((LocalQuickFixWrapper)quickFixAction).getFix(); - - if (!unwrapped.getClass().isInstance(fix)) continue; - if (unwrapped instanceof IntentionWrapper && fix instanceof IntentionWrapper && - !(((IntentionWrapper) unwrapped).getAction().getClass().isInstance(((IntentionWrapper) fix).getAction()))) { - continue; - } - } - - final long startCount = tracker.getModificationCount(); - //CCE here means QuickFix was incorrectly inherited, is there a way to signal (plugin) it is wrong? - fix.applyFix(project, descriptor); - if (startCount != tracker.getModificationCount()) { - DaemonCodeAnalyzer.getInstance(project).restart(); - ((DescriptorProviderInspection)myTool).ignoreProblem(descriptor, fix); - if (descriptor instanceof ProblemDescriptor) { - ignoredElements.add(((ProblemDescriptor)descriptor).getPsiElement()); - } - } - } - } - } - } + applyFix(project, descriptors, ignoredElements); } }); }