[FIR] Support @kotlin.jvm.PurelyImplements annotation
This commit is contained in:
@@ -1,2 +1,2 @@
|
|||||||
Resolved to:
|
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:
|
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.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.fir.*
|
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.createCache
|
||||||
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
||||||
import org.jetbrains.kotlin.fir.caches.getValue
|
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.impl.FirResolvedDeclarationStatusImpl
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility
|
import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
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.FirExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.classId
|
||||||
import org.jetbrains.kotlin.fir.java.declarations.*
|
import org.jetbrains.kotlin.fir.java.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.java.enhancement.FirSignatureEnhancement
|
import org.jetbrains.kotlin.fir.java.enhancement.FirSignatureEnhancement
|
||||||
import org.jetbrains.kotlin.fir.resolve.constructType
|
import org.jetbrains.kotlin.fir.resolve.constructType
|
||||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
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.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
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.fir.types.impl.ConeTypeParameterTypeImpl
|
||||||
|
import org.jetbrains.kotlin.load.java.FakePureImplementationsProvider
|
||||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||||
import org.jetbrains.kotlin.load.java.structure.*
|
import org.jetbrains.kotlin.load.java.structure.*
|
||||||
@@ -148,11 +155,54 @@ class FirJavaFacade(
|
|||||||
firJavaClass.annotations.addFromJava(session, javaClass, javaTypeParameterStack)
|
firJavaClass.annotations.addFromJava(session, javaClass, javaTypeParameterStack)
|
||||||
val enhancement = FirSignatureEnhancement(firJavaClass, session) { emptyList() }
|
val enhancement = FirSignatureEnhancement(firJavaClass, session) { emptyList() }
|
||||||
enhancement.enhanceTypeParameterBounds(firJavaClass.typeParameters)
|
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))
|
firJavaClass.replaceDeprecation(firJavaClass.getDeprecationInfos(session.languageVersionSettings.apiVersion))
|
||||||
return firJavaClass
|
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(
|
private fun createFirJavaClass(
|
||||||
javaClass: JavaClass,
|
javaClass: JavaClass,
|
||||||
classSymbol: FirRegularClassSymbol,
|
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