Skip to content

Conversation

@skydoves
Copy link
Owner

@skydoves skydoves commented Nov 2, 2025

Introduce KotlinCompilerPluginSupportPlugin and adjust StabilityInferred annotation check

Summary by CodeRabbit

Version 0.4.1 Release Notes

  • New Features

    • Added comprehensive stability detection for Compose Foundation shape types.
  • Bug Fixes

    • Fixed stability exports to properly exclude compiler-generated anonymous composables.
  • Improvements

    • Upgraded Gradle plugin infrastructure for enhanced Kotlin compiler integration.
    • Optimized stability analysis flow for more accurate type determination.

@skydoves skydoves self-assigned this Nov 2, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 2, 2025

Walkthrough

This pull request restructures stability analysis workflows, migrates the Gradle plugin to leverage Kotlin compiler plugin infrastructure, filters compiler-generated anonymous composables from exports, expands known-stable shape types, and updates function signatures for composable content parameters—shifting from composable-typed to explicit function types with adjusted nullability.

Changes

Cohort / File(s) Change Summary
Stability Type Expansion
compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/StabilityAnalysisConstants.kt
Added seven new shape types to KNOWN_STABLE_TYPES: RoundedCornerShape, CircleShape, CutCornerShape, CornerBasedShape, AbsoluteRoundedCornerShape, AbsoluteCutCornerShape, RectangleShape.
Stability Analysis Reordering
compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/StabilityAnalyzer.kt, compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/k2/KtStabilityInferencer.kt, stability-compiler/src/main/kotlin/com/skydoves/compose/stability/compiler/lower/StabilityAnalyzerTransformer.kt
Reordered stability determination to prioritize property-based analysis before @StabilityInferred checks; definitive results (STABLE/UNSTABLE) short-circuit further analysis; deferred to @StabilityInferred only for uncertain cases. Introduced placeholder getStabilityInferredParameters() helper.
Anonymous Composable Filtering
stability-compiler/src/main/kotlin/com/skydoves/compose/stability/compiler/StabilityInfoCollector.kt, stability-gradle/src/main/kotlin/com/skydoves/compose/stability/gradle/StabilityCheckTask.kt, stability-gradle/src/main/kotlin/com/skydoves/compose/stability/gradle/StabilityDumpTask.kt
Added filter condition to exclude compiler-generated composables (those with qualifiedName containing <anonymous>) from JSON exports and stability checks.
Gradle Plugin Architecture Migration
stability-gradle/src/main/kotlin/com/skydoves/compose/stability/gradle/StabilityAnalyzerGradlePlugin.kt, stability-gradle/api/stability-gradle.api
Migrated StabilityAnalyzerGradlePlugin from Plugin to KotlinCompilerPluginSupportPlugin; added compiler-plugin-centric wiring with new public methods (isApplicable, getCompilerPluginId, getPluginArtifact, applyToCompilation, getPluginArtifactForNative); refactored task configuration and runtime dependency management.
Function Signature Updates
app/stability/app.stability
Updated Card, Icon, MixedStabilityDisplay, TrackedCounterDisplay signatures: replaced composable function types with explicit function types, expanded parameter nullability (modifier, shape, colors, elevation), changed content parameters from ComposableFunction to Function types.
Version & Build Configuration
gradle.properties
Version bumped from 0.4.0 to 0.4.1.
Repository Configuration
settings.gradle.kts
Added mavenLocal() to pluginManagement and dependencyResolutionManagement repositories.
Dependency Scope Adjustment
stability-compiler/build.gradle.kts
Changed stability-runtime dependency from api(...) to implementation(...), reducing public API surface.

Sequence Diagram

