void (PsiType psiType, final PsiElement context, boolean getRawSubtypes, @NotNull final 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); } }