diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/JavaHierarchyUtil.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/JavaHierarchyUtil.java index fc1614823c..deaf6ad7b8 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/JavaHierarchyUtil.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/JavaHierarchyUtil.java @@ -31,24 +31,20 @@ * @author yole */ public class JavaHierarchyUtil { - private JavaHierarchyUtil() { - } + private JavaHierarchyUtil() { + } - @Nullable - public static String getPackageName(final PsiClass psiClass) { - final PsiFile file = psiClass.getContainingFile(); - if (file instanceof PsiClassOwner) { - return ((PsiClassOwner) file).getPackageName(); - } else { - return null; + @Nullable + public static String getPackageName(PsiClass psiClass) { + if (psiClass.getContainingFile() instanceof PsiClassOwner classOwner) { + return classOwner.getPackageName(); + } + return null; } - } - public static Comparator getComparator(Project project) { - if (HierarchyBrowserManager.getInstance(project).getState().SORT_ALPHABETICALLY) { - return AlphaComparator.INSTANCE; - } else { - return SourceComparator.INSTANCE; + public static Comparator getComparator(Project project) { + HierarchyBrowserManager.State state = HierarchyBrowserManager.getInstance(project).getState(); + assert state != null; + return state.SORT_ALPHABETICALLY ? AlphaComparator.INSTANCE : SourceComparator.INSTANCE; } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CallHierarchyBrowser.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CallHierarchyBrowser.java index 1207516e1b..617cb45d5b 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CallHierarchyBrowser.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CallHierarchyBrowser.java @@ -36,71 +36,69 @@ import java.util.Map; public class CallHierarchyBrowser extends CallHierarchyBrowserBase { - private static final Logger LOG = Logger.getInstance(CallHierarchyBrowser.class); + private static final Logger LOG = Logger.getInstance(CallHierarchyBrowser.class); - public CallHierarchyBrowser(@Nonnull Project project, @Nonnull PsiMethod method) { - super(project, method); - } - - @Override - protected void createTrees(@Nonnull final Map type2TreeMap) { - ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_CALL_HIERARCHY_POPUP); - final JTree tree1 = createTree(false); - PopupHandler.installPopupHandler(tree1, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP, ActionManager.getInstance()); - final BaseOnThisMethodAction baseOnThisMethodAction = new BaseOnThisMethodAction(); - baseOnThisMethodAction - .registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).getShortcutSet(), tree1); - type2TreeMap.put(CALLEE_TYPE, tree1); + public CallHierarchyBrowser(@Nonnull Project project, @Nonnull PsiMethod method) { + super(project, method); + } - final JTree tree2 = createTree(false); - PopupHandler.installPopupHandler(tree2, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP, ActionManager.getInstance()); - baseOnThisMethodAction - .registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).getShortcutSet(), tree2); - type2TreeMap.put(CALLER_TYPE, tree2); - } + @Override + protected void createTrees(@Nonnull Map type2TreeMap) { + ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_CALL_HIERARCHY_POPUP); + JTree tree1 = createTree(false); + PopupHandler.installPopupHandler(tree1, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP, ActionManager.getInstance()); + BaseOnThisMethodAction baseOnThisMethodAction = new BaseOnThisMethodAction(); + baseOnThisMethodAction + .registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).getShortcutSet(), tree1); + type2TreeMap.put(CALLEE_TYPE, tree1); - @Override - protected PsiElement getElementFromDescriptor(@Nonnull HierarchyNodeDescriptor descriptor) { - if (descriptor instanceof CallHierarchyNodeDescriptor) { - CallHierarchyNodeDescriptor nodeDescriptor = (CallHierarchyNodeDescriptor)descriptor; - return nodeDescriptor.getEnclosingElement(); + JTree tree2 = createTree(false); + PopupHandler.installPopupHandler(tree2, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP, ActionManager.getInstance()); + baseOnThisMethodAction + .registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_CALL_HIERARCHY).getShortcutSet(), tree2); + type2TreeMap.put(CALLER_TYPE, tree2); } - return null; - } - @Override - protected PsiElement getOpenFileElementFromDescriptor(@Nonnull HierarchyNodeDescriptor descriptor) { - if (descriptor instanceof CallHierarchyNodeDescriptor) { - CallHierarchyNodeDescriptor nodeDescriptor = (CallHierarchyNodeDescriptor)descriptor; - return nodeDescriptor.getTargetElement(); + @Override + protected PsiElement getElementFromDescriptor(@Nonnull HierarchyNodeDescriptor descriptor) { + if (descriptor instanceof CallHierarchyNodeDescriptor nodeDescriptor) { + return nodeDescriptor.getEnclosingElement(); + } + return null; } - return null; - } - @Override - protected boolean isApplicableElement(@Nonnull final PsiElement element) { - return element instanceof PsiMethod; - } - - @Override - protected HierarchyTreeStructure createHierarchyTreeStructure(@Nonnull final String typeName, @Nonnull final PsiElement psiElement) { - if (CALLER_TYPE.equals(typeName)) { - return new CallerMethodsTreeStructure(myProject, (PsiMethod)psiElement, getCurrentScopeType()); + @Override + protected PsiElement getOpenFileElementFromDescriptor(@Nonnull HierarchyNodeDescriptor descriptor) { + if (descriptor instanceof CallHierarchyNodeDescriptor nodeDescriptor) { + return nodeDescriptor.getTargetElement(); + } + return null; } - else if (CALLEE_TYPE.equals(typeName)) { - return new CalleeMethodsTreeStructure(myProject, (PsiMethod)psiElement, getCurrentScopeType()); + + @Override + protected boolean isApplicableElement(@Nonnull PsiElement element) { + return element instanceof PsiMethod; } - else { - LOG.error("unexpected type: " + typeName); - return null; + + @Override + protected HierarchyTreeStructure createHierarchyTreeStructure(@Nonnull String typeName, @Nonnull PsiElement psiElement) { + if (CALLER_TYPE.equals(typeName)) { + return new CallerMethodsTreeStructure(myProject, (PsiMethod)psiElement, getCurrentScopeType()); + } + else if (CALLEE_TYPE.equals(typeName)) { + return new CalleeMethodsTreeStructure(myProject, (PsiMethod)psiElement, getCurrentScopeType()); + } + else { + LOG.error("unexpected type: " + typeName); + return null; + } } - } - @Override - protected Comparator getComparator() { - return JavaHierarchyUtil.getComparator(myProject); - } + @Override + protected Comparator getComparator() { + return JavaHierarchyUtil.getComparator(myProject); + } - public static final class BaseOnThisMethodAction extends CallHierarchyBrowserBase.BaseOnThisMethodAction { - } + public static final class BaseOnThisMethodAction extends CallHierarchyBrowserBase.BaseOnThisMethodAction { + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CallHierarchyNodeDescriptor.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CallHierarchyNodeDescriptor.java index e0e5eecb72..19e58ba53b 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CallHierarchyNodeDescriptor.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CallHierarchyNodeDescriptor.java @@ -24,7 +24,6 @@ import com.intellij.java.language.psi.util.PsiFormatUtil; import com.intellij.java.language.psi.util.PsiFormatUtilBase; import consulo.annotation.access.RequiredReadAction; -import consulo.application.AllIcons; import consulo.codeEditor.Editor; import consulo.codeEditor.EditorColors; import consulo.codeEditor.markup.RangeHighlighter; @@ -45,6 +44,7 @@ import consulo.language.psi.SyntheticElement; import consulo.language.psi.util.PsiTreeUtil; import consulo.navigation.Navigatable; +import consulo.platform.base.icon.PlatformIconGroup; import consulo.project.Project; import consulo.ui.annotation.RequiredUIAccess; import consulo.ui.ex.awtUnsafe.TargetAWT; @@ -59,203 +59,228 @@ import java.util.List; public final class CallHierarchyNodeDescriptor extends HierarchyNodeDescriptor implements Navigatable { - private int myUsageCount = 1; - private final List myReferences = new ArrayList(); - private final boolean myNavigateToReference; + private int myUsageCount = 1; + private final List myReferences = new ArrayList<>(); + private final boolean myNavigateToReference; - public CallHierarchyNodeDescriptor(@Nonnull Project project, final HierarchyNodeDescriptor parentDescriptor, @Nonnull PsiElement element, final boolean isBase, final boolean navigateToReference) { - super(project, parentDescriptor, element, isBase); - myNavigateToReference = navigateToReference; - } - - /** - * @return PsiMethod or PsiClass or JspFile - */ - public final PsiMember getEnclosingElement() { - PsiElement element = getPsiElement(); - return element == null ? null : getEnclosingElement(element); - } - - public static PsiMember getEnclosingElement(final PsiElement element) { - return PsiTreeUtil.getNonStrictParentOfType(element, PsiMethod.class, PsiClass.class); - } + public CallHierarchyNodeDescriptor( + @Nonnull Project project, + HierarchyNodeDescriptor parentDescriptor, + @Nonnull PsiElement element, + boolean isBase, + boolean navigateToReference + ) { + super(project, parentDescriptor, element, isBase); + myNavigateToReference = navigateToReference; + } - public final void incrementUsageCount() { - myUsageCount++; - } + /** + * @return PsiMethod or PsiClass or JspFile + */ + public final PsiMember getEnclosingElement() { + PsiElement element = getPsiElement(); + return element == null ? null : getEnclosingElement(element); + } - /** - * Element for OpenFileDescriptor - */ - public final PsiElement getTargetElement() { - return getPsiElement(); - } + public static PsiMember getEnclosingElement(PsiElement element) { + return PsiTreeUtil.getNonStrictParentOfType(element, PsiMethod.class, PsiClass.class); + } - @Override - public final boolean isValid() { - return getEnclosingElement() != null; - } + public final void incrementUsageCount() { + myUsageCount++; + } - @Override - @RequiredUIAccess - public final boolean update() { - final CompositeAppearance oldText = myHighlightedText; - final Icon oldIcon = TargetAWT.to(getIcon()); + /** + * Element for OpenFileDescriptor + */ + public final PsiElement getTargetElement() { + return getPsiElement(); + } - int flags = Iconable.ICON_FLAG_VISIBILITY; - if (isMarkReadOnly()) { - flags |= Iconable.ICON_FLAG_READ_STATUS; + @Override + public final boolean isValid() { + return getEnclosingElement() != null; } - boolean changes = super.update(); + @Override + @RequiredUIAccess + public final boolean update() { + CompositeAppearance oldText = myHighlightedText; + Icon oldIcon = TargetAWT.to(getIcon()); - final PsiElement enclosingElement = getEnclosingElement(); + int flags = Iconable.ICON_FLAG_VISIBILITY; + if (isMarkReadOnly()) { + flags |= Iconable.ICON_FLAG_READ_STATUS; + } - if (enclosingElement == null) { - final String invalidPrefix = IdeLocalize.nodeHierarchyInvalid().get(); - if (!myHighlightedText.getText().startsWith(invalidPrefix)) { - myHighlightedText.getBeginning().addText(invalidPrefix, HierarchyNodeDescriptor.getInvalidPrefixAttributes()); - } - return true; - } + boolean changes = super.update(); - Image newIcon = IconDescriptorUpdaters.getIcon(enclosingElement, flags); - if (changes && myIsBase) { - newIcon = ImageEffects.appendRight(AllIcons.Hierarchy.Base, newIcon); - } - setIcon(newIcon); + PsiElement enclosingElement = getEnclosingElement(); - myHighlightedText = new CompositeAppearance(); - TextAttributes mainTextAttributes = null; - if (myColor != null) { - mainTextAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN); - } - if (enclosingElement instanceof PsiMethod) { - if (enclosingElement instanceof SyntheticElement) { - PsiFile file = enclosingElement.getContainingFile(); - myHighlightedText.getEnding().addText( - file != null ? file.getName() : IdeLocalize.nodeCallHierarchyUnknownJsp().get(), - mainTextAttributes - ); - } else { - final PsiMethod method = (PsiMethod) enclosingElement; - final StringBuilder buffer = new StringBuilder(128); - final PsiClass containingClass = method.getContainingClass(); - if (containingClass != null) { - buffer.append(ClassPresentationUtil.getNameForClass(containingClass, false)); - buffer.append('.'); + if (enclosingElement == null) { + String invalidPrefix = IdeLocalize.nodeHierarchyInvalid().get(); + if (!myHighlightedText.getText().startsWith(invalidPrefix)) { + myHighlightedText.getBeginning().addText(invalidPrefix, HierarchyNodeDescriptor.getInvalidPrefixAttributes()); + } + return true; } - final String methodText = PsiFormatUtil.formatMethod(method, PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_TYPE); - buffer.append(methodText); - myHighlightedText.getEnding().addText(buffer.toString(), mainTextAttributes); - } - } else { - myHighlightedText.getEnding().addText(ClassPresentationUtil.getNameForClass((PsiClass) enclosingElement, false), mainTextAttributes); - } - - if (myUsageCount > 1) { - myHighlightedText.getEnding().addText( - IdeLocalize.nodeCallHierarchyNUsages(myUsageCount).get(), - HierarchyNodeDescriptor.getUsageCountPrefixAttributes() - ); - } + Image newIcon = IconDescriptorUpdaters.getIcon(enclosingElement, flags); + if (changes && myIsBase) { + newIcon = ImageEffects.appendRight(PlatformIconGroup.hierarchyBase(), newIcon); + } + setIcon(newIcon); - final PsiClass containingClass = enclosingElement instanceof PsiMethod method ? method.getContainingClass() : (PsiClass) enclosingElement; - if (containingClass != null) { - final String packageName = JavaHierarchyUtil.getPackageName(containingClass); - myHighlightedText.getEnding().addText(" (" + packageName + ")", HierarchyNodeDescriptor.getPackageNameAttributes()); - } + myHighlightedText = new CompositeAppearance(); + TextAttributes mainTextAttributes = null; + if (myColor != null) { + mainTextAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN); + } + if (enclosingElement instanceof PsiMethod) { + if (enclosingElement instanceof SyntheticElement) { + PsiFile file = enclosingElement.getContainingFile(); + myHighlightedText.getEnding().addText( + file != null ? file.getName() : IdeLocalize.nodeCallHierarchyUnknownJsp().get(), + mainTextAttributes + ); + } + else { + PsiMethod method = (PsiMethod)enclosingElement; + StringBuilder buffer = new StringBuilder(128); + PsiClass containingClass = method.getContainingClass(); + if (containingClass != null) { + buffer.append(ClassPresentationUtil.getNameForClass(containingClass, false)); + buffer.append('.'); + } + String methodText = PsiFormatUtil.formatMethod( + method, + PsiSubstitutor.EMPTY, + PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, + PsiFormatUtilBase.SHOW_TYPE + ); + buffer.append(methodText); - myName = myHighlightedText.getText(); + myHighlightedText.getEnding().addText(buffer.toString(), mainTextAttributes); + } + } + else { + myHighlightedText.getEnding() + .addText(ClassPresentationUtil.getNameForClass((PsiClass)enclosingElement, false), mainTextAttributes); + } - if (!Comparing.equal(myHighlightedText, oldText) || !Comparing.equal(getIcon(), oldIcon)) { - changes = true; - } - return changes; - } + if (myUsageCount > 1) { + myHighlightedText.getEnding().addText( + IdeLocalize.nodeCallHierarchyNUsages(myUsageCount).get(), + HierarchyNodeDescriptor.getUsageCountPrefixAttributes() + ); + } - public void addReference(final PsiReference reference) { - myReferences.add(reference); - } + PsiClass containingClass = + enclosingElement instanceof PsiMethod method ? method.getContainingClass() : (PsiClass)enclosingElement; + if (containingClass != null) { + String packageName = JavaHierarchyUtil.getPackageName(containingClass); + myHighlightedText.getEnding().addText(" (" + packageName + ")", HierarchyNodeDescriptor.getPackageNameAttributes()); + } - public boolean hasReference(PsiReference reference) { - return myReferences.contains(reference); - } + myName = myHighlightedText.getText(); - @Override - @RequiredReadAction - public void navigate(boolean requestFocus) { - if (!myNavigateToReference) { - PsiElement element = getPsiElement(); - if (element instanceof Navigatable navigatable && navigatable.canNavigate()) { - navigatable.navigate(requestFocus); - } - return; + if (!Comparing.equal(myHighlightedText, oldText) || !Comparing.equal(getIcon(), oldIcon)) { + changes = true; + } + return changes; } - final PsiReference firstReference = myReferences.get(0); - final PsiElement element = firstReference.getElement(); - if (element == null) { - return; + public void addReference(PsiReference reference) { + myReferences.add(reference); } - final PsiElement callElement = element.getParent(); - if (callElement instanceof Navigatable navigatable && navigatable.canNavigate()) { - navigatable.navigate(requestFocus); - } else { - final PsiFile psiFile = callElement.getContainingFile(); - if (psiFile == null || psiFile.getVirtualFile() == null) { - return; - } - FileEditorManager.getInstance(getProject()).openFile(psiFile.getVirtualFile(), requestFocus); + + public boolean hasReference(PsiReference reference) { + return myReferences.contains(reference); } - Editor editor = PsiUtilBase.findEditor(callElement); + @Override + @RequiredReadAction + public void navigate(boolean requestFocus) { + if (!myNavigateToReference) { + PsiElement element = getPsiElement(); + if (element instanceof Navigatable navigatable && navigatable.canNavigate()) { + navigatable.navigate(requestFocus); + } + return; + } + + PsiReference firstReference = myReferences.get(0); + PsiElement element = firstReference.getElement(); + if (element == null) { + return; + } + PsiElement callElement = element.getParent(); + if (callElement instanceof Navigatable navigatable && navigatable.canNavigate()) { + navigatable.navigate(requestFocus); + } + else { + PsiFile psiFile = callElement.getContainingFile(); + if (psiFile == null || psiFile.getVirtualFile() == null) { + return; + } + FileEditorManager.getInstance(getProject()).openFile(psiFile.getVirtualFile(), requestFocus); + } + + Editor editor = PsiUtilBase.findEditor(callElement); - if (editor != null) { + if (editor != null) { - HighlightManager highlightManager = HighlightManager.getInstance(getProject()); - EditorColorsManager colorManager = EditorColorsManager.getInstance(); - TextAttributes attributes = colorManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); - ArrayList highlighters = new ArrayList<>(); - for (PsiReference psiReference : myReferences) { - final PsiElement eachElement = psiReference.getElement(); - if (eachElement != null) { - final PsiElement eachMethodCall = eachElement.getParent(); - if (eachMethodCall != null) { - final TextRange textRange = eachMethodCall.getTextRange(); - highlightManager.addRangeHighlight(editor, textRange.getStartOffset(), textRange.getEndOffset(), attributes, false, highlighters); - } + HighlightManager highlightManager = HighlightManager.getInstance(getProject()); + EditorColorsManager colorManager = EditorColorsManager.getInstance(); + TextAttributes attributes = colorManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES); + ArrayList highlighters = new ArrayList<>(); + for (PsiReference psiReference : myReferences) { + PsiElement eachElement = psiReference.getElement(); + if (eachElement != null) { + PsiElement eachMethodCall = eachElement.getParent(); + if (eachMethodCall != null) { + TextRange textRange = eachMethodCall.getTextRange(); + highlightManager.addRangeHighlight( + editor, + textRange.getStartOffset(), + textRange.getEndOffset(), + attributes, + false, + highlighters + ); + } + } + } } - } } - } - @Override - public boolean canNavigate() { - if (!myNavigateToReference) { - PsiElement element = getPsiElement(); - return element instanceof Navigatable navigatable && navigatable.canNavigate(); - } - if (myReferences.isEmpty()) { - return false; - } - final PsiReference firstReference = myReferences.get(0); - final PsiElement callElement = firstReference.getElement().getParent(); - if (callElement == null || !callElement.isValid()) { - return false; - } - if (!(callElement instanceof Navigatable navigatable && navigatable.canNavigate())) { - final PsiFile psiFile = callElement.getContainingFile(); - if (psiFile == null) { - return false; - } + @Override + @RequiredReadAction + public boolean canNavigate() { + if (!myNavigateToReference) { + PsiElement element = getPsiElement(); + return element instanceof Navigatable navigatable && navigatable.canNavigate(); + } + if (myReferences.isEmpty()) { + return false; + } + PsiReference firstReference = myReferences.get(0); + PsiElement callElement = firstReference.getElement().getParent(); + if (callElement == null || !callElement.isValid()) { + return false; + } + if (!(callElement instanceof Navigatable navigatable && navigatable.canNavigate())) { + PsiFile psiFile = callElement.getContainingFile(); + if (psiFile == null) { + return false; + } + } + return true; } - return true; - } - @Override - public boolean canNavigateToSource() { - return canNavigate(); - } + @Override + @RequiredReadAction + public boolean canNavigateToSource() { + return canNavigate(); + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CalleeMethodsTreeStructure.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CalleeMethodsTreeStructure.java index 8265c3832f..2375b37b1a 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CalleeMethodsTreeStructure.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CalleeMethodsTreeStructure.java @@ -15,6 +15,7 @@ */ package com.intellij.java.impl.ide.hierarchy.call; +import consulo.annotation.access.RequiredReadAction; import consulo.ide.impl.idea.ide.hierarchy.HierarchyNodeDescriptor; import consulo.ide.impl.idea.ide.hierarchy.HierarchyTreeStructure; import com.intellij.java.language.psi.*; @@ -27,92 +28,94 @@ import java.util.HashMap; public final class CalleeMethodsTreeStructure extends HierarchyTreeStructure { - private final String myScopeType; - - /** - * Should be called in read action - */ - public CalleeMethodsTreeStructure(final Project project, final PsiMethod method, final String scopeType) { - super(project, new CallHierarchyNodeDescriptor(project, null, method, true, false)); - myScopeType = scopeType; - } - - protected final Object[] buildChildren(final HierarchyNodeDescriptor descriptor) { - final PsiMember enclosingElement = ((CallHierarchyNodeDescriptor)descriptor).getEnclosingElement(); - if (!(enclosingElement instanceof PsiMethod)) { - return ArrayUtil.EMPTY_OBJECT_ARRAY; - } - final PsiMethod method = (PsiMethod)enclosingElement; - - final ArrayList methods = new ArrayList(); - - final PsiCodeBlock body = method.getBody(); - if (body != null) { - visitor(body, methods); + private final String myScopeType; + + /** + * Should be called in read action + */ + public CalleeMethodsTreeStructure(Project project, PsiMethod method, String scopeType) { + super(project, new CallHierarchyNodeDescriptor(project, null, method, true, false)); + myScopeType = scopeType; } - final PsiMethod baseMethod = (PsiMethod)((CallHierarchyNodeDescriptor)getBaseDescriptor()).getTargetElement(); - final PsiClass baseClass = baseMethod.getContainingClass(); - - final HashMap methodToDescriptorMap = new HashMap(); + @Override + @RequiredReadAction + protected final Object[] buildChildren(HierarchyNodeDescriptor descriptor) { + PsiMember enclosingElement = ((CallHierarchyNodeDescriptor)descriptor).getEnclosingElement(); + if (!(enclosingElement instanceof PsiMethod method)) { + return ArrayUtil.EMPTY_OBJECT_ARRAY; + } - final ArrayList result = new ArrayList(); + ArrayList methods = new ArrayList<>(); - for (final PsiMethod calledMethod : methods) { - if (!isInScope(baseClass, calledMethod, myScopeType)) continue; + PsiCodeBlock body = method.getBody(); + if (body != null) { + visitor(body, methods); + } - CallHierarchyNodeDescriptor d = methodToDescriptorMap.get(calledMethod); - if (d == null) { - d = new CallHierarchyNodeDescriptor(myProject, descriptor, calledMethod, false, false); - methodToDescriptorMap.put(calledMethod, d); - result.add(d); - } - else { - d.incrementUsageCount(); - } - } + PsiMethod baseMethod = (PsiMethod)((CallHierarchyNodeDescriptor)getBaseDescriptor()).getTargetElement(); + PsiClass baseClass = baseMethod.getContainingClass(); - // also add overriding methods as children - final PsiMethod[] overridingMethods = OverridingMethodsSearch.search(method, true).toArray(PsiMethod.EMPTY_ARRAY); - for (final PsiMethod overridingMethod : overridingMethods) { - if (!isInScope(baseClass, overridingMethod, myScopeType)) continue; - final CallHierarchyNodeDescriptor node = new CallHierarchyNodeDescriptor(myProject, descriptor, overridingMethod, false, false); - if (!result.contains(node)) result.add(node); - } + HashMap methodToDescriptorMap = new HashMap<>(); -/* - // show method implementations in EJB Class - final PsiMethod[] ejbImplementations = EjbUtil.findEjbImplementations(method, null); - for (int i = 0; i < ejbImplementations.length; i++) { - PsiMethod ejbImplementation = ejbImplementations[i]; - result.add(new CallHierarchyNodeDescriptor(myProject, descriptor, ejbImplementation, false)); - } -*/ - return ArrayUtil.toObjectArray(result); - } + ArrayList result = new ArrayList<>(); + for (PsiMethod calledMethod : methods) { + if (!isInScope(baseClass, calledMethod, myScopeType)) { + continue; + } + CallHierarchyNodeDescriptor d = methodToDescriptorMap.get(calledMethod); + if (d == null) { + d = new CallHierarchyNodeDescriptor(myProject, descriptor, calledMethod, false, false); + methodToDescriptorMap.put(calledMethod, d); + result.add(d); + } + else { + d.incrementUsageCount(); + } + } + // also add overriding methods as children + PsiMethod[] overridingMethods = OverridingMethodsSearch.search(method, true).toArray(PsiMethod.EMPTY_ARRAY); + for (PsiMethod overridingMethod : overridingMethods) { + if (!isInScope(baseClass, overridingMethod, myScopeType)) { + continue; + } + CallHierarchyNodeDescriptor node = + new CallHierarchyNodeDescriptor(myProject, descriptor, overridingMethod, false, false); + if (!result.contains(node)) { + result.add(node); + } + } - private static void visitor(final PsiElement element, final ArrayList methods) { - final PsiElement[] children = element.getChildren(); - for (final PsiElement child : children) { - visitor(child, methods); - if (child instanceof PsiMethodCallExpression) { - final PsiMethodCallExpression callExpression = (PsiMethodCallExpression)child; - final PsiReferenceExpression methodExpression = callExpression.getMethodExpression(); - final PsiMethod method = (PsiMethod)methodExpression.resolve(); - if (method != null) { - methods.add(method); + /* + // show method implementations in EJB Class + PsiMethod[] ejbImplementations = EjbUtil.findEjbImplementations(method, null); + for (int i = 0; i < ejbImplementations.length; i++) { + PsiMethod ejbImplementation = ejbImplementations[i]; + result.add(new CallHierarchyNodeDescriptor(myProject, descriptor, ejbImplementation, false)); } - } - else if (child instanceof PsiNewExpression) { - final PsiNewExpression newExpression = (PsiNewExpression)child; - final PsiMethod method = newExpression.resolveConstructor(); - if (method != null) { - methods.add(method); + */ + return ArrayUtil.toObjectArray(result); + } + + @RequiredReadAction + private static void visitor(PsiElement element, ArrayList methods) { + PsiElement[] children = element.getChildren(); + for (PsiElement child : children) { + visitor(child, methods); + if (child instanceof PsiMethodCallExpression methodCall) { + if (methodCall.getMethodExpression().resolve() instanceof PsiMethod method) { + methods.add(method); + } + } + else if (child instanceof PsiNewExpression newExpr) { + PsiMethod method = newExpr.resolveConstructor(); + if (method != null) { + methods.add(method); + } + } } - } } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CallerMethodsTreeStructure.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CallerMethodsTreeStructure.java index e86dd15f4b..429746eedf 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CallerMethodsTreeStructure.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/CallerMethodsTreeStructure.java @@ -15,17 +15,17 @@ */ package com.intellij.java.impl.ide.hierarchy.call; -import consulo.ide.impl.idea.ide.hierarchy.HierarchyNodeDescriptor; -import consulo.ide.impl.idea.ide.hierarchy.HierarchyTreeStructure; -import com.intellij.java.language.psi.*; -import consulo.project.Project; -import consulo.language.psi.*; -import consulo.content.scope.SearchScope; import com.intellij.java.indexing.search.searches.MethodReferencesSearch; +import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.PsiUtil; import com.intellij.java.language.psi.util.TypeConversionUtil; +import consulo.annotation.access.RequiredReadAction; +import consulo.content.scope.SearchScope; +import consulo.ide.impl.idea.ide.hierarchy.HierarchyNodeDescriptor; +import consulo.ide.impl.idea.ide.hierarchy.HierarchyTreeStructure; +import consulo.language.psi.PsiElement; +import consulo.project.Project; import consulo.util.collection.ArrayUtil; -import consulo.application.util.function.Processor; import consulo.util.collection.ContainerUtil; import java.util.HashMap; @@ -34,108 +34,106 @@ import java.util.Set; public final class CallerMethodsTreeStructure extends HierarchyTreeStructure { - private final String myScopeType; - - /** - * Should be called in read action - */ - public CallerMethodsTreeStructure(final Project project, final PsiMethod method, final String scopeType) { - super(project, new CallHierarchyNodeDescriptor(project, null, method, true, false)); - myScopeType = scopeType; - } + private final String myScopeType; - @Override - protected final Object[] buildChildren(final HierarchyNodeDescriptor descriptor) { - final PsiMember enclosingElement = ((CallHierarchyNodeDescriptor)descriptor).getEnclosingElement(); - HierarchyNodeDescriptor nodeDescriptor = getBaseDescriptor(); - if (!(enclosingElement instanceof PsiMethod) || nodeDescriptor == null) { - return ArrayUtil.EMPTY_OBJECT_ARRAY; + /** + * Should be called in read action + */ + public CallerMethodsTreeStructure(Project project, PsiMethod method, String scopeType) { + super(project, new CallHierarchyNodeDescriptor(project, null, method, true, false)); + myScopeType = scopeType; } - final PsiMethod method = (PsiMethod)enclosingElement; - final PsiMethod baseMethod = (PsiMethod)((CallHierarchyNodeDescriptor)nodeDescriptor).getTargetElement(); - final SearchScope searchScope = getSearchScope(myScopeType, baseMethod.getContainingClass()); - final PsiClass originalClass = method.getContainingClass(); - assert originalClass != null; - final PsiClassType originalType = JavaPsiFacade.getElementFactory(myProject).createType(originalClass); - final Set methodsToFind = new HashSet(); - methodsToFind.add(method); - ContainerUtil.addAll(methodsToFind, method.findDeepestSuperMethods()); + @Override + @RequiredReadAction + protected final Object[] buildChildren(HierarchyNodeDescriptor descriptor) { + PsiMember enclosingElement = ((CallHierarchyNodeDescriptor)descriptor).getEnclosingElement(); + HierarchyNodeDescriptor nodeDescriptor = getBaseDescriptor(); + if (!(enclosingElement instanceof PsiMethod) || nodeDescriptor == null) { + return ArrayUtil.EMPTY_OBJECT_ARRAY; + } + PsiMethod method = (PsiMethod)enclosingElement; + PsiMethod baseMethod = (PsiMethod)((CallHierarchyNodeDescriptor)nodeDescriptor).getTargetElement(); + SearchScope searchScope = getSearchScope(myScopeType, baseMethod.getContainingClass()); - final Map methodToDescriptorMap = new HashMap(); - for (final PsiMethod methodToFind : methodsToFind) { - MethodReferencesSearch.search(methodToFind, searchScope, true).forEach(new Processor() { - @Override - public boolean process(final PsiReference reference) { - if (reference instanceof PsiReferenceExpression) { - final PsiExpression qualifier = ((PsiReferenceExpression)reference).getQualifierExpression(); - if (qualifier instanceof PsiSuperExpression) { // filter super.foo() call inside foo() and similar cases (bug 8411) - final PsiClass superClass = PsiUtil.resolveClassInType(qualifier.getType()); - if (originalClass.isInheritor(superClass, true)) { - return true; - } - } - if (qualifier != null && !methodToFind.hasModifierProperty(PsiModifier.STATIC)) { - final PsiType qualifierType = qualifier.getType(); - if (qualifierType instanceof PsiClassType && - !TypeConversionUtil.isAssignable(qualifierType, originalType) && - methodToFind != method) { - final PsiClass psiClass = ((PsiClassType)qualifierType).resolve(); - if (psiClass != null) { - final PsiMethod callee = psiClass.findMethodBySignature(methodToFind, true); - if (callee != null && !methodsToFind.contains(callee)) { - // skip sibling methods - return true; - } + PsiClass originalClass = method.getContainingClass(); + assert originalClass != null; + PsiClassType originalType = JavaPsiFacade.getElementFactory(myProject).createType(originalClass); + Set methodsToFind = new HashSet<>(); + methodsToFind.add(method); + ContainerUtil.addAll(methodsToFind, method.findDeepestSuperMethods()); + + Map methodToDescriptorMap = new HashMap<>(); + for (PsiMethod methodToFind : methodsToFind) { + MethodReferencesSearch.search(methodToFind, searchScope, true).forEach(reference -> { + if (reference instanceof PsiReferenceExpression refExpr) { + PsiExpression qualifier = refExpr.getQualifierExpression(); + if (qualifier instanceof PsiSuperExpression) { + // filter super.foo() call inside foo() and similar cases (bug 8411) + PsiClass superClass = PsiUtil.resolveClassInType(qualifier.getType()); + if (originalClass.isInheritor(superClass, true)) { + return true; + } + } + if (qualifier != null && !methodToFind.isStatic()) { + PsiType qualifierType = qualifier.getType(); + if (qualifierType instanceof PsiClassType classType && + !TypeConversionUtil.isAssignable(classType, originalType) && methodToFind != method) { + PsiClass psiClass = classType.resolve(); + if (psiClass != null) { + PsiMethod callee = psiClass.findMethodBySignature(methodToFind, true); + if (callee != null && !methodsToFind.contains(callee)) { + // skip sibling methods + return true; + } + } + } + } } - } - } - } - else { - if (!(reference instanceof PsiElement)) { - return true; - } + else { + if (!(reference instanceof PsiElement element)) { + return true; + } - final PsiElement parent = ((PsiElement)reference).getParent(); - if (parent instanceof PsiNewExpression) { - if (((PsiNewExpression)parent).getClassReference() != reference) { - return true; - } - } - else if (parent instanceof PsiAnonymousClass) { - if (((PsiAnonymousClass)parent).getBaseClassReference() != reference) { - return true; - } - } - else { - return true; - } - } + PsiElement parent = element.getParent(); + if (parent instanceof PsiNewExpression newExpr) { + if (newExpr.getClassReference() != reference) { + return true; + } + } + else if (parent instanceof PsiAnonymousClass anonymousClass) { + if (anonymousClass.getBaseClassReference() != reference) { + return true; + } + } + else { + return true; + } + } - final PsiElement element = reference.getElement(); - final PsiMember key = CallHierarchyNodeDescriptor.getEnclosingElement(element); + PsiElement element = reference.getElement(); + PsiMember key = CallHierarchyNodeDescriptor.getEnclosingElement(element); - synchronized (methodToDescriptorMap) { - CallHierarchyNodeDescriptor d = methodToDescriptorMap.get(key); - if (d == null) { - d = new CallHierarchyNodeDescriptor(myProject, descriptor, element, false, true); - methodToDescriptorMap.put(key, d); - } - else if (!d.hasReference(reference)) { - d.incrementUsageCount(); - } - d.addReference(reference); - } - return true; + synchronized (methodToDescriptorMap) { + CallHierarchyNodeDescriptor d = methodToDescriptorMap.get(key); + if (d == null) { + d = new CallHierarchyNodeDescriptor(myProject, descriptor, element, false, true); + methodToDescriptorMap.put(key, d); + } + else if (!d.hasReference(reference)) { + d.incrementUsageCount(); + } + d.addReference(reference); + } + return true; + }); } - }); - } - return methodToDescriptorMap.values().toArray(new Object[methodToDescriptorMap.size()]); - } + return methodToDescriptorMap.values().toArray(new Object[methodToDescriptorMap.size()]); + } - @Override - public boolean isAlwaysShowPlus() { - return true; - } + @Override + public boolean isAlwaysShowPlus() { + return true; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/JavaCallHierarchyProvider.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/JavaCallHierarchyProvider.java index db02a622bf..0e7a971977 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/JavaCallHierarchyProvider.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/call/JavaCallHierarchyProvider.java @@ -17,6 +17,7 @@ import com.intellij.java.language.JavaLanguage; import com.intellij.java.language.psi.PsiMethod; +import consulo.annotation.access.RequiredReadAction; import consulo.annotation.component.ExtensionImpl; import consulo.dataContext.DataContext; import consulo.ide.impl.idea.ide.hierarchy.CallHierarchyBrowserBase; @@ -34,29 +35,32 @@ */ @ExtensionImpl public class JavaCallHierarchyProvider implements CallHierarchyProvider { - @Override - public PsiElement getTarget(@Nonnull final DataContext dataContext) { - final Project project = dataContext.getData(Project.KEY); - if (project == null) return null; + @Override + public PsiElement getTarget(@Nonnull DataContext dataContext) { + Project project = dataContext.getData(Project.KEY); + if (project == null) { + return null; + } - final PsiElement element = dataContext.getData(PsiElement.KEY); - return PsiTreeUtil.getParentOfType(element, PsiMethod.class, false); - } + PsiElement element = dataContext.getData(PsiElement.KEY); + return PsiTreeUtil.getParentOfType(element, PsiMethod.class, false); + } - @Override - @Nonnull - public HierarchyBrowser createHierarchyBrowser(final PsiElement target) { - return new CallHierarchyBrowser(target.getProject(), (PsiMethod) target); - } + @Override + @Nonnull + public HierarchyBrowser createHierarchyBrowser(PsiElement target) { + return new CallHierarchyBrowser(target.getProject(), (PsiMethod)target); + } - @Override - public void browserActivated(@Nonnull final HierarchyBrowser hierarchyBrowser) { - ((CallHierarchyBrowser) hierarchyBrowser).changeView(CallHierarchyBrowserBase.CALLER_TYPE); - } + @Override + @RequiredReadAction + public void browserActivated(@Nonnull HierarchyBrowser hierarchyBrowser) { + ((CallHierarchyBrowser)hierarchyBrowser).changeView(CallHierarchyBrowserBase.CALLER_TYPE); + } - @Nonnull - @Override - public Language getLanguage() { - return JavaLanguage.INSTANCE; - } + @Nonnull + @Override + public Language getLanguage() { + return JavaLanguage.INSTANCE; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/ImplementMethodAction.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/ImplementMethodAction.java index 157b749d74..030bcf5e84 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/ImplementMethodAction.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/ImplementMethodAction.java @@ -19,15 +19,16 @@ import consulo.ui.ex.action.Presentation; public final class ImplementMethodAction extends OverrideImplementMethodAction { - protected final void update(final Presentation presentation, final int toImplement, final int toOverride) { - if (toImplement > 0) { - presentation.setEnabled(true); - presentation.setVisible(true); - presentation.setTextValue(toImplement == 1 ? IdeLocalize.actionImplementMethod() : IdeLocalize.actionImplementMethods()); + @Override + protected final void update(Presentation presentation, int toImplement, int toOverride) { + if (toImplement > 0) { + presentation.setEnabled(true); + presentation.setVisible(true); + presentation.setTextValue(toImplement == 1 ? IdeLocalize.actionImplementMethod() : IdeLocalize.actionImplementMethods()); + } + else { + presentation.setEnabled(false); + presentation.setVisible(false); + } } - else { - presentation.setEnabled(false); - presentation.setVisible(false); - } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/JavaMethodHierarchyProvider.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/JavaMethodHierarchyProvider.java index b9076cd24e..d812953e28 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/JavaMethodHierarchyProvider.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/JavaMethodHierarchyProvider.java @@ -19,7 +19,6 @@ import com.intellij.java.language.psi.JavaTokenType; import com.intellij.java.language.psi.PsiJavaToken; import com.intellij.java.language.psi.PsiMethod; -import com.intellij.java.language.psi.PsiModifier; import consulo.annotation.access.RequiredReadAction; import consulo.annotation.component.ExtensionImpl; import consulo.codeEditor.Editor; @@ -34,7 +33,6 @@ import consulo.language.psi.PsiWhiteSpace; import consulo.language.psi.util.PsiTreeUtil; import consulo.project.Project; - import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; @@ -43,75 +41,76 @@ */ @ExtensionImpl public class JavaMethodHierarchyProvider implements MethodHierarchyProvider { - @RequiredReadAction - public PsiElement getTarget(@Nonnull final DataContext dataContext) { - final PsiMethod method = getMethodImpl(dataContext); - if (method != null && method.getContainingClass() != null && !method.hasModifierProperty(PsiModifier.PRIVATE) - && !method.hasModifierProperty(PsiModifier.STATIC)) { - return method; - } else { - return null; - } - } - - @RequiredReadAction - @Nullable - private static PsiMethod getMethodImpl(final DataContext dataContext) { - final Project project = dataContext.getData(Project.KEY); - if (project == null) { - return null; + @Override + @RequiredReadAction + public PsiElement getTarget(@Nonnull DataContext dataContext) { + PsiMethod method = getMethodImpl(dataContext); + if (method != null && method.getContainingClass() != null && !method.isPrivate() && !method.isStatic()) { + return method; + } + return null; } - PsiElement element = dataContext.getData(PsiElement.KEY); - final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class, false); - - if (method != null) { - return method; + @RequiredReadAction + @Nullable + private static PsiMethod getMethodImpl(DataContext dataContext) { + Project project = dataContext.getData(Project.KEY); + if (project == null) { + return null; + } + + PsiElement element = dataContext.getData(PsiElement.KEY); + PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class, false); + + if (method != null) { + return method; + } + + Editor editor = dataContext.getData(Editor.KEY); + if (editor == null) { + return null; + } + + PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); + if (psiFile == null) { + return null; + } + + PsiDocumentManager.getInstance(project).commitAllDocuments(); + + int offset = editor.getCaretModel().getOffset(); + if (offset < 1) { + return null; + } + + element = psiFile.findElementAt(offset); + if (!(element instanceof PsiWhiteSpace)) { + return null; + } + + element = psiFile.findElementAt(offset - 1); + if (!(element instanceof PsiJavaToken javaToken && javaToken.getTokenType() == JavaTokenType.SEMICOLON)) { + return null; + } + + return PsiTreeUtil.getParentOfType(element, PsiMethod.class, false); } - final Editor editor = dataContext.getData(Editor.KEY); - if (editor == null) { - return null; + @Nonnull + @Override + public HierarchyBrowser createHierarchyBrowser(PsiElement target) { + return new MethodHierarchyBrowser(target.getProject(), (PsiMethod)target); } - final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); - if (psiFile == null) { - return null; - } - - PsiDocumentManager.getInstance(project).commitAllDocuments(); - - final int offset = editor.getCaretModel().getOffset(); - if (offset < 1) { - return null; + @Override + @RequiredReadAction + public void browserActivated(@Nonnull HierarchyBrowser hierarchyBrowser) { + ((MethodHierarchyBrowser)hierarchyBrowser).changeView(MethodHierarchyBrowserBase.METHOD_TYPE); } - element = psiFile.findElementAt(offset); - if (!(element instanceof PsiWhiteSpace)) { - return null; + @Nonnull + @Override + public Language getLanguage() { + return JavaLanguage.INSTANCE; } - - element = psiFile.findElementAt(offset - 1); - if (!(element instanceof PsiJavaToken javaToken && javaToken.getTokenType() == JavaTokenType.SEMICOLON)) { - return null; - } - - return PsiTreeUtil.getParentOfType(element, PsiMethod.class, false); - } - - @Nonnull - public HierarchyBrowser createHierarchyBrowser(final PsiElement target) { - return new MethodHierarchyBrowser(target.getProject(), (PsiMethod) target); - } - - @RequiredReadAction - public void browserActivated(@Nonnull final HierarchyBrowser hierarchyBrowser) { - ((MethodHierarchyBrowser) hierarchyBrowser).changeView(MethodHierarchyBrowserBase.METHOD_TYPE); - } - - @Nonnull - @Override - public Language getLanguage() { - return JavaLanguage.INSTANCE; - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyBrowser.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyBrowser.java index da1d1dd131..0f27652dce 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyBrowser.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyBrowser.java @@ -38,61 +38,66 @@ import java.util.Map; public class MethodHierarchyBrowser extends MethodHierarchyBrowserBase { - private static final Logger LOG = Logger.getInstance(MethodHierarchyBrowser.class); + private static final Logger LOG = Logger.getInstance(MethodHierarchyBrowser.class); - public MethodHierarchyBrowser(final Project project, final PsiMethod method) { - super(project, method); - } - - protected void createTrees(@Nonnull Map trees) { - final JTree tree = createTree(false); - ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_METHOD_HIERARCHY_POPUP); - PopupHandler.installPopupHandler(tree, group, ActionPlaces.METHOD_HIERARCHY_VIEW_POPUP, ActionManager.getInstance()); + public MethodHierarchyBrowser(Project project, PsiMethod method) { + super(project, method); + } - final BaseOnThisMethodAction baseOnThisMethodAction = new BaseOnThisMethodAction(); - baseOnThisMethodAction - .registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_METHOD_HIERARCHY).getShortcutSet(), tree); + @Override + protected void createTrees(@Nonnull Map trees) { + JTree tree = createTree(false); + ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_METHOD_HIERARCHY_POPUP); + PopupHandler.installPopupHandler(tree, group, ActionPlaces.METHOD_HIERARCHY_VIEW_POPUP, ActionManager.getInstance()); - trees.put(METHOD_TYPE, tree); - } + BaseOnThisMethodAction baseOnThisMethodAction = new BaseOnThisMethodAction(); + baseOnThisMethodAction + .registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_METHOD_HIERARCHY).getShortcutSet(), tree); - protected JPanel createLegendPanel() { - return createStandardLegendPanel( - IdeLocalize.hierarchyLegendMethodIsDefinedInClass().get(), - IdeLocalize.hierarchyLegendMethodDefinedInSuperclass().get(), - IdeLocalize.hierarchyLegendMethodShouldBeDefined().get() - ); - } + trees.put(METHOD_TYPE, tree); + } + @Override + protected JPanel createLegendPanel() { + return createStandardLegendPanel( + IdeLocalize.hierarchyLegendMethodIsDefinedInClass().get(), + IdeLocalize.hierarchyLegendMethodDefinedInSuperclass().get(), + IdeLocalize.hierarchyLegendMethodShouldBeDefined().get() + ); + } - protected PsiElement getElementFromDescriptor(@Nonnull final HierarchyNodeDescriptor descriptor) { - return descriptor instanceof MethodHierarchyNodeDescriptor methodHierarchyNodeDescriptor - ? methodHierarchyNodeDescriptor.getTargetElement() : null; - } + @Override + protected PsiElement getElementFromDescriptor(@Nonnull HierarchyNodeDescriptor descriptor) { + return descriptor instanceof MethodHierarchyNodeDescriptor methodHierarchyNodeDescriptor + ? methodHierarchyNodeDescriptor.getTargetElement() : null; + } - protected boolean isApplicableElement(@Nonnull final PsiElement psiElement) { - return psiElement instanceof PsiMethod; - } + @Override + protected boolean isApplicableElement(@Nonnull PsiElement psiElement) { + return psiElement instanceof PsiMethod; + } - protected HierarchyTreeStructure createHierarchyTreeStructure(@Nonnull final String typeName, @Nonnull final PsiElement psiElement) { - if (!METHOD_TYPE.equals(typeName)) { - LOG.error("unexpected type: " + typeName); - return null; + @Override + protected HierarchyTreeStructure createHierarchyTreeStructure(@Nonnull String typeName, @Nonnull PsiElement psiElement) { + if (!METHOD_TYPE.equals(typeName)) { + LOG.error("unexpected type: " + typeName); + return null; + } + return new MethodHierarchyTreeStructure(myProject, (PsiMethod)psiElement); } - return new MethodHierarchyTreeStructure(myProject, (PsiMethod)psiElement); - } - protected Comparator getComparator() { - return JavaHierarchyUtil.getComparator(myProject); - } + @Override + protected Comparator getComparator() { + return JavaHierarchyUtil.getComparator(myProject); + } - public PsiMethod getBaseMethod() { - final HierarchyTreeBuilder builder = myBuilders.get(myCurrentViewType); - final MethodHierarchyTreeStructure treeStructure = (MethodHierarchyTreeStructure)builder.getTreeStructure(); - return treeStructure.getBaseMethod(); - } + public PsiMethod getBaseMethod() { + HierarchyTreeBuilder builder = myBuilders.get(myCurrentViewType); + MethodHierarchyTreeStructure treeStructure = (MethodHierarchyTreeStructure)builder.getTreeStructure(); + return treeStructure.getBaseMethod(); + } - public static final class BaseOnThisMethodAction extends MethodHierarchyBrowserBase.BaseOnThisMethodAction { - } + public static final class BaseOnThisMethodAction extends MethodHierarchyBrowserBase.BaseOnThisMethodAction { + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyNodeDescriptor.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyNodeDescriptor.java index 2acc7a54a5..c3d174f0dd 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyNodeDescriptor.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyNodeDescriptor.java @@ -20,8 +20,6 @@ import com.intellij.java.language.psi.PsiClass; import com.intellij.java.language.psi.PsiFunctionalExpression; import com.intellij.java.language.psi.PsiMethod; -import com.intellij.java.language.psi.PsiModifier; -import consulo.application.AllIcons; import consulo.colorScheme.TextAttributes; import consulo.component.util.Iconable; import consulo.ide.impl.idea.ide.hierarchy.HierarchyNodeDescriptor; @@ -29,6 +27,7 @@ import consulo.ide.localize.IdeLocalize; import consulo.language.icon.IconDescriptorUpdaters; import consulo.language.psi.PsiElement; +import consulo.platform.base.icon.PlatformIconGroup; import consulo.project.Project; import consulo.ui.annotation.RequiredUIAccess; import consulo.ui.image.Image; @@ -37,159 +36,139 @@ import java.awt.*; -public final class MethodHierarchyNodeDescriptor extends HierarchyNodeDescriptor -{ - private Image myRawIcon; - private Image myStateIcon; - private MethodHierarchyTreeStructure myTreeStructure; - - public MethodHierarchyNodeDescriptor( - final Project project, - final HierarchyNodeDescriptor parentDescriptor, - final PsiElement aClass, - final boolean isBase, - final MethodHierarchyTreeStructure treeStructure - ) { - super(project, parentDescriptor, aClass, isBase); - myTreeStructure = treeStructure; - } - - public final void setTreeStructure(final MethodHierarchyTreeStructure treeStructure) - { - myTreeStructure = treeStructure; - } - - PsiMethod getMethod(final PsiClass aClass, final boolean checkBases) - { - return MethodHierarchyUtil.findBaseMethodInClass(myTreeStructure.getBaseMethod(), aClass, checkBases); - } - - public final PsiElement getPsiClass() - { - return getPsiElement(); - } - - /** - * Element for OpenFileDescriptor - */ - public final PsiElement getTargetElement() - { - final PsiElement element = getPsiClass(); - if (!(element instanceof PsiClass)) - { - return element; - } - final PsiClass aClass = (PsiClass) getPsiClass(); - if (!aClass.isValid()) - { - return null; - } - final PsiMethod method = getMethod(aClass, false); - if (method != null) - { - return method; - } - return aClass; - } - - @Override - @RequiredUIAccess - public final boolean update() - { - int flags = Iconable.ICON_FLAG_VISIBILITY; - if (isMarkReadOnly()) - { - flags |= Iconable.ICON_FLAG_READ_STATUS; - } - - boolean changes = super.update(); - - final PsiElement aClass = getPsiClass(); - - if (aClass == null) - { - final String invalidPrefix = IdeLocalize.nodeHierarchyInvalid().get(); - if (!myHighlightedText.getText().startsWith(invalidPrefix)) - { - myHighlightedText.getBeginning().addText(invalidPrefix, HierarchyNodeDescriptor.getInvalidPrefixAttributes()); - } - return true; - } - - final Image newRawIcon = IconDescriptorUpdaters.getIcon(aClass, flags); - final Image newStateIcon = aClass instanceof PsiClass psiClass ? calculateState(psiClass) : AllIcons.Hierarchy.MethodDefined; - - if (changes || newRawIcon != myRawIcon || newStateIcon != myStateIcon) - { - changes = true; - - myRawIcon = newRawIcon; - myStateIcon = newStateIcon; - - Image newIcon = myRawIcon; - - if (myIsBase) - { - newIcon = ImageEffects.appendRight(AllIcons.Hierarchy.Base, newIcon); - } - - if (myStateIcon != null) - { - newIcon = ImageEffects.appendRight(myStateIcon, newIcon); - } - - setIcon(newIcon); - } - - final CompositeAppearance oldText = myHighlightedText; - - myHighlightedText = new CompositeAppearance(); - TextAttributes classNameAttributes = null; - if (myColor != null) - { - classNameAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN); - } - if (aClass instanceof PsiClass psiClass) - { - myHighlightedText.getEnding().addText(ClassPresentationUtil.getNameForClass(psiClass, false), classNameAttributes); - myHighlightedText.getEnding().addText( - " (" + JavaHierarchyUtil.getPackageName(psiClass) + ")", - HierarchyNodeDescriptor.getPackageNameAttributes() - ); - } - else if (aClass instanceof PsiFunctionalExpression functionalExpression) - { - myHighlightedText.getEnding().addText(ClassPresentationUtil.getFunctionalExpressionPresentation(functionalExpression, false)); - } - myName = myHighlightedText.getText(); - - if (!Comparing.equal(myHighlightedText, oldText)) - { - changes = true; - } - return changes; - } - - private Image calculateState(final PsiClass psiClass) - { - final PsiMethod method = getMethod(psiClass, false); - if (method != null) - { - return method.hasModifierProperty(PsiModifier.ABSTRACT) ? null : AllIcons.Hierarchy.MethodDefined; - } - - if (myTreeStructure.isSuperClassForBaseClass(psiClass)) - { - return AllIcons.Hierarchy.MethodNotDefined; - } - - final boolean isAbstractClass = psiClass.hasModifierProperty(PsiModifier.ABSTRACT); - - // was it implemented is in superclasses? - final PsiMethod baseClassMethod = getMethod(psiClass, true); - - final boolean hasBaseImplementation = baseClassMethod != null && !baseClassMethod.hasModifierProperty(PsiModifier.ABSTRACT); - - return hasBaseImplementation || isAbstractClass ? AllIcons.Hierarchy.MethodNotDefined : AllIcons.Hierarchy.ShouldDefineMethod; - } +public final class MethodHierarchyNodeDescriptor extends HierarchyNodeDescriptor { + private Image myRawIcon; + private Image myStateIcon; + private MethodHierarchyTreeStructure myTreeStructure; + + public MethodHierarchyNodeDescriptor( + Project project, + HierarchyNodeDescriptor parentDescriptor, + PsiElement aClass, + boolean isBase, + MethodHierarchyTreeStructure treeStructure + ) { + super(project, parentDescriptor, aClass, isBase); + myTreeStructure = treeStructure; + } + + public final void setTreeStructure(MethodHierarchyTreeStructure treeStructure) { + myTreeStructure = treeStructure; + } + + PsiMethod getMethod(PsiClass aClass, boolean checkBases) { + return MethodHierarchyUtil.findBaseMethodInClass(myTreeStructure.getBaseMethod(), aClass, checkBases); + } + + public final PsiElement getPsiClass() { + return getPsiElement(); + } + + /** + * Element for OpenFileDescriptor + */ + public final PsiElement getTargetElement() { + PsiElement element = getPsiClass(); + if (!(element instanceof PsiClass aClass)) { + return element; + } + if (!aClass.isValid()) { + return null; + } + PsiMethod method = getMethod(aClass, false); + if (method != null) { + return method; + } + return aClass; + } + + @Override + @RequiredUIAccess + public final boolean update() { + int flags = Iconable.ICON_FLAG_VISIBILITY; + if (isMarkReadOnly()) { + flags |= Iconable.ICON_FLAG_READ_STATUS; + } + + boolean changes = super.update(); + + PsiElement aClass = getPsiClass(); + + if (aClass == null) { + String invalidPrefix = IdeLocalize.nodeHierarchyInvalid().get(); + if (!myHighlightedText.getText().startsWith(invalidPrefix)) { + myHighlightedText.getBeginning().addText(invalidPrefix, HierarchyNodeDescriptor.getInvalidPrefixAttributes()); + } + return true; + } + + Image newRawIcon = IconDescriptorUpdaters.getIcon(aClass, flags); + Image newStateIcon = aClass instanceof PsiClass psiClass ? calculateState(psiClass) : PlatformIconGroup.hierarchyMethoddefined(); + + if (changes || newRawIcon != myRawIcon || newStateIcon != myStateIcon) { + changes = true; + + myRawIcon = newRawIcon; + myStateIcon = newStateIcon; + + Image newIcon = myRawIcon; + + if (myIsBase) { + newIcon = ImageEffects.appendRight(PlatformIconGroup.hierarchyBase(), newIcon); + } + + if (myStateIcon != null) { + newIcon = ImageEffects.appendRight(myStateIcon, newIcon); + } + + setIcon(newIcon); + } + + CompositeAppearance oldText = myHighlightedText; + + myHighlightedText = new CompositeAppearance(); + TextAttributes classNameAttributes = null; + if (myColor != null) { + classNameAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN); + } + if (aClass instanceof PsiClass psiClass) { + myHighlightedText.getEnding().addText(ClassPresentationUtil.getNameForClass(psiClass, false), classNameAttributes); + myHighlightedText.getEnding().addText( + " (" + JavaHierarchyUtil.getPackageName(psiClass) + ")", + HierarchyNodeDescriptor.getPackageNameAttributes() + ); + } + else if (aClass instanceof PsiFunctionalExpression functionalExpression) { + myHighlightedText.getEnding() + .addText(ClassPresentationUtil.getFunctionalExpressionPresentation(functionalExpression, false)); + } + myName = myHighlightedText.getText(); + + if (!Comparing.equal(myHighlightedText, oldText)) { + changes = true; + } + return changes; + } + + private Image calculateState(PsiClass psiClass) { + PsiMethod method = getMethod(psiClass, false); + if (method != null) { + return method.isAbstract() ? null : PlatformIconGroup.hierarchyMethoddefined(); + } + + if (myTreeStructure.isSuperClassForBaseClass(psiClass)) { + return PlatformIconGroup.hierarchyMethodnotdefined(); + } + + boolean isAbstractClass = psiClass.isAbstract(); + + // was it implemented is in superclasses? + PsiMethod baseClassMethod = getMethod(psiClass, true); + + boolean hasBaseImplementation = baseClassMethod != null && !baseClassMethod.isAbstract(); + + return hasBaseImplementation || isAbstractClass + ? PlatformIconGroup.hierarchyMethodnotdefined() + : PlatformIconGroup.hierarchyShoulddefinemethod(); + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyTreeStructure.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyTreeStructure.java index bbd0ecca1b..1b0683f514 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyTreeStructure.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyTreeStructure.java @@ -15,282 +15,243 @@ */ package com.intellij.java.impl.ide.hierarchy.method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import jakarta.annotation.Nonnull; +import com.intellij.java.indexing.search.searches.ClassInheritorsSearch; +import com.intellij.java.indexing.search.searches.FunctionalExpressionSearch; +import com.intellij.java.language.psi.*; +import consulo.annotation.access.RequiredReadAction; import consulo.ide.impl.idea.ide.hierarchy.HierarchyBrowserManager; import consulo.ide.impl.idea.ide.hierarchy.HierarchyNodeDescriptor; import consulo.ide.impl.idea.ide.hierarchy.HierarchyTreeStructure; -import com.intellij.java.language.psi.*; +import consulo.java.language.module.util.JavaClassNames; +import consulo.language.psi.PsiElement; +import consulo.language.psi.SmartPointerManager; +import consulo.language.psi.SmartPsiElementPointer; import consulo.project.Project; -import consulo.language.psi.*; -import com.intellij.java.indexing.search.searches.ClassInheritorsSearch; -import com.intellij.java.indexing.search.searches.FunctionalExpressionSearch; import consulo.util.collection.ArrayUtil; -import consulo.application.util.function.Processor; -import consulo.java.language.module.util.JavaClassNames; +import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; -public final class MethodHierarchyTreeStructure extends HierarchyTreeStructure -{ - private final SmartPsiElementPointer myMethod; - - /** - * Should be called in read action - */ - public MethodHierarchyTreeStructure(final Project project, final PsiMethod method) - { - super(project, null); - myBaseDescriptor = buildHierarchyElement(project, method); - ((MethodHierarchyNodeDescriptor) myBaseDescriptor).setTreeStructure(this); - myMethod = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(method); - setBaseElement(myBaseDescriptor); //to set myRoot - } - - private HierarchyNodeDescriptor buildHierarchyElement(final Project project, final PsiMethod method) - { - final PsiClass suitableBaseClass = findSuitableBaseClass(method); - - HierarchyNodeDescriptor descriptor = null; - final ArrayList superClasses = createSuperClasses(suitableBaseClass); - - if(!suitableBaseClass.equals(method.getContainingClass())) - { - superClasses.add(0, suitableBaseClass); - } - - // remove from the top of the branch the classes that contain no 'method' - for(int i = superClasses.size() - 1; i >= 0; i--) - { - final PsiClass psiClass = superClasses.get(i); - - if(MethodHierarchyUtil.findBaseMethodInClass(method, psiClass, false) == null) - { - superClasses.remove(i); - } - else - { - break; - } - } - - for(int i = superClasses.size() - 1; i >= 0; i--) - { - final PsiClass superClass = superClasses.get(i); - final HierarchyNodeDescriptor newDescriptor = new MethodHierarchyNodeDescriptor(project, descriptor, superClass, false, this); - if(descriptor != null) - { - descriptor.setCachedChildren(new HierarchyNodeDescriptor[]{newDescriptor}); - } - descriptor = newDescriptor; - } - final HierarchyNodeDescriptor newDescriptor = new MethodHierarchyNodeDescriptor(project, descriptor, method.getContainingClass(), true, this); - if(descriptor != null) - { - descriptor.setCachedChildren(new HierarchyNodeDescriptor[]{newDescriptor}); - } - return newDescriptor; - } - - private static ArrayList createSuperClasses(PsiClass aClass) - { - if(!aClass.isValid()) - { - return new ArrayList(); - } - - final ArrayList superClasses = new ArrayList(); - while(!isJavaLangObject(aClass)) - { - final PsiClass aClass1 = aClass; - final PsiClass[] superTypes = aClass1.getSupers(); - PsiClass superType = null; - // find class first - for(final PsiClass type : superTypes) - { - if(!type.isInterface() && !isJavaLangObject(type)) - { - superType = type; - break; - } - } - // if we haven't found a class, try to find an interface - if(superType == null) - { - for(final PsiClass type : superTypes) - { - if(!isJavaLangObject(type)) - { - superType = type; - break; - } - } - } - if(superType == null) - { - break; - } - if(superClasses.contains(superType)) - { - break; - } - superClasses.add(superType); - aClass = superType; - } - - return superClasses; - } - - private static boolean isJavaLangObject(final PsiClass aClass) - { - return JavaClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName()); - } - - private static PsiClass findSuitableBaseClass(final PsiMethod method) - { - final PsiClass containingClass = method.getContainingClass(); - - if(containingClass instanceof PsiAnonymousClass) - { - return containingClass; - } - - final PsiClass superClass = containingClass.getSuperClass(); - if(superClass == null) - { - return containingClass; - } - - if(MethodHierarchyUtil.findBaseMethodInClass(method, superClass, true) == null) - { - for(final PsiClass anInterface : containingClass.getInterfaces()) - { - if(MethodHierarchyUtil.findBaseMethodInClass(method, anInterface, true) != null) - { - return anInterface; - } - } - } - - return containingClass; - } - - @Nullable - public final PsiMethod getBaseMethod() - { - final PsiElement element = myMethod.getElement(); - return element instanceof PsiMethod ? (PsiMethod) element : null; - } - - - @Nonnull - @Override - protected final Object[] buildChildren(@Nonnull final HierarchyNodeDescriptor descriptor) - { - final PsiElement psiElement = ((MethodHierarchyNodeDescriptor) descriptor).getPsiClass(); - if(!(psiElement instanceof PsiClass)) - { - return ArrayUtil.EMPTY_OBJECT_ARRAY; - } - final PsiClass psiClass = (PsiClass) psiElement; - final Collection subclasses = getSubclasses(psiClass); - - final List descriptors = new ArrayList(subclasses.size()); - for(final PsiClass aClass : subclasses) - { - if(HierarchyBrowserManager.getInstance(myProject).getState().HIDE_CLASSES_WHERE_METHOD_NOT_IMPLEMENTED) - { - if(shouldHideClass(aClass)) - { - continue; - } - } - - final MethodHierarchyNodeDescriptor d = new MethodHierarchyNodeDescriptor(myProject, descriptor, aClass, false, this); - descriptors.add(d); - } - - final PsiMethod existingMethod = ((MethodHierarchyNodeDescriptor) descriptor).getMethod(psiClass, false); - if(existingMethod != null) - { - FunctionalExpressionSearch.search(existingMethod).forEach(new Processor() - { - @Override - public boolean process(PsiFunctionalExpression expression) - { - descriptors.add(new MethodHierarchyNodeDescriptor(myProject, descriptor, expression, false, MethodHierarchyTreeStructure.this)); - return true; - } - }); - } - - return descriptors.toArray(new HierarchyNodeDescriptor[descriptors.size()]); - } - - private static Collection getSubclasses(final PsiClass psiClass) - { - if(psiClass instanceof PsiAnonymousClass || psiClass.hasModifierProperty(PsiModifier.FINAL)) - { - return Collections.emptyList(); - } - - return ClassInheritorsSearch.search(psiClass, false).findAll(); - } - - private boolean shouldHideClass(final PsiClass psiClass) - { - if(getMethod(psiClass, false) != null || isSuperClassForBaseClass(psiClass)) - { - return false; - } - - if(hasBaseClassMethod(psiClass) || isAbstract(psiClass)) - { - for(final PsiClass subclass : getSubclasses(psiClass)) - { - if(!shouldHideClass(subclass)) - { - return false; - } - } - return true; - } - - return false; - } - - private boolean isAbstract(final PsiModifierListOwner owner) - { - return owner.hasModifierProperty(PsiModifier.ABSTRACT); - } - - private boolean hasBaseClassMethod(final PsiClass psiClass) - { - final PsiMethod baseClassMethod = getMethod(psiClass, true); - return baseClassMethod != null && !isAbstract(baseClassMethod); - } - - private PsiMethod getMethod(final PsiClass aClass, final boolean checkBases) - { - return MethodHierarchyUtil.findBaseMethodInClass(getBaseMethod(), aClass, checkBases); - } - - boolean isSuperClassForBaseClass(final PsiClass aClass) - { - final PsiMethod baseMethod = getBaseMethod(); - if(baseMethod == null) - { - return false; - } - final PsiClass baseClass = baseMethod.getContainingClass(); - if(baseClass == null) - { - return false; - } - // NB: parameters here are at CORRECT places!!! - return baseClass.isInheritor(aClass, true); - } +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public final class MethodHierarchyTreeStructure extends HierarchyTreeStructure { + private final SmartPsiElementPointer myMethod; + + /** + * Should be called in read action + */ + public MethodHierarchyTreeStructure(Project project, PsiMethod method) { + super(project, null); + myBaseDescriptor = buildHierarchyElement(project, method); + ((MethodHierarchyNodeDescriptor)myBaseDescriptor).setTreeStructure(this); + myMethod = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(method); + setBaseElement(myBaseDescriptor); //to set myRoot + } + + private HierarchyNodeDescriptor buildHierarchyElement(Project project, PsiMethod method) { + PsiClass suitableBaseClass = findSuitableBaseClass(method); + + HierarchyNodeDescriptor descriptor = null; + ArrayList superClasses = createSuperClasses(suitableBaseClass); + + if (!suitableBaseClass.equals(method.getContainingClass())) { + superClasses.add(0, suitableBaseClass); + } + + // remove from the top of the branch the classes that contain no 'method' + for (int i = superClasses.size() - 1; i >= 0; i--) { + PsiClass psiClass = superClasses.get(i); + + if (MethodHierarchyUtil.findBaseMethodInClass(method, psiClass, false) == null) { + superClasses.remove(i); + } + else { + break; + } + } + + for (int i = superClasses.size() - 1; i >= 0; i--) { + PsiClass superClass = superClasses.get(i); + HierarchyNodeDescriptor newDescriptor = + new MethodHierarchyNodeDescriptor(project, descriptor, superClass, false, this); + if (descriptor != null) { + descriptor.setCachedChildren(new HierarchyNodeDescriptor[]{newDescriptor}); + } + descriptor = newDescriptor; + } + HierarchyNodeDescriptor newDescriptor = + new MethodHierarchyNodeDescriptor(project, descriptor, method.getContainingClass(), true, this); + if (descriptor != null) { + descriptor.setCachedChildren(new HierarchyNodeDescriptor[]{newDescriptor}); + } + return newDescriptor; + } + + private static ArrayList createSuperClasses(PsiClass aClass) { + if (!aClass.isValid()) { + return new ArrayList<>(); + } + + ArrayList superClasses = new ArrayList<>(); + while (!isJavaLangObject(aClass)) { + PsiClass aClass1 = aClass; + PsiClass[] superTypes = aClass1.getSupers(); + PsiClass superType = null; + // find class first + for (PsiClass type : superTypes) { + if (!type.isInterface() && !isJavaLangObject(type)) { + superType = type; + break; + } + } + // if we haven't found a class, try to find an interface + if (superType == null) { + for (PsiClass type : superTypes) { + if (!isJavaLangObject(type)) { + superType = type; + break; + } + } + } + if (superType == null) { + break; + } + if (superClasses.contains(superType)) { + break; + } + superClasses.add(superType); + aClass = superType; + } + + return superClasses; + } + + private static boolean isJavaLangObject(PsiClass aClass) { + return JavaClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName()); + } + + private static PsiClass findSuitableBaseClass(PsiMethod method) { + PsiClass containingClass = method.getContainingClass(); + + if (containingClass instanceof PsiAnonymousClass) { + return containingClass; + } + + PsiClass superClass = containingClass.getSuperClass(); + if (superClass == null) { + return containingClass; + } + + if (MethodHierarchyUtil.findBaseMethodInClass(method, superClass, true) == null) { + for (PsiClass anInterface : containingClass.getInterfaces()) { + if (MethodHierarchyUtil.findBaseMethodInClass(method, anInterface, true) != null) { + return anInterface; + } + } + } + + return containingClass; + } + + @Nullable + @RequiredReadAction + public final PsiMethod getBaseMethod() { + return myMethod.getElement() instanceof PsiMethod method ? method : null; + } + + @Nonnull + @Override + @RequiredReadAction + protected final Object[] buildChildren(@Nonnull HierarchyNodeDescriptor descriptor) { + PsiElement psiElement = ((MethodHierarchyNodeDescriptor)descriptor).getPsiClass(); + if (!(psiElement instanceof PsiClass psiClass)) { + return ArrayUtil.EMPTY_OBJECT_ARRAY; + } + Collection subclasses = getSubclasses(psiClass); + + List descriptors = new ArrayList<>(subclasses.size()); + for (PsiClass aClass : subclasses) { + HierarchyBrowserManager.State state = HierarchyBrowserManager.getInstance(myProject).getState(); + assert state != null; + if (state.HIDE_CLASSES_WHERE_METHOD_NOT_IMPLEMENTED && shouldHideClass(aClass)) { + continue; + } + + MethodHierarchyNodeDescriptor d = new MethodHierarchyNodeDescriptor(myProject, descriptor, aClass, false, this); + descriptors.add(d); + } + + PsiMethod existingMethod = ((MethodHierarchyNodeDescriptor)descriptor).getMethod(psiClass, false); + if (existingMethod != null) { + FunctionalExpressionSearch.search(existingMethod).forEach(expression -> { + descriptors.add(new MethodHierarchyNodeDescriptor( + myProject, + descriptor, + expression, + false, + MethodHierarchyTreeStructure.this + )); + return true; + }); + } + + return descriptors.toArray(new HierarchyNodeDescriptor[descriptors.size()]); + } + + private static Collection getSubclasses(PsiClass psiClass) { + if (psiClass instanceof PsiAnonymousClass || psiClass.isFinal()) { + return Collections.emptyList(); + } + + return ClassInheritorsSearch.search(psiClass, false).findAll(); + } + + @RequiredReadAction + private boolean shouldHideClass(PsiClass psiClass) { + if (getMethod(psiClass, false) != null || isSuperClassForBaseClass(psiClass)) { + return false; + } + + if (hasBaseClassMethod(psiClass) || isAbstract(psiClass)) { + for (PsiClass subclass : getSubclasses(psiClass)) { + if (!shouldHideClass(subclass)) { + return false; + } + } + return true; + } + + return false; + } + + private boolean isAbstract(PsiModifierListOwner owner) { + return owner.hasModifierProperty(PsiModifier.ABSTRACT); + } + + @RequiredReadAction + private boolean hasBaseClassMethod(PsiClass psiClass) { + PsiMethod baseClassMethod = getMethod(psiClass, true); + return baseClassMethod != null && !isAbstract(baseClassMethod); + } + + @RequiredReadAction + private PsiMethod getMethod(PsiClass aClass, boolean checkBases) { + return MethodHierarchyUtil.findBaseMethodInClass(getBaseMethod(), aClass, checkBases); + } + + @RequiredReadAction + boolean isSuperClassForBaseClass(PsiClass aClass) { + PsiMethod baseMethod = getBaseMethod(); + if (baseMethod == null) { + return false; + } + PsiClass baseClass = baseMethod.getContainingClass(); + if (baseClass == null) { + return false; + } + // NB: parameters here are at CORRECT places!!! + return baseClass.isInheritor(aClass, true); + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyUtil.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyUtil.java index 74692c3abc..5fc8643596 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyUtil.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/MethodHierarchyUtil.java @@ -17,25 +17,24 @@ import com.intellij.java.language.psi.PsiClass; import com.intellij.java.language.psi.PsiMethod; -import com.intellij.java.language.psi.PsiModifier; import com.intellij.java.language.psi.util.MethodSignatureUtil; final class MethodHierarchyUtil { - public static PsiMethod findBaseMethodInClass(final PsiMethod baseMethod, final PsiClass aClass, final boolean checkBases) { - if (baseMethod == null) return null; // base method is invalid - if (cannotBeOverridding(baseMethod)) return null; - /*if (!checkBases) return MethodSignatureUtil.findMethodBySignature(aClass, signature, false);*/ - return MethodSignatureUtil.findMethodBySuperMethod(aClass, baseMethod, checkBases); - /*final MethodSignatureBackedByPsiMethod signature = SuperMethodsSearch.search(baseMethod, aClass, checkBases, false).findFirst(); - return signature == null ? null : signature.getMethod();*/ - } - - private static boolean cannotBeOverridding(final PsiMethod method) { - final PsiClass parentClass = method.getContainingClass(); - return parentClass == null - || method.isConstructor() - || method.hasModifierProperty(PsiModifier.STATIC) - || method.hasModifierProperty(PsiModifier.PRIVATE); - } + public static PsiMethod findBaseMethodInClass(PsiMethod baseMethod, PsiClass aClass, boolean checkBases) { + if (baseMethod == null) { + return null; // base method is invalid + } + if (cannotBeOverridding(baseMethod)) { + return null; + } + /*if (!checkBases) return MethodSignatureUtil.findMethodBySignature(aClass, signature, false);*/ + return MethodSignatureUtil.findMethodBySuperMethod(aClass, baseMethod, checkBases); + /*MethodSignatureBackedByPsiMethod signature = SuperMethodsSearch.search(baseMethod, aClass, checkBases, false).findFirst(); + return signature == null ? null : signature.getMethod();*/ + } + private static boolean cannotBeOverridding(PsiMethod method) { + PsiClass parentClass = method.getContainingClass(); + return parentClass == null || method.isConstructor() || method.isStatic() || method.isPrivate(); + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/OverrideImplementMethodAction.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/OverrideImplementMethodAction.java index 8660ccb8c1..b5b2a27c3b 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/OverrideImplementMethodAction.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/OverrideImplementMethodAction.java @@ -29,6 +29,7 @@ import consulo.language.psi.PsiElement; import consulo.language.psi.PsiFile; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.logging.Logger; import consulo.project.Project; import consulo.project.ui.wm.ToolWindowManager; @@ -46,184 +47,151 @@ import java.util.Collection; import java.util.List; -abstract class OverrideImplementMethodAction extends AnAction -{ - private static final Logger LOG = Logger.getInstance(OverrideImplementMethodAction.class); +abstract class OverrideImplementMethodAction extends AnAction { + private static final Logger LOG = Logger.getInstance(OverrideImplementMethodAction.class); - @RequiredUIAccess - @Override - public final void actionPerformed(@Nonnull final AnActionEvent event) - { - final DataContext dataContext = event.getDataContext(); - final MethodHierarchyBrowser methodHierarchyBrowser = (MethodHierarchyBrowser) dataContext.getData(MethodHierarchyBrowserBase.DATA_KEY); - if (methodHierarchyBrowser == null) - { - return; - } - final Project project = dataContext.getData(Project.KEY); - if (project == null) - { - return; - } + @RequiredUIAccess + @Override + public final void actionPerformed(@Nonnull AnActionEvent event) { + DataContext dataContext = event.getDataContext(); + MethodHierarchyBrowser methodHierarchyBrowser = (MethodHierarchyBrowser)dataContext.getData(MethodHierarchyBrowserBase.DATA_KEY); + if (methodHierarchyBrowser == null) { + return; + } + Project project = dataContext.getData(Project.KEY); + if (project == null) { + return; + } - final String commandName = event.getPresentation().getText(); - Application.get().runWriteAction(() -> CommandProcessor.getInstance().executeCommand( - project, - new Runnable() - { - @Override - @RequiredUIAccess - public void run() - { - try - { - final HierarchyNodeDescriptor[] selectedDescriptors = methodHierarchyBrowser.getSelectedDescriptors(); - if (selectedDescriptors.length > 0) - { - final List files = new ArrayList<>(selectedDescriptors.length); - for (HierarchyNodeDescriptor selectedDescriptor : selectedDescriptors) - { - final PsiFile containingFile = ((MethodHierarchyNodeDescriptor) selectedDescriptor).getPsiClass().getContainingFile(); - if (containingFile != null) - { - final VirtualFile vFile = containingFile.getVirtualFile(); - if (vFile != null) - { - files.add(vFile); - } - } - } - final ReadonlyStatusHandler.OperationStatus status = - ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(VfsUtil.toVirtualFileArray(files)); - if (!status.hasReadonlyFiles()) - { - for (HierarchyNodeDescriptor selectedDescriptor : selectedDescriptors) - { - final PsiElement aClass = ((MethodHierarchyNodeDescriptor) selectedDescriptor).getPsiClass(); - if (aClass instanceof PsiClass psiClass) - { - OverrideImplementUtil.overrideOrImplement(psiClass, methodHierarchyBrowser.getBaseMethod()); - } - } - ToolWindowManager.getInstance(project).activateEditorComponent(); - } - else - { - Application.get().invokeLater(() -> Messages.showErrorDialog(project, status.getReadonlyFilesMessage(), commandName)); - } - } - } - catch (IncorrectOperationException e) - { - LOG.error(e); - } - } - }, - commandName, - null - )); - } + LocalizeValue commandName = event.getPresentation().getTextValue(); + CommandProcessor.getInstance().newCommand() + .project(project) + .name(commandName) + .inWriteAction() + .run(() -> { + try { + HierarchyNodeDescriptor[] selectedDescriptors = methodHierarchyBrowser.getSelectedDescriptors(); + if (selectedDescriptors.length > 0) { + List files = new ArrayList<>(selectedDescriptors.length); + for (HierarchyNodeDescriptor selectedDescriptor : selectedDescriptors) { + PsiFile containingFile = + ((MethodHierarchyNodeDescriptor)selectedDescriptor).getPsiClass().getContainingFile(); + if (containingFile != null) { + VirtualFile vFile = containingFile.getVirtualFile(); + if (vFile != null) { + files.add(vFile); + } + } + } + ReadonlyStatusHandler.OperationStatus status = + ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(VfsUtil.toVirtualFileArray(files)); + if (!status.hasReadonlyFiles()) { + for (HierarchyNodeDescriptor selectedDescriptor : selectedDescriptors) { + PsiElement aClass = ((MethodHierarchyNodeDescriptor)selectedDescriptor).getPsiClass(); + if (aClass instanceof PsiClass psiClass) { + OverrideImplementUtil.overrideOrImplement(psiClass, methodHierarchyBrowser.getBaseMethod()); + } + } + ToolWindowManager.getInstance(project).activateEditorComponent(); + } + else { + Application.get().invokeLater( + () -> Messages.showErrorDialog(project, status.getReadonlyFilesMessage(), commandName.get()) + ); + } + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + }); + } - @RequiredUIAccess - @Override - public final void update(@Nonnull final AnActionEvent e) - { - final Presentation presentation = e.getPresentation(); - final DataContext dataContext = e.getDataContext(); + @RequiredUIAccess + @Override + public final void update(@Nonnull AnActionEvent e) { + Presentation presentation = e.getPresentation(); + DataContext dataContext = e.getDataContext(); - final MethodHierarchyBrowser methodHierarchyBrowser = (MethodHierarchyBrowser) dataContext.getData(MethodHierarchyBrowserBase.DATA_KEY); - if (methodHierarchyBrowser == null) - { - presentation.setEnabled(false); - presentation.setVisible(false); - return; - } - final Project project = dataContext.getData(Project.KEY); - if (project == null) - { - presentation.setEnabled(false); - presentation.setVisible(false); - return; - } + MethodHierarchyBrowser methodHierarchyBrowser = + (MethodHierarchyBrowser)dataContext.getData(MethodHierarchyBrowserBase.DATA_KEY); + if (methodHierarchyBrowser == null) { + presentation.setEnabled(false); + presentation.setVisible(false); + return; + } + Project project = dataContext.getData(Project.KEY); + if (project == null) { + presentation.setEnabled(false); + presentation.setVisible(false); + return; + } - final HierarchyNodeDescriptor[] selectedDescriptors = methodHierarchyBrowser.getSelectedDescriptors(); - int toImplement = 0; - int toOverride = 0; + HierarchyNodeDescriptor[] selectedDescriptors = methodHierarchyBrowser.getSelectedDescriptors(); + int toImplement = 0; + int toOverride = 0; - for (final HierarchyNodeDescriptor descriptor : selectedDescriptors) - { - if (canImplementOverride((MethodHierarchyNodeDescriptor) descriptor, methodHierarchyBrowser, true)) - { - if (toOverride > 0) - { - // no mixed actions allowed - presentation.setEnabled(false); - presentation.setVisible(false); - return; - } - toImplement++; - } - else if (canImplementOverride((MethodHierarchyNodeDescriptor) descriptor, methodHierarchyBrowser, false)) - { - if (toImplement > 0) - { - // no mixed actions allowed - presentation.setEnabled(false); - presentation.setVisible(false); - return; - } - toOverride++; - } - else - { - // no action is applicable to this node - presentation.setEnabled(false); - presentation.setVisible(false); - return; - } - } + for (HierarchyNodeDescriptor descriptor : selectedDescriptors) { + if (canImplementOverride((MethodHierarchyNodeDescriptor)descriptor, methodHierarchyBrowser, true)) { + if (toOverride > 0) { + // no mixed actions allowed + presentation.setEnabled(false); + presentation.setVisible(false); + return; + } + toImplement++; + } + else if (canImplementOverride((MethodHierarchyNodeDescriptor)descriptor, methodHierarchyBrowser, false)) { + if (toImplement > 0) { + // no mixed actions allowed + presentation.setEnabled(false); + presentation.setVisible(false); + return; + } + toOverride++; + } + else { + // no action is applicable to this node + presentation.setEnabled(false); + presentation.setVisible(false); + return; + } + } - presentation.setVisible(true); + presentation.setVisible(true); - update(presentation, toImplement, toOverride); - } + update(presentation, toImplement, toOverride); + } - protected abstract void update(Presentation presentation, int toImplement, int toOverride); + protected abstract void update(Presentation presentation, int toImplement, int toOverride); - private static boolean canImplementOverride( - final MethodHierarchyNodeDescriptor descriptor, - final MethodHierarchyBrowser methodHierarchyBrowser, - final boolean toImplement - ) - { - final PsiElement psiElement = descriptor.getPsiClass(); - if (!(psiElement instanceof PsiClass)) - { - return false; - } - final PsiClass psiClass = (PsiClass) psiElement; - if (psiClass instanceof PsiSyntheticClass) - { - return false; - } - final PsiMethod baseMethod = methodHierarchyBrowser.getBaseMethod(); - if (baseMethod == null) - { - return false; - } - final MethodSignature signature = baseMethod.getSignature(PsiSubstitutor.EMPTY); + private static boolean canImplementOverride( + MethodHierarchyNodeDescriptor descriptor, + MethodHierarchyBrowser methodHierarchyBrowser, + boolean toImplement + ) { + PsiElement psiElement = descriptor.getPsiClass(); + if (!(psiElement instanceof PsiClass psiClass)) { + return false; + } + if (psiClass instanceof PsiSyntheticClass) { + return false; + } + PsiMethod baseMethod = methodHierarchyBrowser.getBaseMethod(); + if (baseMethod == null) { + return false; + } + MethodSignature signature = baseMethod.getSignature(PsiSubstitutor.EMPTY); - Collection allOriginalSignatures = toImplement - ? OverrideImplementUtil.getMethodSignaturesToImplement(psiClass) - : OverrideImplementUtil.getMethodSignaturesToOverride(psiClass); - for (final MethodSignature originalSignature : allOriginalSignatures) - { - if (originalSignature.equals(signature)) - { - return true; - } - } + Collection allOriginalSignatures = toImplement + ? OverrideImplementUtil.getMethodSignaturesToImplement(psiClass) + : OverrideImplementUtil.getMethodSignaturesToOverride(psiClass); + for (MethodSignature originalSignature : allOriginalSignatures) { + if (originalSignature.equals(signature)) { + return true; + } + } - return false; - } + return false; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/OverrideMethodAction.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/OverrideMethodAction.java index 5fb3c4766e..447014ccd3 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/OverrideMethodAction.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/method/OverrideMethodAction.java @@ -19,15 +19,16 @@ import consulo.ui.ex.action.Presentation; public final class OverrideMethodAction extends OverrideImplementMethodAction { - protected final void update(final Presentation presentation, final int toImplement, final int toOverride) { - if (toOverride > 0) { - presentation.setEnabled(true); - presentation.setVisible(true); - presentation.setTextValue(toOverride == 1 ? IdeLocalize.actionOverrideMethod() : IdeLocalize.actionOverrideMethods()); + @Override + protected final void update(Presentation presentation, int toImplement, int toOverride) { + if (toOverride > 0) { + presentation.setEnabled(true); + presentation.setVisible(true); + presentation.setTextValue(toOverride == 1 ? IdeLocalize.actionOverrideMethod() : IdeLocalize.actionOverrideMethods()); + } + else { + presentation.setEnabled(false); + presentation.setVisible(false); + } } - else { - presentation.setEnabled(false); - presentation.setVisible(false); - } - } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/JavaTypeHierarchyProvider.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/JavaTypeHierarchyProvider.java index 3faa399939..acca4af7f4 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/JavaTypeHierarchyProvider.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/JavaTypeHierarchyProvider.java @@ -20,6 +20,7 @@ import com.intellij.java.language.psi.PsiClass; import com.intellij.java.language.psi.PsiClassOwner; import com.intellij.java.language.psi.PsiSyntheticClass; +import consulo.annotation.access.RequiredReadAction; import consulo.annotation.component.ExtensionImpl; import consulo.codeEditor.Editor; import consulo.dataContext.DataContext; @@ -35,6 +36,7 @@ import consulo.ui.annotation.RequiredUIAccess; import jakarta.annotation.Nonnull; + import java.util.Set; /** @@ -42,73 +44,75 @@ */ @ExtensionImpl public class JavaTypeHierarchyProvider implements TypeHierarchyProvider { - @Override - @RequiredUIAccess - public PsiElement getTarget(@Nonnull final DataContext dataContext) { - final Project project = dataContext.getData(Project.KEY); - if (project == null) { - return null; - } + @Override + @RequiredUIAccess + public PsiElement getTarget(@Nonnull DataContext dataContext) { + Project project = dataContext.getData(Project.KEY); + if (project == null) { + return null; + } + + Editor editor = dataContext.getData(Editor.KEY); + if (editor != null) { + PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); + if (file == null) { + return null; + } - final Editor editor = dataContext.getData(Editor.KEY); - if (editor != null) { - final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); - if (file == null) { - return null; - } + PsiElement targetElement = TargetElementUtil.findTargetElement( + editor, + Set.of( + TargetElementUtilExtender.ELEMENT_NAME_ACCEPTED, + TargetElementUtilExtender.REFERENCED_ELEMENT_ACCEPTED, + TargetElementUtilExtender.LOOKUP_ITEM_ACCEPTED + ) + ); + if (targetElement instanceof PsiClass) { + return targetElement; + } - final PsiElement targetElement = TargetElementUtil.findTargetElement( - editor, - Set.of( - TargetElementUtilExtender.ELEMENT_NAME_ACCEPTED, - TargetElementUtilExtender.REFERENCED_ELEMENT_ACCEPTED, - TargetElementUtilExtender.LOOKUP_ITEM_ACCEPTED - ) - ); - if (targetElement instanceof PsiClass) { - return targetElement; - } + int offset = editor.getCaretModel().getOffset(); + PsiElement element = file.findElementAt(offset); + while (element != null) { + if (element instanceof PsiFile) { + if (!(element instanceof PsiClassOwner classOwner)) { + return null; + } + PsiClass[] classes = classOwner.getClasses(); + return classes.length == 1 ? classes[0] : null; + } + if (element instanceof PsiClass && !(element instanceof PsiAnonymousClass) && !(element instanceof PsiSyntheticClass)) { + return element; + } + element = element.getParent(); + } - final int offset = editor.getCaretModel().getOffset(); - PsiElement element = file.findElementAt(offset); - while (element != null) { - if (element instanceof PsiFile) { - if (!(element instanceof PsiClassOwner)) { return null; - } - final PsiClass[] classes = ((PsiClassOwner) element).getClasses(); - return classes.length == 1 ? classes[0] : null; } - if (element instanceof PsiClass && !(element instanceof PsiAnonymousClass) && !(element instanceof PsiSyntheticClass)) { - return element; + else { + PsiElement element = dataContext.getData(PsiElement.KEY); + return element instanceof PsiClass psiClass ? psiClass : null; } - element = element.getParent(); - } - - return null; - } else { - final PsiElement element = dataContext.getData(PsiElement.KEY); - return element instanceof PsiClass psiClass ? psiClass : null; } - } - @Override - @Nonnull - public HierarchyBrowser createHierarchyBrowser(final PsiElement target) { - return new TypeHierarchyBrowser(target.getProject(), (PsiClass) target); - } + @Override + @Nonnull + public HierarchyBrowser createHierarchyBrowser(PsiElement target) { + return new TypeHierarchyBrowser(target.getProject(), (PsiClass)target); + } - @Override - public void browserActivated(@Nonnull final HierarchyBrowser hierarchyBrowser) { - final TypeHierarchyBrowser browser = (TypeHierarchyBrowser) hierarchyBrowser; - final String typeName = browser.isInterface() - ? TypeHierarchyBrowserBase.SUBTYPES_HIERARCHY_TYPE : TypeHierarchyBrowserBase.TYPE_HIERARCHY_TYPE; - browser.changeView(typeName); - } + @Override + @RequiredReadAction + public void browserActivated(@Nonnull HierarchyBrowser hierarchyBrowser) { + TypeHierarchyBrowser browser = (TypeHierarchyBrowser)hierarchyBrowser; + String typeName = browser.isInterface() + ? TypeHierarchyBrowserBase.SUBTYPES_HIERARCHY_TYPE : TypeHierarchyBrowserBase.TYPE_HIERARCHY_TYPE; + browser.changeView(typeName); + } - @Nonnull - @Override - public Language getLanguage() { - return JavaLanguage.INSTANCE; - } + @Nonnull + @Override + public Language getLanguage() { + return JavaLanguage.INSTANCE; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/SubtypesHierarchyTreeStructure.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/SubtypesHierarchyTreeStructure.java index 6a439878dd..cdc86a51b5 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/SubtypesHierarchyTreeStructure.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/SubtypesHierarchyTreeStructure.java @@ -19,7 +19,6 @@ import com.intellij.java.indexing.search.searches.FunctionalExpressionSearch; import com.intellij.java.language.psi.PsiAnonymousClass; import com.intellij.java.language.psi.PsiClass; -import com.intellij.java.language.psi.PsiModifier; import consulo.content.scope.SearchScope; import consulo.ide.impl.idea.ide.hierarchy.HierarchyNodeDescriptor; import consulo.ide.impl.idea.ide.hierarchy.HierarchyTreeStructure; @@ -32,55 +31,45 @@ import java.util.ArrayList; import java.util.List; -public class SubtypesHierarchyTreeStructure extends HierarchyTreeStructure -{ - private final String myCurrentScopeType; +public class SubtypesHierarchyTreeStructure extends HierarchyTreeStructure { + private final String myCurrentScopeType; - protected SubtypesHierarchyTreeStructure(final Project project, final HierarchyNodeDescriptor descriptor, String currentScopeType) - { - super(project, descriptor); - myCurrentScopeType = currentScopeType; - } + protected SubtypesHierarchyTreeStructure(Project project, HierarchyNodeDescriptor descriptor, String currentScopeType) { + super(project, descriptor); + myCurrentScopeType = currentScopeType; + } - public SubtypesHierarchyTreeStructure(Project project, PsiClass psiClass, String currentScopeType) - { - super(project, new TypeHierarchyNodeDescriptor(project, null, psiClass, true)); - myCurrentScopeType = currentScopeType; - } + public SubtypesHierarchyTreeStructure(Project project, PsiClass psiClass, String currentScopeType) { + super(project, new TypeHierarchyNodeDescriptor(project, null, psiClass, true)); + myCurrentScopeType = currentScopeType; + } - @Override - @Nonnull - protected final Object[] buildChildren(@Nonnull final HierarchyNodeDescriptor descriptor) - { - final Object element = ((TypeHierarchyNodeDescriptor) descriptor).getPsiClass(); - if (!(element instanceof PsiClass)) - { - return ArrayUtil.EMPTY_OBJECT_ARRAY; - } - final PsiClass psiClass = (PsiClass) element; - if (JavaClassNames.JAVA_LANG_OBJECT.equals(psiClass.getQualifiedName())) - { - return new Object[]{IdeLocalize.nodeHierarchyJavaLangObject().get()}; - } - if (psiClass instanceof PsiAnonymousClass) - { - return ArrayUtil.EMPTY_OBJECT_ARRAY; - } - if (psiClass.hasModifierProperty(PsiModifier.FINAL)) - { - return ArrayUtil.EMPTY_OBJECT_ARRAY; - } - final SearchScope searchScope = psiClass.getUseScope().intersectWith(getSearchScope(myCurrentScopeType, psiClass)); - final List classes = new ArrayList<>(ClassInheritorsSearch.search(psiClass, searchScope, false).findAll()); - final List descriptors = new ArrayList<>(classes.size()); - for (PsiClass aClass : classes) - { - descriptors.add(new TypeHierarchyNodeDescriptor(myProject, descriptor, aClass, false)); - } - FunctionalExpressionSearch.search(psiClass, searchScope).forEach(expression -> { - descriptors.add(new TypeHierarchyNodeDescriptor(myProject, descriptor, expression, false)); - return true; - }); - return descriptors.toArray(new HierarchyNodeDescriptor[descriptors.size()]); - } + @Override + @Nonnull + protected final Object[] buildChildren(@Nonnull HierarchyNodeDescriptor descriptor) { + Object element = ((TypeHierarchyNodeDescriptor)descriptor).getPsiClass(); + if (!(element instanceof PsiClass psiClass)) { + return ArrayUtil.EMPTY_OBJECT_ARRAY; + } + if (JavaClassNames.JAVA_LANG_OBJECT.equals(psiClass.getQualifiedName())) { + return new Object[]{IdeLocalize.nodeHierarchyJavaLangObject().get()}; + } + if (psiClass instanceof PsiAnonymousClass) { + return ArrayUtil.EMPTY_OBJECT_ARRAY; + } + if (psiClass.isFinal()) { + return ArrayUtil.EMPTY_OBJECT_ARRAY; + } + SearchScope searchScope = psiClass.getUseScope().intersectWith(getSearchScope(myCurrentScopeType, psiClass)); + List classes = new ArrayList<>(ClassInheritorsSearch.search(psiClass, searchScope, false).findAll()); + List descriptors = new ArrayList<>(classes.size()); + for (PsiClass aClass : classes) { + descriptors.add(new TypeHierarchyNodeDescriptor(myProject, descriptor, aClass, false)); + } + FunctionalExpressionSearch.search(psiClass, searchScope).forEach(expression -> { + descriptors.add(new TypeHierarchyNodeDescriptor(myProject, descriptor, expression, false)); + return true; + }); + return descriptors.toArray(new HierarchyNodeDescriptor[descriptors.size()]); + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/SupertypesHierarchyTreeStructure.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/SupertypesHierarchyTreeStructure.java index bd27678fa6..3644c212c3 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/SupertypesHierarchyTreeStructure.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/SupertypesHierarchyTreeStructure.java @@ -30,42 +30,38 @@ import com.intellij.java.language.psi.util.PsiUtil; import consulo.util.collection.ArrayUtil; -public final class SupertypesHierarchyTreeStructure extends HierarchyTreeStructure -{ +public final class SupertypesHierarchyTreeStructure extends HierarchyTreeStructure { + public SupertypesHierarchyTreeStructure(Project project, PsiClass aClass) { + super(project, new TypeHierarchyNodeDescriptor(project, null, aClass, true)); + } - public SupertypesHierarchyTreeStructure(final Project project, final PsiClass aClass) - { - super(project, new TypeHierarchyNodeDescriptor(project, null, aClass, true)); - } - - @Override - @Nonnull - protected final Object[] buildChildren(@Nonnull final HierarchyNodeDescriptor descriptor) - { - final Object element = ((TypeHierarchyNodeDescriptor) descriptor).getPsiClass(); - if(element instanceof PsiClass) - { - final PsiClass psiClass = (PsiClass) element; - final PsiClass[] supers = psiClass.getSupers(); - final List descriptors = new ArrayList(); - final PsiClass objectClass = JavaPsiFacade.getInstance(myProject).findClass(JavaClassNames.JAVA_LANG_OBJECT, psiClass.getResolveScope()); - for(PsiClass aSuper : supers) - { - if(!psiClass.isInterface() || !aSuper.equals(objectClass)) - { - descriptors.add(new TypeHierarchyNodeDescriptor(myProject, descriptor, aSuper, false)); - } - } - return descriptors.toArray(new HierarchyNodeDescriptor[descriptors.size()]); - } - else if(element instanceof PsiFunctionalExpression) - { - final PsiClass functionalInterfaceClass = PsiUtil.resolveClassInType(((PsiFunctionalExpression) element).getFunctionalInterfaceType()); - if(functionalInterfaceClass != null) - { - return new HierarchyNodeDescriptor[]{new TypeHierarchyNodeDescriptor(myProject, descriptor, functionalInterfaceClass, false)}; - } - } - return ArrayUtil.EMPTY_OBJECT_ARRAY; - } + @Override + @Nonnull + protected final Object[] buildChildren(@Nonnull HierarchyNodeDescriptor descriptor) { + Object element = ((TypeHierarchyNodeDescriptor)descriptor).getPsiClass(); + if (element instanceof PsiClass psiClass) { + PsiClass[] supers = psiClass.getSupers(); + List descriptors = new ArrayList<>(); + PsiClass objectClass = + JavaPsiFacade.getInstance(myProject).findClass(JavaClassNames.JAVA_LANG_OBJECT, psiClass.getResolveScope()); + for (PsiClass aSuper : supers) { + if (!psiClass.isInterface() || !aSuper.equals(objectClass)) { + descriptors.add(new TypeHierarchyNodeDescriptor(myProject, descriptor, aSuper, false)); + } + } + return descriptors.toArray(new HierarchyNodeDescriptor[descriptors.size()]); + } + else if (element instanceof PsiFunctionalExpression funcExpr) { + PsiClass functionalInterfaceClass = PsiUtil.resolveClassInType(funcExpr.getFunctionalInterfaceType()); + if (functionalInterfaceClass != null) { + return new HierarchyNodeDescriptor[]{new TypeHierarchyNodeDescriptor( + myProject, + descriptor, + functionalInterfaceClass, + false + )}; + } + } + return ArrayUtil.EMPTY_OBJECT_ARRAY; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/TypeHierarchyBrowser.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/TypeHierarchyBrowser.java index 72adee8b61..6067c42784 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/TypeHierarchyBrowser.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/TypeHierarchyBrowser.java @@ -19,6 +19,7 @@ import java.util.Comparator; import java.util.Map; +import consulo.annotation.access.RequiredReadAction; import jakarta.annotation.Nonnull; import javax.swing.JPanel; @@ -42,127 +43,105 @@ import com.intellij.java.language.impl.psi.presentation.java.ClassPresentationUtil; import jakarta.annotation.Nullable; -public class TypeHierarchyBrowser extends TypeHierarchyBrowserBase -{ - private static final Logger LOG = Logger.getInstance(TypeHierarchyBrowser.class); - - - public TypeHierarchyBrowser(final Project project, final PsiClass psiClass) - { - super(project, psiClass); - } - - @Override - protected boolean isInterface(PsiElement psiElement) - { - return psiElement instanceof PsiClass && ((PsiClass) psiElement).isInterface(); - } - - @Override - protected void createTrees(@Nonnull Map trees) - { - createTreeAndSetupCommonActions(trees, IdeActions.GROUP_TYPE_HIERARCHY_POPUP); - } - - @Override - protected void prependActions(DefaultActionGroup actionGroup) - { - super.prependActions(actionGroup); - actionGroup.add(new ChangeScopeAction() - { - @Override - protected boolean isEnabled() - { - return !Comparing.strEqual(myCurrentViewType, SUPERTYPES_HIERARCHY_TYPE); - } - }); - } - - @Override - protected String getContentDisplayName(@Nonnull String typeName, @Nonnull PsiElement element) - { - return MessageFormat.format(typeName, ClassPresentationUtil.getNameForClass((PsiClass) element, false)); - } - - @Override - protected PsiElement getElementFromDescriptor(@Nonnull HierarchyNodeDescriptor descriptor) - { - if(!(descriptor instanceof TypeHierarchyNodeDescriptor)) - { - return null; - } - return ((TypeHierarchyNodeDescriptor) descriptor).getPsiClass(); - } - - @Override - @Nullable - protected JPanel createLegendPanel() - { - return null; - } - - @Override - protected boolean isApplicableElement(@Nonnull final PsiElement element) - { - return element instanceof PsiClass; - } - - @Override - protected Comparator getComparator() - { - return JavaHierarchyUtil.getComparator(myProject); - } - - @Override - protected HierarchyTreeStructure createHierarchyTreeStructure(@Nonnull final String typeName, @Nonnull final PsiElement psiElement) - { - if(SUPERTYPES_HIERARCHY_TYPE.equals(typeName)) - { - return new SupertypesHierarchyTreeStructure(myProject, (PsiClass) psiElement); - } - else if(SUBTYPES_HIERARCHY_TYPE.equals(typeName)) - { - return new SubtypesHierarchyTreeStructure(myProject, (PsiClass) psiElement, getCurrentScopeType()); - } - else if(TYPE_HIERARCHY_TYPE.equals(typeName)) - { - return new TypeHierarchyTreeStructure(myProject, (PsiClass) psiElement, getCurrentScopeType()); - } - else - { - LOG.error("unexpected type: " + typeName); - return null; - } - } - - @Override - protected boolean canBeDeleted(final PsiElement psiElement) - { - return psiElement instanceof PsiClass && !(psiElement instanceof PsiAnonymousClass); - } - - @Override - protected String getQualifiedName(final PsiElement psiElement) - { - if(psiElement instanceof PsiClass) - { - return ((PsiClass) psiElement).getQualifiedName(); - } - return ""; - } - - public static class BaseOnThisTypeAction extends TypeHierarchyBrowserBase.BaseOnThisTypeAction - { - protected boolean isEnabled(@Nonnull final HierarchyBrowserBaseEx browser, @Nonnull final PsiElement psiElement) - { - return super.isEnabled(browser, psiElement) && !JavaClassNames.JAVA_LANG_OBJECT.equals(((PsiClass) psiElement).getQualifiedName()); - } - } - - @Nonnull - @Override - protected TypeHierarchyBrowserBase.BaseOnThisTypeAction createBaseOnThisAction() - { - return new BaseOnThisTypeAction(); - } +public class TypeHierarchyBrowser extends TypeHierarchyBrowserBase { + private static final Logger LOG = Logger.getInstance(TypeHierarchyBrowser.class); + + public TypeHierarchyBrowser(Project project, PsiClass psiClass) { + super(project, psiClass); + } + + @Override + protected boolean isInterface(PsiElement psiElement) { + return psiElement instanceof PsiClass psiClass && psiClass.isInterface(); + } + + @Override + protected void createTrees(@Nonnull Map trees) { + createTreeAndSetupCommonActions(trees, IdeActions.GROUP_TYPE_HIERARCHY_POPUP); + } + + @Override + protected void prependActions(DefaultActionGroup actionGroup) { + super.prependActions(actionGroup); + actionGroup.add(new ChangeScopeAction() { + @Override + protected boolean isEnabled() { + return !Comparing.strEqual(myCurrentViewType, SUPERTYPES_HIERARCHY_TYPE); + } + }); + } + + @Override + @RequiredReadAction + protected String getContentDisplayName(@Nonnull String typeName, @Nonnull PsiElement element) { + return MessageFormat.format(typeName, ClassPresentationUtil.getNameForClass((PsiClass)element, false)); + } + + @Override + protected PsiElement getElementFromDescriptor(@Nonnull HierarchyNodeDescriptor descriptor) { + if (descriptor instanceof TypeHierarchyNodeDescriptor nodeDescriptor) { + return nodeDescriptor.getPsiClass(); + } + return null; + } + + @Override + @Nullable + protected JPanel createLegendPanel() { + return null; + } + + @Override + protected boolean isApplicableElement(@Nonnull PsiElement element) { + return element instanceof PsiClass; + } + + @Override + protected Comparator getComparator() { + return JavaHierarchyUtil.getComparator(myProject); + } + + @Override + protected HierarchyTreeStructure createHierarchyTreeStructure(@Nonnull String typeName, @Nonnull PsiElement psiElement) { + if (SUPERTYPES_HIERARCHY_TYPE.equals(typeName)) { + return new SupertypesHierarchyTreeStructure(myProject, (PsiClass)psiElement); + } + else if (SUBTYPES_HIERARCHY_TYPE.equals(typeName)) { + return new SubtypesHierarchyTreeStructure(myProject, (PsiClass)psiElement, getCurrentScopeType()); + } + else if (TYPE_HIERARCHY_TYPE.equals(typeName)) { + return new TypeHierarchyTreeStructure(myProject, (PsiClass)psiElement, getCurrentScopeType()); + } + else { + LOG.error("unexpected type: " + typeName); + return null; + } + } + + @Override + protected boolean canBeDeleted(PsiElement psiElement) { + return psiElement instanceof PsiClass && !(psiElement instanceof PsiAnonymousClass); + } + + @Override + protected String getQualifiedName(PsiElement psiElement) { + if (psiElement instanceof PsiClass psiClass) { + return psiClass.getQualifiedName(); + } + return ""; + } + + public static class BaseOnThisTypeAction extends TypeHierarchyBrowserBase.BaseOnThisTypeAction { + @Override + protected boolean isEnabled(@Nonnull HierarchyBrowserBaseEx browser, @Nonnull PsiElement psiElement) { + return super.isEnabled(browser, psiElement) + && !JavaClassNames.JAVA_LANG_OBJECT.equals(((PsiClass)psiElement).getQualifiedName()); + } + } + + @Nonnull + @Override + protected TypeHierarchyBrowserBase.BaseOnThisTypeAction createBaseOnThisAction() { + return new BaseOnThisTypeAction(); + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/TypeHierarchyNodeDescriptor.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/TypeHierarchyNodeDescriptor.java index f72d0bab21..f955d2a303 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/TypeHierarchyNodeDescriptor.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/TypeHierarchyNodeDescriptor.java @@ -32,67 +32,61 @@ import java.awt.*; -public final class TypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor -{ - public TypeHierarchyNodeDescriptor(final Project project, final HierarchyNodeDescriptor parentDescriptor, final PsiElement classOrFunctionalExpression, final boolean isBase) - { - super(project, parentDescriptor, classOrFunctionalExpression, isBase); - } +public final class TypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor { + public TypeHierarchyNodeDescriptor( + Project project, + HierarchyNodeDescriptor parentDescriptor, + PsiElement classOrFunctionalExpression, + boolean isBase + ) { + super(project, parentDescriptor, classOrFunctionalExpression, isBase); + } - public final PsiElement getPsiClass() - { - return getPsiElement(); - } + public final PsiElement getPsiClass() { + return getPsiElement(); + } - @RequiredUIAccess - public final boolean update() - { - boolean changes = super.update(); + @RequiredUIAccess + public final boolean update() { + boolean changes = super.update(); - if (getPsiElement() == null) - { - final String invalidPrefix = IdeLocalize.nodeHierarchyInvalid().get(); - if (!myHighlightedText.getText().startsWith(invalidPrefix)) - { - myHighlightedText.getBeginning().addText(invalidPrefix, HierarchyNodeDescriptor.getInvalidPrefixAttributes()); - } - return true; - } + if (getPsiElement() == null) { + String invalidPrefix = IdeLocalize.nodeHierarchyInvalid().get(); + if (!myHighlightedText.getText().startsWith(invalidPrefix)) { + myHighlightedText.getBeginning().addText(invalidPrefix, HierarchyNodeDescriptor.getInvalidPrefixAttributes()); + } + return true; + } - if (changes && myIsBase) - { - setIcon(ImageEffects.appendRight(AllIcons.Hierarchy.Base, getIcon())); - } + if (changes && myIsBase) { + setIcon(ImageEffects.appendRight(AllIcons.Hierarchy.Base, getIcon())); + } - final PsiElement psiElement = getPsiClass(); + PsiElement psiElement = getPsiClass(); - final CompositeAppearance oldText = myHighlightedText; + CompositeAppearance oldText = myHighlightedText; - myHighlightedText = new CompositeAppearance(); + myHighlightedText = new CompositeAppearance(); - TextAttributes classNameAttributes = null; - if (myColor != null) - { - classNameAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN); - } - if (psiElement instanceof PsiClass psiClass) - { - myHighlightedText.getEnding().addText(ClassPresentationUtil.getNameForClass(psiClass, false), classNameAttributes); - myHighlightedText.getEnding().addText( - " (" + JavaHierarchyUtil.getPackageName(psiClass) + ")", - HierarchyNodeDescriptor.getPackageNameAttributes() - ); - } - else if (psiElement instanceof PsiFunctionalExpression functionalExpression) - { - myHighlightedText.getEnding().addText(ClassPresentationUtil.getFunctionalExpressionPresentation(functionalExpression, false)); - } - myName = myHighlightedText.getText(); + TextAttributes classNameAttributes = null; + if (myColor != null) { + classNameAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN); + } + if (psiElement instanceof PsiClass psiClass) { + myHighlightedText.getEnding().addText(ClassPresentationUtil.getNameForClass(psiClass, false), classNameAttributes); + myHighlightedText.getEnding().addText( + " (" + JavaHierarchyUtil.getPackageName(psiClass) + ")", + HierarchyNodeDescriptor.getPackageNameAttributes() + ); + } + else if (psiElement instanceof PsiFunctionalExpression functionalExpression) { + myHighlightedText.getEnding().addText(ClassPresentationUtil.getFunctionalExpressionPresentation(functionalExpression, false)); + } + myName = myHighlightedText.getText(); - if (!Comparing.equal(myHighlightedText, oldText)) - { - changes = true; - } - return changes; - } + if (!Comparing.equal(myHighlightedText, oldText)) { + changes = true; + } + return changes; + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/TypeHierarchyTreeStructure.java b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/TypeHierarchyTreeStructure.java index 71ac8b763c..c0cae4ba17 100644 --- a/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/TypeHierarchyTreeStructure.java +++ b/plugin/src/main/java/com/intellij/java/impl/ide/hierarchy/type/TypeHierarchyTreeStructure.java @@ -23,52 +23,58 @@ import java.util.ArrayList; public final class TypeHierarchyTreeStructure extends SubtypesHierarchyTreeStructure { - - public TypeHierarchyTreeStructure(final Project project, final PsiClass aClass, String currentScopeType) { - super(project, buildHierarchyElement(project, aClass), currentScopeType); - setBaseElement(myBaseDescriptor); //to set myRoot - } - - private static HierarchyNodeDescriptor buildHierarchyElement(final Project project, final PsiClass aClass) { - HierarchyNodeDescriptor descriptor = null; - final PsiClass[] superClasses = createSuperClasses(aClass); - for(int i = superClasses.length - 1; i >= 0; i--){ - final PsiClass superClass = superClasses[i]; - final HierarchyNodeDescriptor newDescriptor = new TypeHierarchyNodeDescriptor(project, descriptor, superClass, false); - if (descriptor != null){ - descriptor.setCachedChildren(new HierarchyNodeDescriptor[] {newDescriptor}); - } - descriptor = newDescriptor; + public TypeHierarchyTreeStructure(Project project, PsiClass aClass, String currentScopeType) { + super(project, buildHierarchyElement(project, aClass), currentScopeType); + setBaseElement(myBaseDescriptor); //to set myRoot } - final HierarchyNodeDescriptor newDescriptor = new TypeHierarchyNodeDescriptor(project, descriptor, aClass, true); - if (descriptor != null) { - descriptor.setCachedChildren(new HierarchyNodeDescriptor[] {newDescriptor}); + + private static HierarchyNodeDescriptor buildHierarchyElement(Project project, PsiClass aClass) { + HierarchyNodeDescriptor descriptor = null; + PsiClass[] superClasses = createSuperClasses(aClass); + for (int i = superClasses.length - 1; i >= 0; i--) { + PsiClass superClass = superClasses[i]; + HierarchyNodeDescriptor newDescriptor = new TypeHierarchyNodeDescriptor(project, descriptor, superClass, false); + if (descriptor != null) { + descriptor.setCachedChildren(new HierarchyNodeDescriptor[]{newDescriptor}); + } + descriptor = newDescriptor; + } + HierarchyNodeDescriptor newDescriptor = new TypeHierarchyNodeDescriptor(project, descriptor, aClass, true); + if (descriptor != null) { + descriptor.setCachedChildren(new HierarchyNodeDescriptor[]{newDescriptor}); + } + return newDescriptor; } - return newDescriptor; - } - private static PsiClass[] createSuperClasses(PsiClass aClass) { - if (!aClass.isValid()) return PsiClass.EMPTY_ARRAY; - if (aClass.isInterface()) return PsiClass.EMPTY_ARRAY; + private static PsiClass[] createSuperClasses(PsiClass aClass) { + if (!aClass.isValid()) { + return PsiClass.EMPTY_ARRAY; + } + if (aClass.isInterface()) { + return PsiClass.EMPTY_ARRAY; + } - final ArrayList superClasses = new ArrayList(); - while (!JavaClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName())) { - final PsiClass aClass1 = aClass; - final PsiClass[] superTypes = aClass1.getSupers(); - PsiClass superType = null; - for (int i = 0; i < superTypes.length; i++) { - final PsiClass type = superTypes[i]; - if (!type.isInterface()) { - superType = type; - break; + ArrayList superClasses = new ArrayList<>(); + while (!JavaClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName())) { + PsiClass aClass1 = aClass; + PsiClass[] superTypes = aClass1.getSupers(); + PsiClass superType = null; + for (PsiClass type : superTypes) { + if (!type.isInterface()) { + superType = type; + break; + } + } + if (superType == null) { + break; + } + if (superClasses.contains(superType)) { + break; + } + superClasses.add(superType); + aClass = superType; } - } - if (superType == null) break; - if (superClasses.contains(superType)) break; - superClasses.add(superType); - aClass = superType; - } - return superClasses.toArray(new PsiClass[superClasses.size()]); - } + return superClasses.toArray(new PsiClass[superClasses.size()]); + } }