FIR: built-in resolve, preliminary version #KT-24091 Fixed
This commit is contained in:
@@ -5,21 +5,29 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.symbols
|
package org.jetbrains.kotlin.fir.symbols
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
interface ConeSymbol
|
interface ConeSymbol
|
||||||
|
|
||||||
interface ConeTypeParameterSymbol : ConeSymbol
|
interface ConeTypeParameterSymbol : ConeSymbol {
|
||||||
|
val name: Name
|
||||||
|
}
|
||||||
|
|
||||||
interface ConeClassLikeSymbol : ConeSymbol {
|
interface ConeClassLikeSymbol : ConeSymbol {
|
||||||
val classId: ClassId
|
val classId: ClassId
|
||||||
|
|
||||||
|
val typeParameters: List<ConeTypeParameterSymbol>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConeTypeAliasSymbol : ConeClassLikeSymbol {
|
interface ConeTypeAliasSymbol : ConeClassLikeSymbol {
|
||||||
val expansionType: ConeClassLikeType
|
val expansionType: ConeClassLikeType?
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConeClassSymbol : ConeClassLikeSymbol {
|
interface ConeClassSymbol : ConeClassLikeSymbol {
|
||||||
|
val kind: ClassKind
|
||||||
|
|
||||||
val superTypes: List<ConeClassLikeType>
|
val superTypes: List<ConeClassLikeType>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,14 @@ class ConeKotlinErrorType(val reason: String) : ConeKotlinType() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ConeClassErrorType(val reason: String): ConeClassLikeType() {
|
||||||
|
override val symbol: ConeClassLikeSymbol
|
||||||
|
get() = error("!")
|
||||||
|
override val typeArguments: List<ConeKotlinTypeProjection>
|
||||||
|
get() = emptyList()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
sealed class ConeSymbolBasedType : ConeKotlinType() {
|
sealed class ConeSymbolBasedType : ConeKotlinType() {
|
||||||
abstract val symbol: ConeSymbol
|
abstract val symbol: ConeSymbol
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ jvmTarget = "1.6"
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile(project(":core:descriptors"))
|
compile(project(":core:descriptors"))
|
||||||
|
compile(project(":core:deserialization"))
|
||||||
compile(project(":compiler:fir:cones"))
|
compile(project(":compiler:fir:cones"))
|
||||||
compile(project(":compiler:fir:tree"))
|
compile(project(":compiler:fir:tree"))
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.declarations.FirImport
|
|||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedImportImpl
|
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedImportImpl
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedPackageStarImport
|
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedPackageStarImport
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||||
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||||
import org.jetbrains.kotlin.fir.visitors.compose
|
import org.jetbrains.kotlin.fir.visitors.compose
|
||||||
@@ -28,13 +29,13 @@ class FirImportResolveTransformer : FirTransformer<Nothing?>() {
|
|||||||
|
|
||||||
override fun transformImport(import: FirImport, data: Nothing?): CompositeTransformResult<FirImport> {
|
override fun transformImport(import: FirImport, data: Nothing?): CompositeTransformResult<FirImport> {
|
||||||
val fqName = import.importedFqName ?: return import.compose()
|
val fqName = import.importedFqName ?: return import.compose()
|
||||||
val firProvider = FirProvider.getInstance(import.session)
|
val firProvider = FirSymbolProvider.getInstance(import.session)
|
||||||
|
|
||||||
if (!fqName.isRoot) {
|
if (!fqName.isRoot) {
|
||||||
val lastPart = mutableListOf<String>()
|
val lastPart = mutableListOf<String>()
|
||||||
var firstPart = fqName
|
var firstPart = fqName
|
||||||
|
|
||||||
if (import.isAllUnder && firProvider.getFirFilesByPackage(firstPart).isNotEmpty()) {
|
if (import.isAllUnder && firProvider.getPackage(firstPart) != null) {
|
||||||
return FirResolvedPackageStarImport(import, firstPart).compose()
|
return FirResolvedPackageStarImport(import, firstPart).compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,9 +44,9 @@ class FirImportResolveTransformer : FirTransformer<Nothing?>() {
|
|||||||
firstPart = firstPart.parent()
|
firstPart = firstPart.parent()
|
||||||
|
|
||||||
val resolvedFqName = ClassId(firstPart, FqName.fromSegments(lastPart), false)
|
val resolvedFqName = ClassId(firstPart, FqName.fromSegments(lastPart), false)
|
||||||
val foundClassifier = firProvider.getFirClassifierByFqName(resolvedFqName)
|
val foundSymbol = firProvider.getSymbolByFqName(resolvedFqName)
|
||||||
|
|
||||||
if (foundClassifier != null) {
|
if (foundSymbol != null) {
|
||||||
return FirResolvedImportImpl(import, resolvedFqName).compose()
|
return FirResolvedImportImpl(import, resolvedFqName).compose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+65
-55
@@ -12,24 +12,19 @@ import org.jetbrains.kotlin.fir.resolve.FirProvider
|
|||||||
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
|
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
import org.jetbrains.kotlin.fir.scopes.impl.*
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
import org.jetbrains.kotlin.fir.symbols.*
|
||||||
import org.jetbrains.kotlin.fir.transformSingle
|
import org.jetbrains.kotlin.fir.transformSingle
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeImpl
|
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeImpl
|
||||||
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
|
||||||
import org.jetbrains.kotlin.fir.visitors.compose
|
import org.jetbrains.kotlin.fir.visitors.compose
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
class FirTypeResolveTransformer(val superTypesOnly: Boolean = false) : FirTransformer<Nothing?>() {
|
open class FirTypeResolveTransformer : FirTransformer<Nothing?>() {
|
||||||
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
||||||
return if (superTypesOnly) {
|
return (element.transformChildren(this, data) as E).compose()
|
||||||
element.compose()
|
|
||||||
} else {
|
|
||||||
(element.transformChildren(this, data) as E).compose()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lateinit var scope: FirCompositeScope
|
lateinit var scope: FirCompositeScope
|
||||||
@@ -50,9 +45,7 @@ class FirTypeResolveTransformer(val superTypesOnly: Boolean = false) : FirTransf
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun lookupSuperTypes(klass: FirClass): List<ClassId> {
|
private fun lookupSuperTypes(klass: FirClass): List<ClassId> {
|
||||||
val superTypesBuilder = SuperClassHierarchyBuilder()
|
return mutableListOf<ConeClassLikeType>().also { klass.symbol.collectSuperTypes(it) }.map { it.symbol.classId }
|
||||||
klass.superTypes.any { it.accept(superTypesBuilder, null) }
|
|
||||||
return superTypesBuilder.classes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveSuperTypesAndExpansions(element: FirMemberDeclaration) {
|
private fun resolveSuperTypesAndExpansions(element: FirMemberDeclaration) {
|
||||||
@@ -140,31 +133,55 @@ class FirTypeResolveTransformer(val superTypesOnly: Boolean = false) : FirTransf
|
|||||||
return typeProjectionWithVariance.compose()
|
return typeProjectionWithVariance.compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class SuperTypeResolveTransformer(val elementIterator: Iterator<FirElement>) : FirTypeResolveTransformer() {
|
||||||
|
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
||||||
|
if (elementIterator.hasNext()) elementIterator.next().transformSingle(this, data)
|
||||||
|
return element.compose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private inner class SuperTypeResolver : FirTransformer<Nothing?>() {
|
private inner class SuperTypeResolver : FirTransformer<Nothing?>() {
|
||||||
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
||||||
return element.compose()
|
return element.compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun walkSymbols(symbol: ConeSymbol) {
|
||||||
|
if (symbol is ConeClassLikeSymbol) {
|
||||||
|
if (symbol is FirBasedSymbol<*>) {
|
||||||
|
val classId = symbol.classId
|
||||||
|
val firProvider = FirProvider.getInstance(symbol.fir.session)
|
||||||
|
|
||||||
|
val classes = generateSequence(classId) { it.outerClassId }.toList().asReversed()
|
||||||
|
|
||||||
|
|
||||||
|
val file = firProvider.getFirClassifierContainerFile(classes.first())
|
||||||
|
|
||||||
|
val firElementsToVisit = classes.asSequence().map {
|
||||||
|
firProvider.getFirClassifierByFqName(it)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
val transformer = SuperTypeResolveTransformer(firElementsToVisit.iterator())
|
||||||
|
file.transformSingle(transformer, null)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (symbol is ConeTypeAliasSymbol) {
|
||||||
|
symbol.expansionType?.let { walkSymbols(it.symbol) }
|
||||||
|
} else if (symbol is ConeClassSymbol) {
|
||||||
|
symbol.superTypes.forEach { walkSymbols(it.symbol) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun transformType(type: FirType, data: Nothing?): CompositeTransformResult<FirType> {
|
override fun transformType(type: FirType, data: Nothing?): CompositeTransformResult<FirType> {
|
||||||
val typeResolver = FirTypeResolver.getInstance(type.session)
|
val typeResolver = FirTypeResolver.getInstance(type.session)
|
||||||
val symbol = typeResolver.resolveToSymbol(type, scope, position = FirPosition.SUPER_TYPE_OR_EXPANSION)
|
val symbol = typeResolver.resolveToSymbol(type, scope, position = FirPosition.SUPER_TYPE_OR_EXPANSION)
|
||||||
val myTransformer = this@FirTypeResolveTransformer
|
val myTransformer = this@FirTypeResolveTransformer
|
||||||
|
|
||||||
|
if (symbol != null) walkSymbols(symbol)
|
||||||
|
|
||||||
if (type !is FirUserType) return myTransformer.transformType(type, data)
|
if (type !is FirUserType) return myTransformer.transformType(type, data)
|
||||||
val classId = (symbol as? ConeClassLikeSymbol)?.classId ?: return myTransformer.transformType(type, data)
|
|
||||||
val firProvider = FirProvider.getInstance(type.session)
|
|
||||||
|
|
||||||
val classes = generateSequence(classId) { it.outerClassId }.toList()
|
|
||||||
|
|
||||||
val transformer = FirTypeResolveTransformer(superTypesOnly = true)
|
|
||||||
|
|
||||||
val file = firProvider.getFirClassifierContainerFile(classes.last())
|
|
||||||
|
|
||||||
file.transformSingle(transformer, null)
|
|
||||||
|
|
||||||
classes.forEach {
|
|
||||||
firProvider.getFirClassifierByFqName(it)!!.transformSingle(transformer, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type.transformChildren(myTransformer, null)
|
type.transformChildren(myTransformer, null)
|
||||||
@@ -172,36 +189,29 @@ class FirTypeResolveTransformer(val superTypesOnly: Boolean = false) : FirTransf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class SuperClassHierarchyBuilder : FirVisitor<Boolean, Nothing?>() {
|
private tailrec fun ConeClassLikeType.computePartialExpansion(): ConeClassLikeType? {
|
||||||
|
return when (this) {
|
||||||
override fun visitElement(element: FirElement, data: Nothing?): Boolean {
|
is ConeAbbreviatedType -> directExpansion.takeIf { it !is ConeClassErrorType }?.computePartialExpansion()
|
||||||
return false
|
else -> return this
|
||||||
}
|
}
|
||||||
|
|
||||||
private tailrec fun ConeClassLikeType.computePartialExpansion(): ClassId {
|
|
||||||
return when (this) {
|
|
||||||
!is ConeAbbreviatedType -> this.symbol.classId
|
|
||||||
else -> this.directExpansion.computePartialExpansion()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val classes = mutableListOf<ClassId>()
|
|
||||||
|
|
||||||
override fun visitResolvedType(resolvedType: FirResolvedType, data: Nothing?): Boolean {
|
|
||||||
val provider = FirProvider.getInstance(resolvedType.session)
|
|
||||||
val targetClassId = resolvedType.coneTypeSafe<ConeClassLikeType>()?.computePartialExpansion() ?: return false
|
|
||||||
val classifier = provider.getFirClassifierByFqName(targetClassId)!!
|
|
||||||
when (classifier) {
|
|
||||||
is FirClass -> {
|
|
||||||
if (classifier.classKind == ClassKind.CLASS) {
|
|
||||||
classes += targetClassId
|
|
||||||
classifier.superTypes.any { it.accept(this, data) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is FirTypeAlias -> classifier.expandedType.accept(this, data)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private tailrec fun ConeClassLikeSymbol.collectSuperTypes(list: MutableList<ConeClassLikeType>) {
|
||||||
|
return when (this) {
|
||||||
|
is ConeClassSymbol -> {
|
||||||
|
val superClassType =
|
||||||
|
this.superTypes
|
||||||
|
.map { it.computePartialExpansion() }
|
||||||
|
.firstOrNull { (it?.symbol as? ConeClassSymbol)?.kind == ClassKind.CLASS } ?: return
|
||||||
|
list += superClassType
|
||||||
|
superClassType.symbol.collectSuperTypes(list)
|
||||||
|
}
|
||||||
|
is ConeTypeAliasSymbol -> {
|
||||||
|
val expansion = expansionType?.computePartialExpansion() ?: return
|
||||||
|
expansion.symbol.collectSuperTypes(list)
|
||||||
|
}
|
||||||
|
else -> error("?!id:1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+129
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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.fir.deserialization
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.LibraryTypeParameterSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeAbbreviatedTypeImpl
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeKotlinTypeProjectionInImpl
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeKotlinTypeProjectionOutImpl
|
||||||
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.*
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.getName
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class FirTypeDeserializer(
|
||||||
|
val nameResolver: NameResolver,
|
||||||
|
val typeTable: TypeTable,
|
||||||
|
val symbolProvider: FirSymbolProvider,
|
||||||
|
typeParameterProtos: List<ProtoBuf.TypeParameter>,
|
||||||
|
val parent: FirTypeDeserializer?
|
||||||
|
) {
|
||||||
|
|
||||||
|
private fun computeClassifier(fqNameIndex: Int): ConeSymbol? {
|
||||||
|
val id = nameResolver.getClassId(fqNameIndex)
|
||||||
|
return symbolProvider.getSymbolByFqName(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun type(proto: ProtoBuf.Type): ConeKotlinType {
|
||||||
|
if (proto.hasFlexibleTypeCapabilitiesId()) {
|
||||||
|
val id = nameResolver.getString(proto.flexibleTypeCapabilitiesId)
|
||||||
|
val lowerBound = classLikeType(proto)
|
||||||
|
val upperBound = classLikeType(proto.flexibleUpperBound(typeTable)!!)
|
||||||
|
return ConeKotlinErrorType("Not supported: Flexible types")//c.components.flexibleTypeDeserializer.create(proto, id, lowerBound, upperBound)
|
||||||
|
}
|
||||||
|
|
||||||
|
return classLikeType(proto) ?: ConeKotlinErrorType("?!id:0")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun typeParameterSymbol(typeParameterId: Int): ConeTypeParameterSymbol? =
|
||||||
|
typeParameterDescriptors[typeParameterId] ?: parent?.typeParameterSymbol(typeParameterId)
|
||||||
|
|
||||||
|
private val typeParameterDescriptors =
|
||||||
|
if (typeParameterProtos.isEmpty()) {
|
||||||
|
mapOf<Int, ConeTypeParameterSymbol>()
|
||||||
|
} else {
|
||||||
|
val result = LinkedHashMap<Int, ConeTypeParameterSymbol>()
|
||||||
|
for ((index, proto) in typeParameterProtos.withIndex()) {
|
||||||
|
result[proto.id] = LibraryTypeParameterSymbol(nameResolver.getName(proto.name))
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
val ownTypeParameters: List<ConeTypeParameterSymbol>
|
||||||
|
get() = typeParameterDescriptors.values.toList()
|
||||||
|
|
||||||
|
|
||||||
|
fun classLikeType(proto: ProtoBuf.Type): ConeClassLikeType? {
|
||||||
|
|
||||||
|
val constructor = typeSymbol(proto) as? ConeClassLikeSymbol ?: return null
|
||||||
|
// if (ErrorUtils.isError(constructor.declarationDescriptor)) {
|
||||||
|
// return ErrorUtils.createErrorTypeWithCustomConstructor(constructor.toString(), constructor)
|
||||||
|
// }
|
||||||
|
|
||||||
|
fun ProtoBuf.Type.collectAllArguments(): List<ProtoBuf.Type.Argument> =
|
||||||
|
argumentList + outerType(typeTable)?.collectAllArguments().orEmpty()
|
||||||
|
|
||||||
|
val arguments = proto.collectAllArguments().mapIndexed { index, proto ->
|
||||||
|
typeArgument(constructor.typeParameters.getOrNull(index), proto)
|
||||||
|
}.toList()
|
||||||
|
|
||||||
|
val simpleType = if (Flags.SUSPEND_TYPE.get(proto.flags)) {
|
||||||
|
//createSuspendFunctionType(annotations, constructor, arguments, proto.nullable)
|
||||||
|
ConeClassErrorType("createSuspendFunctionType not supported")
|
||||||
|
} else {
|
||||||
|
ConeClassTypeImpl(constructor, arguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
val abbreviatedTypeProto = proto.abbreviatedType(typeTable) ?: return simpleType
|
||||||
|
|
||||||
|
return ConeAbbreviatedTypeImpl(typeSymbol(abbreviatedTypeProto) as ConeClassLikeSymbol, arguments, simpleType)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun typeSymbol(proto: ProtoBuf.Type): ConeSymbol? {
|
||||||
|
|
||||||
|
return when {
|
||||||
|
proto.hasClassName() -> computeClassifier(proto.className)
|
||||||
|
proto.hasTypeAliasName() -> computeClassifier(proto.typeAliasName)
|
||||||
|
proto.hasTypeParameter() -> typeParameterSymbol(proto.typeParameter)
|
||||||
|
proto.hasTypeParameterName() -> {
|
||||||
|
val name = nameResolver.getString(proto.typeParameterName)
|
||||||
|
|
||||||
|
// TODO: Optimize
|
||||||
|
ownTypeParameters.find { it.name.asString() == name }
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun typeArgument(parameter: ConeTypeParameterSymbol?, typeArgumentProto: ProtoBuf.Type.Argument): ConeKotlinTypeProjection {
|
||||||
|
if (typeArgumentProto.projection == ProtoBuf.Type.Argument.Projection.STAR) {
|
||||||
|
return StarProjection
|
||||||
|
}
|
||||||
|
|
||||||
|
val projection = ProtoEnumFlags.variance(typeArgumentProto.projection)
|
||||||
|
val type = typeArgumentProto.type(typeTable) ?: return ConeKotlinErrorType("No type recorded")
|
||||||
|
|
||||||
|
val coneType = type(type)
|
||||||
|
return when (projection) {
|
||||||
|
Variance.INVARIANT -> coneType
|
||||||
|
Variance.IN_VARIANCE -> ConeKotlinTypeProjectionInImpl(coneType)
|
||||||
|
Variance.OUT_VARIANCE -> ConeKotlinTypeProjectionOutImpl(coneType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -14,10 +14,15 @@ import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
|||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
interface FirProvider {
|
interface FirProvider : FirSymbolProvider {
|
||||||
fun getFirClassifierByFqName(fqName: ClassId): FirMemberDeclaration?
|
fun getFirClassifierByFqName(fqName: ClassId): FirMemberDeclaration?
|
||||||
|
|
||||||
fun getSymbolByFqName(fqName: ClassId): ConeSymbol?
|
override fun getSymbolByFqName(classId: ClassId): ConeSymbol?
|
||||||
|
|
||||||
|
override fun getPackage(fqName: FqName): FqName? {
|
||||||
|
if (getFirFilesByPackage(fqName).isNotEmpty()) return fqName
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
fun getFirClassifierContainerFile(fqName: ClassId): FirFile
|
fun getFirClassifierContainerFile(fqName: ClassId): FirFile
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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.fir.resolve
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.service
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
|
interface FirSymbolProvider {
|
||||||
|
|
||||||
|
fun getSymbolByFqName(classId: ClassId): ConeSymbol?
|
||||||
|
|
||||||
|
fun getPackage(fqName: FqName): FqName? // TODO: Replace to symbol sometime
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun getInstance(session: FirSession) = session.service<FirSymbolProvider>()
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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.fir.resolve.impl
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||||
|
|
||||||
|
class FirCompositeSymbolProvider(val providers: List<FirSymbolProvider>) : FirSymbolProvider {
|
||||||
|
override fun getPackage(fqName: FqName): FqName? {
|
||||||
|
return providers.firstNotNullResult { it.getPackage(fqName) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSymbolByFqName(classId: ClassId): ConeSymbol? {
|
||||||
|
return providers.firstNotNullResult { it.getSymbolByFqName(classId) }
|
||||||
|
}
|
||||||
|
}
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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.fir.resolve.impl
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.deserialization.FirTypeDeserializer
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.LibraryClassSymbol
|
||||||
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
|
import org.jetbrains.kotlin.metadata.builtins.BuiltInsBinaryVersion
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.ProtoBasedClassDataFinder
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
|
class FirLibrarySymbolProviderImpl(val session: FirSession) : FirSymbolProvider {
|
||||||
|
|
||||||
|
private class BuiltInsPackageFragment(stream: InputStream, val fqName: FqName) {
|
||||||
|
lateinit var version: BuiltInsBinaryVersion
|
||||||
|
|
||||||
|
val packageProto = run {
|
||||||
|
|
||||||
|
version = BuiltInsBinaryVersion.readFrom(stream)
|
||||||
|
|
||||||
|
if (!version.isCompatible()) {
|
||||||
|
// TODO: report a proper diagnostic
|
||||||
|
throw UnsupportedOperationException(
|
||||||
|
"Kotlin built-in definition format version is not supported: " +
|
||||||
|
"expected ${BuiltInsBinaryVersion.INSTANCE}, actual $version. " +
|
||||||
|
"Please update Kotlin"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtoBuf.PackageFragment.parseFrom(stream, BuiltInSerializerProtocol.extensionRegistry)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected val nameResolver = NameResolverImpl(packageProto.strings, packageProto.qualifiedNames)
|
||||||
|
|
||||||
|
val classDataFinder = ProtoBasedClassDataFinder(packageProto, nameResolver, version) { SourceElement.NO_SOURCE }
|
||||||
|
|
||||||
|
|
||||||
|
val lookup = mutableMapOf<ClassId, ConeSymbol>()
|
||||||
|
|
||||||
|
fun getSymbolByFqName(classId: ClassId, provider: FirSymbolProvider): ConeSymbol? {
|
||||||
|
|
||||||
|
if (classId !in classDataFinder.allClassIds) return null
|
||||||
|
return lookup.getOrPut(classId) {
|
||||||
|
val classData = classDataFinder.findClassData(classId)!!
|
||||||
|
LibraryClassSymbol(
|
||||||
|
classData.classProto, classData.nameResolver,
|
||||||
|
FirTypeDeserializer(
|
||||||
|
classData.nameResolver,
|
||||||
|
TypeTable(classData.classProto.typeTable),
|
||||||
|
provider,
|
||||||
|
classData.classProto.typeParameterList,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPackage(fqName: FqName): FqName? {
|
||||||
|
if (allPackageFragments.containsKey(fqName)) return fqName
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadBuiltIns(): List<BuiltInsPackageFragment> {
|
||||||
|
val classLoader = this::class.java.classLoader
|
||||||
|
val streamProvider = { path: String -> classLoader?.getResourceAsStream(path) ?: ClassLoader.getSystemResourceAsStream(path) }
|
||||||
|
val packageFqNames = KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAMES
|
||||||
|
|
||||||
|
return packageFqNames.map { fqName ->
|
||||||
|
val resourcePath = BuiltInSerializerProtocol.getBuiltInsFilePath(fqName)
|
||||||
|
val inputStream = streamProvider(resourcePath) ?: throw IllegalStateException("Resource not found in classpath: $resourcePath")
|
||||||
|
BuiltInsPackageFragment(inputStream, fqName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val allPackageFragments = loadBuiltIns().groupBy { it.fqName }
|
||||||
|
|
||||||
|
override fun getSymbolByFqName(classId: ClassId): ConeSymbol? {
|
||||||
|
return allPackageFragments[classId.packageFqName]?.firstNotNullResult { it.getSymbolByFqName(classId, this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -26,8 +26,8 @@ class FirProviderImpl(val session: FirSession) : FirProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSymbolByFqName(fqName: ClassId): ConeSymbol? {
|
override fun getSymbolByFqName(classId: ClassId): ConeSymbol? {
|
||||||
return (getFirClassifierByFqName(fqName) as? FirSymbolOwner<*>)?.symbol
|
return (getFirClassifierByFqName(classId) as? FirSymbolOwner<*>)?.symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFirClassifierContainerFile(fqName: ClassId): FirFile {
|
override fun getFirClassifierContainerFile(fqName: ClassId): FirFile {
|
||||||
|
|||||||
+7
-8
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.impl
|
|||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirQualifierResolver
|
import org.jetbrains.kotlin.fir.resolve.FirQualifierResolver
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirSymbolOwner
|
import org.jetbrains.kotlin.fir.symbols.FirSymbolOwner
|
||||||
import org.jetbrains.kotlin.fir.types.FirQualifierPart
|
import org.jetbrains.kotlin.fir.types.FirQualifierPart
|
||||||
@@ -17,20 +18,18 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
class FirQualifierResolverImpl(val session: FirSession) : FirQualifierResolver {
|
class FirQualifierResolverImpl(val session: FirSession) : FirQualifierResolver {
|
||||||
|
|
||||||
override fun resolveSymbolWithPrefix(parts: List<FirQualifierPart>, prefix: ClassId): ConeSymbol? {
|
override fun resolveSymbolWithPrefix(parts: List<FirQualifierPart>, prefix: ClassId): ConeSymbol? {
|
||||||
val firProvider = FirProvider.getInstance(session)
|
val symbolProvider = FirSymbolProvider.getInstance(session)
|
||||||
|
|
||||||
val fqName = ClassId(
|
val fqName = ClassId(
|
||||||
prefix.packageFqName,
|
prefix.packageFqName,
|
||||||
parts.drop(1).fold(prefix.relativeClassName) { prefix, suffix -> prefix.child(suffix.name) },
|
parts.drop(1).fold(prefix.relativeClassName) { prefix, suffix -> prefix.child(suffix.name) },
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
val classifier = firProvider.getFirClassifierByFqName(fqName) ?: return null
|
return symbolProvider.getSymbolByFqName(fqName) ?: return null
|
||||||
|
|
||||||
return (classifier as? FirSymbolOwner<*>)?.symbol
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun resolveSymbol(parts: List<FirQualifierPart>): ConeSymbol? {
|
override fun resolveSymbol(parts: List<FirQualifierPart>): ConeSymbol? {
|
||||||
val firProvider = FirProvider.getInstance(session)
|
val firProvider = FirSymbolProvider.getInstance(session)
|
||||||
|
|
||||||
if (parts.isNotEmpty()) {
|
if (parts.isNotEmpty()) {
|
||||||
val lastPart = mutableListOf<FirQualifierPart>()
|
val lastPart = mutableListOf<FirQualifierPart>()
|
||||||
@@ -41,9 +40,9 @@ class FirQualifierResolverImpl(val session: FirSession) : FirQualifierResolver {
|
|||||||
firstPart.removeAt(firstPart.lastIndex)
|
firstPart.removeAt(firstPart.lastIndex)
|
||||||
|
|
||||||
val fqName = ClassId(firstPart.toFqName(), lastPart.toFqName(), false)
|
val fqName = ClassId(firstPart.toFqName(), lastPart.toFqName(), false)
|
||||||
val foundClassifier = firProvider.getFirClassifierByFqName(fqName)
|
val foundSymbol = firProvider.getSymbolByFqName(fqName)
|
||||||
if (foundClassifier != null) {
|
if (foundSymbol != null) {
|
||||||
return (foundClassifier as? FirSymbolOwner<*>)?.symbol
|
return foundSymbol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-16
@@ -14,9 +14,7 @@ import org.jetbrains.kotlin.fir.resolve.FirQualifierResolver
|
|||||||
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
|
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
import org.jetbrains.kotlin.fir.symbols.*
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.*
|
import org.jetbrains.kotlin.fir.types.impl.*
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
@@ -42,23 +40,19 @@ class FirTypeResolverImpl : FirTypeResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ConeSymbol.toConeKotlinType(parts: List<FirQualifierPart>, session: FirSession): ConeKotlinType? {
|
private fun ConeSymbol.toConeKotlinType(parts: List<FirQualifierPart>, session: FirSession): ConeKotlinType? {
|
||||||
val firProvider = FirProvider.getInstance(session)
|
|
||||||
val fir = firProvider.getFirClassifierBySymbol(this) ?: return null
|
|
||||||
return when (fir) {
|
|
||||||
is FirTypeParameter -> {
|
|
||||||
ConeTypeParameterTypeImpl(this as ConeTypeParameterSymbol)
|
|
||||||
}
|
|
||||||
is FirClass -> {
|
|
||||||
ConeClassTypeImpl(this as ConeClassLikeSymbol, parts.toTypeProjections())
|
|
||||||
}
|
|
||||||
is FirTypeAlias -> {
|
|
||||||
val coneTypeSafe = fir.expandedType.coneTypeSafe<ConeClassLikeType>()
|
|
||||||
val expansion = coneTypeSafe ?: return ConeKotlinErrorType("Couldn't resolve expansion")
|
|
||||||
|
|
||||||
|
return when (this) {
|
||||||
|
is ConeTypeParameterSymbol -> {
|
||||||
|
ConeTypeParameterTypeImpl(this)
|
||||||
|
}
|
||||||
|
is ConeClassSymbol -> {
|
||||||
|
ConeClassTypeImpl(this, parts.toTypeProjections())
|
||||||
|
}
|
||||||
|
is ConeTypeAliasSymbol -> {
|
||||||
ConeAbbreviatedTypeImpl(
|
ConeAbbreviatedTypeImpl(
|
||||||
abbreviationSymbol = this as ConeClassLikeSymbol,
|
abbreviationSymbol = this as ConeClassLikeSymbol,
|
||||||
typeArguments = parts.toTypeProjections(),
|
typeArguments = parts.toTypeProjections(),
|
||||||
directExpansion = expansion
|
directExpansion = expansionType ?: ConeClassErrorType("Unresolved expansion")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> error("!")
|
else -> error("!")
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.fir.scopes.impl
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirImport
|
import org.jetbrains.kotlin.fir.declarations.FirImport
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedImportImpl
|
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedImportImpl
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||||
@@ -27,7 +27,7 @@ class FirExplicitImportingScope(imports: List<FirImport>) : FirScope {
|
|||||||
): Boolean {
|
): Boolean {
|
||||||
val imports = simpleImports[name] ?: return true
|
val imports = simpleImports[name] ?: return true
|
||||||
if (imports.isEmpty()) return true
|
if (imports.isEmpty()) return true
|
||||||
val provider = FirProvider.getInstance(imports.first().session)
|
val provider = FirSymbolProvider.getInstance(imports.first().session)
|
||||||
for (import in imports) {
|
for (import in imports) {
|
||||||
val symbol = provider.getSymbolByFqName(import.resolvedFqName) ?: continue
|
val symbol = provider.getSymbolByFqName(import.resolvedFqName) ?: continue
|
||||||
if (!processor(symbol)) {
|
if (!processor(symbol)) {
|
||||||
|
|||||||
+2
-3
@@ -8,11 +8,10 @@ package org.jetbrains.kotlin.fir.scopes.impl
|
|||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirImport
|
import org.jetbrains.kotlin.fir.declarations.FirImport
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirResolvedImport
|
import org.jetbrains.kotlin.fir.declarations.FirResolvedImport
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirSymbolOwner
|
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
@@ -25,7 +24,7 @@ class FirStarImportingScope(imports: List<FirImport>, val session: FirSession) :
|
|||||||
position: FirPosition,
|
position: FirPosition,
|
||||||
processor: (ConeSymbol) -> Boolean
|
processor: (ConeSymbol) -> Boolean
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val provider = FirProvider.getInstance(session)
|
val provider = FirSymbolProvider.getInstance(session)
|
||||||
for (import in starImports) {
|
for (import in starImports) {
|
||||||
val relativeClassName = import.relativeClassName
|
val relativeClassName = import.relativeClassName
|
||||||
val classId = if (relativeClassName == null) {
|
val classId = if (relativeClassName == null) {
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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.fir.symbols
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.fir.deserialization.FirTypeDeserializer
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
|
||||||
|
import org.jetbrains.kotlin.metadata.deserialization.supertypes
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags
|
||||||
|
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||||
|
|
||||||
|
class LibraryClassSymbol(
|
||||||
|
val classProto: ProtoBuf.Class,
|
||||||
|
nameResolver: NameResolver,
|
||||||
|
val typeDeserializer: FirTypeDeserializer
|
||||||
|
) : ConeClassSymbol {
|
||||||
|
|
||||||
|
override val kind: ClassKind = ProtoEnumFlags.classKind(Flags.CLASS_KIND[classProto.flags])
|
||||||
|
|
||||||
|
override val typeParameters: List<ConeTypeParameterSymbol> by lazy { typeDeserializer.ownTypeParameters }
|
||||||
|
override val classId: ClassId = nameResolver.getClassId(classProto.fqName)
|
||||||
|
|
||||||
|
val typeTable = TypeTable(classProto.typeTable)
|
||||||
|
|
||||||
|
override val superTypes: List<ConeClassLikeType>
|
||||||
|
get() {
|
||||||
|
val result = classProto.supertypes(typeTable).map { supertypeProto ->
|
||||||
|
typeDeserializer.classLikeType(supertypeProto)
|
||||||
|
}// TODO: + c.components.additionalClassPartsProvider.getSupertypes(this@DeserializedClassDescriptor)
|
||||||
|
|
||||||
|
return result.filterNotNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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.fir.symbols
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
class LibraryTypeParameterSymbol(override val name: Name) : ConeTypeParameterSymbol {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.declarations
|
|||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.fir.BaseTransformedType
|
import org.jetbrains.kotlin.fir.BaseTransformedType
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirSymbolOwner
|
import org.jetbrains.kotlin.fir.symbols.FirSymbolOwner
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.FirType
|
import org.jetbrains.kotlin.fir.types.FirType
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||||
|
|
||||||
@@ -26,6 +27,8 @@ interface FirClass : FirDeclarationContainer, FirMemberDeclaration, FirSymbolOwn
|
|||||||
|
|
||||||
val isData: Boolean
|
val isData: Boolean
|
||||||
|
|
||||||
|
override val symbol: FirClassSymbol
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
|
||||||
visitor.visitClass(this, data)
|
visitor.visitClass(this, data)
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.FirClass
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirMemberPlatformStatus
|
import org.jetbrains.kotlin.fir.declarations.FirMemberPlatformStatus
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.transformInplace
|
import org.jetbrains.kotlin.fir.transformInplace
|
||||||
import org.jetbrains.kotlin.fir.types.FirType
|
import org.jetbrains.kotlin.fir.types.FirType
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -22,7 +23,7 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
|||||||
open class FirClassImpl(
|
open class FirClassImpl(
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
psi: PsiElement?,
|
psi: PsiElement?,
|
||||||
final override val symbol: FirBasedSymbol<FirClass>,
|
final override val symbol: FirClassSymbol,
|
||||||
name: Name,
|
name: Name,
|
||||||
visibility: Visibility,
|
visibility: Visibility,
|
||||||
modality: Modality?,
|
modality: Modality?,
|
||||||
|
|||||||
@@ -5,14 +5,24 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.symbols.impl
|
package org.jetbrains.kotlin.fir.symbols.impl
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.ConeClassSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeTypeParameterType
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||||
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
class FirClassSymbol(override val classId: ClassId) : ConeClassSymbol, AbstractFirBasedSymbol<FirClass>() {
|
class FirClassSymbol(override val classId: ClassId) : ConeClassSymbol, AbstractFirBasedSymbol<FirClass>() {
|
||||||
|
override val kind: ClassKind
|
||||||
|
get() = fir.classKind
|
||||||
|
|
||||||
override val superTypes: List<ConeClassLikeType>
|
override val superTypes: List<ConeClassLikeType>
|
||||||
get() = fir.superTypes.map { it.coneTypeUnsafe<ConeClassLikeType>() }
|
get() = fir.superTypes.mapNotNull { it.coneTypeSafe<ConeClassLikeType>() }
|
||||||
|
|
||||||
|
override val typeParameters: List<ConeTypeParameterSymbol>
|
||||||
|
get() = fir.typeParameters.map { it.symbol }
|
||||||
}
|
}
|
||||||
@@ -8,12 +8,15 @@ package org.jetbrains.kotlin.fir.symbols.impl
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
|
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
|
||||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeAliasSymbol
|
import org.jetbrains.kotlin.fir.symbols.ConeTypeAliasSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|
||||||
class FirTypeAliasSymbol(override val classId: ClassId) : ConeTypeAliasSymbol, AbstractFirBasedSymbol<FirTypeAlias>() {
|
class FirTypeAliasSymbol(override val classId: ClassId) : ConeTypeAliasSymbol, AbstractFirBasedSymbol<FirTypeAlias>() {
|
||||||
override val expansionType: ConeClassLikeType
|
override val typeParameters: List<ConeTypeParameterSymbol>
|
||||||
get() = fir.expandedType.coneTypeUnsafe()
|
get() = fir.typeParameters.map { it.symbol }
|
||||||
|
override val expansionType: ConeClassLikeType?
|
||||||
|
get() = fir.expandedType.coneTypeSafe()
|
||||||
|
|
||||||
}
|
}
|
||||||
+5
-1
@@ -8,5 +8,9 @@ package org.jetbrains.kotlin.fir.symbols.impl
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
||||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
|
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
class FirTypeParameterSymbol : AbstractFirBasedSymbol<FirTypeParameter>(), ConeTypeParameterSymbol
|
class FirTypeParameterSymbol : AbstractFirBasedSymbol<FirTypeParameter>(), ConeTypeParameterSymbol {
|
||||||
|
override val name: Name
|
||||||
|
get() = fir.name
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import kotlin.*
|
||||||
|
import kotlin.collections.*
|
||||||
|
|
||||||
|
abstract class MyStringList : List<String>
|
||||||
|
abstract class MyMutableStringList : MutableList<String>
|
||||||
|
|
||||||
|
fun List<String>.convert(): MyStringList = this as MyStringList
|
||||||
|
fun ret(l: MutableList<String>): MyMutableStringList = this as MyMutableStringList
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
FILE: lists.kt
|
||||||
|
(resolved) public? abstract class MyStringList() : R/kotlin/collections/List<kotlin/String>/ {
|
||||||
|
}
|
||||||
|
(resolved) public? abstract class MyMutableStringList() : R/kotlin/collections/MutableList<kotlin/String>/ {
|
||||||
|
}
|
||||||
|
public? final? function convertR/kotlin/collections/List<kotlin/String>/.(): R/MyStringList/ {
|
||||||
|
STUB
|
||||||
|
}
|
||||||
|
public? final? function ret(l: R/kotlin/collections/MutableList<kotlin/String>/): R/MyMutableStringList/ {
|
||||||
|
STUB
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import kotlin.*
|
||||||
|
|
||||||
interface SomeInterface {
|
interface SomeInterface {
|
||||||
fun foo(x: Int, y: String): String
|
fun foo(x: Int, y: String): String
|
||||||
|
|
||||||
|
|||||||
+9
-9
@@ -1,27 +1,27 @@
|
|||||||
FILE: simpleClass.kt
|
FILE: simpleClass.kt
|
||||||
(resolved) public? abstract interface SomeInterface() {
|
(resolved) public? abstract interface SomeInterface() {
|
||||||
public? final? function foo(x: R/error: Symbol not found/, y: R/error: Symbol not found/): R/error: Symbol not found/
|
public? final? function foo(x: R/kotlin/Int/, y: R/kotlin/String/): R/kotlin/String/
|
||||||
|
|
||||||
public? final? property bar(val): R/error: Symbol not found/
|
public? final? property bar(val): R/kotlin/Boolean/
|
||||||
public? get(): R/error: Symbol not found/
|
public? get(): R/kotlin/Boolean/
|
||||||
|
|
||||||
}
|
}
|
||||||
(resolved) public? final class SomeClass() : R/SomeInterface/ {
|
(resolved) public? final class SomeClass() : R/SomeInterface/ {
|
||||||
private final? property baz(val): R/error: Not supported: FirImplicitTypeImpl/ = STUB
|
private final? property baz(val): R/error: Not supported: FirImplicitTypeImpl/ = STUB
|
||||||
public? get(): R/error: Not supported: FirImplicitTypeImpl/
|
public? get(): R/error: Not supported: FirImplicitTypeImpl/
|
||||||
|
|
||||||
public? open? override function foo(x: R/error: Symbol not found/, y: R/error: Symbol not found/): R/error: Symbol not found/ {
|
public? open? override function foo(x: R/kotlin/Int/, y: R/kotlin/String/): R/kotlin/String/ {
|
||||||
}
|
}
|
||||||
|
|
||||||
public? open? override property bar(var): R/error: Symbol not found/
|
public? open? override property bar(var): R/kotlin/Boolean/
|
||||||
public? get(): R/error: Not supported: FirImplicitTypeImpl/ {
|
public? get(): R/error: Not supported: FirImplicitTypeImpl/ {
|
||||||
STUB
|
STUB
|
||||||
}
|
}
|
||||||
public? set(value: R/error: Symbol not found/): R/error: Not supported: FirImplicitTypeImpl/ {
|
public? set(value: R/kotlin/Boolean/): R/error: Not supported: FirImplicitTypeImpl/ {
|
||||||
}
|
}
|
||||||
|
|
||||||
public? final? property fau(var): R/error: Symbol not found/
|
public? final? property fau(var): R/kotlin/Double/
|
||||||
public? get(): R/error: Symbol not found/
|
public? get(): R/kotlin/Double/
|
||||||
public? set(value: R/error: Symbol not found/): R/kotlin/Unit/
|
public? set(value: R/kotlin/Double/): R/kotlin/Unit/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,29 +11,22 @@ import org.jetbrains.kotlin.fir.builder.RawFirBuilder
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirQualifierResolver
|
import org.jetbrains.kotlin.fir.resolve.FirQualifierResolver
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
|
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
|
||||||
import org.jetbrains.kotlin.fir.resolve.impl.FirProviderImpl
|
import org.jetbrains.kotlin.fir.resolve.impl.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.impl.FirQualifierResolverImpl
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.impl.FirTypeResolverImpl
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
|
import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
abstract class AbstractFirResolveTestCase : KotlinTestWithEnvironment() {
|
abstract class AbstractFirResolveTestCase : AbstractFirResolveWithSessionTestCase() {
|
||||||
override fun createEnvironment(): KotlinCoreEnvironment {
|
override fun createEnvironment(): KotlinCoreEnvironment {
|
||||||
return createEnvironmentWithMockJdk(ConfigurationKind.JDK_NO_RUNTIME)
|
return createEnvironmentWithMockJdk(ConfigurationKind.JDK_NO_RUNTIME)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun doCreateAndProcessFir(ktFiles: List<KtFile>): List<FirFile> {
|
fun doCreateAndProcessFir(ktFiles: List<KtFile>): List<FirFile> {
|
||||||
val session = object : FirSessionBase() {
|
val session = createSession()
|
||||||
init {
|
|
||||||
registerComponent(FirProvider::class, FirProviderImpl(this))
|
|
||||||
registerComponent(FirQualifierResolver::class, FirQualifierResolverImpl(this))
|
|
||||||
registerComponent(FirTypeResolver::class, FirTypeResolverImpl())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val builder = RawFirBuilder(session)
|
val builder = RawFirBuilder(session)
|
||||||
|
|
||||||
@@ -43,7 +36,12 @@ abstract class AbstractFirResolveTestCase : KotlinTestWithEnvironment() {
|
|||||||
(session.service<FirProvider>() as FirProviderImpl).recordFile(firFile)
|
(session.service<FirProvider>() as FirProviderImpl).recordFile(firFile)
|
||||||
firFile
|
firFile
|
||||||
}.also {
|
}.also {
|
||||||
transformer.processFiles(it)
|
try {
|
||||||
|
transformer.processFiles(it)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
it.forEach { println(it.render()) }
|
||||||
|
throw e
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return firFiles
|
return firFiles
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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.fir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.FirQualifierResolver
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.impl.*
|
||||||
|
import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
|
||||||
|
|
||||||
|
abstract class AbstractFirResolveWithSessionTestCase : KotlinTestWithEnvironment() {
|
||||||
|
|
||||||
|
fun createSession(): FirSession {
|
||||||
|
return object : FirSessionBase() {
|
||||||
|
init {
|
||||||
|
val firProvider = FirProviderImpl(this)
|
||||||
|
registerComponent(FirProvider::class, firProvider)
|
||||||
|
registerComponent(
|
||||||
|
FirSymbolProvider::class,
|
||||||
|
FirCompositeSymbolProvider(listOf(firProvider, FirLibrarySymbolProviderImpl(this)))
|
||||||
|
)
|
||||||
|
registerComponent(FirQualifierResolver::class, FirQualifierResolverImpl(this))
|
||||||
|
registerComponent(FirTypeResolver::class, FirTypeResolverImpl())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -85,6 +85,21 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/fir/resolve/builtins")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Builtins extends AbstractFirResolveTestCase {
|
||||||
|
public void testAllFilesPresentInBuiltins() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/fir/resolve/builtins"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("lists.kt")
|
||||||
|
public void testLists() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/fir/resolve/builtins/lists.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/fir/resolve/multifile")
|
@TestMetadata("compiler/testData/fir/resolve/multifile")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ class ProtoBasedClassDataFinder(
|
|||||||
nameResolver.getClassId(klass.fqName)
|
nameResolver.getClassId(klass.fqName)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val allClassIds: Collection<ClassId> get() = classIdToProto.keys
|
val allClassIds: Collection<ClassId> get() = classIdToProto.keys
|
||||||
|
|
||||||
override fun findClassData(classId: ClassId): ClassData? {
|
override fun findClassData(classId: ClassId): ClassData? {
|
||||||
val classProto = classIdToProto[classId] ?: return null
|
val classProto = classIdToProto[classId] ?: return null
|
||||||
|
|||||||
Reference in New Issue
Block a user