tree: 8e2cd089c271de06e1e6fe712441798ca52e269d
  1. testData/
  2. testFixtures/
  3. tests/
  4. tests-gen/
  5. build.gradle.kts
  6. README.md
analysis/stubs/README.md

Kotlin stubs architecture

This document describes how Kotlin PSI stubs are modeled and built, and how the Kotlin support integrates with the IntelliJ Platform stub infrastructure. It covers source stubs, binary (compiled) stubs, and the decompiled PSI/light-class views built on top of binaries.

Scope note: the IntelliJ Kotlin plugin lives in a separate repository (JetBrains/intellij-community). This repo provides the stub interfaces, element types, stub builders, decompilers, and their tests.

Overview: IntelliJ PSI stubs

  • IntelliJ uses stub trees (a compact, serializable, indexable summary of the PSI) to support fast indexing, navigation, and partial PSI loading without parsing whole files. See Stub Indexes for more details.
  • A stub tree mirrors the structural PSI for declarations and references but omits statement bodies and trivia. In Kotlin, only declarations (and selected modifiers/annotations/references) are stubbed.
  • Each PSI element that can be stubbed has an element type. In Kotlin these extend IStubElementType (platform API) via KtStubElementType; an element type knows how to create PSI from an AST node or from a stub, serialize/deserialize the stub, and decide whether a stub should be created.
    • Note: the Kotlin code uses the platform's IStubElementType API. The newer platform StubElementFactory/StubSerializer API is not used here.
  • File-level stubs implement PsiFileStub and are the roots consumed by indexes.

Where things live

AreaModule / packageWhat it contains
Stub interfaces & contractscompiler/psi/psi-apiorg.jetbrains.kotlin.psi.stubsStubInterfaces.kt, KotlinFileStubKind.kt, KotlinStubVersions.kt; element-type base elements/KtStubElementType.java; API registry KtStubBasedElementTypes.kt; base PSI KtElementImplStub.java
Element-type & stub implscompiler/psi/psi-impl…psi.stubs.elements / …psi.stubs.implKt*ElementType impls, registry KtStubElementTypes.java, indexing glue StubIndexService.kt; stub data classes in …psi.stubs.impl (KotlinPropertyStubImpl, …), StubUtils, KotlinStubOrigin, createConstantValue
Shared cls stub buildersanalysis/decompiled/decompiler-to-stubs…analysis.decompiler.stubMetadata(proto)→stub builders shared by all binary formats: ClassClsStubBuilder, CallableClsStubBuilder, TypeClsStubBuilder, typeAliasClsStubBuilding, ClsContractBuilder, …
JVM .class entry pointanalysis/decompiled/decompiler-to-file-stubsKotlinClsStubBuilder (ClsStubBuilder for .class), plus the private JvmClsAnnotationLoader
Decompiled PSI / text & builtinsanalysis/decompiled/decompiler-to-psiKotlinClassFileDecompiler, KotlinDecompiledFileViewProvider, KtDecompiledFile, and the built-ins stub builder KotlinBuiltInMetadataStubBuilder
Native / KLIBanalysis/decompiled/decompiler-native…analysis.decompiler.konanKotlinKlibMetadataDecompiler for .knm metadata (KlibMetaFileType)
Light classes over decompiledanalysis/decompiled/light-classes-for-decompiledJava-facing light classes built on decompiled declarations: DecompiledLightClassesFactory, KtLightClassForDecompiledDeclaration, KtLightMethodForDecompiledDeclaration, …
Stub testsanalysis/stubsGenerated tests (tests-gen) + engines/fixtures in testFixtures

Core Kotlin PSI stub interfaces

Defined in compiler/psi/psi-api/src/org/jetbrains/kotlin/psi/stubs/StubInterfaces.kt. All of them are implementation details, but exposed due to the current technical limitations.

  • KotlinStubElement<T> — base contract for all Kotlin stubs (copyInto, isEquivalentTo).

Element types and stub creation

  • KtStubElementType<StubT, PsiT> (compiler/psi/psi-api/.../elements/KtStubElementType.java) extends IStubElementType. It bridges AST/PSI/stub.
  • Base PSI for stub-backed elements is KtElementImplStub.
  • Element types are registered in KtStubElementTypes (psi-impl, the IStubElementType instances). API consumers reference element-type constants through KtStubBasedElementTypes (psi-api).
  • Serialization — each element type writes/reads its fields via StubOutputStream/ StubInputStream (see e.g. KtFunctionElementType.serialize/deserialize). Stub data classes live in org.jetbrains.kotlin.psi.stubs.impl.
  • KotlinElementTypeProvider (compiler/psi/psi-api/.../KotlinElementTypeProvider.kt) is a bridge between element types and their implementations (KotlinElementTypeProviderImpl).

Stub versions

KotlinStubVersions (compiler/psi/psi-api/.../KotlinStubVersions.kt). Bumping a version forces reindexing of the corresponding artifact kind on the next IDE start.

  • SOURCE_STUB_VERSION — bump on parser/PSI/stub-format changes affecting source .kt/.kts.
  • BINARY_STUB_VERSION (private) — base for binary formats; derived constants:
    • CLASSFILE_STUB_VERSION — JVM .class stubs.
    • BUILTIN_STUB_VERSION — built-in metadata stubs.
    • KLIB_STUB_VERSION — Native/Common KLIB metadata (.knm).
  • JS_STUB_VERSION is @Deprecated — the Kotlin/JS metadata decompiler has been removed.

Kinds of Kotlin stubs

1) Source stubs