sequenceDiagram
    participant Old as Old Flow
    participant New as New Flow

    rect rgba(200, 220, 255, 0.2)
    Note over Old: Previous Approach
    Old->>Old: Check @StabilityInferred (early)
    Old->>Old: Return RUNTIME if present
    Old->>Old: Check other properties
    end

    rect rgba(200, 255, 220, 0.2)
    Note over New: New Approach
    New->>New: Analyze class properties first
    alt Property analysis conclusive
        New->>New: Return STABLE or UNSTABLE
    else Property analysis inconclusive
        New->>New: Check @StabilityInferred parameters
        alt Parameters == 0
            New->>New: Return STABLE
        else Parameters > 0
            New->>New: Return RUNTIME
        end
    end
    end
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • Gradle plugin migration logic (StabilityAnalyzerGradlePlugin.kt): Comprehensive refactoring from direct plugin API to KotlinCompilerPluginSupportPlugin; verify all lifecycle hooks (isApplicable, applyToCompilation, getCompilerPluginId) are correctly wired and that multiplatform/JVM/Android distinctions are handled correctly.
  • Stability analysis reordering (StabilityAnalyzer.kt, KtStabilityInferencer.kt, StabilityAnalyzerTransformer.kt): Verify that the new early-return logic for definitive property-based results does not break edge cases; confirm placeholder getStabilityInferredParameters() implementation is documented as TODO and will be replaced with proper K2 API integration.
  • Anonymous composable filtering across three collector/task files: Ensure "" filtering is consistently applied and does not unintentionally exclude legitimate composables with similar naming patterns.
  • Function signature changes in app.stability: Validate that the shift from composable-typed to explicit function types (Function2, Function3) maintains backward compatibility or intentionally breaks callers as designed.
  • Gradle configuration in settings.gradle.kts: Review repository ordering and ensure mavenLocal() precedence does not cause unintended artifact resolution.

Poem

🐰 Hopping through stability with newfound grace,
We reorder the checks to a proper place—
Properties first, then inferred if needed,
And filter those anonymous ghosts that sped it!
The Gradle plugin wears plugin support's new face, 🎩
A restructured realm in the compiler's embrace!

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description is entirely incomplete and does not follow the required template structure. The author has provided only the PR title repeated verbatim, with no actual description content. The required template specifies four sections: Goal, Implementation details, Explain examples, and Preparing a pull request for review (including spotlessApply and apiDump commands). None of these sections are present in the provided description—there is no explanation of the big picture, no implementation details, no code examples, and no mention of the required build validation steps. The author should expand the PR description to follow the repository's template structure. Add a Goal section explaining why this migration to KotlinCompilerPluginSupportPlugin is needed and what problems it solves; provide Implementation details documenting the key changes across the various modified files; include code examples showing before/after if relevant; and confirm that spotlessApply and apiDump have been run successfully. This will help reviewers understand the motivation and impact of the changes more clearly.
Docstring Coverage ⚠️ Warning Docstring coverage is 45.83% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "Introduce KotlinCompilerPluginSupportPlugin and adjust StabilityInferred annotation check" accurately captures the two primary changes in this pull request: the migration of StabilityAnalyzerGradlePlugin to use KotlinCompilerPluginSupportPlugin (a high-effort architectural change) and the reordering of StabilityInferred annotation checks across multiple analyzer files (another high-effort logical change). The title is concise, specific, and clear enough that a teammate scanning the commit history would understand the main architectural and logic modifications being made. While the PR includes additional secondary changes such as filtering anonymous composables and version bumping, these are appropriately not emphasized in the title, as the instructions note that titles need not cover every detail of the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/compiler-supporter-plugin

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@skydoves skydoves changed the title Introduce KotlinCompilerPluginSupportPlugin and adjust StabilityInfer… Introduce KotlinCompilerPluginSupportPlugin and adjust StabilityInferred annotation check Nov 2, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
settings.gradle.kts (1)

3-7: Duplicate mavenLocal() in pluginManagement repositories.

The mavenLocal() repository is declared twice in the pluginManagement.repositories block (lines 3 and 7). Remove the duplicate entry to avoid redundancy.

