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.KSObjectCache
21 import com.google.devtools.ksp.isConstructor
22 import com.google.devtools.ksp.memoized
23 import com.google.devtools.ksp.processing.impl.KSNameImpl
24 import com.google.devtools.ksp.processing.impl.ResolverImpl
25 import com.google.devtools.ksp.processing.impl.workaroundForNested
26 import com.google.devtools.ksp.symbol.*
27 import com.google.devtools.ksp.symbol.impl.*
28 import com.google.devtools.ksp.symbol.impl.binary.getAllFunctions
29 import com.google.devtools.ksp.symbol.impl.binary.getAllProperties
30 import com.google.devtools.ksp.symbol.impl.kotlin.KSErrorType
31 import com.google.devtools.ksp.symbol.impl.kotlin.KSExpectActualNoImpl
32 import com.google.devtools.ksp.symbol.impl.kotlin.getKSTypeCached
33 import com.google.devtools.ksp.symbol.impl.replaceTypeArguments
34 import com.google.devtools.ksp.symbol.impl.synthetic.KSConstructorSyntheticImpl
35 import com.google.devtools.ksp.toKSModifiers
36 import com.intellij.psi.PsiClass
37 import com.intellij.psi.PsiEnumConstant
38 import com.intellij.psi.PsiJavaFile
39 import org.jetbrains.kotlin.descriptors.ClassDescriptor
40 import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
41 import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
42 
43 class KSClassDeclarationJavaImpl private constructor(val psi: PsiClass) :
44     KSClassDeclaration,
45     KSDeclarationJavaImpl(psi),
46     KSExpectActual by KSExpectActualNoImpl() {
47     companion object : KSObjectCache<PsiClass, KSClassDeclarationJavaImpl>() {
<lambda>null48         fun getCached(psi: PsiClass) = cache.getOrPut(psi) { KSClassDeclarationJavaImpl(psi) }
49     }
50 
51     override val origin = Origin.JAVA
52 
<lambda>null53     override val location: Location by lazy {
54         psi.toLocation()
55     }
56 
<lambda>null57     override val annotations: Sequence<KSAnnotation> by lazy {
58         psi.annotations.asSequence().map { KSAnnotationJavaImpl.getCached(it) }.memoized()
59     }
60 
<lambda>null61     override val classKind: ClassKind by lazy {
62         when {
63             psi.isAnnotationType -> ClassKind.ANNOTATION_CLASS
64             psi.isInterface -> ClassKind.INTERFACE
65             psi.isEnum -> ClassKind.ENUM_CLASS
66             else -> ClassKind.CLASS
67         }
68     }
69 
<lambda>null70     override val containingFile: KSFile? by lazy {
71         KSFileJavaImpl.getCached(psi.containingFile as PsiJavaFile)
72     }
73 
74     override val isCompanionObject = false
75 
76     // Could the resolution ever fail?
<lambda>null77     private val descriptor: ClassDescriptor? by lazy {
78         ResolverImpl.instance!!.moduleClassResolver.resolveClass(JavaClassImpl(psi).apply { workaroundForNested() })
79     }
80 
81     // TODO in 1.5 + jvmTarget 15, will we return Java permitted types?
getSealedSubclassesnull82     override fun getSealedSubclasses(): Sequence<KSClassDeclaration> = emptySequence()
83 
84     override fun getAllFunctions(): Sequence<KSFunctionDeclaration> =
85         descriptor?.getAllFunctions() ?: emptySequence()
86 
87     override fun getAllProperties(): Sequence<KSPropertyDeclaration> =
88         descriptor?.getAllProperties() ?: emptySequence()
89 
90     override val declarations: Sequence<KSDeclaration> by lazy {
91         val allDeclarations = (
92             psi.fields.asSequence().map {
93                 when (it) {
94                     is PsiEnumConstant -> KSClassDeclarationJavaEnumEntryImpl.getCached(it)
95                     else -> KSPropertyDeclarationJavaImpl.getCached(it)
96                 }
97             } +
98                 psi.innerClasses.map { KSClassDeclarationJavaImpl.getCached(it) } +
99                 psi.constructors.map { KSFunctionDeclarationJavaImpl.getCached(it) } +
100                 psi.methods.map { KSFunctionDeclarationJavaImpl.getCached(it) }
101             )
102             .distinct()
103         // java annotation classes are interface. they get a constructor in .class
104         // hence they should get one here.
105         if (classKind == ClassKind.ANNOTATION_CLASS || !psi.isInterface) {
106             val hasConstructor = allDeclarations.any {
107                 it is KSFunctionDeclaration && it.isConstructor()
108             }
109             if (hasConstructor) {
110                 allDeclarations.memoized()
111             } else {
112                 (allDeclarations + KSConstructorSyntheticImpl.getCached(this)).memoized()
113             }
114         } else {
115             allDeclarations.memoized()
116         }
117     }
118 
<lambda>null119     override val modifiers: Set<Modifier> by lazy {
120         val modifiers = mutableSetOf<Modifier>()
121         modifiers.addAll(psi.toKSModifiers())
122         if (psi.isAnnotationType) {
123             modifiers.add(Modifier.ANNOTATION)
124         }
125         if (psi.isEnum) {
126             modifiers.add(Modifier.ENUM)
127         }
128         modifiers
129     }
130 
131     override val primaryConstructor: KSFunctionDeclaration? = null
132 
<lambda>null133     override val qualifiedName: KSName by lazy {
134         KSNameImpl.getCached(psi.qualifiedName!!)
135     }
136 
<lambda>null137     override val simpleName: KSName by lazy {
138         KSNameImpl.getCached(psi.name!!)
139     }
140 
<lambda>null141     override val superTypes: Sequence<KSTypeReference> by lazy {
142         val adjusted = if (!psi.isInterface && psi.superTypes.size > 1) {
143             psi.superTypes.filterNot {
144                 it.className == "Object" && it.canonicalText == "java.lang.Object"
145             }
146         } else {
147             psi.superTypes.toList()
148         }
149         adjusted.asSequence().map { KSTypeReferenceJavaImpl.getCached(it, this) }.memoized()
150     }
151 
<lambda>null152     override val typeParameters: List<KSTypeParameter> by lazy {
153         psi.typeParameters.map { KSTypeParameterJavaImpl.getCached(it) }
154     }
155 
asTypenull156     override fun asType(typeArguments: List<KSTypeArgument>): KSType {
157         return descriptor?.let {
158             it.defaultType.replaceTypeArguments(typeArguments)?.let {
159                 getKSTypeCached(it, typeArguments)
160             }
161         } ?: KSErrorType
162     }
163 
asStarProjectedTypenull164     override fun asStarProjectedType(): KSType {
165         return descriptor?.let {
166             getKSTypeCached(it.defaultType.replaceArgumentsWithStarProjections())
167         } ?: KSErrorType
168     }
169 
acceptnull170     override fun <D, R> accept(visitor: KSVisitor<D, R>, data: D): R {
171         return visitor.visitClassDeclaration(this, data)
172     }
173 }
174