public static void processSubTypes(PsiType psiType,
                                     final PsiElement context,
                                     boolean getRawSubtypes,
                                     final @NotNull PrefixMatcher matcher,
                                     Consumer<? super PsiType> consumer) {
    int arrayDim = psiType.getArrayDimensions();

    psiType = psiType.getDeepComponentType();
    if (!(psiType instanceof PsiClassType)) return;

    PsiClassType baseType = JavaCompletionUtil.originalize((PsiClassType)psiType);
    PsiClassType.ClassResolveResult baseResult = baseType.resolveGenerics();
    PsiClass baseClass = baseResult.getElement();
    if(baseClass == null) return;

    GlobalSearchScope scope = context.getResolveScope();

    Object lock = ObjectUtils.sentinel("CodeInsightUtil.processSubTypes");
    Processor<PsiClass> inheritorProcessor = inheritor -> {
      PsiType toAdd = getSubTypeBySubClass(context, baseType, arrayDim, getRawSubtypes, baseClass, inheritor);
      if (toAdd != null) {
        synchronized (lock) {
          consumer.consume(toAdd);
        }
      }
      return true;
    };

    addContextTypeArguments(context, baseType, inheritorProcessor);

    if (baseClass.hasModifierProperty(PsiModifier.FINAL)) return;

    Set<PsiClass> imported = processImportedInheritors(context, baseClass, inheritorProcessor);

    if (matcher.getPrefix().length() > 2) {
      JBTreeTraverser<PsiClass> traverser = JBTreeTraverser.of(PsiClass::getInnerClasses);
      AllClassesGetter.processJavaClasses(matcher, context.getProject(), scope, psiClass -> {
        Iterable<PsiClass> inheritors = traverser.withRoot(psiClass).filter(c -> c.isInheritor(baseClass, true) && !imported.contains(c));
        return ContainerUtil.process(inheritors, inheritorProcessor);
      });
    }
    else {
      Query<PsiClass> baseQuery = ClassInheritorsSearch.search(baseClass, scope, true, true, false);
      Query<PsiClass> query = new FilteredQuery<>(baseQuery, psiClass ->
        !(psiClass instanceof PsiTypeParameter) &&
        psiClass.getName() != null &&
        ContainerUtil.exists(JavaCompletionUtil.getAllLookupStrings(psiClass), matcher::prefixMatches) &&
        !imported.contains(psiClass));
      query.allowParallelProcessing().forEach(inheritorProcessor);
    }
  }
public static void processSubTypes(PsiType psiType,
                                     final PsiElement context,
                                     boolean getRawSubtypes,
                                     final @NotNull PrefixMatcher matcher,
                                     Consumer<? super PsiType> consumer)