All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.codegen.typeAnnotationCollector.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.codegen

import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeVariance
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.TypePath


class TypePathInfo(
    val path: TypePath?,
    val annotations: List
)

private class State(val path: MutableList) {

    val results = arrayListOf>()


    fun addStep(step: String) {
        path.add(step)
    }

    fun removeStep() {
        path.removeAt(path.lastIndex)
    }

    fun rememberAnnotations(annotations: List) {
        results.add(TypePathInfo(TypePath.fromString(path.joinToString("")), annotations))
    }
}

class PsiTypeAnnotationCollector : TypeAnnotationCollector(SimpleClassicTypeSystemContext) {

    override fun KotlinTypeMarker.extractAnnotations(): List {
        require(this is KotlinType)
        return annotations.filter {
            //We only generate annotations which have the TYPE_USE Java target.
            // Those are type annotations which were compiled with JVM target bytecode version 1.8 or greater
            isCompiledToJvm8OrHigher(it.annotationClass)
        }
    }
}

abstract class TypeAnnotationCollector(val context: TypeSystemCommonBackendContext) {

    private lateinit var state: State

    fun collectTypeAnnotations(kotlinType: KotlinTypeMarker): ArrayList> {
        state = State(arrayListOf())
        kotlinType.gatherTypeAnnotations()
        return state.results
    }

    private fun KotlinTypeMarker.gatherTypeAnnotations() {
        with(context) {
            if (isFlexible()) {
                return upperBoundIfFlexible().gatherTypeAnnotations()
            } else if (typeConstructor().isInnerClass()) {
                //skip inner classes for now it's not clear should type annotations on outer be supported or not
                return
            }

            extractAnnotations().takeIf { it.isNotEmpty() }?.let { state.rememberAnnotations(it) }

            for (index in 0 until argumentsCount()) {
                val type = getArgument(index)
                //skip in/out variance for now it's not clear should type annotations on wildcard bound be supported or not
                if (type.getVariance() == TypeVariance.INV) {
                    when {
                        [email protected]() -> type.getType().process("[")
                        else -> type.getType().process("$index;")
                    }
                }
            }
        }
    }

    fun KotlinTypeMarker.process(step: String) {
        state.addStep(step)
        this.gatherTypeAnnotations()
        state.removeStep()
    }


    abstract fun KotlinTypeMarker.extractAnnotations(): List

    fun isCompiledToJvm8OrHigher(descriptor: ClassDescriptor?): Boolean =
        (descriptor as? DeserializedClassDescriptor)?.let { classDescriptor -> isCompiledToJvm8OrHigher(classDescriptor.source) }
            ?: true

    fun isCompiledToJvm8OrHigher(source: SourceElement): Boolean =
        (source !is KotlinJvmBinarySourceElement ||
                (source.binaryClass as? FileBasedKotlinClass)?.classVersion ?: 0 >= Opcodes.V1_8)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy