diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt new file mode 100644 index 00000000000..c54992b6046 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt @@ -0,0 +1,140 @@ +/* + * Copyright 2010-2019 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.descriptors.annotations.Annotations +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.FirNamedFunction +import org.jetbrains.kotlin.fir.declarations.FirValueParameter +import org.jetbrains.kotlin.fir.declarations.impl.FirMemberFunctionImpl +import org.jetbrains.kotlin.fir.declarations.impl.FirTypeParameterImpl +import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl +import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall +import org.jetbrains.kotlin.fir.symbols.CallableId +import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl +import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.deserialization.* +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.protobuf.MessageLite +import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind +import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags +import org.jetbrains.kotlin.serialization.deserialization.getName +import org.jetbrains.kotlin.types.Variance + +class FirDeserializationContext( + val nameResolver: NameResolver, + val typeTable: TypeTable, + val versionRequirementTable: VersionRequirementTable, + val session: FirSession, + val packageFqName: FqName, + val relativeClassName: FqName?, + val typeDeserializer: FirTypeDeserializer, + val components: FirDeserializationComponents +) { + fun childContext( + typeParameterProtos: List + ): FirDeserializationContext = FirDeserializationContext( + nameResolver, typeTable, versionRequirementTable, session, packageFqName, relativeClassName, + FirTypeDeserializer( + nameResolver, typeTable, typeParameterProtos, typeDeserializer + ), + components + ) + + val memberDeserializer: FirMemberDeserializer = FirMemberDeserializer(this) +} + +// TODO: Move something here +class FirDeserializationComponents + +class FirMemberDeserializer(private val c: FirDeserializationContext) { + private fun loadOldFlags(oldFlags: Int): Int { + val lowSixBits = oldFlags and 0x3f + val rest = (oldFlags shr 8) shl 6 + return lowSixBits + rest + } + + fun loadFunction(proto: ProtoBuf.Function): FirNamedFunction { + val flags = if (proto.hasFlags()) proto.flags else loadOldFlags(proto.oldFlags) + + val receiverAnnotations = + // TODO: support annotations + Annotations.EMPTY + + val versionRequirementTable = + // TODO: Support case for KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME + c.versionRequirementTable + + val callableName = c.nameResolver.getName(proto.name) + val symbol = FirFunctionSymbol(CallableId(c.packageFqName, c.relativeClassName, callableName)) + val local = c.childContext(proto.typeParameterList) + + // TODO: support contracts + return FirMemberFunctionImpl( + c.session, + null, + symbol, + callableName, + ProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags)), + ProtoEnumFlags.modality(Flags.MODALITY.get(flags)), + Flags.IS_EXPECT_FUNCTION.get(flags), + false, + false, + Flags.IS_OPERATOR.get(flags), + Flags.IS_INFIX.get(flags), + Flags.IS_INLINE.get(flags), + Flags.IS_TAILREC.get(flags), + Flags.IS_EXTERNAL_FUNCTION.get(flags), + Flags.IS_SUSPEND.get(flags), + proto.receiverType(c.typeTable)?.let(local.typeDeserializer::type)?.toTypeRef(), + local.typeDeserializer.type(proto.returnType(c.typeTable)).toTypeRef() + ).apply { + typeParameters += local.typeDeserializer.ownTypeParameters.map { createTypeParameterSymbol(it.name).fir } + valueParameters += local.memberDeserializer.valueParameters(proto.valueParameterList) + annotations += getAnnotations(proto, flags, AnnotatedCallableKind.FUNCTION) + } + } + + private fun createTypeParameterSymbol(name: Name): FirTypeParameterSymbol { + val firSymbol = FirTypeParameterSymbol() + FirTypeParameterImpl(c.session, null, firSymbol, name, variance = Variance.INVARIANT, isReified = false) + return firSymbol + } + + private fun valueParameters( + valueParameters: List + ): List { + return valueParameters.mapIndexed { i, proto -> + val flags = if (proto.hasFlags()) proto.flags else 0 + FirValueParameterImpl( + c.session, null, c.nameResolver.getName(proto.name), + c.typeDeserializer.type(proto.type(c.typeTable)).toTypeRef(), + null, // TODO: default value + Flags.IS_CROSSINLINE.get(flags), + Flags.IS_NOINLINE.get(flags), + proto.varargElementType(c.typeTable) != null + ).apply { + annotations += emptyList() // TODO: parameter annotations + } + }.toList() + } + + + // TODO: Annotations + private fun getAnnotations(proto: MessageLite, flags: Int, kind: AnnotatedCallableKind) = emptyList() + + private fun ConeKotlinType.toTypeRef(): FirTypeRef { + // TODO: annotations + return FirResolvedTypeRefImpl(c.session, null, this, nullability.isNullable, emptyList()) + } + +} + diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirSymbolProvider.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirSymbolProvider.kt index 2ed4a6a8d72..3be0713a280 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirSymbolProvider.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirSymbolProvider.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.service import org.jetbrains.kotlin.fir.symbols.* import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name interface FirSymbolProvider { @@ -26,6 +27,8 @@ interface FirSymbolProvider { fun getCallableSymbols(callableId: CallableId): List + fun getAllCallableNamesInPackage(fqName: FqName): Set = emptySet() + fun getPackage(fqName: FqName): FqName? // TODO: Replace to symbol sometime // TODO: should not retrieve session through the FirElement::session diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirCompositeSymbolProvider.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirCompositeSymbolProvider.kt index e4b1be75d97..faff5af7a44 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirCompositeSymbolProvider.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirCompositeSymbolProvider.kt @@ -11,15 +11,12 @@ import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult class FirCompositeSymbolProvider(val providers: List) : FirSymbolProvider { override fun getCallableSymbols(callableId: CallableId): List { - for (provider in providers) { - val symbols = provider.getCallableSymbols(callableId) - if (symbols.isNotEmpty()) return symbols - } - return emptyList() + return providers.flatMap { it.getCallableSymbols(callableId) } } override fun getPackage(fqName: FqName): FqName? { @@ -29,4 +26,8 @@ class FirCompositeSymbolProvider(val providers: List) : FirSy override fun getClassLikeSymbolByFqName(classId: ClassId): ConeClassLikeSymbol? { return providers.firstNotNullResult { it.getClassLikeSymbolByFqName(classId) } } -} \ No newline at end of file + + override fun getAllCallableNamesInPackage(fqName: FqName): Set { + return providers.flatMapTo(mutableSetOf()) { it.getAllCallableNamesInPackage(fqName) } + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirDependenciesSymbolProviderImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirDependenciesSymbolProviderImpl.kt index 962d19163b2..3e1d2732b99 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirDependenciesSymbolProviderImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirDependenciesSymbolProviderImpl.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name class FirDependenciesSymbolProviderImpl(val session: FirSession) : AbstractFirSymbolProvider() { private val dependencyProviders by lazy { @@ -26,13 +27,8 @@ class FirDependenciesSymbolProviderImpl(val session: FirSession) : AbstractFirSy override fun getCallableSymbols(callableId: CallableId): List { return callableCache.lookupCacheOrCalculate(callableId) { - for (provider in dependencyProviders) { - provider.getCallableSymbols(callableId).let { - if (it.isNotEmpty()) return@lookupCacheOrCalculate it - } - } - emptyList() - }.orEmpty() + dependencyProviders.flatMap { provider -> provider.getCallableSymbols(callableId) } + } ?: emptyList() } override fun getClassLikeSymbolByFqName(classId: ClassId): ConeClassLikeSymbol? { @@ -56,4 +52,8 @@ class FirDependenciesSymbolProviderImpl(val session: FirSession) : AbstractFirSy null } } -} \ No newline at end of file + + override fun getAllCallableNamesInPackage(fqName: FqName): Set { + return dependencyProviders.flatMapTo(mutableSetOf()) { it.getAllCallableNamesInPackage(fqName) } + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirLibrarySymbolProviderImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirLibrarySymbolProviderImpl.kt index 07e7692e6e1..9a820c8f466 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirLibrarySymbolProviderImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/impl/FirLibrarySymbolProviderImpl.kt @@ -14,6 +14,8 @@ import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.impl.FirClassImpl import org.jetbrains.kotlin.fir.declarations.impl.FirTypeParameterImpl +import org.jetbrains.kotlin.fir.deserialization.FirDeserializationComponents +import org.jetbrains.kotlin.fir.deserialization.FirDeserializationContext import org.jetbrains.kotlin.fir.deserialization.FirTypeDeserializer import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.getOrPut @@ -26,10 +28,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.builtins.BuiltInsBinaryVersion -import org.jetbrains.kotlin.metadata.deserialization.Flags -import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl -import org.jetbrains.kotlin.metadata.deserialization.TypeTable -import org.jetbrains.kotlin.metadata.deserialization.supertypes +import org.jetbrains.kotlin.metadata.deserialization.* import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -42,11 +41,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import java.io.InputStream class FirLibrarySymbolProviderImpl(val session: FirSession) : FirSymbolProvider { - override fun getCallableSymbols(callableId: CallableId): List { - // TODO - return emptyList() - } - private class BuiltInsPackageFragment(stream: InputStream, val fqName: FqName, val session: FirSession) { lateinit var version: BuiltInsBinaryVersion @@ -70,6 +64,22 @@ class FirLibrarySymbolProviderImpl(val session: FirSession) : FirSymbolProvider val classDataFinder = ProtoBasedClassDataFinder(packageProto, nameResolver, version) { SourceElement.NO_SOURCE } + private val memberDeserializer by lazy { + FirDeserializationContext( + nameResolver, TypeTable(packageProto.`package`.typeTable), + VersionRequirementTable.EMPTY, // TODO: + session, + fqName, + null, + FirTypeDeserializer( + nameResolver, + TypeTable(packageProto.`package`.typeTable), + emptyList(), + null + ), + FirDeserializationComponents() + ).memberDeserializer + } val lookup = mutableMapOf() @@ -124,6 +134,16 @@ class FirLibrarySymbolProviderImpl(val session: FirSession) : FirSymbolProvider } } } + + fun getTopLevelCallableSymbols(name: Name): List { + return packageProto.`package`.functionList.filter { nameResolver.getName(it.name) == name }.map { + memberDeserializer.loadFunction(it).symbol + } + } + + fun getAllCallableNames(): Set { + return packageProto.`package`.functionList.mapTo(mutableSetOf()) { nameResolver.getName(it.name) } + } } override fun getPackage(fqName: FqName): FqName? { @@ -176,4 +196,21 @@ class FirLibrarySymbolProviderImpl(val session: FirSession) : FirSymbolProvider } } } + + override fun getCallableSymbols(callableId: CallableId): List { + if (callableId.classId != null) { + // TODO: Support classes + return emptyList() + } + + return allPackageFragments[callableId.packageName]?.flatMap { + it.getTopLevelCallableSymbols(callableId.callableName) + } ?: emptyList() + } + + override fun getAllCallableNamesInPackage(fqName: FqName): Set { + return allPackageFragments[fqName]?.flatMapTo(mutableSetOf()) { + it.getAllCallableNames() + } ?: emptySet() + } } diff --git a/compiler/fir/resolve/testData/builtIns/kotlin-collections.txt b/compiler/fir/resolve/testData/builtIns/kotlin-collections.txt new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/compiler/fir/resolve/testData/builtIns/kotlin-collections.txt @@ -0,0 +1 @@ + diff --git a/compiler/fir/resolve/testData/builtIns/kotlin-ranges.txt b/compiler/fir/resolve/testData/builtIns/kotlin-ranges.txt new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/compiler/fir/resolve/testData/builtIns/kotlin-ranges.txt @@ -0,0 +1 @@ + diff --git a/compiler/fir/resolve/testData/builtIns/kotlin.txt b/compiler/fir/resolve/testData/builtIns/kotlin.txt new file mode 100644 index 00000000000..202d65d2045 --- /dev/null +++ b/compiler/fir/resolve/testData/builtIns/kotlin.txt @@ -0,0 +1,30 @@ + public final inline fun arrayOf(vararg elements: R|kotlin/Array|): R|kotlin/Array| + + public final fun arrayOfNulls(size: R|kotlin/Int|): R|kotlin/Array| + +public final fun booleanArrayOf(vararg elements: R|kotlin/BooleanArray|): R|kotlin/BooleanArray| + +public final fun byteArrayOf(vararg elements: R|kotlin/ByteArray|): R|kotlin/ByteArray| + +public final fun charArrayOf(vararg elements: R|kotlin/CharArray|): R|kotlin/CharArray| + +public final fun doubleArrayOf(vararg elements: R|kotlin/DoubleArray|): R|kotlin/DoubleArray| + + public final inline fun emptyArray(): R|kotlin/Array| + + public final inline fun enumValueOf(name: R|kotlin/String|): R|T| + + public final inline fun enumValues(): R|kotlin/Array| + +public final fun floatArrayOf(vararg elements: R|kotlin/FloatArray|): R|kotlin/FloatArray| + +public final fun intArrayOf(vararg elements: R|kotlin/IntArray|): R|kotlin/IntArray| + +public final fun longArrayOf(vararg elements: R|kotlin/LongArray|): R|kotlin/LongArray| + +public final fun shortArrayOf(vararg elements: R|kotlin/ShortArray|): R|kotlin/ShortArray| + +public final operator fun R|kotlin/String|.plus(other: R|kotlin/Any|): R|kotlin/String| + +public final fun R|kotlin/Any|.toString(): R|kotlin/String| + diff --git a/compiler/fir/resolve/testData/resolve/fromBuilder/simpleClass.txt b/compiler/fir/resolve/testData/resolve/fromBuilder/simpleClass.txt index 37b3bab1c2a..257ecceaf7c 100644 --- a/compiler/fir/resolve/testData/resolve/fromBuilder/simpleClass.txt +++ b/compiler/fir/resolve/testData/resolve/fromBuilder/simpleClass.txt @@ -13,7 +13,7 @@ FILE: simpleClass.kt private get(): R|kotlin/Int| public final override fun foo(x: R|kotlin/Int|, y: R|kotlin/String|): R|kotlin/String| { - ^foo #(#(R|/y|, R|/x|), R|/SomeClass.baz|) + ^foo R|kotlin/plus|(R|kotlin/plus|(R|/y|, R|/x|), R|/SomeClass.baz|) } public final override var bar: R|kotlin/Boolean| diff --git a/compiler/fir/resolve/testData/resolve/simpleClass.txt b/compiler/fir/resolve/testData/resolve/simpleClass.txt index 48a838160da..92659f586b9 100644 --- a/compiler/fir/resolve/testData/resolve/simpleClass.txt +++ b/compiler/fir/resolve/testData/resolve/simpleClass.txt @@ -13,7 +13,7 @@ FILE: simpleClass.kt private get(): R|kotlin/Int| public final override fun foo(x: R|kotlin/Int|, y: R|kotlin/String|): R|kotlin/String| { - ^foo #(#(R|/y|, R|/x|), R|/SomeClass.baz|) + ^foo R|kotlin/plus|(R|kotlin/plus|(R|/y|, R|/x|), R|/SomeClass.baz|) } public final override var bar: R|kotlin/Boolean| diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/BuiltInsDeserializationForFirTestCase.kt b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/BuiltInsDeserializationForFirTestCase.kt new file mode 100644 index 00000000000..b203db9b11e --- /dev/null +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/BuiltInsDeserializationForFirTestCase.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2010-2019 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 com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider +import org.jetbrains.kotlin.fir.symbols.CallableId +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.test.ConfigurationKind +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.TestJdkKind +import java.io.File + +class BuiltInsDeserializationForFirTestCase : AbstractFirResolveWithSessionTestCase() { + override fun createEnvironment(): KotlinCoreEnvironment { + return createEnvironmentWithJdk(ConfigurationKind.ALL, TestJdkKind.FULL_JDK) + } + + fun testCallables() { + for (packageFqName in listOf( + KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME, + KotlinBuiltIns.COLLECTIONS_PACKAGE_FQ_NAME, + KotlinBuiltIns.RANGES_PACKAGE_FQ_NAME + )) { + checkCallablesInPackage(packageFqName) + } + } + + private fun checkCallablesInPackage(packageFqName: FqName) { + val session = createSession(project, GlobalSearchScope.allScope(project)) + val provider = session.getService(FirSymbolProvider::class) + val names = provider.getAllCallableNamesInPackage(packageFqName) + + val builder = StringBuilder() + val firRenderer = FirRenderer(builder) + + for (name in names) { + for (symbol in provider.getCallableSymbols(CallableId(packageFqName, null, name))) { + (symbol as FirCallableSymbol).fir.accept(firRenderer) + builder.appendln() + } + } + + KotlinTestUtils.assertEqualsToFile( + File("compiler/fir/resolve/testData/builtIns/" + packageFqName.asString().replace('.', '-') + ".txt"), + builder.toString() + ) + } +} diff --git a/idea/testData/fir/multiModule/basicWithPrimitiveJava/jvm/jvm.txt b/idea/testData/fir/multiModule/basicWithPrimitiveJava/jvm/jvm.txt index c1d6e38dd1e..f1cd091481f 100644 --- a/idea/testData/fir/multiModule/basicWithPrimitiveJava/jvm/jvm.txt +++ b/idea/testData/fir/multiModule/basicWithPrimitiveJava/jvm/jvm.txt @@ -5,7 +5,7 @@ FILE: jvm.kt public final fun test(): R|kotlin/Unit| { lval res1: R|kotlin/Boolean| = R|/Some.foo|(Int(1)) lval res2: R|kotlin/Boolean| = R|/Some.foo|(#(Int(1))) - lval res3: R|kotlin/Array>| = R|/Some.bar|(#(Int(0), Int(2), #(Int(2)))) + lval res3: R|kotlin/Array>| = R|/Some.bar|(R|kotlin/intArrayOf|(Int(0), Int(2), #(Int(2)))) } }