Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce AffectedComposable #38

Merged
merged 1 commit into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@
package land.sungbin.composeinvestigator.compiler.test.source

import androidx.compose.runtime.Composable
import land.sungbin.composeinvestigator.runtime.AffectedComposable
import land.sungbin.composeinvestigator.runtime.ComposeInvestigateLogType
import land.sungbin.composeinvestigator.runtime.ComposeInvestigateLogger

@ComposeInvestigateLogger
fun composeInvestigateLogger(composableName: String, logType: ComposeInvestigateLogType) {
fun composeInvestigateLogger(composable: AffectedComposable, logType: ComposeInvestigateLogType) {
when (logType) {
is ComposeInvestigateLogType.InvalidationProcessed -> {
println("<$composableName> InvalidationProcessed. DiffParams: ${logType.diffParams}")
println("<${composable.name} in ${composable.pkg}> InvalidationProcessed. DiffParams: ${logType.diffParams}")
}
is ComposeInvestigateLogType.InvalidationSkipped -> {
println("<$composableName> InvalidationSkipped")
println("<${composable.name} in ${composable.pkg}> InvalidationSkipped")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package land.sungbin.composeinvestigator.compiler.internal.logger

import land.sungbin.composeinvestigator.compiler.internal.COMPOSE_INVESTIGATE_AFFECTED_COMPOSABLE_FQN
import land.sungbin.composeinvestigator.compiler.internal.COMPOSE_INVESTIGATE_LOG_TYPE_FQN
import land.sungbin.composeinvestigator.compiler.internal.COMPOSE_INVESTIGATE_LOG_TYPE_INVALIDATION_PROCESSED_FQN
import land.sungbin.composeinvestigator.compiler.internal.COMPOSE_INVESTIGATE_LOG_TYPE_INVALIDATION_SKIPPED_FQN
Expand All @@ -28,6 +29,8 @@ internal object InvestigateLogger {
private var loggerSymbol: IrSimpleFunctionSymbol? = null
private var loggerType: LoggerType? = null

private var affectedComposableSymbol: IrClassSymbol? = null

private var logTypeSymbol: IrClassSymbol? = null
private var logTypeInvalidationProcessedSymbol: IrClassSymbol? = null
private var logTypeInvalidationSkippedSymbol: IrClassSymbol? = null
Expand Down Expand Up @@ -58,7 +61,7 @@ internal object InvestigateLogger {
}

internal fun makeIrCall(
composableName: IrConst<String>,
composable: IrDeclarationReference,
logType: IrDeclarationReference,
originalMessage: IrConst<String>,
): IrCall =
Expand All @@ -72,12 +75,20 @@ internal object InvestigateLogger {
putValueArgument(0, originalMessage)
}
LoggerType.Custom -> {
putValueArgument(0, composableName)
putValueArgument(0, composable)
putValueArgument(1, logType)
}
}
}

internal fun obtainAffectedComposableSymbol(context: IrPluginContext): IrClassSymbol {
if (affectedComposableSymbol == null) {
affectedComposableSymbol =
context.referenceClass(ClassId.topLevel(COMPOSE_INVESTIGATE_AFFECTED_COMPOSABLE_FQN))
}
return affectedComposableSymbol!!
}

internal fun obtainLogTypeSymbol(context: IrPluginContext): IrClassSymbol {
if (logTypeSymbol == null) {
logTypeSymbol = context.referenceClass(ClassId.topLevel(COMPOSE_INVESTIGATE_LOG_TYPE_FQN))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package land.sungbin.composeinvestigator.compiler.internal.logger

import land.sungbin.composeinvestigator.compiler.internal.COMPOSABLE_FQN
import land.sungbin.composeinvestigator.compiler.internal.COMPOSE_INVESTIGATE_AFFECTED_COMPOSABLE_FQN
import land.sungbin.composeinvestigator.compiler.internal.COMPOSE_INVESTIGATE_LOGGER_FQN
import land.sungbin.composeinvestigator.compiler.internal.COMPOSE_INVESTIGATE_LOG_TYPE_FQN
import land.sungbin.composeinvestigator.compiler.internal.origin.InvestigateLoggerUsedFuntionOrigin
Expand All @@ -17,7 +18,6 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.types.classFqName
import org.jetbrains.kotlin.ir.types.isString
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.hasAnnotation
Expand Down Expand Up @@ -51,7 +51,7 @@ internal class InvestigateLoggerVisitor(
// 4. no extension receiver and no context receiver
// 5. not suspend
// 6. unit type
// 7. has only two parameters: <String, LogType>
// 7. has only two parameters: <AffectedComposable, ComposeInvestigateLogType>
private fun IrFunction.isValidComposeInvestigateLoggerFunction(): Boolean =
hasAnnotation(COMPOSE_INVESTIGATE_LOGGER_FQN) &&
!hasAnnotation(COMPOSABLE_FQN) &&
Expand All @@ -62,6 +62,6 @@ internal class InvestigateLoggerVisitor(
!isSuspend &&
returnType.isUnit() &&
valueParameters.size == 2 &&
valueParameters[0].type.isString() &&
valueParameters[0].type.classFqName == COMPOSE_INVESTIGATE_AFFECTED_COMPOSABLE_FQN &&
valueParameters[1].type.classFqName == COMPOSE_INVESTIGATE_LOG_TYPE_FQN
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ internal val COMPOSER_FQN = FqName("$AndroidxComposeRuntime.Composer")
internal val COMPOSER_KT_FQN = FqName("$AndroidxComposeRuntime.ComposerKt")

internal val COMPOSE_INVESTIGATE_LOGGER_FQN = FqName("$ComposeInvestigatorRuntime.ComposeInvestigateLogger")
internal val COMPOSE_INVESTIGATE_AFFECTED_COMPOSABLE_FQN = FqName("$ComposeInvestigatorRuntime.AffectedComposable")
internal val COMPOSE_INVESTIGATE_LOG_TYPE_FQN = FqName("$ComposeInvestigatorRuntime.ComposeInvestigateLogType")
internal val COMPOSE_INVESTIGATE_LOG_TYPE_INVALIDATION_PROCESSED_FQN = COMPOSE_INVESTIGATE_LOG_TYPE_FQN.child(Name.identifier("InvalidationProcessed"))
internal val COMPOSE_INVESTIGATE_LOG_TYPE_INVALIDATION_SKIPPED_FQN = COMPOSE_INVESTIGATE_LOG_TYPE_FQN.child(Name.identifier("InvalidationSkipped"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.IrCall
Expand All @@ -23,9 +24,11 @@ import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.isInt
import org.jetbrains.kotlin.ir.types.isNullableAny
import org.jetbrains.kotlin.ir.types.isString
import org.jetbrains.kotlin.ir.util.kotlinFqName
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.utils.addToStdlib.cast

internal abstract class AbstractInvalidationTrackingLower(context: IrPluginContext) :
Expand Down Expand Up @@ -74,6 +77,20 @@ internal abstract class AbstractInvalidationTrackingLower(context: IrPluginConte
return (currentFunctionOrNull ?: return "<unknown>").name.asString()
}

protected fun getCurrentFunctionPackage() = currentFunctionOrNull?.kotlinFqName?.asString() ?: "<unknown>"

protected fun getCurrentFunctionNameIntercepttedAnonymous(): String {
val currentFunctionName = currentFunctionOrNull?.name
return if (currentFunctionName == SpecialNames.ANONYMOUS) {
try {
val parent = currentFunction!!.irElement.cast<IrSimpleFunction>().parent
"${SpecialNames.ANONYMOUS_STRING} in ${parent.kotlinFqName.asString()}"
} catch (_: Exception) {
SpecialNames.ANONYMOUS_STRING
}
} else currentFunctionName?.asString() ?: "<unknown>"
}

protected fun irGetValue(value: IrValueDeclaration): IrGetValue =
IrGetValueImpl(
startOffset = UNDEFINED_OFFSET,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import org.jetbrains.kotlin.ir.declarations.IrAttributeContainer
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
import org.jetbrains.kotlin.ir.expressions.IrBlock
import org.jetbrains.kotlin.ir.expressions.IrCall
Expand All @@ -54,7 +53,6 @@ import org.jetbrains.kotlin.ir.util.isTopLevel
import org.jetbrains.kotlin.ir.util.kotlinFqName
import org.jetbrains.kotlin.load.kotlin.FacadeClassSource
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.cast

Expand Down Expand Up @@ -165,6 +163,14 @@ internal class InvalidationTrackableTransformer(
newStatements += computeDiffParamsIfPresentVariable

val originalLogMessage = irString("[INVALIDATION_TRACKER] <${getCurrentFunctionNameIntercepttedAnonymous()}> invalidation processed")
val affectedComposableSymbol = InvestigateLogger.obtainAffectedComposableSymbol(context)
val affectedComposableCall = IrConstructorCallImpl.fromSymbolOwner(
type = affectedComposableSymbol.owner.defaultType,
constructorSymbol = affectedComposableSymbol.constructors.single(),
).apply {
putValueArgument(0, irString(currentFunctionName))
putValueArgument(1, irString(getCurrentFunctionPackage()))
}
val logTypeSymbol = InvestigateLogger.obtainLogTypeSymbol(context)
val logTypeInvalidationProcessedSymbol = InvestigateLogger.obtainLogTypeInvalidationProcessedSymbol(context)
val logTypeCall = IrConstructorCallImpl.fromSymbolOwner(
Expand All @@ -174,7 +180,7 @@ internal class InvalidationTrackableTransformer(
putValueArgument(0, irGetValue(computeDiffParamsIfPresentVariable))
}
val loggerCall = InvestigateLogger.makeIrCall(
composableName = irString(currentFunctionName),
composable = affectedComposableCall,
logType = logTypeCall,
originalMessage = originalLogMessage,
)
Expand Down Expand Up @@ -218,6 +224,14 @@ internal class InvalidationTrackableTransformer(
// SKIP_TO_GROUP_END is declared in 'androidx.compose.runtime.Composer'
if (fnName == SKIP_TO_GROUP_END && fnParentFqn == COMPOSER_FQN) {
val originalLogMessage = irString("[INVALIDATION_TRACKER] <${getCurrentFunctionNameIntercepttedAnonymous()}> invalidation skipped")
val affectedComposableSymbol = InvestigateLogger.obtainAffectedComposableSymbol(context)
val affectedComposableCall = IrConstructorCallImpl.fromSymbolOwner(
type = affectedComposableSymbol.owner.defaultType,
constructorSymbol = affectedComposableSymbol.constructors.single(),
).apply {
putValueArgument(0, irString(currentFunctionName))
putValueArgument(1, irString(getCurrentFunctionPackage()))
}
val logTypeSymbol = InvestigateLogger.obtainLogTypeSymbol(context)
val logTypeInvalidationSkippedSymbol = InvestigateLogger.obtainLogTypeInvalidationSkippedSymbol(context)
val logTypeCall = IrGetObjectValueImpl(
Expand All @@ -227,7 +241,7 @@ internal class InvalidationTrackableTransformer(
symbol = logTypeInvalidationSkippedSymbol,
)
val loggerCall = InvestigateLogger.makeIrCall(
composableName = irString(currentFunctionName),
composable = affectedComposableCall,
logType = logTypeCall,
originalMessage = originalLogMessage,
)
Expand All @@ -247,18 +261,6 @@ internal class InvalidationTrackableTransformer(
return super.visitElseBranch(branch)
}

private fun getCurrentFunctionNameIntercepttedAnonymous(): String {
val currentFunctionName = currentFunctionOrNull?.name
return if (currentFunctionName == SpecialNames.ANONYMOUS) {
try {
val parent = currentFunction!!.irElement.cast<IrSimpleFunction>().parent
"${SpecialNames.ANONYMOUS_STRING} in ${parent.kotlinFqName.asString()}"
} catch (_: Exception) {
SpecialNames.ANONYMOUS_STRING
}
} else currentFunctionName?.asString() ?: "<unknown>"
}

private fun IrWhen.isComposerTrackBranch(): Boolean {
val branch = branches.singleOrNull() ?: return false
val `if` = (branch.condition as? IrCall ?: return false).symbol.owner
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ package land.sungbin.composeinvestigator.runtime
/**
* ```
* @ComposeInvestigateLogger
* public fun composeInvestigateLogger(composableName: String, logType: ComposeInvestigateLogType) {
* public fun composeInvestigateLogger(composable: AffectedComposable, logType: ComposeInvestigateLogType) {
* // Your logger code here
* }
* ```
Expand All @@ -20,6 +20,8 @@ package land.sungbin.composeinvestigator.runtime
@Target(AnnotationTarget.FUNCTION)
public annotation class ComposeInvestigateLogger

public data class AffectedComposable(public val name: String, public val pkg: String)

public sealed class ComposeInvestigateLogType {
public class InvalidationProcessed(public val diffParams: DiffParams?) : ComposeInvestigateLogType()
public data object InvalidationSkipped : ComposeInvestigateLogType()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import land.sungbin.composeinvestigator.runtime.AffectedComposable
import land.sungbin.composeinvestigator.runtime.ComposeInvestigateLogType
import land.sungbin.composeinvestigator.runtime.ComposeInvestigateLogger

@Suppress("unused")
@ComposeInvestigateLogger
fun composeInvestigateLogger(composable: AffectedComposable, logType: ComposeInvestigateLogType) {
when (logType) {
is ComposeInvestigateLogType.InvalidationProcessed -> {
println("<${composable.name} in ${composable.pkg}> InvalidationProcessed. DiffParams: ${logType.diffParams}")
}
is ComposeInvestigateLogType.InvalidationSkipped -> {
println("<${composable.name} in ${composable.pkg}> InvalidationSkipped")
}
}
}

class SampleActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
Expand Down