package com.jetbrains.lang.dart.ide.hierarchy.method; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.intellij.ide.hierarchy.HierarchyBrowserManager; import com.intellij.ide.hierarchy.HierarchyNodeDescriptor; import com.intellij.ide.hierarchy.HierarchyTreeStructure; import com.intellij.openapi.project.Project; import com.intellij.psi.SmartPointerManager; import com.intellij.psi.SmartPsiElementPointer; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; import com.jetbrains.lang.dart.psi.DartClass; import com.jetbrains.lang.dart.psi.DartComponent; import org.dartlang.analysis.server.protocol.TypeHierarchyItem; import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.Set; import static com.jetbrains.lang.dart.ide.hierarchy.DartHierarchyUtil.findDartClass; import static com.jetbrains.lang.dart.ide.hierarchy.DartHierarchyUtil.getTypeHierarchyItems; public class DartMethodHierarchyTreeStructure extends HierarchyTreeStructure { private final SmartPsiElementPointer myMethod; public DartMethodHierarchyTreeStructure(Project project, DartComponent element) { super(project, null); DartClass baseClass = PsiTreeUtil.getParentOfType(element, DartClass.class); myBaseDescriptor = new DartMethodHierarchyNodeDescriptor(project, null, baseClass, true, this); setBaseElement(myBaseDescriptor); ((DartMethodHierarchyNodeDescriptor)myBaseDescriptor).setTreeStructure(this); myMethod = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(element); } @NotNull @Override protected Object[] buildChildren(@NotNull HierarchyNodeDescriptor descript) { final DartMethodHierarchyNodeDescriptor descriptor = (DartMethodHierarchyNodeDescriptor)descript; final DartClass dartClass = descriptor.getType(); if (dartClass == null) return ArrayUtil.EMPTY_OBJECT_ARRAY; final List<TypeHierarchyItem> items = getTypeHierarchyItems(dartClass); if (items.isEmpty()) return ArrayUtil.EMPTY_OBJECT_ARRAY; addAllVisibleSubclasses(Sets.newHashSet(), myProject, items, items.get(0), descriptor); return descriptor.getCachedChildren(); } private void addAllVisibleSubclasses(@NotNull final Set<TypeHierarchyItem> stackItems, @NotNull final Project project, @NotNull final List<TypeHierarchyItem> items, @NotNull final TypeHierarchyItem item, @NotNull final DartMethodHierarchyNodeDescriptor descriptor) { if (!stackItems.add(item)) { descriptor.setCachedChildren(ArrayUtil.EMPTY_OBJECT_ARRAY); return; } HierarchyBrowserManager.State state = HierarchyBrowserManager.getInstance(myProject).getState(); if (state == null) throw new NullPointerException(); List<DartMethodHierarchyNodeDescriptor> subDescriptors = Lists.newArrayList(); try { for (int index : item.getSubclasses()) { final TypeHierarchyItem subItem = items.get(index); final DartClass subclass = findDartClass(project, subItem); if (subclass != null) { final DartMethodHierarchyNodeDescriptor subDescriptor = new DartMethodHierarchyNodeDescriptor(project, descriptor, subclass, false, this); subDescriptors.add(subDescriptor); addAllVisibleSubclasses(stackItems, project, items, subItem, subDescriptor); } } DartClass dartClass = findDartClass(project, item); assert dartClass != null; String methodName = getBaseMethod().getName(); if (methodName != null) { DartComponent method = dartClass.findMethodByName(methodName); if (method != null) { DartClass definingClass = PsiTreeUtil.getParentOfType(method, DartClass.class); if (definingClass == dartClass) { descriptor.myIsImplementor = true; } else { descriptor.myShouldImplement = method.isAbstract() && !dartClass.isAbstract(); } } } for (DartMethodHierarchyNodeDescriptor subDescriptor : subDescriptors) { if (subDescriptor.myIsSuperclassOfImplementor || subDescriptor.myIsImplementor) { descriptor.myIsSuperclassOfImplementor = true; break; } } if (state.HIDE_CLASSES_WHERE_METHOD_NOT_IMPLEMENTED) { List<DartMethodHierarchyNodeDescriptor> toRemove = Lists.newArrayList(); for (DartMethodHierarchyNodeDescriptor subDescriptor : subDescriptors) { if (!(subDescriptor.myIsSuperclassOfImplementor || subDescriptor.myIsImplementor)) { toRemove.add(subDescriptor); } } subDescriptors.removeAll(toRemove); } } finally { stackItems.remove(item); } descriptor.setCachedChildren(subDescriptors.toArray(new HierarchyNodeDescriptor[subDescriptors.size()])); } private DartComponent getBaseMethod() { return (DartComponent)myMethod.getElement(); } }