diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/afterChooseTopFileOverInjected.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/afterChooseTopFileOverInjected.java new file mode 100644 index 000000000000..05ef068d1ade --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/afterChooseTopFileOverInjected.java @@ -0,0 +1,6 @@ +// "Fix all 'My fake inspection on literal' problems in file" "true" +public class Test { + void foo1() { + String java = "replaced"; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/beforeChooseTopFileOverInjected.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/beforeChooseTopFileOverInjected.java new file mode 100644 index 000000000000..93d1855bb821 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/fixAll/beforeChooseTopFileOverInjected.java @@ -0,0 +1,6 @@ +// "Fix all 'My fake inspection on literal' problems in file" "true" +public class Test { + void foo1() { + String java = "class B {{}}"; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/FixAllQuickfixTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/FixAllQuickfixTest.java index ac0124976872..f673fb559460 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/FixAllQuickfixTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/FixAllQuickfixTest.java @@ -17,13 +17,20 @@ package com.intellij.java.codeInsight.daemon.quickFix; import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase; import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.dataFlow.DataFlowInspection; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper; import com.intellij.codeInspection.visibility.VisibilityInspection; +import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.psi.*; +import com.intellij.psi.impl.source.tree.injected.MyTestInjector; import com.intellij.testFramework.IdeaTestUtil; import com.siyeh.ig.style.UnnecessaryFullyQualifiedNameInspection; +import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -31,9 +38,10 @@ public class FixAllQuickfixTest extends LightQuickFixParameterizedTestCase { @NotNull @Override protected LocalInspectionTool[] configureLocalInspectionTools() { - return new LocalInspectionTool[] { + return new LocalInspectionTool[]{ new DataFlowInspection(), - new UnnecessaryFullyQualifiedNameInspection() + new UnnecessaryFullyQualifiedNameInspection(), + new MyLocalInspectionTool() }; } @@ -42,6 +50,7 @@ public class FixAllQuickfixTest extends LightQuickFixParameterizedTestCase { super.setUp(); enableInspectionTool(new GlobalInspectionToolWrapper(new VisibilityInspection())); enableInspectionTool(new UnusedDeclarationInspection(true)); + new MyTestInjector(getPsiManager()).injectAll(getTestRootDisposable()); } @Override @@ -55,4 +64,54 @@ public class FixAllQuickfixTest extends LightQuickFixParameterizedTestCase { // jdk 1.7 needed because it contains java.sql.Date for FullyQualifiedName test return IdeaTestUtil.getMockJdk17(); } + + private static class MyLocalInspectionTool extends LocalInspectionTool { + @Override + @Nls + @NotNull + public String getGroupDisplayName() { + return "MyGroup"; + } + + @Override + @Nls + @NotNull + public String getDisplayName() { + return "My fake inspection on literal"; + } + + @Override + @NonNls + @NotNull + public String getShortName() { + return "My"; + } + + @Override + @NotNull + public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { + return new JavaElementVisitor() { + @Override + public void visitLiteralExpression(PsiLiteralExpression expression) { + if ("replaced".equals(expression.getValue())) return; + holder.registerProblem(expression, "Even in injection", new LocalQuickFix() { + @Nls(capitalization = Nls.Capitalization.Sentence) + @NotNull + @Override + public String getFamilyName() { + return "Fix over injection"; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PsiElement element = descriptor.getPsiElement(); + if (element instanceof PsiLiteralExpression) { + element.replace(JavaPsiFacade.getElementFactory(project).createExpressionFromText("\"replaced\"", null)); + } + } + }); + } + }; + } + } } \ No newline at end of file diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java index 47b66e58052c..73038d939894 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java @@ -103,6 +103,12 @@ public class QuickFixWrapper implements IntentionAction, PriorityAction { public ProblemHighlightType getHighlightType() { return myDescriptor.getHighlightType(); } + + @Nullable + public PsiFile getFile() { + PsiElement element = myDescriptor.getPsiElement(); + return element != null ? element.getContainingFile() : null; + } public String toString() { return getText(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/IntentionManagerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/IntentionManagerImpl.java index d3f091439a1c..a66e8d747214 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/IntentionManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/config/IntentionManagerImpl.java @@ -16,7 +16,6 @@ import com.intellij.codeInspection.actions.CleanupAllIntention; import com.intellij.codeInspection.actions.CleanupInspectionIntention; import com.intellij.codeInspection.actions.RunInspectionIntention; import com.intellij.codeInspection.ex.*; -import com.intellij.diagnostic.PluginException; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -176,20 +175,12 @@ public class IntentionManagerImpl extends IntentionManager implements Disposable } if (toolWrapper instanceof LocalInspectionToolWrapper) { - FileModifier fix = action; - if (action instanceof QuickFixWrapper) { - fix = ((QuickFixWrapper)action).getFix(); - } - return new CleanupInspectionIntention(toolWrapper, fix, action.getText()); + return createFixAllIntentionInternal(toolWrapper, action); } if (toolWrapper instanceof GlobalInspectionToolWrapper) { GlobalInspectionTool wrappedTool = ((GlobalInspectionToolWrapper)toolWrapper).getTool(); if (wrappedTool instanceof GlobalSimpleInspectionTool && (action instanceof LocalQuickFix || action instanceof QuickFixWrapper)) { - FileModifier fix = action; - if (action instanceof QuickFixWrapper) { - fix = ((QuickFixWrapper)action).getFix(); - } - return new CleanupInspectionIntention(toolWrapper, fix, action.getText()); + return createFixAllIntentionInternal(toolWrapper, action); } } else { @@ -198,6 +189,17 @@ public class IntentionManagerImpl extends IntentionManager implements Disposable return null; } + private static IntentionAction createFixAllIntentionInternal(@NotNull InspectionToolWrapper toolWrapper, + @NotNull IntentionAction action) { + PsiFile file = null; + FileModifier fix = action; + if (action instanceof QuickFixWrapper) { + fix = ((QuickFixWrapper)action).getFix(); + file = ((QuickFixWrapper)action).getFile(); + } + return new CleanupInspectionIntention(toolWrapper, fix, file, action.getText()); + } + @NotNull @Override public IntentionAction createCleanupAllIntention() { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/actions/CleanupInspectionIntention.java b/platform/lang-impl/src/com/intellij/codeInspection/actions/CleanupInspectionIntention.java index 8e17a71072e7..f38c7d7403d6 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/actions/CleanupInspectionIntention.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/CleanupInspectionIntention.java @@ -19,6 +19,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -27,11 +28,16 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority private final InspectionToolWrapper myToolWrapper; private final FileModifier myQuickfix; + @Nullable private final PsiFile myFile; private final String myText; - public CleanupInspectionIntention(@NotNull InspectionToolWrapper toolWrapper, @NotNull FileModifier quickFix, String text) { + public CleanupInspectionIntention(@NotNull InspectionToolWrapper toolWrapper, + @NotNull FileModifier quickFix, + @Nullable PsiFile file, + String text) { myToolWrapper = toolWrapper; myQuickfix = quickFix; + myFile = file; myText = text; } @@ -49,14 +55,14 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority @Override public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { - + PsiFile targetFile = myFile != null ? myFile : file; final List descriptions = ProgressManager.getInstance().runProcess(() -> { InspectionManager inspectionManager = InspectionManager.getInstance(project); - return InspectionEngine.runInspectionOnFile(file, myToolWrapper, inspectionManager.createNewGlobalContext()); + return InspectionEngine.runInspectionOnFile(targetFile, myToolWrapper, inspectionManager.createNewGlobalContext()); }, new EmptyProgressIndicator()); - if (descriptions.isEmpty() || !FileModificationService.getInstance().preparePsiElementForWrite(file)) return; + if (descriptions.isEmpty() || !FileModificationService.getInstance().preparePsiElementForWrite(targetFile)) return; final AbstractPerformFixesTask fixesTask = CleanupInspectionUtil.getInstance().applyFixes(project, "Apply Fixes", descriptions, myQuickfix.getClass(), myQuickfix.startInWriteAction()); @@ -70,7 +76,6 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority return myQuickfix.getClass() != EmptyIntentionAction.class && (myQuickfix.startInWriteAction() || myQuickfix instanceof BatchQuickFix) && editor != null && - (!(myQuickfix instanceof IntentionAction) || ((IntentionAction)myQuickfix).isAvailable(project, editor, file)) && !(myToolWrapper instanceof LocalInspectionToolWrapper && ((LocalInspectionToolWrapper)myToolWrapper).isUnfair()); }