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.ExceptionMessage 21 import com.google.devtools.ksp.KSObjectCache 22 import com.google.devtools.ksp.memoized 23 import com.google.devtools.ksp.processing.impl.ResolverImpl 24 import com.google.devtools.ksp.symbol.KSAnnotation 25 import com.google.devtools.ksp.symbol.KSNode 26 import com.google.devtools.ksp.symbol.KSReferenceElement 27 import com.google.devtools.ksp.symbol.KSType 28 import com.google.devtools.ksp.symbol.KSTypeReference 29 import com.google.devtools.ksp.symbol.KSVisitor 30 import com.google.devtools.ksp.symbol.Location 31 import com.google.devtools.ksp.symbol.Modifier 32 import com.google.devtools.ksp.symbol.Origin 33 import com.google.devtools.ksp.symbol.impl.toLocation 34 import com.google.devtools.ksp.toKSModifiers 35 import org.jetbrains.kotlin.psi.* 36 37 class KSTypeReferenceImpl private constructor(val ktTypeReference: KtTypeReference) : KSTypeReference { 38 companion object : KSObjectCache<KtTypeReference, KSTypeReferenceImpl>() { <lambda>null39 fun getCached(ktTypeReference: KtTypeReference) = cache.getOrPut(ktTypeReference) { 40 KSTypeReferenceImpl(ktTypeReference) 41 } 42 } 43 44 override val origin = Origin.KOTLIN 45 <lambda>null46 override val location: Location by lazy { 47 ktTypeReference.toLocation() 48 } 49 override val parent: KSNode? by lazy { 50 var parentPsi = ktTypeReference.parent 51 while ( 52 parentPsi != null && parentPsi !is KtAnnotationEntry && parentPsi !is KtFunctionType && 53 parentPsi !is KtClassOrObject && parentPsi !is KtFunction && parentPsi !is KtUserType && 54 parentPsi !is KtProperty && parentPsi !is KtTypeAlias && parentPsi !is KtTypeProjection && 55 parentPsi !is KtTypeParameter && parentPsi !is KtParameter 56 ) { 57 parentPsi = parentPsi.parent 58 } 59 when (parentPsi) { 60 is KtAnnotationEntry -> KSAnnotationImpl.getCached(parentPsi) 61 is KtFunctionType -> KSCallableReferenceImpl.getCached(parentPsi) 62 is KtClassOrObject -> KSClassDeclarationImpl.getCached(parentPsi) 63 is KtFunction -> KSFunctionDeclarationImpl.getCached(parentPsi) 64 is KtUserType -> KSClassifierReferenceImpl.getCached(parentPsi) 65 is KtProperty -> KSPropertyDeclarationImpl.getCached(parentPsi) 66 is KtTypeAlias -> KSTypeAliasImpl.getCached(parentPsi) 67 is KtTypeProjection -> KSTypeArgumentKtImpl.getCached(parentPsi) 68 is KtTypeParameter -> KSTypeParameterImpl.getCached(parentPsi) 69 is KtParameter -> KSValueParameterImpl.getCached(parentPsi) 70 else -> null 71 } 72 } 73 74 // Parenthesized type in grammar seems to be implemented as KtNullableType. visitNullableTypenull75 private fun visitNullableType(visit: (KtNullableType) -> Unit) { 76 var typeElement = ktTypeReference.typeElement 77 while (typeElement is KtNullableType) { 78 visit(typeElement) 79 typeElement = typeElement.innerType 80 } 81 } 82 83 // Annotations and modifiers are only allowed in one of the parenthesized type. 84 // https://github.com/JetBrains/kotlin/blob/50e12239ef8141a45c4dca2bf0544be6191ecfb6/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java#L608 <lambda>null85 override val annotations: Sequence<KSAnnotation> by lazy { 86 fun List<KtAnnotationEntry>.toKSAnnotations(): Sequence<KSAnnotation> = 87 asSequence().map { 88 KSAnnotationImpl.getCached(it) 89 } 90 91 val innerAnnotations = mutableListOf<Sequence<KSAnnotation>>() 92 visitNullableType { 93 innerAnnotations.add(it.annotationEntries.toKSAnnotations()) 94 } 95 96 (ktTypeReference.annotationEntries.toKSAnnotations() + innerAnnotations.asSequence().flatten()).memoized() 97 } 98 <lambda>null99 override val modifiers: Set<Modifier> by lazy { 100 val innerModifiers = mutableSetOf<Modifier>() 101 visitNullableType { 102 innerModifiers.addAll(it.modifierList.toKSModifiers()) 103 } 104 ktTypeReference.toKSModifiers() + innerModifiers 105 } 106 <lambda>null107 override val element: KSReferenceElement by lazy { 108 var typeElement = ktTypeReference.typeElement 109 while (typeElement is KtNullableType) 110 typeElement = typeElement.innerType 111 when (typeElement) { 112 is KtFunctionType -> KSCallableReferenceImpl.getCached(typeElement) 113 is KtUserType -> KSClassifierReferenceImpl.getCached(typeElement) 114 is KtDynamicType -> KSDynamicReferenceImpl.getCached(this) 115 is KtIntersectionType -> KSDefNonNullReferenceImpl.getCached(typeElement) 116 else -> throw IllegalStateException("Unexpected type element ${typeElement?.javaClass}, $ExceptionMessage") 117 } 118 } 119 acceptnull120 override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R { 121 return visitor.visitTypeReference(this, data) 122 } 123 resolvenull124 override fun resolve(): KSType = ResolverImpl.instance!!.resolveUserType(this) 125 126 override fun toString(): String { 127 return element.toString() 128 } 129 } 130