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.java
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.KSAnnotated
25 import com.google.devtools.ksp.symbol.KSAnnotation
26 import com.google.devtools.ksp.symbol.KSNode
27 import com.google.devtools.ksp.symbol.KSReferenceElement
28 import com.google.devtools.ksp.symbol.KSType
29 import com.google.devtools.ksp.symbol.KSTypeReference
30 import com.google.devtools.ksp.symbol.KSVisitor
31 import com.google.devtools.ksp.symbol.Location
32 import com.google.devtools.ksp.symbol.Modifier
33 import com.google.devtools.ksp.symbol.NonExistLocation
34 import com.google.devtools.ksp.symbol.Origin
35 import com.google.devtools.ksp.symbol.impl.binary.KSClassDeclarationDescriptorImpl
36 import com.google.devtools.ksp.symbol.impl.binary.KSClassifierReferenceDescriptorImpl
37 import com.google.devtools.ksp.symbol.impl.kotlin.KSErrorType
38 import com.google.devtools.ksp.symbol.impl.kotlin.KSTypeImpl
39 import com.google.devtools.ksp.symbol.impl.toLocation
40 import com.intellij.psi.PsiArrayType
41 import com.intellij.psi.PsiClassType
42 import com.intellij.psi.PsiPrimitiveType
43 import com.intellij.psi.PsiType
44 import com.intellij.psi.PsiWildcardType
45 import com.intellij.psi.impl.source.PsiClassReferenceType
46 import org.jetbrains.kotlin.descriptors.NotFoundClasses
47 import org.jetbrains.kotlin.load.java.NOT_NULL_ANNOTATIONS
48 import org.jetbrains.kotlin.load.java.NULLABLE_ANNOTATIONS
49 import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
50 import org.jetbrains.kotlin.types.KotlinType
51 import org.jetbrains.kotlin.types.Variance
52 import org.jetbrains.kotlin.types.typeUtil.makeNullable
53 
54 class KSTypeReferenceJavaImpl private constructor(val psi: PsiType, override val parent: KSNode?) : KSTypeReference {
55     companion object : KSObjectCache<Pair<PsiType, KSNode?>, KSTypeReferenceJavaImpl>() {
getCachednull56         fun getCached(psi: PsiType, parent: KSNode?) = cache
57             .getOrPut(Pair(psi, parent)) { KSTypeReferenceJavaImpl(psi, parent) }
58     }
59 
60     override val origin = Origin.JAVA
61 
<lambda>null62     override val location: Location by lazy {
63         (psi as? PsiClassReferenceType)?.reference?.toLocation() ?: NonExistLocation
64     }
65 
<lambda>null66     override val annotations: Sequence<KSAnnotation> by lazy {
67         psi.annotations.asSequence().map { KSAnnotationJavaImpl.getCached(it) }.memoized()
68     }
69 
70     override val modifiers: Set<Modifier> = emptySet()
71 
<lambda>null72     override val element: KSReferenceElement by lazy {
73         fun PsiPrimitiveType.toKotlinType(): KotlinType {
74             return when (this.name) {
75                 "int" -> ResolverImpl.instance!!.module.builtIns.intType
76                 "short" -> ResolverImpl.instance!!.module.builtIns.shortType
77                 "byte" -> ResolverImpl.instance!!.module.builtIns.byteType
78                 "long" -> ResolverImpl.instance!!.module.builtIns.longType
79                 "float" -> ResolverImpl.instance!!.module.builtIns.floatType
80                 "double" -> ResolverImpl.instance!!.module.builtIns.doubleType
81                 "char" -> ResolverImpl.instance!!.module.builtIns.charType
82                 "boolean" -> ResolverImpl.instance!!.module.builtIns.booleanType
83                 "void" -> ResolverImpl.instance!!.module.builtIns.unitType
84                 else -> throw IllegalStateException("Unexpected primitive type ${this.name}, $ExceptionMessage")
85             }
86         }
87 
88         val type = if (psi is PsiWildcardType) {
89             psi.bound
90         } else {
91             psi
92         }
93         when (type) {
94             is PsiClassType -> KSClassifierReferenceJavaImpl.getCached(type, this)
95             is PsiWildcardType -> KSClassifierReferenceJavaImpl.getCached(type.extendsBound as PsiClassType, this)
96             is PsiPrimitiveType -> KSClassifierReferenceDescriptorImpl.getCached(type.toKotlinType(), origin, this)
97             is PsiArrayType -> {
98                 val componentType = ResolverImpl.instance!!.resolveJavaType(type.componentType, this)
99                 if (type.componentType !is PsiPrimitiveType) {
100                     KSClassifierReferenceDescriptorImpl.getCached(
101                         ResolverImpl.instance!!.module.builtIns.getArrayType(Variance.INVARIANT, componentType),
102                         origin,
103                         this
104                     )
105                 } else {
106                     KSClassifierReferenceDescriptorImpl.getCached(
107                         ResolverImpl.instance!!.module.builtIns
108                             .getPrimitiveArrayKotlinTypeByPrimitiveKotlinType(componentType)!!,
109                         origin, this
110                     )
111                 }
112             }
113             null ->
114                 KSClassifierReferenceDescriptorImpl.getCached(
115                     (ResolverImpl.instance!!.builtIns.anyType as KSTypeImpl).kotlinType.makeNullable(), origin, this
116                 )
117             else -> throw IllegalStateException("Unexpected psi type for ${type.javaClass}, $ExceptionMessage")
118         }
119     }
120 
resolvenull121     override fun resolve(): KSType {
122         val resolvedType = ResolverImpl.instance!!.resolveUserType(this)
123         val relatedAnnotations = (annotations + ((parent as? KSAnnotated)?.annotations ?: emptySequence()))
124             .mapNotNull {
125                 (it.annotationType.resolve() as? KSTypeImpl)?.kotlinType?.constructor?.declarationDescriptor?.fqNameSafe
126             }
127         val resolved = if ((resolvedType.declaration as? KSClassDeclarationDescriptorImpl)
128             ?.descriptor is NotFoundClasses.MockClassDescriptor
129         ) {
130             KSErrorType
131         } else resolvedType
132         val hasNotNull = relatedAnnotations.any { it in NOT_NULL_ANNOTATIONS }
133         val hasNullable = relatedAnnotations.any { it in NULLABLE_ANNOTATIONS }
134         return if (hasNullable && !hasNotNull) {
135             resolved.makeNullable()
136         } else if (!hasNullable && hasNotNull) {
137             resolved.makeNotNullable()
138         } else resolved
139     }
140 
acceptnull141     override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
142         return visitor.visitTypeReference(this, data)
143     }
144 
toStringnull145     override fun toString(): String {
146         return element.toString()
147     }
148 }
149