diff --git a/app/src/main/kotlin/com/skydoves/myapplication/MainActivity.kt b/app/src/main/kotlin/com/skydoves/myapplication/MainActivity.kt index aec576c..ee78973 100644 --- a/app/src/main/kotlin/com/skydoves/myapplication/MainActivity.kt +++ b/app/src/main/kotlin/com/skydoves/myapplication/MainActivity.kt @@ -44,8 +44,10 @@ import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.ViewModel +import com.skydoves.compose.stability.runtime.IgnoreStabilityReport import com.skydoves.myapplication.models.ImmutableData import com.skydoves.myapplication.models.MyClass2 import com.skydoves.myapplication.models.NormalClass @@ -356,9 +358,9 @@ fun StableUserCardPreview() { /** * Example: Debug composable excluded from stability reports. */ -@com.skydoves.compose.stability.runtime.IgnoreStabilityReport +@Preview @Composable -fun DebugInfoPanel() { +fun DebugInfoPanelPreview() { Card { Column(modifier = Modifier.padding(16.dp)) { Text("Debug Information", fontWeight = FontWeight.Bold) diff --git a/stability-compiler/src/main/kotlin/com/skydoves/compose/stability/compiler/lower/StabilityAnalyzerTransformer.kt b/stability-compiler/src/main/kotlin/com/skydoves/compose/stability/compiler/lower/StabilityAnalyzerTransformer.kt index 487a6db..dfe0944 100644 --- a/stability-compiler/src/main/kotlin/com/skydoves/compose/stability/compiler/lower/StabilityAnalyzerTransformer.kt +++ b/stability-compiler/src/main/kotlin/com/skydoves/compose/stability/compiler/lower/StabilityAnalyzerTransformer.kt @@ -41,7 +41,7 @@ import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.name.FqName public class StabilityAnalyzerTransformer( - private val context: IrPluginContext, + context: IrPluginContext, private val stabilityCollector: StabilityInfoCollector? = null, ) : IrElementTransformerVoidWithContext() { @@ -52,6 +52,7 @@ public class StabilityAnalyzerTransformer( FqName("com.skydoves.compose.stability.runtime.TraceRecomposition") private val ignoreStabilityReportFqName = FqName("com.skydoves.compose.stability.runtime.IgnoreStabilityReport") + private val previewFqName = FqName("androidx.compose.ui.tooling.preview.Preview") private val irBuilder = RecompositionIrBuilder(context) private var irBuilderInitialized = false @@ -71,8 +72,9 @@ public class StabilityAnalyzerTransformer( return super.visitFunctionNew(declaration) } - // Skip stability reporting if function has @IgnoreStabilityReport annotation - val shouldIgnoreReport = declaration.hasAnnotation(ignoreStabilityReportFqName) + // Skip stability reporting if function has @IgnoreStabilityReport annotation or @Preview annotation + val shouldIgnoreReport = declaration.hasAnnotation(ignoreStabilityReportFqName) || + hasPreviewAnnotation(declaration) // Collect stability information if collector is available and not ignored if (!shouldIgnoreReport) { @@ -601,6 +603,35 @@ public class StabilityAnalyzerTransformer( return fqName in KNOWN_STABLE_TYPES } + /** + * Check if a function has @Preview annotation (directly or via meta-annotation). + * This includes: + * - Direct @Preview annotation + * - Custom annotations that are meta-annotated with @Preview + */ + private fun hasPreviewAnnotation(function: IrFunction): Boolean { + // Check direct @Preview annotation + if (function.hasAnnotation(previewFqName)) { + return true + } + + // Check for meta-annotations (annotations on annotations) + for (annotation in function.annotations) { + try { + val annotationType = annotation.type + val annotationClass = annotationType.classOrNull?.owner + if (annotationClass != null && annotationClass.hasAnnotation(previewFqName)) { + return true + } + } catch (e: Exception) { + // Skip annotations that can't be resolved + continue + } + } + + return false + } + /** * Check if a type is a known unstable Java class. *