PSI represents Kotlin source code as a syntax tree. It is the foundation for code analysis, navigation, and refactoring in both the compiler and IDE.
PSI provides syntax information (structure of code). Analysis API builds on top of PSI to provide semantic information (meaning of code).
Source Code → PSI Tree (syntax) → Analysis API (semantics) → Symbols
KtResolvable interface marks PSI elements that can be resolved to Analysis API symbolspsi-api/ - Core PSI interfaces (KtElement, KtExpression, KtDeclaration), plus the platform interfaces the code hosting the PSI implements: the binary Kotlin file types and their services in org.jetbrains.kotlin.analysis.decompilerpsi-impl/ - Implementations and stubs for incremental compilationpsi-frontend-utils/ - Compiler integration utilitiespsi-utils/ - Helper utilitiesKtElement (root interface)
├── KtExpression (calls, literals, operators, etc.)
│ ├── KtCallExpression
│ ├── KtBinaryExpression
│ ├── KtLambdaExpression
│ └── ...
└── KtDeclaration (classes, functions, properties)
├── KtClass, KtObjectDeclaration
├── KtNamedFunction
├── KtProperty
└── ...
KtFile - root of a Kotlin file's PSI treeKtPsiFactory - factory for creating PSI elements programmaticallyVisitor pattern for AST traversal:
KtVisitor<R, D> - base visitor with return type R and data DKtTreeVisitor<D> - recursive tree traversalStubs for performance:
PSI and Analysis API share common development principles. Before contributing:
→ READ analysis/docs/contribution-guide/api-development.md for API design principles → READ analysis/docs/contribution-guide/api-evolution.md for stability and deprecation
J2K Conversion Limitations:
Converting Java PSI classes to Kotlin is NOT always possible. Before attempting:
@JvmName unavailable in interfaces — in some cases it is impossible to convert Java methods to Kotlin properties in a binary-compatible way since @JvmName cannot be used to fix potential clashes.
Platform type handling — IntelliJ Platform APIs use Java types extensively; Kotlin's null-safety interop requires careful handling.
PsiElement.getParent() returning PsiElement!. After conversion to Kotlin it becomes either PsiElement? or PsiElement – both of them are breaking changes. A workaround is to delegate the implementation to a Java method and keep the return type implicit.Binary compatibility — PSI classes are widely used; the binary and source compatibility must be preserved as much as possible.
Guidance: Always consult with PSI maintainers before converting Java classes to Kotlin.
Naming: All PSI types use the Kt prefix (vs Ka for Analysis API).
Stability annotations:
@KtExperimentalApi — Experimental public API@KtImplementationDetail — Internal implementation@KtNonPublicApi — JetBrains-internal APIs@KtIdeApi — APIs designed for and internal to the Kotlin IntelliJ plugin@KtPlatformInterface — APIs forming a contract with the Analysis API engine and its platforms (stub building, element types, indexing)@KtSpi/@KtSpiExtensionPoint — Service provider interfaces and their members, designed to be implemented rather than called@KtPsiInconsistencyHandling — Code handling inconsistent PSI statesJava-Kotlin interop: See the “Java-Kotlin Interoperability” section in api-development.md.
PSI-specific naming patterns:
visit prefix for visitor methods (e.g., visitCallExpression)create prefix for factory methods in KtPsiFactory (e.g., createExpression)General documentation rules from api-development.md apply to all PSI classes. This section describes additional requirements specific to concrete classes implementing KtElement.
Required documentation for concrete KtElement classes:
Class description — A simple explanation of which Kotlin language concept or syntax construct the class represents.
Code example — A code snippet showing the syntax in context. Use ASCII-art markers (^___^) to indicate the specific portion that the class represents.
Example documentation format:
/** * Represents a function call expression. * * ### Example: * * ```kotlin * fun main() { * println(0) * // ^_________^ * } * ``` */ class KtCallExpression : ...
Reference examples:
KtCallExpression and KtAnnotationEntry demonstrate the code example format with ASCII-art markers.Test coverage requirement:
All concrete KtElement classes must be covered by tests in compiler/psi/psi-impl/testData/psi/:
.kt file containing example Kotlin code and a corresponding .txt file showing the expected PSI tree structureKtElement class, add corresponding test cases demonstrating the syntax it representsPSI test data (compiler/psi/psi-impl/testData/) is managed by the same test data manager as the Analysis API, since the test-data-manager convention is applied to :compiler:psi:psi-impl. When modifying test data files or running generated tests (*Generated) that compare output against .txt files, use updateTestData (to rewrite files) or checkTestData (to verify only) instead of standard test commands.
# Update all PSI test data ./gradlew :compiler:psi:psi-impl:updateTestData # Update by directory (preferred for iteration) ./gradlew updateTestData -Porg.jetbrains.kotlin.testDataManager.options.testDataPath=compiler/psi/psi-impl/testData/psi/annotation/
Note that a single .kt file under testData/psi/ feeds several suites across two modules: the PSI tree (.txt) from :compiler:psi:psi-impl (PsiParsingTest), plus source stubs (.stubs.txt) and compiled stubs (.compiled.stubs.txt, .knm.compiled.stubs.txt) together with the decompiled text (.decompiledText.txt, .knm.decompiledText.txt) from :analysis:stubs. Prefer a path-filtered updateTestData from the repo root so that every affected module is picked up.
→ READ analysis/AGENTS.md (“Working with Test Data”) for the full set of options and the rationale
WHEN modifying PSI interfaces or adding new element types: → Explore psi-api/src/org/jetbrains/kotlin/psi/ for existing patterns
WHEN working with PSI visitors: → READ psi-api/src/org/jetbrains/kotlin/psi/KtVisitor.java → READ psi-api/src/org/jetbrains/kotlin/psi/KtTreeVisitor.java
WHEN creating PSI elements programmatically: → READ psi-api/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt
WHEN working with stubs: → READ analysis/stubs/README.md