diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolver/LLLibraryScopeAwareConeCallConflictResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCodeFragmentDependenciesSymbolProvider.kt similarity index 51% rename from analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolver/LLLibraryScopeAwareConeCallConflictResolver.kt rename to analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCodeFragmentDependenciesSymbolProvider.kt index 9d3c19daf65..fde8a990fce 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolver/LLLibraryScopeAwareConeCallConflictResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCodeFragmentDependenciesSymbolProvider.kt @@ -3,45 +3,48 @@ * 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.analysis.low.level.api.fir.resolver +package org.jetbrains.kotlin.analysis.low.level.api.fir.providers import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.fir.psi -import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents -import org.jetbrains.kotlin.fir.resolve.calls.Candidate -import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolver -import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory -import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.name.CallableId +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator -internal class LLLibraryScopeAwareCallConflictResolverFactory( - private val delegateFactory: ConeCallConflictResolverFactory -) : ConeCallConflictResolverFactory() { - override fun create( - typeSpecificityComparator: TypeSpecificityComparator, - components: InferenceComponents, - transformerComponents: BodyResolveComponents, - ): ConeCallConflictResolver { - val delegate = delegateFactory.create(typeSpecificityComparator, components, transformerComponents) - return LLLibraryScopeAwareConeCallConflictResolver(delegate, transformerComponents) +class LLFirCodeFragmentDependenciesSymbolProvider(private val delegate: FirSymbolProvider) : FirSymbolProvider(delegate.session) { + override val symbolNamesProvider: FirSymbolNamesProvider + get() = delegate.symbolNamesProvider + + override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? { + return delegate.getClassLikeSymbolByClassId(classId) } -} -private class LLLibraryScopeAwareConeCallConflictResolver( - private val delegate: ConeCallConflictResolver, - private val bodyResolveComponents: BodyResolveComponents -) : ConeCallConflictResolver() { - override fun chooseMaximallySpecificCandidates(candidates: Set, discriminateAbstracts: Boolean): Set { - val filteredCandidates = when { - candidates.size > 1 -> filterCodeFragmentCandidates(candidates) - else -> candidates - } + @FirSymbolProviderInternals + override fun getTopLevelCallableSymbolsTo(destination: MutableList>, packageFqName: FqName, name: Name) { + destination += delegate.getTopLevelCallableSymbols(packageFqName, name).let(::filterSymbols) + } - return delegate.chooseMaximallySpecificCandidates(filteredCandidates, discriminateAbstracts) + @FirSymbolProviderInternals + override fun getTopLevelFunctionSymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) { + destination += delegate.getTopLevelFunctionSymbols(packageFqName, name).let(::filterSymbols) + } + + @FirSymbolProviderInternals + override fun getTopLevelPropertySymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) { + destination += delegate.getTopLevelPropertySymbols(packageFqName, name).let(::filterSymbols) + } + + override fun getPackage(fqName: FqName): FqName? { + return delegate.getPackage(fqName) } // In complex projects, there might be several library copies (with the same or different versions). @@ -50,18 +53,20 @@ private class LLLibraryScopeAwareConeCallConflictResolver( // Normally, K2 issues a 'resolution ambiguity' error on calls to such libraries. It is sort of acceptable for resolution, as // resolution errors are never shown in the library code. However, the backend, to which 'evaluate expression' needs to pass FIR // afterwards, is not designed for compiling ambiguous (and non-completed) calls. - // The code below scans for declaration duplicates, and chooses a set of them from a single class input (a JAR or a directory). + // The code below scans for declaration duplicates, and chooses a number of them from a single class input (a JAR or a directory). // The logic is not ideal, as, in theory, versions might differ non-trivially: each artifact may have unique declarations. // However, such cases should be relatively rare, and to provide the candidate list more precisely, one would need to also compare // signatures of each declaration. - private fun filterCodeFragmentCandidates(candidates: Set): Set { - val binaryCallableCandidates = LinkedHashMap>>() - val otherCandidates = ArrayList() + private fun > filterSymbols(symbols: List): List { + if (symbols.size < 2) { + return symbols + } - for (candidate in candidates) { - val symbol = candidate.symbol + val binarySymbols = LinkedHashMap>>() + val otherSymbols = ArrayList() - if (symbol is FirCallableSymbol<*> && symbol.callableId.className == null) { + for (symbol in symbols) { + if (symbol.callableId.className == null) { val callableId = symbol.callableId val symbolFile = symbol.fir.psi?.containingFile @@ -69,29 +74,32 @@ private class LLLibraryScopeAwareConeCallConflictResolver( if (symbolFile is KtFile && symbolFile.isCompiled && symbolVirtualFile != null) { val symbolRootVirtualFile = getSymbolRootFile(symbolVirtualFile, symbolFile.packageFqName) if (symbolRootVirtualFile != null) { - binaryCallableCandidates + binarySymbols .getOrPut(callableId, ::LinkedHashMap) .getOrPut(symbolRootVirtualFile, ::ArrayList) - .add(candidate) + .add(symbol) continue } } } - otherCandidates.add(candidate) + otherSymbols.add(symbol) } - if (binaryCallableCandidates.isNotEmpty()) { - return buildSet { - addAll(otherCandidates) - for (binaryCallableCandidateGroup in binaryCallableCandidates.values) { - val chosenGroupKey = binaryCallableCandidateGroup.keys.maxBy { it.path } - addAll(binaryCallableCandidateGroup[chosenGroupKey].orEmpty()) + if (binarySymbols.isNotEmpty()) { + return buildList { + addAll(otherSymbols) + for (binarySymbolGroup in binarySymbols.values) { + // For consistency with class symbol fetching, callable symbols are returned in the same order as indices returned. + val firstBinarySymbolGroupValue = binarySymbolGroup.values.first() + if (firstBinarySymbolGroupValue.isNotEmpty()) { + addAll(firstBinarySymbolGroupValue) + } } } } - return candidates + return symbols } private fun getSymbolRootFile(virtualFile: VirtualFile, packageFqName: FqName): VirtualFile? { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirAbstractSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirAbstractSessionFactory.kt index 5c8e29e9568..fe93e859c74 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirAbstractSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirAbstractSessionFactory.kt @@ -13,7 +13,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirLazyDeclarationResol import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.* import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.* -import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.LLLibraryScopeAwareCallConflictResolverFactory import org.jetbrains.kotlin.analysis.project.structure.* import org.jetbrains.kotlin.analysis.providers.KotlinAnchorModuleProvider import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider @@ -33,12 +32,11 @@ import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper import org.jetbrains.kotlin.fir.extensions.* import org.jetbrains.kotlin.fir.java.JavaSymbolProvider import org.jetbrains.kotlin.fir.languageVersionSettings -import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory -import org.jetbrains.kotlin.fir.resolve.calls.callConflictResolverFactory import org.jetbrains.kotlin.fir.resolve.providers.DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.dependenciesSymbolProvider +import org.jetbrains.kotlin.fir.resolve.providers.impl.FirCompositeSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.impl.FirExtensionSyntheticFunctionInterfaceProvider import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped @@ -494,11 +492,14 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje registerCommonComponentsAfterExtensionsAreConfigured() val dependencyProvider = LLFirDependenciesSymbolProvider(this) { - buildList { + val providers = buildList { addMerged(computeFlattenedSymbolProviders(listOf(contextSession))) add(contextSession.dependenciesSymbolProvider) // Add the context module dependency symbol provider as is add(builtinsSession.symbolProvider) } + + // Wrap dependencies into a single classpath-filtering provider + listOf(LLFirCodeFragmentDependenciesSymbolProvider(FirCompositeSymbolProvider(session, providers))) } register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider) @@ -533,8 +534,6 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje ) register(FirJvmTypeMapper::class, FirJvmTypeMapper(this)) - - register(ConeCallConflictResolverFactory::class, LLLibraryScopeAwareCallConflictResolverFactory(callConflictResolverFactory)) } }