[FIR] Support @kotlin.jvm.PurelyImplements annotation
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
Resolved to:
|
||||
0: (in java.util) open class HashSet<E : kotlin.Any!> : java.util.AbstractSet<E!>, kotlin.collections.MutableSet<E!>, kotlin.Cloneable, java.io.Serializable
|
||||
0: (in java.util) open class HashSet<E : kotlin.Any!> : java.util.AbstractSet<E!>, kotlin.Cloneable, java.io.Serializable, kotlin.collections.MutableSet<E>
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Resolved to:
|
||||
0: (in java.util) open class HashMap<K : kotlin.Any!, V : kotlin.Any!> : java.util.AbstractMap<K!, V!>, kotlin.collections.MutableMap<K!, V!>, kotlin.Cloneable, java.io.Serializable
|
||||
0: (in java.util) open class HashMap<K : kotlin.Any!, V : kotlin.Any!> : java.util.AbstractMap<K!, V!>, kotlin.Cloneable, java.io.Serializable, kotlin.collections.MutableMap<K, V>
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols
|
||||
import org.jetbrains.kotlin.fir.caches.createCache
|
||||
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
||||
import org.jetbrains.kotlin.fir.caches.getValue
|
||||
@@ -25,15 +26,21 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.classId
|
||||
import org.jetbrains.kotlin.fir.java.declarations.*
|
||||
import org.jetbrains.kotlin.fir.java.enhancement.FirSignatureEnhancement
|
||||
import org.jetbrains.kotlin.fir.resolve.constructType
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.load.java.FakePureImplementationsProvider
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
@@ -148,11 +155,54 @@ class FirJavaFacade(
|
||||
firJavaClass.annotations.addFromJava(session, javaClass, javaTypeParameterStack)
|
||||
val enhancement = FirSignatureEnhancement(firJavaClass, session) { emptyList() }
|
||||
enhancement.enhanceTypeParameterBounds(firJavaClass.typeParameters)
|
||||
firJavaClass.superTypeRefs.replaceAll { enhancement.enhanceSuperType(it) }
|
||||
val enhancedSuperTypes = buildList {
|
||||
val purelyImplementedSupertype = firJavaClass.getPurelyImplementedSupertype()
|
||||
val purelyImplementedSupertypeClassId = purelyImplementedSupertype?.classId
|
||||
firJavaClass.superTypeRefs.mapNotNullTo(this) { superType ->
|
||||
enhancement.enhanceSuperType(superType).takeUnless {
|
||||
purelyImplementedSupertypeClassId != null && it.coneType.classId == purelyImplementedSupertypeClassId
|
||||
}
|
||||
}
|
||||
purelyImplementedSupertype?.let {
|
||||
add(buildResolvedTypeRef { type = it })
|
||||
}
|
||||
}
|
||||
firJavaClass.replaceSuperTypeRefs(enhancedSuperTypes)
|
||||
firJavaClass.replaceDeprecation(firJavaClass.getDeprecationInfos(session.languageVersionSettings.apiVersion))
|
||||
return firJavaClass
|
||||
}
|
||||
|
||||
private fun FirJavaClass.getPurelyImplementedSupertype(): ConeKotlinType? {
|
||||
val purelyImplementedClassIdFromAnnotation = annotations
|
||||
.firstOrNull { it.classId?.asSingleFqName() == JvmAnnotationNames.PURELY_IMPLEMENTS_ANNOTATION }
|
||||
?.let { (it.argumentMapping.mapping.values.firstOrNull() as? FirConstExpression<*>) }
|
||||
?.let { it.value as? String }
|
||||
?.takeIf { it.isNotBlank() && isValidJavaFqName(it) }
|
||||
?.let { ClassId.topLevel(FqName(it)) }
|
||||
val purelyImplementedClassId = purelyImplementedClassIdFromAnnotation
|
||||
?: FakePureImplementationsProvider.getPurelyImplementedInterface(symbol.classId)
|
||||
?: return null
|
||||
val superTypeSymbol = session.symbolProvider.getClassLikeSymbolByClassId(purelyImplementedClassId) ?: return null
|
||||
val superTypeParameterSymbols = superTypeSymbol.typeParameterSymbols ?: return null
|
||||
val typeParameters = this.typeParameters
|
||||
val supertypeParameterCount = superTypeParameterSymbols.size
|
||||
val typeParameterCount = typeParameters.size
|
||||
val parametersAsTypeProjections = when {
|
||||
typeParameterCount == supertypeParameterCount ->
|
||||
typeParameters.map { ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(it.symbol), isNullable = false) }
|
||||
typeParameterCount == 1 && supertypeParameterCount > 1 && purelyImplementedClassIdFromAnnotation == null -> {
|
||||
val projection = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(typeParameters.first().symbol), isNullable = false)
|
||||
(1..supertypeParameterCount).map { projection }
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
return ConeClassLikeTypeImpl(
|
||||
ConeClassLikeLookupTagImpl(purelyImplementedClassId),
|
||||
parametersAsTypeProjections.toTypedArray(),
|
||||
isNullable = false
|
||||
)
|
||||
}
|
||||
|
||||
private fun createFirJavaClass(
|
||||
javaClass: JavaClass,
|
||||
classSymbol: FirRegularClassSymbol,
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.load.java
|
||||
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
|
||||
object FakePureImplementationsProvider {
|
||||
fun getPurelyImplementedInterface(classFqName: ClassId): ClassId? = pureImplementationsClassIds[classFqName]
|
||||
fun getPurelyImplementedInterface(classFqName: FqName): FqName? = pureImplementationsFqNames[classFqName]
|
||||
|
||||
private val pureImplementationsClassIds = mutableMapOf<ClassId, ClassId>()
|
||||
private infix fun ClassId.implementedWith(implementations: List<ClassId>) {
|
||||
implementations.associateWithTo(pureImplementationsClassIds) { this }
|
||||
}
|
||||
|
||||
init {
|
||||
StandardClassIds.MutableList implementedWith fqNameListOf("java.util.ArrayList", "java.util.LinkedList")
|
||||
StandardClassIds.MutableSet implementedWith fqNameListOf("java.util.HashSet", "java.util.TreeSet", "java.util.LinkedHashSet")
|
||||
StandardClassIds.MutableMap implementedWith fqNameListOf(
|
||||
"java.util.HashMap", "java.util.TreeMap", "java.util.LinkedHashMap",
|
||||
"java.util.concurrent.ConcurrentHashMap", "java.util.concurrent.ConcurrentSkipListMap"
|
||||
)
|
||||
ClassId.topLevel(FqName("java.util.function.Function")) implementedWith fqNameListOf("java.util.function.UnaryOperator")
|
||||
ClassId.topLevel(FqName("java.util.function.BiFunction")) implementedWith fqNameListOf("java.util.function.BinaryOperator")
|
||||
}
|
||||
|
||||
private val pureImplementationsFqNames = pureImplementationsClassIds.map { (key, value) ->
|
||||
key.asSingleFqName() to value.asSingleFqName()
|
||||
}.toMap()
|
||||
|
||||
private fun fqNameListOf(vararg names: String): List<ClassId> = names.map { ClassId.topLevel(FqName(it)) }
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.load.java
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames.FqNames
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
object FakePureImplementationsProvider {
|
||||
fun getPurelyImplementedInterface(classFqName: FqName): FqName? = pureImplementations[classFqName]
|
||||
|
||||
private val pureImplementations = hashMapOf<FqName, FqName>()
|
||||
private infix fun FqName.implementedWith(implementations: List<FqName>) {
|
||||
implementations.associateWithTo(pureImplementations) { this }
|
||||
}
|
||||
|
||||
init {
|
||||
FqNames.mutableList implementedWith fqNameListOf("java.util.ArrayList", "java.util.LinkedList")
|
||||
FqNames.mutableSet implementedWith fqNameListOf("java.util.HashSet", "java.util.TreeSet", "java.util.LinkedHashSet")
|
||||
FqNames.mutableMap implementedWith fqNameListOf(
|
||||
"java.util.HashMap", "java.util.TreeMap", "java.util.LinkedHashMap",
|
||||
"java.util.concurrent.ConcurrentHashMap", "java.util.concurrent.ConcurrentSkipListMap"
|
||||
)
|
||||
FqName("java.util.function.Function") implementedWith fqNameListOf("java.util.function.UnaryOperator")
|
||||
FqName("java.util.function.BiFunction") implementedWith fqNameListOf("java.util.function.BinaryOperator")
|
||||
}
|
||||
|
||||
private fun fqNameListOf(vararg names: String): List<FqName> = names.map(::FqName)
|
||||
}
|
||||
Reference in New Issue
Block a user