1 /* 2 * Copyright 2020 Google LLC 3 * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.google.devtools.ksp.symbol.impl.kotlin 19 20 import com.google.devtools.ksp.IdKey 21 import com.google.devtools.ksp.KSObjectCache 22 import com.google.devtools.ksp.processing.impl.ResolverImpl 23 import com.google.devtools.ksp.symbol.KSAnnotation 24 import com.google.devtools.ksp.symbol.KSDeclaration 25 import com.google.devtools.ksp.symbol.KSType 26 import com.google.devtools.ksp.symbol.KSTypeArgument 27 import com.google.devtools.ksp.symbol.Nullability 28 import com.google.devtools.ksp.symbol.Origin 29 import com.google.devtools.ksp.symbol.impl.binary.KSAnnotationDescriptorImpl 30 import com.google.devtools.ksp.symbol.impl.binary.KSTypeArgumentDescriptorImpl 31 import com.google.devtools.ksp.symbol.impl.convertKotlinType 32 import com.google.devtools.ksp.symbol.impl.replaceTypeArguments 33 import org.jetbrains.kotlin.builtins.isFunctionType 34 import org.jetbrains.kotlin.builtins.isKFunctionType 35 import org.jetbrains.kotlin.builtins.isKSuspendFunctionType 36 import org.jetbrains.kotlin.builtins.isSuspendFunctionType 37 import org.jetbrains.kotlin.descriptors.NotFoundClasses 38 import org.jetbrains.kotlin.descriptors.SourceElement 39 import org.jetbrains.kotlin.types.* 40 import org.jetbrains.kotlin.types.typeUtil.TypeNullability 41 import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf 42 import org.jetbrains.kotlin.types.typeUtil.makeNotNullable 43 import org.jetbrains.kotlin.types.typeUtil.makeNullable 44 import org.jetbrains.kotlin.types.typeUtil.nullability 45 import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections 46 47 class KSTypeImpl private constructor( 48 val kotlinType: KotlinType, 49 private val ksTypeArguments: List<KSTypeArgument>? = null, 50 override val annotations: Sequence<KSAnnotation> = sequenceOf() 51 ) : KSType { 52 companion object : KSObjectCache<IdKey<KotlinType>, KSTypeImpl>() { getCachednull53 fun getCached( 54 kotlinType: KotlinType, 55 ksTypeArguments: List<KSTypeArgument>? = null, 56 annotations: Sequence<KSAnnotation> = sequenceOf() 57 ): KSTypeImpl { 58 return cache.getOrPut(IdKey(kotlinType)) { KSTypeImpl(kotlinType, ksTypeArguments, annotations) } 59 } 60 } 61 <lambda>null62 override val declaration: KSDeclaration by lazy { 63 ResolverImpl.instance!!.findDeclaration(kotlinType.getAbbreviation() ?: kotlinType) 64 } 65 <lambda>null66 override val nullability: Nullability by lazy { 67 when (kotlinType.nullability()) { 68 TypeNullability.NULLABLE -> Nullability.NULLABLE 69 TypeNullability.NOT_NULL -> Nullability.NOT_NULL 70 TypeNullability.FLEXIBLE -> Nullability.PLATFORM 71 } 72 } 73 74 // TODO: fix calls to getKSTypeCached and use ksTypeArguments when available. <lambda>null75 override val arguments: List<KSTypeArgument> by lazy { 76 (kotlinType.getAbbreviation() ?: kotlinType).arguments.map { 77 KSTypeArgumentDescriptorImpl.getCached(it, Origin.SYNTHETIC, null) 78 } 79 } 80 isAssignableFromnull81 override fun isAssignableFrom(that: KSType): Boolean { 82 val subType = (that as? KSTypeImpl)?.kotlinType?.convertKotlinType() ?: return false 83 ResolverImpl.instance!!.incrementalContext.recordLookupWithSupertypes(subType) 84 val thisType = (this as? KSTypeImpl)?.kotlinType?.convertKotlinType() ?: return false 85 return subType.isSubtypeOf(thisType) 86 } 87 88 // TODO: find a better way to reuse the logic in [DescriptorRendererImpl.renderFlexibleType]. isMutabilityFlexiblenull89 override fun isMutabilityFlexible(): Boolean { 90 return kotlinType.toString().startsWith("(Mutable)") 91 } 92 93 // TODO: find a better way to reuse the logic in [DescriptorRendererImpl.renderFlexibleType]. isCovarianceFlexiblenull94 override fun isCovarianceFlexible(): Boolean { 95 return kotlinType.toString().startsWith("Array<(out) ") 96 } 97 replacenull98 override fun replace(arguments: List<KSTypeArgument>): KSType { 99 return kotlinType.replaceTypeArguments(arguments)?.let { 100 getKSTypeCached(it, arguments) 101 } ?: KSErrorType 102 } 103 starProjectionnull104 override fun starProjection(): KSType { 105 return getKSTypeCached(kotlinType.replaceArgumentsWithStarProjections()) 106 } 107 <lambda>null108 private val meNullable: KSType by lazy { getKSTypeCached(kotlinType.makeNullable()) } makeNullablenull109 override fun makeNullable(): KSType = meNullable 110 111 private val meNotNullable: KSType by lazy { getKSTypeCached(kotlinType.makeNotNullable()) } makeNotNullablenull112 override fun makeNotNullable(): KSType = meNotNullable 113 114 override val isMarkedNullable: Boolean = kotlinType.isMarkedNullable 115 116 override val isError: Boolean = false 117 118 override fun equals(other: Any?): Boolean { 119 if (other !is KSTypeImpl) 120 return false 121 return kotlinType.equals(other.kotlinType) 122 } 123 hashCodenull124 override fun hashCode(): Int = kotlinType.hashCode() 125 126 override fun toString(): String = (kotlinType.getAbbreviation() ?: kotlinType).toString() 127 128 override val isFunctionType: Boolean 129 get() = kotlinType.isFunctionType || kotlinType.isKFunctionType 130 131 override val isSuspendFunctionType: Boolean 132 get() = kotlinType.isSuspendFunctionType || kotlinType.isKSuspendFunctionType 133 } 134 135 fun getKSTypeCached( 136 kotlinType: KotlinType, 137 ksTypeArguments: List<KSTypeArgument>? = null, 138 annotations: Sequence<KSAnnotation> = sequenceOf() 139 ): KSType { 140 return if (kotlinType.isError || 141 kotlinType.constructor.declarationDescriptor is NotFoundClasses.MockClassDescriptor 142 ) { 143 KSErrorType 144 } else { 145 KSTypeImpl.getCached( 146 kotlinType, 147 ksTypeArguments, 148 annotations + kotlinType.annotations 149 .filter { it.source == SourceElement.NO_SOURCE } 150 .map { KSAnnotationDescriptorImpl.getCached(it, null) } 151 .asSequence() 152 ) 153 } 154 } 155