analysis/docs/contribution-guide/api-evolution.md
This guide covers the lifecycle of Analysis API endpoints from introduction to deprecation, including stability transitions and migration strategies. For guidance on designing new APIs, see the API Development Guide.
The Analysis API consists of several interconnected components, each serving a specific purpose:
The Kotlin PSI (source, guidelines)
KtElement
hierarchyKt prefix (compared to Ka for Analysis API)@KtExperimentalApi, @KtImplementationDetail, @KtNonPublicApiKtFile,
KtDeclaration,
and KtExpressionAnalysis API Surface (source)
Platform Interface (source)
KotlinPlatformComponent,
KaEngineServiceAnalysis API Standalone (source)
Implementations
Light Classes (source)
Low-level API (source)
Every part of the Analysis API falls under one of these stability categories:
Stable API
Unstable API
@KaExperimentalApi, @KaNonPublicApi, @KaIdeApiImplementation Details
@KaImplementationDetail[!NOTE] PSI uses parallel annotations:
@KtExperimentalApi,@KtImplementationDetail,@KtNonPublicApi. The@KtPsiInconsistencyHandlingannotation marks code handling inconsistent PSI states (no Analysis API equivalent).
New APIs follow a three-phase lifecycle designed to prevent premature stabilization while gathering real-world feedback. This process protects both API designers and users from the cost of breaking changes.
Goal: Ship the API to early adopters while explicitly communicating its experimental nature.
Mark with @KaExperimentalApi
This annotation serves as both a compiler warning and documentation that the API may change.
Users must explicitly opt-in, ensuring they understand the risks.
Choose whether to implement for both K1 and K2
If K1 support is impractical, use @KaK1Unsupported with clear documentation.
Provide comprehensive documentation and tests
Experimental doesn't mean untested. Include edge cases, error conditions, and usage examples.
This helps early adopters use the API correctly and provides valuable feedback.
Follow the design principles outlined in the API Development Guide
Experimental APIs should still adhere to design principles.
Fixing design issues later is more expensive than getting them right initially.
Goal: Confirm the API design through real usage and identify necessary refinements.
Gather usage feedback
Monitor how developers actually use the API versus intended usage.
Look for common workarounds, frequent questions, or misuse patterns that suggest design issues.
Ensure idiomatic usage patterns emerge
The API should feel natural to Kotlin developers.
If users consistently need helper functions or complex setup code, consider incorporating these patterns into the API itself.
Verify edge case handling
Real-world usage often reveals edge cases not covered in initial testing.
Ensure the API gracefully handles malformed input, incomplete analysis results, and platform-specific variations.
Goal: Ensure the API is ready for long-term compatibility commitments.
Before removing @KaExperimentalApi, verify that:
API is actively used with positive feedback
Look for evidence that the API solves real problems efficiently.
Lack of usage may indicate the API isn't needed anymore.
Naming is consistent and self-explanatory
Names should align with Analysis API conventions and be understandable without extensive documentation.
Consider whether parameter names can be improved based on usage patterns.
No anticipated design changes
The team should have high confidence that the API design will remain stable.
Major changes after stabilization require the full deprecation process.
Deprecation follows a careful multi-release cycle with clear migration paths. The process balances giving users time to migrate while preventing indefinite maintenance of obsolete APIs.
Goal: Signal the intent to remove the API while providing clear migration guidance.
Add the @Deprecated(WARNING) annotation
This generates compiler warnings that alert users to the deprecation without breaking builds.
The warning level ensures existing code continues to compile while encouraging migration.
Explain alternatives in the deprecation message and KDoc
Provide guidance on replacement APIs. Include code examples when the migration is non-trivial.
If no direct replacement exists, explain the recommended approach.
Update all usages in Kotlin and IntelliJ repositories
Test the migration by updating internal usage.
This serves as real-world examples for external users and ensures the migration path is practical.
Document migration in COMPATIBILITY.md
Mention the deprecation in the compatibility document for smoother communication with the Analysis API users.
ERROR AdvancementGoal: Prevent new usage while maintaining both source and binary compatibility for existing code.
Ensure there's at least one major release with WARNING
This gives users a full release cycle to discover and plan their migration.
Advance the deprecation level to ERROR
This prevents new usage while allowing existing code to compile with explicit suppression.
Users can still build their code but must acknowledge they're using deprecated APIs that will be removed shortly.
Goal: Complete the deprecation process while maintaining ecosystem compatibility.
Ensure there's at least one major release with ERROR
This provides a final grace period for users who need additional time to migrate complex codebases.
Choose between complete removal and @Deprecated(HIDDEN)
Annotating by @Deprecated(HIDDEN) might be useful when the API is still needed for compatibility with already built JARs.