package com.jetbrains.lang.dart.ide.hierarchy.call; import com.intellij.find.findUsages.FindUsagesHandler; import com.intellij.ide.hierarchy.HierarchyBrowserBaseEx; import com.intellij.ide.hierarchy.HierarchyNodeDescriptor; import com.intellij.ide.hierarchy.HierarchyTreeStructure; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.psi.PsiElement; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; import com.jetbrains.lang.dart.ide.findUsages.DartServerFindUsagesHandler; import com.jetbrains.lang.dart.ide.hierarchy.DartHierarchyUtil; import com.jetbrains.lang.dart.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public abstract class DartCallHierarchyTreeStructure extends HierarchyTreeStructure { private final String myScopeType; public DartCallHierarchyTreeStructure(Project project, PsiElement element, String currentScopeType) { super(project, new DartHierarchyNodeDescriptor(null, element, true)); myScopeType = currentScopeType; } @Nullable protected static FindUsagesHandler createFindUsageHandler(@NotNull final PsiElement element) { return new DartServerFindUsagesHandler(element); } public static void collectDeclarations(@Nullable final PsiElement element, @NotNull final List<PsiElement> results) { if (element != null) { Condition<PsiElement> isExecutable = object -> { if (object == null) return false; return DartHierarchyUtil.isExecutable(object); }; PsiElement ref = PsiTreeUtil.findFirstParent(element, isExecutable); if (ref != null) { results.add(ref); } } } @NotNull protected abstract List<PsiElement> getChildren(@NotNull PsiElement element); @NotNull @Override protected Object[] buildChildren(@NotNull HierarchyNodeDescriptor descriptor) { final List<DartHierarchyNodeDescriptor> descriptors = new ArrayList<>(); if (descriptor instanceof DartHierarchyNodeDescriptor) { final DartHierarchyNodeDescriptor dartDescriptor = (DartHierarchyNodeDescriptor)descriptor; PsiElement element = dartDescriptor.getPsiElement(); if (element == null) { return ArrayUtil.EMPTY_OBJECT_ARRAY; } boolean isCallable = DartHierarchyUtil.isExecutable(element); HierarchyNodeDescriptor nodeDescriptor = getBaseDescriptor(); if (!(element instanceof DartComponent) || !isCallable || nodeDescriptor == null) { return ArrayUtil.EMPTY_OBJECT_ARRAY; } DartComponentName name = ((DartComponent)element).getComponentName(); if (name == null) { return ArrayUtil.EMPTY_OBJECT_ARRAY; } final List<PsiElement> children = getChildren(name); final HashMap<PsiElement, DartHierarchyNodeDescriptor> callerToDescriptorMap = new HashMap<>(); PsiElement baseClass = element instanceof DartMethodDeclaration ? PsiTreeUtil.getParentOfType(name, DartClass.class) : null; for (PsiElement caller : children) { if (isInScope(baseClass, caller, myScopeType)) { DartHierarchyNodeDescriptor callerDescriptor = callerToDescriptorMap.get(caller); if (callerDescriptor == null) { callerDescriptor = new DartHierarchyNodeDescriptor(descriptor, caller, false); callerToDescriptorMap.put(caller, callerDescriptor); descriptors.add(callerDescriptor); } } } } return ArrayUtil.toObjectArray(descriptors); } @NotNull protected GlobalSearchScope getScope() { if (HierarchyBrowserBaseEx.SCOPE_CLASS.equals(myScopeType)) { Object root = getRootElement(); if (root instanceof DartHierarchyNodeDescriptor) { DartHierarchyNodeDescriptor rootElement = (DartHierarchyNodeDescriptor)root; PsiElement element = rootElement.getPsiElement(); PsiElement file = PsiTreeUtil.getParentOfType(element, DartFile.class); if (file != null) { return GlobalSearchScope.fileScope((DartFile)file); } } return GlobalSearchScope.projectScope(myProject); } else if (HierarchyBrowserBaseEx.SCOPE_PROJECT.equals(myScopeType)) { return GlobalSearchScope.projectScope(myProject); } else if (HierarchyBrowserBaseEx.SCOPE_TEST.equals(myScopeType)) { return GlobalSearchScope.projectScope(myProject); // We do not have a module to get its test scope. } else if (HierarchyBrowserBaseEx.SCOPE_ALL.equals(myScopeType)) { return GlobalSearchScope.allScope(myProject); } return GlobalSearchScope.projectScope(myProject); } }