@Override
    protected Object[] buildChildren(HierarchyNodeDescriptor descriptor) {
        final List<SdCallHierarchyNodeDescriptor> descriptors = new ArrayList<>();
        
        if (descriptor instanceof SdCallHierarchyNodeDescriptor) {
            PsiElement element = descriptor.getPsiElement();
            if (element == null) {
                return ArrayUtilRt.EMPTY_OBJECT_ARRAY;
            }
            boolean isCallable = SdHierarchyUtil.isExecutable(element);
            HierarchyNodeDescriptor nodeDescriptor = getBaseDescriptor();
            if (!isCallable || nodeDescriptor == null) {
                return ArrayUtilRt.EMPTY_OBJECT_ARRAY;
            }
            
            Set<Function> children = getChildren((SdFunctionDefinition) element);
            
            Map<PsiElement, SdCallHierarchyNodeDescriptor> callerToDescriptorMap = new HashMap<>();
            PsiElement baseClass = PsiTreeUtil.getParentOfType(element, SdRankProfileDefinition.class);
            
            for (Function caller : children) {
                if (isInScope(baseClass, caller.definition(), myScopeType)) {
                    SdCallHierarchyNodeDescriptor callerDescriptor = callerToDescriptorMap.get(caller);
                    if (callerDescriptor == null) {
                        callerDescriptor = new SdCallHierarchyNodeDescriptor(descriptor, caller.definition(), false);
                        callerToDescriptorMap.put(caller.definition(), callerDescriptor);
                        descriptors.add(callerDescriptor);
                    }
                }
            }
        }
        return ArrayUtil.toObjectArray(descriptors);
    }
A general tree in the "Call Hierarchy" window.

@author Shahar Ariel
integration/intellij/src/main/java/ai/vespa/intellij/schema/hierarchy/SdCallTreeStructure.java