blob: 9b70b3147f8fc8c357b7eb1bf0ffb5f23be4cc8a [file] [log] [blame]
package androidx.compose.plugins.kotlin.frames.analysis
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.container.ComponentProvider
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.diagnostics.reportFromPlugin
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import androidx.compose.plugins.kotlin.ComposeFlags
import androidx.compose.plugins.kotlin.analysis.ComposeDefaultErrorMessages
import androidx.compose.plugins.kotlin.analysis.ComposeErrors
import androidx.compose.plugins.kotlin.frames.FrameRecordClassDescriptor
import androidx.compose.plugins.kotlin.frames.SyntheticFramePackageDescriptor
import androidx.compose.plugins.kotlin.frames.abstractRecordClassName
import androidx.compose.plugins.kotlin.frames.findTopLevel
import androidx.compose.plugins.kotlin.frames.modelClassName
import androidx.compose.plugins.kotlin.frames.recordClassName
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
import org.jetbrains.kotlin.types.typeUtil.isInterface
class FramePackageAnalysisHandlerExtension : AnalysisHandlerExtension {
companion object {
fun doAnalysis(
module: ModuleDescriptor,
bindingTrace: BindingTrace,
files: Collection<KtFile>,
resolveSession: ResolveSession
) {
if (!ComposeFlags.FRAMED_MODEL_CLASSES) return
for (file in files) {
for (declaration in file.declarations) {
val ktClass = declaration as? KtClassOrObject ?: continue
val framedDescriptor = resolveSession.resolveToDescriptor(declaration) as?
ClassDescriptor ?: continue
if (!framedDescriptor.hasModelAnnotation()) continue
val classFqName = ktClass.fqName!!
val recordFqName = classFqName.parent().child(Name.identifier(
"${classFqName.shortName()}\$Record")
)
val recordSimpleName = recordFqName.shortName()
val recordPackage =
SyntheticFramePackageDescriptor(
module,
recordFqName.parent()
)
val baseTypeDescriptor = module.findTopLevel(abstractRecordClassName)
val recordDescriptor = module.findTopLevel(recordClassName)
val baseType = baseTypeDescriptor.defaultType
val frameClass =
FrameRecordClassDescriptor(
recordSimpleName,
recordPackage,
recordDescriptor,
framedDescriptor,
listOf(baseType),
bindingTrace.bindingContext
)
recordPackage.setClassDescriptor(frameClass)
bindingTrace.record(FrameWritableSlices.RECORD_CLASS, classFqName, frameClass)
bindingTrace.record(
FrameWritableSlices.FRAMED_DESCRIPTOR,
classFqName,
framedDescriptor
)
}
}
}
}
override fun doAnalysis(
project: Project,
module: ModuleDescriptor,
projectContext: ProjectContext,
files: Collection<KtFile>,
bindingTrace: BindingTrace,
componentProvider: ComponentProvider
): AnalysisResult? {
val resolveSession = componentProvider.get<ResolveSession>()
doAnalysis(
module,
bindingTrace,
files,
resolveSession
)
return null
}
}
private fun Annotated.hasModelAnnotation() = annotations.findAnnotation(modelClassName) != null