From 61712f77ac8304de7e322ddaa61e981ad546851e Mon Sep 17 00:00:00 2001 From: Nikita Eshkeev Date: Fri, 24 Apr 2020 08:03:21 +0300 Subject: [PATCH] [codeInsight] IDEA-236735 Java enum constant is called "Anonymous inner class" There used to be a vague error message for enum constants that don't implement methods from an interface which refers to them as 'Anonymous class deriving from *Enum'. This patch makes the message clear displaying the real names of the enum constants in the error message. Signed-off-by: Nikita Eshkeev GitOrigin-RevId: 700bc2b579e0c8552858ab881d9a3e4e8d81b1f8 --- .../impl/analysis/HighlightClassUtil.java | 48 +++++++++++++++++-- .../src/messages/JavaErrorBundle.properties | 1 + ...onstantWithoutInterfaceImplementation.java | 2 +- .../EnumImplementsInterface.java | 41 ++++++++++++++++ .../EnumWithAbstractMethods.java | 4 +- .../EnumWithAbstractMethods.java | 4 +- .../daemon/GenericsHighlightingTest.java | 1 + 7 files changed, 91 insertions(+), 10 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/EnumImplementsInterface.java 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 c9eb0ebe09b8..3f35ec415b6c 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 @@ -73,11 +73,7 @@ public class HighlightClassUtil { return null; } - String baseClassName = HighlightUtil.formatClass(aClass, false); - String methodName = JavaHighlightUtil.formatMethod(abstractMethod); - String messageKey = aClass instanceof PsiEnumConstantInitializer || aClass.isRecord() || implementsFixElement instanceof PsiEnumConstant ? - "class.must.implement.method" : "class.must.be.abstract"; - String message = JavaErrorBundle.message(messageKey, baseClassName, methodName, HighlightUtil.formatClass(superClass, false)); + final String message = getMustImplementMethodErrorMessage(aClass, implementsFixElement); HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip(message).create(); final PsiMethod anyMethodToImplement = ClassUtil.getAnyMethodToImplement(aClass); @@ -92,6 +88,7 @@ public class HighlightClassUtil { } if (!(aClass instanceof PsiAnonymousClass) && !aClass.isEnum() + && aClass.getModifierList() != null && HighlightUtil.getIncompatibleModifier(PsiModifier.ABSTRACT, aClass.getModifierList()) == null) { QuickFixAction.registerQuickFixAction( errorResult, @@ -101,6 +98,47 @@ public class HighlightClassUtil { return errorResult; } + /** + * The method generates a error message for a class that has an unimplemented abstract method. + * + * @param aClass the class to generate the error message for + * @param implementsFixElement either enum constant that is being analyzed or the same value as aClass + * @return the error message that matches + */ + @NotNull + private static String getMustImplementMethodErrorMessage(@NotNull final PsiClass aClass, + @NotNull final PsiElement implementsFixElement) { + final PsiMethod abstractMethod = ClassUtil.getAnyAbstractMethod(aClass); + assert abstractMethod != null; + + final PsiClass superClass = abstractMethod.getContainingClass(); + assert superClass != null; + + final String baseClassName = HighlightUtil.formatClass(aClass, false); + final String superClassName = HighlightUtil.formatClass(superClass, false); + final String methodName = JavaHighlightUtil.formatMethod(abstractMethod); + + if (aClass instanceof PsiEnumConstantInitializer) { + final PsiEnumConstantInitializer enumConstant = (PsiEnumConstantInitializer)aClass; + final String name = enumConstant.getEnumConstant().getName(); + + return JavaErrorBundle.message("enum.constant.must.implement.method", + name, + methodName, + superClassName); + } + else if (aClass.isRecord() || implementsFixElement instanceof PsiEnumConstant) { + return JavaErrorBundle.message("class.must.implement.method", + baseClassName, + methodName, + superClassName); + } + return JavaErrorBundle.message("class.must.be.abstract", + baseClassName, + methodName, + superClassName); + } + static HighlightInfo checkClassMustBeAbstract(@NotNull PsiClass aClass, @NotNull TextRange textRange) { if (aClass.isEnum()) { if (hasEnumConstantsWithInitializer(aClass)) return null; diff --git a/java/java-psi-impl/src/messages/JavaErrorBundle.properties b/java/java-psi-impl/src/messages/JavaErrorBundle.properties index 7065bbc5323b..e450b47efe9a 100644 --- a/java/java-psi-impl/src/messages/JavaErrorBundle.properties +++ b/java/java-psi-impl/src/messages/JavaErrorBundle.properties @@ -95,6 +95,7 @@ implements.after.interface=No implements clause allowed for interface extends.after.enum=No extends clause allowed for enum static.declaration.in.inner.class=Inner classes cannot have static declarations class.must.be.abstract=Class ''{0}'' must either be declared abstract or implement abstract method ''{1}'' in ''{2}'' +enum.constant.must.implement.method=Enum constant ''{0}'' must implement abstract method ''{1}'' in ''{2}'' class.must.implement.method=Class ''{0}'' must implement abstract method ''{1}'' in ''{2}'' abstract.cannot.be.instantiated=''{0}'' is abstract; cannot be instantiated duplicate.class.in.other.file=Duplicate class found in the file ''{0}'' diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/EnumConstantWithoutInterfaceImplementation.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/EnumConstantWithoutInterfaceImplementation.java index 138ab8abc2e3..b8ca8679a028 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/EnumConstantWithoutInterfaceImplementation.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting6/EnumConstantWithoutInterfaceImplementation.java @@ -4,5 +4,5 @@ interface A { } enum E implements A { - F() {}; + F() {}; } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/EnumImplementsInterface.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/EnumImplementsInterface.java new file mode 100644 index 000000000000..c2ee2d8e2258 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/EnumImplementsInterface.java @@ -0,0 +1,41 @@ +interface MyInterface { + void method1(); +} + +enum SampleEnum1 implements MyInterface { + ONE; +} + +enum SampleEnum2 implements MyInterface { + ONE{}; +} + +enum SampleEnum3 implements MyInterface { + ONE; + + @Override + public void method1() { } +} + +enum SampleEnum4 implements MyInterface { + ONE { + @Override + public void method1() { } + }; +} + +enum SampleEnum5 implements MyInterface { + ONE("one") {}; + + SampleEnum5(final String name) {} +} + + +enum SampleEnum6 implements MyInterface { + ONE("one") { + @Override + public void method1() {} + }; + + SampleEnum6(final String name) {} +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/EnumWithAbstractMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/EnumWithAbstractMethods.java index 1abae6b17a2d..7bcf0f00a58c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/EnumWithAbstractMethods.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/EnumWithAbstractMethods.java @@ -1,5 +1,5 @@ abstract enum OurEnum { - A { + A { }, B, C { @@ -12,7 +12,7 @@ enum xxx { X, - Y { + Y { }; abstract void f(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/EnumWithAbstractMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/EnumWithAbstractMethods.java index 1abae6b17a2d..7bcf0f00a58c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/EnumWithAbstractMethods.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/EnumWithAbstractMethods.java @@ -1,5 +1,5 @@ abstract enum OurEnum { - A { + A { }, B, C { @@ -12,7 +12,7 @@ enum xxx { X, - Y { + Y { }; abstract void f(); diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/GenericsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/GenericsHighlightingTest.java index fbb1a16ccc09..b13c4aaf3ee3 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/GenericsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/GenericsHighlightingTest.java @@ -81,6 +81,7 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase { public void testAutoboxingMethods() { doTest5(false); } public void testAutoboxingConstructors() { doTest5(false); } public void testEnumWithAbstractMethods() { doTest5(false); } + public void testEnumImplementsInterface() { doTest7(false); } public void testEnum() { doTest5(false); } public void testEnum56239() { doTest6(false); } public void testSameErasure() { doTest5(false); }