| # Kotlin PSI (Program Structure Interface) |
| |
| 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. |
| |
| ## Relationship with Analysis API |
| |
| 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 symbols |
| - When working with PSI, you often need Analysis API to understand what the code means |
| - See [analysis/AGENTS.md](../../analysis/AGENTS.md) for Analysis API guidelines |
| |
| ## Module Structure |
| |
| - `psi-api/` - Core PSI interfaces (`KtElement`, `KtExpression`, `KtDeclaration`) |
| - `psi-impl/` - Implementations and stubs for incremental compilation |
| - `psi-frontend-utils/` - Compiler integration utilities |
| - `psi-utils/` - Helper utilities |
| |
| ## Main Classes |
| |
| ``` |
| KtElement (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 tree |
| - `KtPsiFactory` - factory for creating PSI elements programmatically |
| |
| ## Key Patterns |
| |
| **Visitor pattern** for AST traversal: |
| - `KtVisitor<R, D>` - base visitor with return type R and data D |
| - `KtTreeVisitor<D>` - recursive tree traversal |
| |
| **Stubs** for performance: |
| - Binary PSI representation for faster parsing |
| - Used for library files and caching |
| |
| ## PSI Development Rules |
| |
| ### Shared Principles with Analysis API |
| |
| PSI and Analysis API share common development principles. Before contributing: |
| |
| → READ [`analysis/docs/contribution-guide/api-development.md`](../../analysis/docs/contribution-guide/api-development.md) for API design principles |
| → READ [`analysis/docs/contribution-guide/api-evolution.md`](../../analysis/docs/contribution-guide/api-evolution.md) for stability and deprecation |
| |
| ### Java-Kotlin Interoperability |
| |
| **J2K Conversion Limitations:** |
| |
| Converting Java PSI classes to Kotlin is NOT always possible. Before attempting: |
| |
| 1. **`@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. |
| |
| 2. **Platform type handling** — IntelliJ Platform APIs use Java types extensively; Kotlin's null-safety interop requires careful handling. |
| - The classic example is `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. |
| |
| 3. **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. |
| |
| ### PSI-Specific Notes |
| |
| **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 |
| - `@KtPsiInconsistencyHandling` — Code handling inconsistent PSI states |
| |
| **Java-Kotlin interop:** See the "Java-Kotlin Interoperability" section in [api-development.md](../../analysis/docs/contribution-guide/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`) |
| |
| ### Documenting KtElement Classes |
| |
| General documentation rules from [api-development.md](../../analysis/docs/contribution-guide/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:** |
| |
| 1. **Class description** — A simple explanation of which Kotlin language concept or syntax construct the class represents. |
| |
| 2. **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: |
| ````kotlin |
| /** |
| * 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/testData/psi/`: |
| - Each test consists of a `.kt` file containing example Kotlin code and a corresponding `.txt` file showing the expected PSI tree structure |
| - These tests serve as documentation showing which code constructs map to which PSI elements |
| - When adding a new `KtElement` class, add corresponding test cases demonstrating the syntax it represents |
| |
| ## Detailed Documentation |
| |
| WHEN modifying PSI interfaces or adding new element types: |
| → Explore [psi-api/src/org/jetbrains/kotlin/psi/](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](psi-api/src/org/jetbrains/kotlin/psi/KtVisitor.java) |
| → READ [psi-api/src/org/jetbrains/kotlin/psi/KtTreeVisitor.java](psi-api/src/org/jetbrains/kotlin/psi/KtTreeVisitor.java) |
| |
| WHEN creating PSI elements programmatically: |
| → READ [psi-api/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt](psi-api/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt) |