Apply this diff to remove the duplicate:

 pluginManagement {
   repositories {
     mavenLocal()
     gradlePluginPortal()
     google()
     mavenCentral()
-    mavenLocal()
   }
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e8280a and d4d2776.

📒 Files selected for processing (13)
  • app/stability/app.stability (4 hunks)
  • compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/StabilityAnalysisConstants.kt (1 hunks)
  • compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/StabilityAnalyzer.kt (2 hunks)
  • compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/k2/KtStabilityInferencer.kt (3 hunks)
  • gradle.properties (1 hunks)
  • gradle/libs.versions.toml (1 hunks)
  • settings.gradle.kts (2 hunks)
  • stability-compiler/src/main/kotlin/com/skydoves/compose/stability/compiler/StabilityInfoCollector.kt (3 hunks)
  • stability-compiler/src/main/kotlin/com/skydoves/compose/stability/compiler/lower/StabilityAnalyzerTransformer.kt (3 hunks)
  • stability-gradle/api/stability-gradle.api (1 hunks)
  • stability-gradle/src/main/kotlin/com/skydoves/compose/stability/gradle/StabilityAnalyzerGradlePlugin.kt (2 hunks)
  • stability-gradle/src/main/kotlin/com/skydoves/compose/stability/gradle/StabilityCheckTask.kt (1 hunks)
  • stability-gradle/src/main/kotlin/com/skydoves/compose/stability/gradle/StabilityDumpTask.kt (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/k2/KtStabilityInferencer.kt (2)
compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/StabilityAnalyzer.kt (1)
  • analyzeClassProperties (886-944)
stability-compiler/src/main/kotlin/com/skydoves/compose/stability/compiler/lower/StabilityAnalyzerTransformer.kt (1)
  • analyzeClassProperties (345-372)
stability-compiler/src/main/kotlin/com/skydoves/compose/stability/compiler/lower/StabilityAnalyzerTransformer.kt (2)
compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/StabilityAnalyzer.kt (1)
  • analyzeClassProperties (886-944)
compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/k2/KtStabilityInferencer.kt (1)
  • analyzeClassProperties (322-405)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build and Tests
🔇 Additional comments (14)
app/stability/app.stability (4)

16-27: Signature update reflects Compose IR types correctly.

The nullable wrappers and the explicit Function2/Function3 encodings line up with the transformed Compose signatures, and the stability flags still look accurate for the analyzer output. Nicely done.


65-74: Icon export stays consistent with stability rules.

The tighter List<StableUser> typing and nullable elevation mirror the source API while keeping the correct runtime-versus-stable markings.


89-99: Nullable modifier keeps the right stability classification.

Modifier? remains treated as stable, so this export matches Compose expectations.


200-206: Function2 encoding for content looks spot on.

The analyzer now emits the lowered signature while keeping the stable classification, which is what we want.

gradle.properties (1)

54-54: LGTM!

Version bump to 0.4.1 is consistent with the PR objectives and other version changes across the codebase.

gradle/libs.versions.toml (1)

15-15: LGTM!

Version bump to 0.4.1 is consistent with the version changes in gradle.properties and the PR objectives.

stability-gradle/src/main/kotlin/com/skydoves/compose/stability/gradle/StabilityCheckTask.kt (1)

140-143: LGTM!

The anonymous composable filtering logic is correctly implemented and aligns with the same filtering approach used in StabilityDumpTask.kt and StabilityInfoCollector.kt.

stability-gradle/src/main/kotlin/com/skydoves/compose/stability/gradle/StabilityDumpTask.kt (1)

256-260: LGTM!

The anonymous composable filtering is correctly placed before the ignoredPackages and ignoredClasses filters, ensuring compiler-generated entries are excluded early in the pipeline. This aligns with the filtering approach in StabilityCheckTask.kt and StabilityInfoCollector.kt.

stability-compiler/src/main/kotlin/com/skydoves/compose/stability/compiler/StabilityInfoCollector.kt (2)

40-50: LGTM!

The filtering of anonymous composables from the JSON export is correctly implemented and aligns with the filtering approach in the Gradle tasks. The emptiness check now operates on the filtered list, which is the correct behavior.


58-91: LGTM!

All references to the composables collection have been correctly updated to use filteredComposables, ensuring anonymous entries are excluded from the JSON output.

stability-compiler/src/main/kotlin/com/skydoves/compose/stability/compiler/lower/StabilityAnalyzerTransformer.kt (3)

313-339: LGTM - Two-phase stability analysis correctly implemented.

The refactored logic correctly implements the two-phase approach:

  1. First, analyze class properties to determine if the class is definitively STABLE or UNSTABLE
  2. Only if properties yield RUNTIME, then check @StabilityInferred parameters

This aligns with the updated flow in the K2 implementation shown in the relevant code snippets.


407-413: Verify the impact of the placeholder implementation.

The getStabilityInferredParameters() helper currently returns null, which means all classes with runtime-dependent property stability will be treated as RUNTIME regardless of their @StabilityInferred annotation. This is conservative but may lead to more RUNTIME classifications than necessary.

Please verify that this placeholder implementation is acceptable for the 0.4.1 release, or if a working implementation should be prioritized. The TODO indicates this is intentional, but it's worth confirming the impact on stability analysis accuracy.


568-576: Fix package name typos for Compose Foundation shapes.

Lines 571-574 contain typos: androidxx should be androidx. These typos will prevent the stability analyzer from recognizing these types as stable. This is the same issue as in StabilityAnalysisConstants.kt.

Apply this diff to fix the typos:

       // Compose Foundation shapes
       "androidx.compose.foundation.shape.RoundedCornerShape",
       "androidx.compose.foundation.shape.CircleShape",
-      "androidxx.compose.foundation.shape.CutCornerShape",
-      "androidxx.compose.foundation.shape.CornerBasedShape",
-      "androidxx.compose.foundation.shape.AbsoluteRoundedCornerShape",
-      "androidxx.compose.foundation.shape.AbsoluteCutCornerShape",
+      "androidx.compose.foundation.shape.CutCornerShape",
+      "androidx.compose.foundation.shape.CornerBasedShape",
+      "androidx.compose.foundation.shape.AbsoluteRoundedCornerShape",
+      "androidx.compose.foundation.shape.AbsoluteCutCornerShape",
       "androidx.compose.ui.graphics.RectangleShape",

Likely an incorrect or invalid review comment.

compose-stability-analyzer-idea/src/main/kotlin/com/skydoves/compose/stability/idea/StabilityAnalysisConstants.kt (1)

87-95: Fix package name typos for Compose Foundation shapes.

Lines 90-93 contain typos: androidxx should be androidx. These typos will prevent the stability analyzer from recognizing these types as stable.

Apply this diff to fix the typos:

     // Compose Foundation shapes
     "androidx.compose.foundation.shape.RoundedCornerShape",
     "androidx.compose.foundation.shape.CircleShape",
-    "androidxx.compose.foundation.shape.CutCornerShape",
-    "androidxx.compose.foundation.shape.CornerBasedShape",
-    "androidxx.compose.foundation.shape.AbsoluteRoundedCornerShape",
-    "androidxx.compose.foundation.shape.AbsoluteCutCornerShape",
+    "androidx.compose.foundation.shape.CutCornerShape",
+    "androidx.compose.foundation.shape.CornerBasedShape",
+    "androidx.compose.foundation.shape.AbsoluteRoundedCornerShape",
+    "androidx.compose.foundation.shape.AbsoluteCutCornerShape",
     "androidx.compose.ui.graphics.RectangleShape",

Likely an incorrect or invalid review comment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
stability-gradle/src/main/kotlin/com/skydoves/compose/stability/gradle/StabilityAnalyzerGradlePlugin.kt (1)

57-61: Extension construction is missing required services

StabilityAnalyzerExtension still exposes a constructor (ProjectLayout, ObjectFactory, ProviderFactory). Calling extensions.create with only target.layout means Gradle will try to invoke a non-existent (ProjectLayout) ctor and will throw NoSuchMethodException when the plugin is applied. Please wire the missing services:

 val extension = target.extensions.create(
   "composeStabilityAnalyzer",
   StabilityAnalyzerExtension::class.java,
-  target.layout,
+  target.layout,
+  target.objects,
+  target.providers,
 )
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4d2776 and 610da31.

📒 Files selected for processing (3)
  • settings.gradle.kts (1 hunks)
  • stability-compiler/build.gradle.kts (1 hunks)
  • stability-gradle/src/main/kotlin/com/skydoves/compose/stability/gradle/StabilityAnalyzerGradlePlugin.kt (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Runtime Module Tests
  • GitHub Check: Test IntelliJ Plugin
  • GitHub Check: Build IntelliJ Plugin
  • GitHub Check: Build and Tests
  • GitHub Check: API check
  • GitHub Check: Spotless check
🔇 Additional comments (2)
settings.gradle.kts (1)

1-30: AI summary inconsistency detected.

The AI-generated summary states: "Added mavenLocal() to... Removed the trailing mavenLocal() entries from both...". However, the provided code (final state) shows mavenLocal() as added (marked with ~) at lines 3 and 13, with no evidence of removals. This discrepancy suggests either the summary is outdated or the code state does not reflect what the summary describes.

stability-compiler/build.gradle.kts (1)

32-32: No breaking API changes—dependency change is correct.

The concern about public API exposure is invalid in this context. While RecompositionIrBuilder is marked public, it and all other public classes in stability-compiler are compiler plugin infrastructure (extending or implementing Kotlin compiler plugin interfaces like CompilerPluginRegistrar, FirExtensionRegistrar, IrGenerationExtension). These classes are not consumer-facing APIs—they are discovered and instantiated by the Kotlin compiler framework via reflection. RecompositionIrBuilder is only used internally by StabilityAnalyzerTransformer and is not intended for direct consumer usage.

Changing the dependency scope from api to implementation is correct and safe for this use case, as it accurately reflects the internal-only nature of the stability-runtime dependency.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants