From c19534589bae886a1d3232367f478daf713e484a Mon Sep 17 00:00:00 2001 From: "Andrey.Cherkasov" Date: Tue, 9 Mar 2021 23:59:53 +0300 Subject: [PATCH] [java-highlighting] IDEA-216274 Provide fix for the "Not allowed in interface" error GitOrigin-RevId: 1290ab27997b03c6a75b1c8172a3477722144941 --- .../intention/QuickFixFactory.java | 2 + .../impl/analysis/HighlightClassUtil.java | 5 +- .../impl/config/QuickFixFactoryImpl.java | 5 ++ .../afterConstructor.java | 5 ++ .../afterInitializer.java | 5 ++ .../afterStaticInitializer.java | 5 ++ .../beforeConstructor.java | 5 ++ .../beforeInitializer.java | 5 ++ .../beforeStaticInitializer.java | 5 ++ .../afterConstructor.java | 4 ++ .../afterInitializer.java | 4 ++ .../afterStaticInitializer.java | 4 ++ .../beforeConstructor.java | 5 ++ .../beforeInitializer.java | 5 ++ .../beforeStaticInitializer.java | 5 ++ ...aceContainingNotAllowedToClassFixTest.java | 12 ++++ .../RemoveNotAllowedInInterfaceFixTest.java | 12 ++++ ...terfaceContainingNotAllowedToClassFix.java | 63 +++++++++++++++++++ .../ConvertInterfaceToClassIntention.java | 2 +- 19 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/afterConstructor.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/afterInitializer.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/afterStaticInitializer.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/beforeConstructor.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/beforeInitializer.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/beforeStaticInitializer.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/afterConstructor.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/afterInitializer.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/afterStaticInitializer.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/beforeConstructor.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/beforeInitializer.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/beforeStaticInitializer.java create mode 100644 java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/ConvertInterfaceContainingNotAllowedToClassFixTest.java create mode 100644 java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/RemoveNotAllowedInInterfaceFixTest.java create mode 100644 plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceContainingNotAllowedToClassFix.java diff --git a/java/java-analysis-api/src/com/intellij/codeInsight/intention/QuickFixFactory.java b/java/java-analysis-api/src/com/intellij/codeInsight/intention/QuickFixFactory.java index 13119747e923..a758086c99c3 100644 --- a/java/java-analysis-api/src/com/intellij/codeInsight/intention/QuickFixFactory.java +++ b/java/java-analysis-api/src/com/intellij/codeInsight/intention/QuickFixFactory.java @@ -512,4 +512,6 @@ public abstract class QuickFixFactory { public abstract @NotNull IntentionAction createReceiverParameterTypeFix(@NotNull PsiReceiverParameter receiverParameter, @NotNull PsiType enclosingClassType); + + public abstract @NotNull IntentionAction createConvertInterfaceContainingNotAllowedToClassFix(@NotNull PsiClass aClass); } \ No newline at end of file diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java index 29b5c3efb90b..42e482044d55 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java @@ -752,7 +752,10 @@ public final class HighlightClassUtil { static HighlightInfo checkThingNotAllowedInInterface(@NotNull PsiElement element, @Nullable PsiClass aClass) { if (aClass == null || !aClass.isInterface()) return null; String description = JavaErrorBundle.message("not.allowed.in.interface"); - return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); + HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); + QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createDeleteFix(element)); + QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createConvertInterfaceContainingNotAllowedToClassFix(aClass)); + return info; } static HighlightInfo checkQualifiedNew(@NotNull PsiNewExpression expression, @Nullable PsiType type, @Nullable PsiClass aClass) { diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java index 7d284a68cfb1..25c215b3fef4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java @@ -46,6 +46,7 @@ import com.intellij.util.DocumentUtil; import com.intellij.util.IncorrectOperationException; import com.siyeh.ig.fixes.CreateDefaultBranchFix; import com.siyeh.ig.fixes.CreateMissingSwitchBranchesFix; +import com.siyeh.ipp.interfacetoclass.ConvertInterfaceContainingNotAllowedToClassFix; import com.siyeh.ipp.modifiers.ChangeModifierIntention; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -999,4 +1000,8 @@ public final class QuickFixFactoryImpl extends QuickFixFactory { } }; } + + public @NotNull IntentionAction createConvertInterfaceContainingNotAllowedToClassFix(@NotNull PsiClass aClass) { + return new ConvertInterfaceContainingNotAllowedToClassFix(aClass); + } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/afterConstructor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/afterConstructor.java new file mode 100644 index 000000000000..3bddd937c9cf --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/afterConstructor.java @@ -0,0 +1,5 @@ +// "Convert to 'class'" "true" + +abstract class A { + public A(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/afterInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/afterInitializer.java new file mode 100644 index 000000000000..311bc0ae8bfa --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/afterInitializer.java @@ -0,0 +1,5 @@ +// "Convert to 'class'" "true" + +abstract class A { + {}; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/afterStaticInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/afterStaticInitializer.java new file mode 100644 index 000000000000..1b3fc069f676 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/afterStaticInitializer.java @@ -0,0 +1,5 @@ +// "Convert to 'class'" "true" + +abstract class A { + static {}; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/beforeConstructor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/beforeConstructor.java new file mode 100644 index 000000000000..e7147a1258c7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/beforeConstructor.java @@ -0,0 +1,5 @@ +// "Convert to 'class'" "true" + +interface A { + A(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/beforeInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/beforeInitializer.java new file mode 100644 index 000000000000..b3d58fc85be6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/beforeInitializer.java @@ -0,0 +1,5 @@ +// "Convert to 'class'" "true" + +interface A { + {}; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/beforeStaticInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/beforeStaticInitializer.java new file mode 100644 index 000000000000..73f42f85946e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass/beforeStaticInitializer.java @@ -0,0 +1,5 @@ +// "Convert to 'class'" "true" + +interface A { + static {}; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/afterConstructor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/afterConstructor.java new file mode 100644 index 000000000000..1e935e1fc6ed --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/afterConstructor.java @@ -0,0 +1,4 @@ +// "Remove constructor" "true" + +interface A { +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/afterInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/afterInitializer.java new file mode 100644 index 000000000000..9b9b0afce886 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/afterInitializer.java @@ -0,0 +1,4 @@ +// "Remove initializer" "true" + +interface A { +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/afterStaticInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/afterStaticInitializer.java new file mode 100644 index 000000000000..9b9b0afce886 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/afterStaticInitializer.java @@ -0,0 +1,4 @@ +// "Remove initializer" "true" + +interface A { +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/beforeConstructor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/beforeConstructor.java new file mode 100644 index 000000000000..79a0ddfcc065 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/beforeConstructor.java @@ -0,0 +1,5 @@ +// "Remove constructor" "true" + +interface A { + A(); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/beforeInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/beforeInitializer.java new file mode 100644 index 000000000000..349fb91c4a2a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/beforeInitializer.java @@ -0,0 +1,5 @@ +// "Remove initializer" "true" + +interface A { + {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/beforeStaticInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/beforeStaticInitializer.java new file mode 100644 index 000000000000..1527f116fad7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface/beforeStaticInitializer.java @@ -0,0 +1,5 @@ +// "Remove initializer" "true" + +interface A { + static {} +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/ConvertInterfaceContainingNotAllowedToClassFixTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/ConvertInterfaceContainingNotAllowedToClassFixTest.java new file mode 100644 index 000000000000..4ffef92c12ff --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/ConvertInterfaceContainingNotAllowedToClassFixTest.java @@ -0,0 +1,12 @@ +// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.java.codeInsight.daemon.quickFix; + +import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase; + +public class ConvertInterfaceContainingNotAllowedToClassFixTest extends LightQuickFixParameterizedTestCase { + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/convertInterfaceContainingNotAllowedToClass"; + } +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/RemoveNotAllowedInInterfaceFixTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/RemoveNotAllowedInInterfaceFixTest.java new file mode 100644 index 000000000000..81f5cba1e1ea --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/RemoveNotAllowedInInterfaceFixTest.java @@ -0,0 +1,12 @@ +// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.java.codeInsight.daemon.quickFix; + +import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase; + +public class RemoveNotAllowedInInterfaceFixTest extends LightQuickFixParameterizedTestCase { + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/removeNotAllowedInInterface"; + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceContainingNotAllowedToClassFix.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceContainingNotAllowedToClassFix.java new file mode 100644 index 000000000000..881e8f6dce09 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceContainingNotAllowedToClassFix.java @@ -0,0 +1,63 @@ +// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.siyeh.ipp.interfacetoclass; + +import com.intellij.codeInsight.intention.PriorityAction; +import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement; +import com.intellij.codeInspection.util.IntentionFamilyName; +import com.intellij.codeInspection.util.IntentionName; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.ObjectUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ConvertInterfaceContainingNotAllowedToClassFix extends LocalQuickFixAndIntentionActionOnPsiElement implements PriorityAction { + + public ConvertInterfaceContainingNotAllowedToClassFix(@Nullable PsiClass aClass) { + super(aClass); + } + + @Override + public boolean isAvailable(@NotNull Project project, + @NotNull PsiFile file, + @Nullable Editor editor, + @NotNull PsiElement startElement, + @NotNull PsiElement endElement) { + final PsiElement nameIdentifier = getNameIdentifier(startElement); + if (nameIdentifier == null) return false; + return new ConvertInterfaceToClassIntention().getElementPredicate().satisfiedBy(nameIdentifier); + } + + @Override + public void invoke(@NotNull Project project, + @NotNull PsiFile file, + @Nullable Editor editor, + @NotNull PsiElement startElement, + @NotNull PsiElement endElement) { + final PsiElement nameIdentifier = getNameIdentifier(startElement); + if (nameIdentifier == null) return; + new ConvertInterfaceToClassIntention().processIntention(nameIdentifier); + } + + @Override + public @NotNull Priority getPriority() { + return Priority.LOW; + } + + private static PsiIdentifier getNameIdentifier(@NotNull PsiElement element) { + final PsiClass aClass = ObjectUtils.tryCast(element, PsiClass.class); + if (aClass == null) return null; + return aClass.getNameIdentifier(); + } + + @Override + public @IntentionName @NotNull String getText() { + return new ConvertInterfaceToClassIntention().getText(); + } + + @Override + public @IntentionFamilyName @NotNull String getFamilyName() { + return new ConvertInterfaceToClassIntention().getFamilyName(); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassIntention.java index f636975ecf2e..84a8cb39da9b 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/interfacetoclass/ConvertInterfaceToClassIntention.java @@ -79,7 +79,7 @@ public class ConvertInterfaceToClassIntention extends Intention { if (method.hasModifierProperty(PsiModifier.DEFAULT)) { PsiUtil.setModifierProperty(method, PsiModifier.DEFAULT, false); } - else if (!method.hasModifierProperty(PsiModifier.STATIC)) { + else if (!method.hasModifierProperty(PsiModifier.STATIC) && !method.isConstructor()) { PsiUtil.setModifierProperty(method, PsiModifier.ABSTRACT, true); } }