diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplementedAtRuntimeConditionImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplementedAtRuntimeConditionImpl.java index 914a927b5960..12a1653b62ce 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplementedAtRuntimeConditionImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplementedAtRuntimeConditionImpl.java @@ -23,7 +23,7 @@ public class ImplementedAtRuntimeConditionImpl extends ImplementedAtRuntimeCondi @Override public boolean isImplementedAtRuntime(@NotNull PsiClass psiClass) { for (ImplicitSubclassProvider provider : ImplicitSubclassProvider.Companion.getEP_NAME().getExtensions()) { - SubclassingInfo info = provider.getSubclassingInfo(psiClass); + ImplicitSubclassProvider.SubclassingInfo info = provider.getSubclassingInfo(psiClass); if (info != null && !info.isAbstract()) { return true; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplicitSubclassInspection.kt b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplicitSubclassInspection.kt index d5f16c76d032..5d92b1ddc91b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplicitSubclassInspection.kt +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplicitSubclassInspection.kt @@ -39,7 +39,7 @@ class ImplicitSubclassInspection : AbstractBaseUastLocalInspectionTool() { val methodsToOverride = aClass.methods.mapNotNull { method -> subclassInfos - .mapNotNull { it.getOverridingInfo(method)?.description } + .mapNotNull { it.methodsInfo?.get(method)?.description } .firstOrNull()?.let { description -> method to description } @@ -55,8 +55,8 @@ class ImplicitSubclassInspection : AbstractBaseUastLocalInspectionTool() { if (method.isFinal || method.isStatic || method.hasModifierProperty(PsiModifier.PRIVATE)) { methodsToAttachToClassFix?.add(smartPointerManager.createSmartPsiElementPointer(method, method.containingFile)) - val methodFixes = if (method.modifierList.isWritable) - arrayOf(FixSubclassing(method, method.name)) + val methodFixes = if (canApplyFix(method)) + arrayOf(MakeExtendableFix(method, method.name)) else emptyArray() @@ -76,7 +76,7 @@ class ImplicitSubclassInspection : AbstractBaseUastLocalInspectionTool() { problems.add(manager.createProblemDescriptor( it, classReasonToBeSubclassed ?: InspectionsBundle.message("inspection.implicit.subclass.display.forClass", aClass.name), isOnTheFly, - arrayOf(FixSubclassing(aClass, aClass.name ?: "class", methodsToAttachToClassFix ?: emptyList())), + arrayOf(MakeExtendableFix(aClass, aClass.name ?: "class", methodsToAttachToClassFix ?: emptyList())), ProblemHighlightType.GENERIC_ERROR_OR_WARNING) ) } @@ -86,7 +86,7 @@ class ImplicitSubclassInspection : AbstractBaseUastLocalInspectionTool() { return problems.toTypedArray() } - private fun canApplyFix(aClass: UClass) = aClass.modifierList?.isWritable ?: false + private fun canApplyFix(aClass: UDeclaration) = aClass.modifierList?.isWritable ?: false private fun problemTargets(declaration: UDeclaration, highlightableModifiersSet: Set): List { val modifiersElements = declaration.modifierList?.let { @@ -105,9 +105,9 @@ class ImplicitSubclassInspection : AbstractBaseUastLocalInspectionTool() { private val classHighlightableModifiersSet = setOf(PsiModifier.FINAL, PsiModifier.PRIVATE) - private class FixSubclassing(uDeclaration: UDeclaration, - hintTargetName: String, - val siblings: List> = emptyList()) + private class MakeExtendableFix(uDeclaration: UDeclaration, + hintTargetName: String, + val siblings: List> = emptyList()) : LocalQuickFixOnPsiElement(uDeclaration) { override fun getFamilyName(): String = QuickFixBundle.message("fix.modifiers.family") diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplicitSubclassProvider.kt b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplicitSubclassProvider.kt index 0665a508b8b9..2f8008e53310 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplicitSubclassProvider.kt +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/inheritance/ImplicitSubclassProvider.kt @@ -55,34 +55,30 @@ abstract class ImplicitSubclassProvider { */ abstract fun getSubclassingInfo(psiClass: PsiClass): SubclassingInfo? + /** + * Information about implicitly overridden methods. + * @property description an explanation why this method was overridden. + * @property isAbstract is overridden method abstract. + */ + class OverridingInfo @JvmOverloads constructor(@Nls(capitalization = Sentence) + val description: String, + val isAbstract: Boolean = false) + + /** + * Information about implicitly created subclass. + * @property description an explanation why this class was subclassed. + * @property isAbstract is created subclass abstract. + * @property methodsInfo map of methods overridden in class and corresponding [OverridingInfo]s, + * or `null` if no method-level info is provided + */ + class SubclassingInfo @JvmOverloads constructor(@Nls(capitalization = Sentence) + val description: String, + val methodsInfo: Map? = null, + val isAbstract: Boolean = false) + companion object { val EP_NAME = ExtensionPointName.create("com.intellij.codeInsight.implicitSubclassProvider") } } - -/** - * Information about implicitly overridden methods. - * @property description an explanation why this method was overridden. - * @property isAbstract is overridden method abstract. - */ -class OverridingInfo @JvmOverloads constructor(@Nls(capitalization = Sentence) - val description: String, - val isAbstract: Boolean = false) - -/** - * Information about implicitly created subclass. - * @property description an explanation why this class was subclassed. - * @property isAbstract is created subclass abstract. - */ -open class SubclassingInfo @JvmOverloads constructor(@Nls(capitalization = Sentence) - val description: String, - val isAbstract: Boolean = false) { - /** - * @param method a method of class for which the info was created. - * @return an info about reason for method overriding, or `null` if this method will not be overridden. - */ - open fun getOverridingInfo(method: PsiMethod): OverridingInfo? = null - -} diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index a07e27c15f1c..8a7844ee1bd3 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -825,11 +825,11 @@ inspection.reflection.invocation.argument.not.assignable=Argument is not assigna inspection.reflection.invocation.item.not.assignable=Array item is not assignable to ''{0}'' inspection.reflection.invocation.array.not.assignable=Array {0,choice,1#item has|1 -Reports if class is eligible for being subclassed at runtime by some framework (like Spring or Hibernate), +Reports if class is could be subclassed at runtime by some framework (like Spring or Hibernate), but something in code prevents this class from being subclassed or method from being overridden. \ No newline at end of file