TypeMigrationUsageInfo[] (TypeMigrationUsageInfo[] infos) { final DFSTBuilder<TypeMigrationUsageInfo> builder = new DFSTBuilder<>(GraphGenerator.generate( new InboundSemiGraph<>() { @NotNull @Override public Collection<TypeMigrationUsageInfo> getNodes() { final Set<TypeMigrationUsageInfo> infos = new HashSet<>(); for (Map.Entry<TypeMigrationUsageInfo, HashSet<Pair<TypeMigrationUsageInfo, PsiType>>> entry : myRootsTree.entrySet()) { infos.add(entry.getKey()); infos.addAll(ContainerUtil.map(entry.getValue(), pair -> pair.getFirst())); } return infos; } @NotNull @Override public Iterator<TypeMigrationUsageInfo> getIn(TypeMigrationUsageInfo n) { final HashSet<Pair<TypeMigrationUsageInfo, PsiType>> rawNodes = myRootsTree.get(n); if (rawNodes == null) { return Collections.emptyIterator(); } final List<TypeMigrationUsageInfo> in = ContainerUtil.map(rawNodes, pair -> pair.getFirst()); return in.iterator(); } })); final Comparator<TypeMigrationUsageInfo> cmp = builder.comparator(); Arrays.sort(infos, (info1, info2) -> { final TypeMigrationUsageInfo i1 = info1.getOwnerRoot(); final TypeMigrationUsageInfo i2 = info2.getOwnerRoot(); if (i1 == null && i2 == null) { return 0; } if (i1 == null) { return 1; } if (i2 == null) { return -1; } final PsiElement element1 = info1.getElement(); final PsiElement element2 = info2.getElement(); LOG.assertTrue(element1 != null && element2 != null); if (element1.equals(element2)) { return 0; } final TextRange range1 = element1.getTextRange(); final TextRange range2 = element2.getTextRange(); if (range1.contains(range2)) { return 1; } if (range2.contains(range1)) { return -1; } final int res = cmp.compare(i1, i2); if (res != 0) { return res; } return Integer.compare(range2.getStartOffset(), range1.getStartOffset()); }); return infos; }