Built for .kt/.kts from the parsed PSI via KtStubElementType and the registered element types. Carry package, imports, declarations, modifiers, annotations, signatures, and selected flags — but no statement bodies. Consumed by indexes (Go To, Find Usages) and by analysis to locate declarations quickly.

2) Compiled / binary stubs

Built from binary artifacts without sources, by reading Kotlin metadata. All formats produce stubs implementing the same StubInterfaces.kt contracts via the shared builders in decompiler-to-stubs (ClassClsStubBuilder, CallableClsStubBuilder, TypeClsStubBuilder, …).

  • JVM .class — entry point KotlinClsStubBuilder.buildFileStubdoBuildFileStub:

    1. Resolve the KotlinJvmBinaryClass and its KotlinClassHeader.
    2. If the metadata version is incompatible, return an “invalid” file stub (createIncompatibleAbiVersionFileStub).
    3. createStubBuilderComponents prepares the class/data finders and JvmClsAnnotationLoader.
    4. Dispatch on header.kind: CLASScreateTopLevelClassStub; FILE_FACADE / MULTIFILE_CLASS_PARTcreateFileFacadeStub; MULTIFILE_CLASScreateMultifileClassStub.
    5. The shared builders construct the tree; a PsiFileStub<KtFile> is returned to the platform.
    • Annotations & constants: JvmClsAnnotationLoader (a private class in KotlinClsStubBuilder.kt, not a separately named class) walks the class with KotlinJvmBinaryClass member visitors, collecting member annotations, field initializers, and annotation default values; values are converted via createConstantValue.
  • Built-insKotlinBuiltInMetadataStubBuilder (decompiler-to-psi), BUILTIN_STUB_VERSION.

  • Native / KLIBKotlinKlibMetadataDecompiler (decompiler-native, …analysis.decompiler.konan), KLIB_STUB_VERSION, .knm (KlibMetaFileType).

3) Decompiled PSI and light classes

For navigation/quick-doc, the platform builds a read-only text + PSI view over binaries:

  • KotlinClassFileDecompiler / KotlinDecompiledFileViewProvider / KtDecompiledFile (decompiler-to-psi) produce decompiled text-backed PSI.
  • light-classes-for-decompiled builds Java light classes (KtLightClassForDecompiledDeclaration, KtLightMethodForDecompiledDeclaration, …) for Java interop.

The decompiled view and the binary file stubs share the same metadata deserialization, so indexes and decompiled views agree on structure and names.

Indexing and versioning

  • Element types contribute to indexes through indexStub, which delegates to StubIndexService (indexFunction, indexProperty, indexClass, …). The Kotlin support registers file- and element-level indexes that consume KotlinFileStub and its children.
  • Bump the relevant KotlinStubVersions constant whenever stub shape, names, or index-significant flags change.

Key PSI integration points

  • Stub-backed PSI reads children from either the stub or the AST. Example: KtClassOrObject.getSuperTypeList() uses getStubOrPsiChild(SUPER_TYPE_LIST).
  • KtClassOrObject.isLocal() / getClassId() are stub-aware: the stub carries the data; PSI falls back to computation (and resets isLocal on subtreeChanged).

Testing

  • Stub behavior is covered by generated tests in analysis/stubs (tests-gen), driven by the engines/fixtures in analysis/stubs/testFixtures/org/jetbrains/kotlin/analysis/stubs: AbstractStubsTest, AbstractSourceStubsTest, AbstractCompiledStubsTest, StubsTestEngine, SourceStubsTestEngine, CompiledStubsTestEngine (plus additionalStubInfoExtractor, TestGenerator).
  • Regenerate the generated tests with ./gradlew generateTests after adding test data.

Useful entry points

  • compiler/psi/psi-api/.../psi/stubs/StubInterfaces.kt — all Kotlin stub contracts.
  • compiler/psi/psi-api/.../psi/stubs/KotlinFileStubKind.kt — file stub classification.
  • compiler/psi/psi-api/.../psi/stubs/KotlinStubVersions.kt — versioning.
  • compiler/psi/psi-api/.../psi/stubs/elements/KtStubElementType.java — AST/PSI/stub bridge.
  • compiler/psi/psi-impl/.../psi/stubs/elements/ — element-type impls, KtStubElementTypes, StubIndexService; stub data classes in …/psi/stubs/impl/.
  • analysis/decompiled/decompiler-to-stubs/... — shared cls builders (ClassClsStubBuilder, CallableClsStubBuilder, TypeClsStubBuilder).
  • analysis/decompiled/decompiler-to-file-stubs/.../KotlinClsStubBuilder.kt — JVM .class entry.
  • analysis/decompiled/decompiler-to-psi/... — decompiled PSI + KotlinBuiltInMetadataStubBuilder.
  • analysis/decompiled/decompiler-native/.../konan/KotlinKlibMetadataDecompiler.kt — KLIB/Native.

FAQ

  • Why both binary file stubs and decompiled PSI? Stubs power indexing and are lightweight for headless operations; decompiled PSI/light classes give a readable, navigable, Java-interoperable view. They share metadata so they stay consistent.
  • Which stub version do I bump? SOURCE_STUB_VERSION for source .kt changes; CLASSFILE_STUB_VERSION for JVM .class builders; BUILTIN_STUB_VERSION for built-ins; KLIB_STUB_VERSION for Native/KLIB. (JS no longer produces stubs.)
  • Where do I start debugging a missing stub element? Source: the element's Kt*ElementType and its shouldCreateStub. Binary (JVM): KotlinClsStubBuilder.doBuildFileStub, then into the shared ClassClsStubBuilder / CallableClsStubBuilder in decompiler-to-stubs. Compare against the generated stub tests in analysis/stubs.