How to index all annotation definitions in a project, including source code and dependencies?

I’m developing a plugin based on the IntelliJ platform, and I need to list all available annotation definitions within a project — including those from the project’s own source code, dependencies, and any libraries visible in the project.

I’m trying to achieve an experience similar to IntelliJ’s intelligent code completion:
for example, when typing “@” in Java or Kotlin files, the IDE can quickly suggest all available annotations.
The speed and user experience are excellent, and I’d like to replicate something similar.

Currently, I’m using an approach like this:

val index = StubIndex.getInstance()
val scope = ProjectScope.getAllScope(project)
val result = mutableListOf<PsiClass>()

val resultProcessor = Processors.cancelableCollectProcessor(result)
val annotationProcessor = Processors.filter(resultProcessor) { it.isAnnotationType }
val uniqueProcessor = CommonProcessors.UniqueProcessor(annotationProcessor)

index.getAllKeys(JavaStubIndexKeys.CLASS_SHORT_NAMES, project)
    .forEach {
        index.processElements(JavaStubIndexKeys.CLASS_SHORT_NAMES, it, project, scope, PsiClass::class.java, uniqueProcessor)
    }

val ktResult = mutableListOf<KtClassOrObject>()
val ktResultProcessor = Processors.cancelableCollectProcessor(ktResult)
val ktUniqueProcessor = CommonProcessors.UniqueProcessor(ktResultProcessor)

KotlinClassShortNameIndex.getAllKeys(project)
    .forEach {
        KotlinClassShortNameIndex.processElements(it, project, scope, ktUniqueProcessor)
    }

val allAnnotations = result + ktResult
    .filterIsInstance<KtClass>()
    .filter { it.isAnnotation() }
    .map { it.toLightClass() ?: it.toFakeLightClass() }

This approach works correctly for finding annotations, but it has some issues:

  • It can be relatively slow, especially in large projects.
  • It re-traverses the index each time, and it seems there’s no caching optimization.

My questions are:

  1. How does IntelliJ manage to suggest all available annotations so quickly when typing “@”?
    Is there a special caching or optimized indexing mechanism involved?
  2. Is there a recommended or better way to more efficiently index and retrieve all annotation definitions?
  3. Can I somehow leverage existing PSI caches, Stub caches, or other internal mechanisms to avoid full traversal via getAllKeys() every time?

Any advice or insights would be greatly appreciated. Thanks a lot!

It is already indexed I think com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex

JavaAnnotationIndex.getInstance().getAnnotations(shortAnnotationName, project, scope)

and

KotlinAnnotationsIndex[name, klass.project, scope]

As far as I can tell, PsiAnnotation and KtAnnotationEntry represent annotation usages, not their definitions — so I’m not sure if JavaAnnotationIndex and KotlinAnnotationsIndex can actually be used to retrieve all annotation definitions in the project

I’m wondering — is there no built-in index for annotation definitions?
And if not, is there any faster or more efficient way to retrieve them?