From 9952c373068ae1540478db33ef005678efdbdfd1 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 17 May 2017 14:24:50 +0300 Subject: [PATCH] implement abstract: allow to choose classes under interface hierarchy (IDEA-132662) --- .../impl/ImplementAbstractMethodAction.java | 2 -- .../impl/ImplementAbstractMethodHandler.java | 27 +++++++++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ImplementAbstractMethodAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ImplementAbstractMethodAction.java index 15a582a303d6..f460c13ee2fa 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ImplementAbstractMethodAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ImplementAbstractMethodAction.java @@ -25,7 +25,6 @@ import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.PsiElementProcessorAdapter; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -113,7 +112,6 @@ public class ImplementAbstractMethodAction extends BaseIntentionAction { public boolean execute(@NotNull PsiElement element) { if (element instanceof PsiClass) { PsiClass aClass = (PsiClass) element; - if (aClass.isInterface() && !PsiUtil.isLanguageLevel8OrHigher(aClass)) return true; final PsiMethod existingImplementation = findExistingImplementation(aClass, myMethod); if (existingImplementation != null && !existingImplementation.hasModifierProperty(PsiModifier.ABSTRACT)) { myHasExistingImplementations = true; diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ImplementAbstractMethodHandler.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ImplementAbstractMethodHandler.java index 7d230d366255..ece5da5a9145 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ImplementAbstractMethodHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ImplementAbstractMethodHandler.java @@ -30,12 +30,11 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.PopupChooserBuilder; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.search.searches.ClassInheritorsSearch; -import com.intellij.psi.util.MethodSignatureUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.PsiUtilCore; -import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.psi.util.*; import com.intellij.ui.components.JBList; import com.intellij.util.IncorrectOperationException; @@ -59,12 +58,13 @@ public class ImplementAbstractMethodHandler { public void invoke() { PsiDocumentManager.getInstance(myProject).commitAllDocuments(); + Ref problemDetected = new Ref<>(); final PsiElement[][] result = new PsiElement[1][]; ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> ApplicationManager.getApplication().runReadAction(() -> { final PsiClass psiClass = myMethod.getContainingClass(); if (!psiClass.isValid()) return; if (!psiClass.isEnum()) { - result[0] = getClassImplementations(psiClass); + result[0] = getClassImplementations(psiClass, problemDetected); } else { final List enumConstants = new ArrayList<>(); @@ -90,7 +90,7 @@ public class ImplementAbstractMethodHandler { if (result[0].length == 0) { Messages.showMessageDialog(myProject, - CodeInsightBundle.message("intention.implement.abstract.method.error.no.classes.message"), + problemDetected.isNull() ? CodeInsightBundle.message("intention.implement.abstract.method.error.no.classes.message") : problemDetected.get(), CodeInsightBundle.message("intention.implement.abstract.method.error.no.classes.title"), Messages.getInformationIcon()); return; @@ -154,18 +154,29 @@ public class ImplementAbstractMethodHandler { }, CodeInsightBundle.message("intention.implement.abstract.method.command.name"), null); } - private PsiClass[] getClassImplementations(final PsiClass psiClass) { + private PsiClass[] getClassImplementations(final PsiClass psiClass, Ref problemDetected) { ArrayList list = new ArrayList<>(); + Set classNamesWithPotentialImplementations = new LinkedHashSet<>(); for (PsiClass inheritor : ClassInheritorsSearch.search(psiClass)) { if (!inheritor.isInterface() || PsiUtil.isLanguageLevel8OrHigher(inheritor)) { final PsiSubstitutor classSubstitutor = TypeConversionUtil.getClassSubstitutor(psiClass, inheritor, PsiSubstitutor.EMPTY); PsiMethod method = classSubstitutor != null ? MethodSignatureUtil.findMethodBySignature(inheritor, myMethod.getSignature(classSubstitutor), true) : inheritor.findMethodBySignature(myMethod, true); - if (method == null || !psiClass.equals(method.getContainingClass())) continue; + if (method == null) continue; + PsiClass containingClass = method.getContainingClass(); + if (!psiClass.equals(containingClass)) { + if (containingClass != null) { + classNamesWithPotentialImplementations.add(PsiFormatUtil.formatClass(containingClass, PsiFormatUtilBase.SHOW_NAME)); + } + continue; + } list.add(inheritor); } } + if (!classNamesWithPotentialImplementations.isEmpty()) { + problemDetected.set("Potential implementations with weaker access privileges are found: " + StringUtil.join(classNamesWithPotentialImplementations, ", ")); + } return list.toArray(new PsiClass[list.size()]); }