From f8d50d585d8f0940f4da30b6838cccfb3ca523bf Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Tue, 1 Dec 2020 10:38:27 +0100 Subject: [PATCH] FIR: Implement lookup tracking --- .../testingUtils/BuildLogFinder.kt | 5 +- .../compiler/KotlinToJVMBytecodeCompiler.kt | 4 +- .../declaration/FirConflictsChecker.kt | 25 +++-- ...mentalPassThroughLookupTrackerComponent.kt | 41 ++++++++ .../fir/session/ComponentsContainers.kt | 14 ++- .../kotlin/fir/session/FirSessionFactory.kt | 4 +- .../kotlin/fir/sessionCreationUtils.kt | 7 ++ .../jetbrains/kotlin/fir/java/JavaUtils.kt | 1 + .../java/enhancement/SignatureEnhancement.kt | 10 +- .../scopes/JavaClassStaticUseSiteScope.kt | 3 + .../jetbrains/kotlin/fir/FirCallResolver.kt | 4 + .../kotlin/fir/FirLookupTrackerComponent.kt | 61 ++++++++++++ .../kotlin/fir/resolve/ResolveUtils.kt | 8 +- .../kotlin/fir/resolve/calls/Arguments.kt | 30 +++++- .../kotlin/fir/resolve/calls/Candidate.kt | 2 + .../fir/resolve/calls/ResolutionStages.kt | 1 + .../calls/tower/FirTowerResolveTask.kt | 1 - .../resolve/calls/tower/TowerLevelHandler.kt | 10 +- .../fir/resolve/calls/tower/TowerLevels.kt | 98 ++++++++++++------- .../fir/resolve/inference/FirCallCompleter.kt | 21 ++-- .../inference/PostponedArgumentsAnalyzer.kt | 6 +- ...rCallCompletionResultsWriterTransformer.kt | 30 ++++-- .../FirImportResolveTransformer.kt | 18 +++- .../FirSpecificTypeResolverTransformer.kt | 20 ++++ .../transformers/FirSupertypesResolution.kt | 13 ++- .../transformers/FirSyntheticCallGenerator.kt | 11 ++- .../transformers/FirTypeResolveTransformer.kt | 4 +- .../body/resolve/FirBodyResolveTransformer.kt | 4 +- .../FirDeclarationsResolveTransformer.kt | 12 ++- .../FirExpressionsResolveTransformer.kt | 6 +- .../body/resolve/FirImplicitBodyResolve.kt | 7 +- .../impl/FirExplicitSimpleImportingScope.kt | 4 + .../impl/FirExplicitStarImportingScope.kt | 4 + ...irNestedClassifierScopeWithSubstitution.kt | 3 + .../fir/scopes/impl/FirOnlyCallablesScope.kt | 3 + .../fir/scopes/impl/FirPackageMemberScope.kt | 8 +- .../FirScopeWithFakeOverrideTypeCalculator.kt | 3 + .../kotlin/fir/scopes/FirCompositeScope.kt | 4 + .../jetbrains/kotlin/fir/scopes/FirScope.kt | 2 + .../jetbrains/kotlin/fir/SessionTestUtils.kt | 7 +- .../api/resolver/candidateInfoProviders.kt | 1 + 41 files changed, 423 insertions(+), 97 deletions(-) create mode 100644 compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/IncrementalPassThroughLookupTrackerComponent.kt create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirLookupTrackerComponent.kt diff --git a/build-common/test/org/jetbrains/kotlin/incremental/testingUtils/BuildLogFinder.kt b/build-common/test/org/jetbrains/kotlin/incremental/testingUtils/BuildLogFinder.kt index 1509d7c8a7c..7afda67267a 100644 --- a/build-common/test/org/jetbrains/kotlin/incremental/testingUtils/BuildLogFinder.kt +++ b/build-common/test/org/jetbrains/kotlin/incremental/testingUtils/BuildLogFinder.kt @@ -33,6 +33,8 @@ data class BuildLogFinder( private const val GRADLE_LOG = "gradle-build.log" private const val DATA_CONTAINER_LOG = "data-container-version-build.log" const val JS_JPS_LOG = "js-jps-build.log" + private const val FIR_LOG = "fir-build.log" + private const val GRADLE_FIR_LOG = "gradle-fir-build.log" private const val SIMPLE_LOG = "build.log" fun isJpsLogFile(file: File): Boolean = @@ -46,10 +48,11 @@ data class BuildLogFinder( isScopeExpansionEnabled && SCOPE_EXPANDING_LOG in files -> SCOPE_EXPANDING_LOG isKlibEnabled && KLIB_LOG in files -> KLIB_LOG isJsEnabled && JS_LOG in files -> JS_LOG + isGradleEnabled && isFirEnabled && GRADLE_FIR_LOG in files -> GRADLE_FIR_LOG + isFirEnabled && FIR_LOG in files -> FIR_LOG isGradleEnabled && GRADLE_LOG in files -> GRADLE_LOG isJsEnabled && JS_JPS_LOG in files -> JS_JPS_LOG isDataContainerBuildLogEnabled && DATA_CONTAINER_LOG in files -> DATA_CONTAINER_LOG - isFirEnabled && FIR_LOG in files -> FIR_LOG SIMPLE_LOG in files -> SIMPLE_LOG else -> null } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt index df8df29eefe..6ca6ce328a6 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt @@ -333,6 +333,7 @@ object KotlinToJVMBytecodeCompiler { languageVersionSettings, sourceScope, librariesScope, + lookupTracker = environment.configuration.get(CommonConfigurationKeys.LOOKUP_TRACKER), environment::createPackagePartProvider ) { if (extendedAnalysisMode) { @@ -350,9 +351,6 @@ object KotlinToJVMBytecodeCompiler { ) performanceManager?.notifyAnalysisFinished() - // TODO: maybe we should not do it in presence of errors, but tests at the moment expect lookups to be reported - session.firLookupTracker?.flushLookups() - if (syntaxErrors || firDiagnostics.any { it.severity == Severity.ERROR }) { return false } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsChecker.kt index 76b4cd225ee..c408453b811 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConflictsChecker.kt @@ -11,9 +11,8 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn -import org.jetbrains.kotlin.fir.declarations.FirDeclaration -import org.jetbrains.kotlin.fir.declarations.FirFile -import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.lookupTracker import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol object FirConflictsChecker : FirBasicDeclarationChecker() { @@ -21,7 +20,7 @@ object FirConflictsChecker : FirBasicDeclarationChecker() { val inspector = FirDeclarationInspector() when (declaration) { - is FirFile -> checkFile(declaration, inspector) + is FirFile -> checkFile(declaration, inspector, context) is FirRegularClass -> checkRegularClass(declaration, inspector) else -> return } @@ -47,9 +46,21 @@ object FirConflictsChecker : FirBasicDeclarationChecker() { } } - private fun checkFile(declaration: FirFile, inspector: FirDeclarationInspector) { - for (it in declaration.declarations) { - inspector.collect(it) + private fun checkFile(file: FirFile, inspector: FirDeclarationInspector, context: CheckerContext) { + val lookupTracker = context.session.lookupTracker + for (topLevelDeclaration in file.declarations) { + inspector.collect(topLevelDeclaration) + if (lookupTracker != null) { + when (topLevelDeclaration) { + is FirSimpleFunction -> topLevelDeclaration.name + is FirVariable<*> -> topLevelDeclaration.name + is FirRegularClass -> topLevelDeclaration.name + is FirTypeAlias -> topLevelDeclaration.name + else -> null + }?.let { + lookupTracker.recordLookup(it, file.packageFqName.asString(), topLevelDeclaration.source, file.source) + } + } } } diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/IncrementalPassThroughLookupTrackerComponent.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/IncrementalPassThroughLookupTrackerComponent.kt new file mode 100644 index 00000000000..af9ad242410 --- /dev/null +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/IncrementalPassThroughLookupTrackerComponent.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2020 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.fir + +import org.jetbrains.kotlin.diagnostics.DiagnosticUtils.getLineAndColumnInPsiFile +import org.jetbrains.kotlin.incremental.components.LookupTracker +import org.jetbrains.kotlin.incremental.components.Position +import org.jetbrains.kotlin.incremental.components.ScopeKind +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.SmartList +import java.util.concurrent.ConcurrentHashMap + +class IncrementalPassThroughLookupTrackerComponent( + private val lookupTracker: LookupTracker, + private val sourceToFilePath: (FirSourceElement) -> String +) : FirLookupTrackerComponent() { + + private val requiresPosition = lookupTracker.requiresPosition + private val sourceToFilePathsCache = ConcurrentHashMap() + + override fun recordLookup(name: Name, inScopes: List, source: FirSourceElement?, fileSource: FirSourceElement?) { + val definedSource = fileSource ?: source ?: throw AssertionError("Cannot record lookup for \"$name\" without a source") + val path = sourceToFilePathsCache.getOrPut(definedSource) { + sourceToFilePath(definedSource) + } + val position = if (requiresPosition && source != null && source is FirPsiSourceElement<*>) { + getLineAndColumnInPsiFile(source.psi.containingFile, source.psi.textRange).let { Position(it.line, it.column) } + } else Position.NO_POSITION + + for (scope in inScopes) { + lookupTracker.record(path, position, scope, ScopeKind.PACKAGE, name.asString()) + } + } + + override fun recordLookup(name: Name, inScope: String, source: FirSourceElement?, fileSource: FirSourceElement?) { + recordLookup(name, SmartList(inScope), source, fileSource) + } +} diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt index b8d86129a5c..4423453a464 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/ComponentsContainers.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.session +import com.intellij.psi.PsiFile import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.analysis.CheckersComponent @@ -25,6 +26,7 @@ import org.jetbrains.kotlin.fir.resolve.providers.impl.FirTypeResolverImpl import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedClassIndex import org.jetbrains.kotlin.fir.scopes.impl.FirDeclaredMemberScopeProvider import org.jetbrains.kotlin.fir.types.FirCorrespondingSupertypesCache +import org.jetbrains.kotlin.incremental.components.LookupTracker // -------------------------- Required components -------------------------- @@ -55,10 +57,20 @@ fun FirSession.registerThreadUnsafeCaches() { * Resolve components which are same on all platforms */ @OptIn(SessionConfiguration::class) -fun FirSession.registerResolveComponents() { +fun FirSession.registerResolveComponents(lookupTracker: LookupTracker? = null) { register(FirQualifierResolver::class, FirQualifierResolverImpl(this)) register(FirTypeResolver::class, FirTypeResolverImpl(this)) register(CheckersComponent::class, CheckersComponent()) + if (lookupTracker != null) { + val firFileToPath: (FirSourceElement) -> String = { + val psiSource = (it as? FirPsiSourceElement<*>) ?: TODO("Not implemented for non-FirPsiSourceElement") + ((psiSource.psi as? PsiFile) ?: psiSource.psi.containingFile).virtualFile.path + } + register( + FirLookupTrackerComponent::class, + IncrementalPassThroughLookupTrackerComponent(lookupTracker, firFileToPath) + ) + } } /* diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactory.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactory.kt index 9593d047d8b..336bcb72e9b 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactory.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactory.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.impl.* import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped import org.jetbrains.kotlin.fir.scopes.KotlinScopeProvider +import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.load.java.JavaClassFinderImpl import org.jetbrains.kotlin.load.kotlin.PackagePartProvider import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory @@ -68,12 +69,13 @@ object FirSessionFactory { project: Project, dependenciesProvider: FirSymbolProvider? = null, languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, + lookupTracker: LookupTracker? = null, init: FirSessionConfigurator.() -> Unit = {} ): FirJavaModuleBasedSession { return FirJavaModuleBasedSession(moduleInfo, sessionProvider).apply { registerThreadUnsafeCaches() registerCommonComponents(languageVersionSettings) - registerResolveComponents() + registerResolveComponents(lookupTracker) registerJavaSpecificResolveComponents() val kotlinScopeProvider = KotlinScopeProvider(::wrapScopeWithJvmMapped) diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/sessionCreationUtils.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/sessionCreationUtils.kt index 6e95d941bfb..737d5d43caf 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/sessionCreationUtils.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/sessionCreationUtils.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.fir.session.FirJvmModuleInfo import org.jetbrains.kotlin.fir.session.FirSessionFactory +import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.load.kotlin.PackagePartProvider import org.jetbrains.kotlin.modules.Module import org.jetbrains.kotlin.name.Name @@ -24,6 +25,7 @@ fun createSessionWithDependencies( languageVersionSettings: LanguageVersionSettings, sourceScope: GlobalSearchScope, librariesScope: GlobalSearchScope, + lookupTracker: LookupTracker?, packagePartProvider: (GlobalSearchScope) -> PackagePartProvider, sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit = {} ): FirSession { @@ -33,6 +35,7 @@ fun createSessionWithDependencies( languageVersionSettings, sourceScope, librariesScope, + lookupTracker, packagePartProvider, sessionConfigurator ) { @@ -46,6 +49,7 @@ fun createSessionWithDependencies( languageVersionSettings: LanguageVersionSettings, sourceScope: GlobalSearchScope, librariesScope: GlobalSearchScope, + lookupTracker: LookupTracker?, packagePartProvider: (GlobalSearchScope) -> PackagePartProvider, sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit = {} ): FirSession { @@ -55,6 +59,7 @@ fun createSessionWithDependencies( languageVersionSettings, sourceScope, librariesScope, + lookupTracker, packagePartProvider, sessionConfigurator ) { @@ -68,6 +73,7 @@ private inline fun createSessionWithDependencies( languageVersionSettings: LanguageVersionSettings, sourceScope: GlobalSearchScope, librariesScope: GlobalSearchScope, + lookupTracker: LookupTracker?, packagePartProvider: (GlobalSearchScope) -> PackagePartProvider, noinline sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit, moduleInfoProvider: (dependencies: List) -> ModuleInfo, @@ -84,6 +90,7 @@ private inline fun createSessionWithDependencies( sourceScope, project, languageVersionSettings = languageVersionSettings, + lookupTracker = lookupTracker, init = sessionConfigurator ) } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt index e840312fe21..0c6ad16c76b 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt @@ -702,6 +702,7 @@ private fun FirConstExpression<*>.setProperType(session: FirSession): FirConstEx type = kind.expectedConeType(session) } replaceTypeRef(typeRef) + session.lookupTracker?.recordTypeResolveAsLookup(typeRef, source, null) return this } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt index 50a4d10940f..dfcaf385ae7 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt @@ -8,8 +8,7 @@ package org.jetbrains.kotlin.fir.java.enhancement import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.fir.FirAnnotationContainer -import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.builder.FirConstructorBuilder import org.jetbrains.kotlin.fir.declarations.builder.FirPrimaryConstructorBuilder @@ -19,11 +18,9 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.declarations.synthetic.buildSyntheticProperty -import org.jetbrains.kotlin.fir.initialSignatureAttr import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack import org.jetbrains.kotlin.fir.java.declarations.* import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible -import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.fir.symbols.impl.* @@ -85,7 +82,10 @@ class FirSignatureEnhancement( ) val newReturnTypeRef = enhanceReturnType(firElement, emptyList(), memberContext, predefinedInfo) - return firElement.symbol.apply { this.fir.replaceReturnTypeRef(newReturnTypeRef) } + return firElement.symbol.apply { + this.fir.replaceReturnTypeRef(newReturnTypeRef) + session.lookupTracker?.recordTypeResolveAsLookup(newReturnTypeRef, this.fir.source, null) + } } is FirField -> { if (firElement.returnTypeRef !is FirJavaTypeRef) return original diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassStaticUseSiteScope.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassStaticUseSiteScope.kt index ba531606c4e..802ae9a7a58 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassStaticUseSiteScope.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassStaticUseSiteScope.kt @@ -104,4 +104,7 @@ class JavaClassStaticUseSiteScope internal constructor( override fun mayContainName(name: Name): Boolean { return declaredMemberScope.mayContainName(name) || superTypesScopes.any { it.mayContainName(name) } } + + override val scopeOwnerLookupNames: List + get() = declaredMemberScope.scopeOwnerLookupNames } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index 4d86259c745..0ed3b8214b7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -135,6 +135,7 @@ class FirCallResolver( val typeArguments = (qualifiedAccess as? FirFunctionCall)?.typeArguments.orEmpty() val info = CallInfo( + qualifiedAccess, if (qualifiedAccess is FirFunctionCall) CallKind.Function else CallKind.VariableAccess, name, explicitReceiver, @@ -304,6 +305,7 @@ class FirCallResolver( } val callInfo = CallInfo( + delegatedConstructorCall, CallKind.DelegatingConstructorCall, name, explicitReceiver = null, @@ -352,6 +354,7 @@ class FirCallResolver( annotationCall.argumentList.transformArguments(transformer, ResolutionMode.ContextDependent) val callInfo = CallInfo( + annotationCall, CallKind.Function, name = reference.name, explicitReceiver = null, @@ -462,6 +465,7 @@ class FirCallResolver( outerConstraintSystemBuilder: ConstraintSystemBuilder?, ): CallInfo { return CallInfo( + callableReferenceAccess, CallKind.CallableReference, callableReferenceAccess.calleeReference.name, callableReferenceAccess.explicitReceiver, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirLookupTrackerComponent.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirLookupTrackerComponent.kt new file mode 100644 index 00000000000..168418a041c --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirLookupTrackerComponent.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2010-2020 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.fir + +import org.jetbrains.kotlin.fir.resolve.calls.CallInfo +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.SmartList + +abstract class FirLookupTrackerComponent : FirSessionComponent { + + abstract fun recordLookup(name: Name, inScopes: List, source: FirSourceElement?, fileSource: FirSourceElement?) + + abstract fun recordLookup(name: Name, inScope: String, source: FirSourceElement?, fileSource: FirSourceElement?) +} + +fun FirLookupTrackerComponent.recordCallLookup(callInfo: CallInfo, inType: ConeKotlinType) { + if (inType.classId?.isLocal == true) return + val scopes = SmartList(inType.render().replace('/', '.')) + if (inType.classId?.shortClassName?.asString() == "Companion") { + scopes.add(inType.classId!!.outerClassId!!.asString().replace('/', '.')) + } + recordLookup(callInfo.name, scopes, callInfo.callSite.source, callInfo.containingFile.source) +} + +fun FirLookupTrackerComponent.recordCallLookup(callInfo: CallInfo, inScopes: List) { + recordLookup(callInfo.name, inScopes, callInfo.callSite.source, callInfo.containingFile.source) +} + +fun FirLookupTrackerComponent.recordTypeLookup(typeRef: FirTypeRef, inScopes: List, fileSource: FirSourceElement?) { + if (typeRef is FirUserTypeRef) recordLookup(typeRef.qualifier.first().name, inScopes, typeRef.source, fileSource) +} + +fun FirLookupTrackerComponent.recordTypeResolveAsLookup(typeRef: FirTypeRef, source: FirSourceElement?, fileSource: FirSourceElement?) { + if (typeRef !is FirResolvedTypeRef) return // TODO: check if this is the correct behavior + if (source == null && fileSource == null) return // TODO: investigate all cases + + fun recordIfValid(type: ConeKotlinType) { + if (type is ConeKotlinErrorType) return // TODO: investigate whether some cases should be recorded, e.g. unresolved + type.classId?.let { + if (!it.isLocal) { + if (it.shortClassName.asString() != "Companion") { + recordLookup(it.shortClassName, it.packageFqName.asString(), source, fileSource) + } else { + recordLookup(it.outerClassId!!.shortClassName, it.outerClassId!!.packageFqName.asString(), source, fileSource) + } + } + } + type.typeArguments.forEach { + if (it is ConeKotlinType) recordIfValid(it) + } + } + + recordIfValid(typeRef.type) +} + + +val FirSession.lookupTracker: FirLookupTrackerComponent? by FirSession.nullableSessionComponentAccessor() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index 1af90debf00..7062b78ca73 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -298,7 +298,9 @@ fun FirCheckedSafeCallSubject.propagateTypeFromOriginalReceiver(nullableReceiver val expandedReceiverType = if (receiverType is ConeClassLikeType) receiverType.fullyExpandedType(session) else receiverType - replaceTypeRef(typeRef.resolvedTypeFromPrototype(expandedReceiverType.makeConeTypeDefinitelyNotNullOrNotNull())) + val resolvedTypeRef = typeRef.resolvedTypeFromPrototype(expandedReceiverType.makeConeTypeDefinitelyNotNullOrNotNull()) + replaceTypeRef(resolvedTypeRef) + session.lookupTracker?.recordTypeResolveAsLookup(resolvedTypeRef, source, null) } fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck( @@ -315,7 +317,9 @@ fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck( else typeAfterNullCheck - replaceTypeRef(typeRef.resolvedTypeFromPrototype(resultingType)) + val resolvedTypeRef = typeRef.resolvedTypeFromPrototype(resultingType) + replaceTypeRef(resolvedTypeRef) + session.lookupTracker?.recordTypeResolveAsLookup(resolvedTypeRef, source, null) } private fun FirQualifiedAccess.expressionTypeOrUnitForAssignment(): ConeKotlinType? { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index cb495ab2c3b..88131a04648 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.calls import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.lookupTracker import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.inference.* @@ -20,6 +21,7 @@ import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition @@ -29,6 +31,8 @@ import org.jetbrains.kotlin.types.model.CaptureStatus import org.jetbrains.kotlin.types.model.TypeSystemCommonSuperTypesContext import org.jetbrains.kotlin.utils.addToStdlib.runIf +val SAM_LOOKUP_NAME = Name.special("") + fun Candidate.resolveArgumentExpression( csBuilder: ConstraintSystemBuilder, argument: FirExpression, @@ -391,6 +395,7 @@ private fun checkApplicabilityForArgumentType( } internal fun Candidate.resolveArgument( + callInfo: CallInfo, argument: FirExpression, parameter: FirValueParameter?, isReceiver: Boolean, @@ -399,7 +404,8 @@ internal fun Candidate.resolveArgument( ) { argument.resultType.ensureResolvedTypeDeclaration(context.session) - val expectedType = prepareExpectedType(context.session, context.bodyResolveComponents.scopeSession, argument, parameter, context) + val expectedType = + prepareExpectedType(context.session, context.bodyResolveComponents.scopeSession, callInfo, argument, parameter, context) resolveArgumentExpression( this.system.getBuilder(), argument, @@ -415,13 +421,33 @@ internal fun Candidate.resolveArgument( private fun Candidate.prepareExpectedType( session: FirSession, scopeSession: ScopeSession, + callInfo: CallInfo, argument: FirExpression, parameter: FirValueParameter?, context: ResolutionContext ): ConeKotlinType? { if (parameter == null) return null val basicExpectedType = argument.getExpectedTypeForSAMConversion(parameter/*, LanguageVersionSettings*/) - val expectedType = getExpectedTypeWithSAMConversion(session, scopeSession, argument, basicExpectedType, context) ?: basicExpectedType + + val expectedType = + getExpectedTypeWithSAMConversion(session, scopeSession, argument, basicExpectedType, context)?.also { + session.lookupTracker?.let { lookupTracker -> + parameter.returnTypeRef.coneType.lowerBoundIfFlexible().classId?.takeIf { !it.isLocal }?.let { classId -> + lookupTracker.recordLookup( + SAM_LOOKUP_NAME, + classId.asString(), + callInfo.callSite.source, + callInfo.containingFile.source + ) + lookupTracker.recordLookup( + classId.shortClassName, + classId.packageFqName.asString(), + callInfo.callSite.source, + callInfo.containingFile.source + ) + } + } + } ?: basicExpectedType return this.substitutor.substituteOrSelf(expectedType) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt index 03c49b1ed0d..32d103cce1b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Candidate.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve.calls +import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirFile @@ -35,6 +36,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability import org.jetbrains.kotlin.resolve.calls.tower.isSuccess data class CallInfo( + val callSite: FirElement, val callKind: CallKind, val name: Name, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt index e7231ac0283..661cf478097 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt @@ -144,6 +144,7 @@ internal object CheckArguments : CheckerStage() { for (argument in callInfo.arguments) { val parameter = argumentMapping[argument] candidate.resolveArgument( + callInfo, argument, parameter, isReceiver = false, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt index 24b9e468dae..9f7678d406d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirTowerResolveTask.kt @@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.scopes.FirScope -import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef import org.jetbrains.kotlin.name.Name diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevelHandler.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevelHandler.kt index 5e8ecf8814e..a4fc646ab61 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevelHandler.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevelHandler.kt @@ -44,18 +44,18 @@ internal class TowerLevelHandler { when (info.callKind) { CallKind.VariableAccess -> { - processResult += towerLevel.processPropertiesByName(info.name, processor) + processResult += towerLevel.processPropertiesByName(info, processor) if (!collector.isSuccess() && towerLevel is ScopeTowerLevel && towerLevel.extensionReceiver == null) { - processResult += towerLevel.processObjectsByName(info.name, processor) + processResult += towerLevel.processObjectsByName(info, processor) } } CallKind.Function -> { - processResult += towerLevel.processFunctionsByName(info.name, processor) + processResult += towerLevel.processFunctionsByName(info, processor) } CallKind.CallableReference -> { - processResult += towerLevel.processFunctionsByName(info.name, processor) - processResult += towerLevel.processPropertiesByName(info.name, processor) + processResult += towerLevel.processFunctionsByName(info, processor) + processResult += towerLevel.processPropertiesByName(info, processor) } else -> { throw AssertionError("Unsupported call kind in tower resolver: ${info.callKind}") diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt index 856ff5f835f..07f1ca0b704 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerLevels.kt @@ -5,29 +5,23 @@ package org.jetbrains.kotlin.fir.resolve.calls.tower -import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.declarations.isInner -import org.jetbrains.kotlin.fir.dispatchReceiverClassOrNull import org.jetbrains.kotlin.fir.expressions.builder.buildResolvedQualifier import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.scopes.FirScope -import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.impl.FirDefaultStarImportingScope import org.jetbrains.kotlin.fir.scopes.impl.importedFromObjectData import org.jetbrains.kotlin.fir.scopes.processClassifiersByName import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* -import org.jetbrains.kotlin.fir.typeContext -import org.jetbrains.kotlin.fir.types.ConeClassLikeType -import org.jetbrains.kotlin.fir.types.ConeStarProjection -import org.jetbrains.kotlin.fir.types.coneType -import org.jetbrains.kotlin.fir.types.constructClassType -import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.util.OperatorNameConventions +import org.jetbrains.kotlin.utils.SmartList enum class ProcessResult { FOUND, SCOPE_EMPTY; @@ -46,11 +40,11 @@ abstract class TowerScopeLevel { object Objects : Token>() } - abstract fun processFunctionsByName(name: Name, processor: TowerScopeLevelProcessor>): ProcessResult + abstract fun processFunctionsByName(info: CallInfo, processor: TowerScopeLevelProcessor>): ProcessResult - abstract fun processPropertiesByName(name: Name, processor: TowerScopeLevelProcessor>): ProcessResult + abstract fun processPropertiesByName(info: CallInfo, processor: TowerScopeLevelProcessor>): ProcessResult - abstract fun processObjectsByName(name: Name, processor: TowerScopeLevelProcessor>): ProcessResult + abstract fun processObjectsByName(info: CallInfo, processor: TowerScopeLevelProcessor>): ProcessResult interface TowerScopeLevelProcessor> { fun consumeCandidate( @@ -131,41 +125,50 @@ class MemberScopeTowerLevel( } override fun processFunctionsByName( - name: Name, + info: CallInfo, processor: TowerScopeLevelProcessor> ): ProcessResult { - val isInvoke = name == OperatorNameConventions.INVOKE + val isInvoke = info.name == OperatorNameConventions.INVOKE if (implicitExtensionInvokeMode && !isInvoke) { return ProcessResult.FOUND } + val lookupTracker = session.lookupTracker return processMembers(processor) { consumer -> - this.processFunctionsAndConstructorsByName( - name, session, bodyResolveComponents, - includeInnerConstructors = true, - processor = { - // WARNING, DO NOT CAST FUNCTIONAL TYPE ITSELF - @Suppress("UNCHECKED_CAST") - consumer(it as FirFunctionSymbol<*>) - } - ) + withMemberCallLookup(lookupTracker, info) { lookupCtx -> + this.processFunctionsAndConstructorsByName( + info.name, session, bodyResolveComponents, + includeInnerConstructors = true, + processor = { + lookupCtx.recordCallableMemberLookup(it) + // WARNING, DO NOT CAST FUNCTIONAL TYPE ITSELF + @Suppress("UNCHECKED_CAST") + consumer(it as FirFunctionSymbol<*>) + } + ) + } } } override fun processPropertiesByName( - name: Name, + info: CallInfo, processor: TowerScopeLevelProcessor> ): ProcessResult { + val lookupTracker = session.lookupTracker return processMembers(processor) { consumer -> - this.processPropertiesByName(name) { - // WARNING, DO NOT CAST FUNCTIONAL TYPE ITSELF - @Suppress("UNCHECKED_CAST") - consumer(it) + withMemberCallLookup(lookupTracker, info) { lookupCtx -> + lookupTracker?.recordCallLookup(info, dispatchReceiverValue.type) + this.processPropertiesByName(info.name) { + lookupCtx.recordCallableMemberLookup(it) + // WARNING, DO NOT CAST FUNCTIONAL TYPE ITSELF + @Suppress("UNCHECKED_CAST") + consumer(it) + } } } } override fun processObjectsByName( - name: Name, + info: CallInfo, processor: TowerScopeLevelProcessor> ): ProcessResult { return ProcessResult.FOUND @@ -176,6 +179,28 @@ class MemberScopeTowerLevel( session, bodyResolveComponents, receiverValue, extensionReceiver, implicitExtensionInvokeMode, scopeSession ) } + + private inline fun withMemberCallLookup( + lookupTracker: FirLookupTrackerComponent?, + info: CallInfo, + body: (Triple, CallInfo>) -> Unit + ) { + lookupTracker?.recordCallLookup(info, dispatchReceiverValue.type) + val lookupScopes = SmartList() + body(Triple(lookupTracker, lookupScopes, info)) + if (lookupScopes.isNotEmpty()) { + lookupTracker?.recordCallLookup(info, lookupScopes) + } + } + + private fun Triple, CallInfo>.recordCallableMemberLookup(callable: FirCallableSymbol<*>) { + first?.run { + recordTypeResolveAsLookup(callable.fir.returnTypeRef, third.callSite.source, third.containingFile.source) + callable.callableId.className?.let { lookupScope -> + second.add(lookupScope.asString()) + } + } + } } // This is more like "scope-based tower level" @@ -269,12 +294,13 @@ class ScopeTowerLevel( } override fun processFunctionsByName( - name: Name, + info: CallInfo, processor: TowerScopeLevelProcessor> ): ProcessResult { var empty = true + session.lookupTracker?.recordCallLookup(info, scope.scopeOwnerLookupNames) scope.processFunctionsAndConstructorsByName( - name, + info.name, session, bodyResolveComponents, includeInnerConstructors = includeInnerConstructors @@ -286,11 +312,12 @@ class ScopeTowerLevel( } override fun processPropertiesByName( - name: Name, + info: CallInfo, processor: TowerScopeLevelProcessor> ): ProcessResult { var empty = true - scope.processPropertiesByName(name) { candidate -> + session.lookupTracker?.recordCallLookup(info, scope.scopeOwnerLookupNames) + scope.processPropertiesByName(info.name) { candidate -> empty = false consumeCallableCandidate(candidate, processor) } @@ -298,11 +325,12 @@ class ScopeTowerLevel( } override fun processObjectsByName( - name: Name, + info: CallInfo, processor: TowerScopeLevelProcessor> ): ProcessResult { var empty = true - scope.processClassifiersByName(name) { + session.lookupTracker?.recordCallLookup(info, scope.scopeOwnerLookupNames) + scope.processClassifiersByName(info.name) { empty = false processor.consumeCandidate( it, dispatchReceiverValue = null, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt index 15dd3acf85a..c06bf187bdd 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/FirCallCompleter.kt @@ -5,14 +5,13 @@ package org.jetbrains.kotlin.fir.resolve.inference -import org.jetbrains.kotlin.fir.FirFakeSourceElementKind +import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirResolvable import org.jetbrains.kotlin.fir.expressions.FirStatement -import org.jetbrains.kotlin.fir.fakeElement import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.calls.Candidate import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate @@ -26,7 +25,6 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBod import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.resolve.typeFromCallee -import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef @@ -62,7 +60,9 @@ class FirCallCompleter( val initialType = components.initialTypeOfCandidate(candidate, call) if (call is FirExpression) { - call.resultType = typeRef.resolvedTypeFromPrototype(initialType) + val resolvedTypeRef = typeRef.resolvedTypeFromPrototype(initialType) + call.resultType = resolvedTypeRef + session.lookupTracker?.recordTypeResolveAsLookup(resolvedTypeRef, call.source, null) } if (expectedTypeRef is FirResolvedTypeRef) { @@ -208,14 +208,19 @@ class FirCallCompleter( } ) + val lookupTracker = session.lookupTracker lambdaArgument.valueParameters.forEachIndexed { index, parameter -> - parameter.replaceReturnTypeRef( - parameter.returnTypeRef.resolvedTypeFromPrototype(parameters[index].approximateLambdaInputType()) - ) + val newReturnTypeRef = parameter.returnTypeRef.resolvedTypeFromPrototype(parameters[index].approximateLambdaInputType()) + parameter.replaceReturnTypeRef(newReturnTypeRef) + lookupTracker?.recordTypeResolveAsLookup(newReturnTypeRef, parameter.source, null) } lambdaArgument.replaceValueParameters(lambdaArgument.valueParameters + listOfNotNull(itParam)) - lambdaArgument.replaceReturnTypeRef(expectedReturnTypeRef ?: components.noExpectedType) + lambdaArgument.replaceReturnTypeRef( + expectedReturnTypeRef?.also { + lookupTracker?.recordTypeResolveAsLookup(it, lambdaArgument.source, null) + } ?: components.noExpectedType + ) val builderInferenceSession = runIf(stubsForPostponedVariables.isNotEmpty()) { @Suppress("UNCHECKED_CAST") diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt index 6b1ad430c3b..87b58871a00 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt @@ -8,6 +8,8 @@ package org.jetbrains.kotlin.fir.resolve.inference import org.jetbrains.kotlin.fir.FirCallResolver import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirStatement +import org.jetbrains.kotlin.fir.lookupTracker +import org.jetbrains.kotlin.fir.recordTypeResolveAsLookup import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedReferenceError @@ -93,7 +95,9 @@ class PostponedArgumentsAnalyzer( namedReference ).apply { if (resultingCandidate != null) { - replaceTypeRef(buildResolvedTypeRef { type = resultingCandidate.resultingTypeForCallableReference!! }) + val resolvedTypeRef = buildResolvedTypeRef { type = resultingCandidate.resultingTypeForCallableReference!! } + replaceTypeRef(resolvedTypeRef) + resolutionContext.session.lookupTracker?.recordTypeResolveAsLookup(resolvedTypeRef, source, null) } } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt index 4972ea4e9aa..61a029e3a2d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt @@ -113,6 +113,7 @@ class FirCallCompletionResultsWriterTransformer( if (declaration !is FirErrorFunction) { result.replaceTypeArguments(typeArguments) } + session.lookupTracker?.recordTypeResolveAsLookup(typeRef, qualifiedAccessExpression.source, null) return result } @@ -135,6 +136,7 @@ class FirCallCompletionResultsWriterTransformer( val resultType = typeRef.substituteTypeRef(subCandidate) resultType.ensureResolvedTypeDeclaration(session) result.replaceTypeRef(resultType) + session.lookupTracker?.recordTypeResolveAsLookup(resultType, qualifiedAccessExpression.source, null) if (mode == Mode.DelegatedPropertyCompletion) { subCandidate.symbol.fir.transformSingle(declarationWriter, null) @@ -179,6 +181,7 @@ class FirCallCompletionResultsWriterTransformer( } result.replaceTypeRef(resultType) + session.lookupTracker?.recordTypeResolveAsLookup(resultType, functionCall.source, null) if (mode == Mode.DelegatedPropertyCompletion) { subCandidate.symbol.fir.transformSingle(declarationWriter, null) @@ -249,6 +252,7 @@ class FirCallCompletionResultsWriterTransformer( ): D { val resultTypeRef = typeRef.substituteTypeRef(calleeReference.candidate) replaceTypeRef(resultTypeRef) + session.lookupTracker?.recordTypeResolveAsLookup(resultTypeRef, source, null) return this } @@ -297,6 +301,7 @@ class FirCallCompletionResultsWriterTransformer( val resultType = typeRef.withReplacedConeType(finalType) callableReferenceAccess.replaceTypeRef(resultType) callableReferenceAccess.replaceTypeArguments(typeArguments) + session.lookupTracker?.recordTypeResolveAsLookup(resultType, typeRef.source ?: callableReferenceAccess.source, null) return callableReferenceAccess.transformCalleeReference( StoreCalleeReference, @@ -338,9 +343,9 @@ class FirCallCompletionResultsWriterTransformer( ): CompositeTransformResult { val originalType = qualifiedAccessExpression.typeRef.coneType val substitutedReceiverType = finalSubstitutor.substituteOrNull(originalType) ?: return qualifiedAccessExpression.compose() - qualifiedAccessExpression.replaceTypeRef( - qualifiedAccessExpression.typeRef.resolvedTypeFromPrototype(substitutedReceiverType) - ) + val resolvedTypeRef = qualifiedAccessExpression.typeRef.resolvedTypeFromPrototype(substitutedReceiverType) + qualifiedAccessExpression.replaceTypeRef(resolvedTypeRef) + session.lookupTracker?.recordTypeResolveAsLookup(resolvedTypeRef, qualifiedAccessExpression.source, null) return qualifiedAccessExpression.compose() } } @@ -500,9 +505,9 @@ class FirCallCompletionResultsWriterTransformer( } if (needUpdateLambdaType) { - anonymousFunction.replaceTypeRef( - anonymousFunction.constructFunctionalTypeRef(isSuspend = expectedType?.isSuspendFunctionType(session) == true) - ) + val resolvedTypeRef = anonymousFunction.constructFunctionalTypeRef(isSuspend = expectedType?.isSuspendFunctionType(session) == true) + anonymousFunction.replaceTypeRef(resolvedTypeRef) + session.lookupTracker?.recordTypeResolveAsLookup(resolvedTypeRef, anonymousFunction.source, null) } val result = transformElement(anonymousFunction, null) @@ -519,10 +524,14 @@ class FirCallCompletionResultsWriterTransformer( (returnExpressionsOfAnonymousFunction.lastOrNull() as? FirExpression) ?.typeRef?.coneTypeSafe() - resultFunction.replaceReturnTypeRef(resultFunction.returnTypeRef.withReplacedConeType(lastExpressionType)) - resultFunction.replaceTypeRef( - resultFunction.constructFunctionalTypeRef(isSuspend = expectedType?.isSuspendFunctionType(session) == true) - ) + val newReturnTypeRef = resultFunction.returnTypeRef.withReplacedConeType(lastExpressionType) + resultFunction.replaceReturnTypeRef(newReturnTypeRef) + val resolvedTypeRef = resultFunction.constructFunctionalTypeRef(isSuspend = expectedType?.isSuspendFunctionType(session) == true) + resultFunction.replaceTypeRef(resolvedTypeRef) + session.lookupTracker?.let { + it.recordTypeResolveAsLookup(newReturnTypeRef, anonymousFunction.source, null) + it.recordTypeResolveAsLookup(resolvedTypeRef, anonymousFunction.source, null) + } } return result @@ -576,6 +585,7 @@ class FirCallCompletionResultsWriterTransformer( resultType = resultType.resolvedTypeFromPrototype(it.getApproximatedType(data?.getExpectedType(block))) } block.replaceTypeRef(resultType) + session.lookupTracker?.recordTypeResolveAsLookup(resultType, block.source, null) } transformElement(block, data) if (block.resultType is FirErrorTypeRef) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirImportResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirImportResolveTransformer.kt index cc0e15fd84a..f0277c56bb5 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirImportResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirImportResolveTransformer.kt @@ -11,8 +11,9 @@ import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirImport import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.builder.buildResolvedImport -import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider +import org.jetbrains.kotlin.fir.lookupTracker import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.symbolProvider import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult @@ -36,10 +37,20 @@ open class FirImportResolveTransformer protected constructor( private val symbolProvider: FirSymbolProvider = session.symbolProvider + private var currentFile: FirFile? = null + override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult { checkSessionConsistency(file) file.replaceResolvePhase(transformerPhase) - return file.also { it.transformChildren(this, null) }.compose() + return file.also { + val prevValue = currentFile + currentFile = file + try { + it.transformChildren(this, null) + } finally { + currentFile = prevValue + } + }.compose() } override fun transformImport(import: FirImport, data: Nothing?): CompositeTransformResult { @@ -52,6 +63,9 @@ open class FirImportResolveTransformer protected constructor( } val parentFqName = fqName.parent() + currentFile?.let { + session.lookupTracker?.recordLookup(fqName.shortName(), parentFqName.asString(), import.source, it.source) + } return transformImportForFqName(parentFqName, import) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt index 7443b9003aa..0f5b48e0e28 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSpecificTypeResolverTransformer.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.resolve.transformers import org.jetbrains.kotlin.fir.* +import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeUnexpectedTypeArgumentsError @@ -38,16 +39,35 @@ class FirSpecificTypeResolverTransformer( } } + @PrivateForInline + @JvmField + var currentFile: FirFile? = null + + @OptIn(PrivateForInline::class) + inline fun withFile(file: FirFile?, block: FirSpecificTypeResolverTransformer.() -> R): R { + val oldValue = currentFile + currentFile = file + return try { + block() + } finally { + currentFile = oldValue + } + } + + @OptIn(PrivateForInline::class) override fun transformTypeRef(typeRef: FirTypeRef, data: FirScope): CompositeTransformResult { + session.lookupTracker?.recordTypeLookup(typeRef, data.scopeOwnerLookupNames, currentFile?.source) typeRef.transformChildren(this, data) return transformType(typeRef, typeResolver.resolveType(typeRef, data, areBareTypesAllowed)) } + @OptIn(PrivateForInline::class) override fun transformFunctionTypeRef( functionTypeRef: FirFunctionTypeRef, data: FirScope ): CompositeTransformResult { functionTypeRef.transformChildren(this, data) + session.lookupTracker?.recordTypeLookup(functionTypeRef, data.scopeOwnerLookupNames, currentFile?.source) val resolvedType = typeResolver.resolveType(functionTypeRef, data, areBareTypesAllowed).takeIfAcceptable() return if (resolvedType != null && resolvedType !is ConeClassErrorType) { buildResolvedTypeRef { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt index 18f26cff764..dfafcfb31f6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt @@ -8,16 +8,15 @@ package org.jetbrains.kotlin.fir.resolve.transformers import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList -import org.jetbrains.kotlin.fir.FirElement -import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.extensions.extensionService import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider import org.jetbrains.kotlin.fir.extensions.supertypeGenerators -import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.* +import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isLocalClassOrAnonymousObject import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeTypeParameterSupertype import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.LocalClassesNavigationInfo import org.jetbrains.kotlin.fir.scopes.FirCompositeScope @@ -284,6 +283,14 @@ private class FirSupertypeResolverVisitor( supertypeRefs: List ): List { return resolveSpecificClassLikeSupertypes(classLikeDeclaration) { transformer, scope -> + if (!classLikeDeclaration.isLocalClassOrAnonymousObject()) { + session.lookupTracker?.let { + val fileSource = session.firProvider.getFirClassifierContainerFile(classLikeDeclaration.symbol).source + for (supertypeRef in supertypeRefs) { + it.recordTypeLookup(supertypeRef, scope.scopeOwnerLookupNames, fileSource) + } + } + } /* This list is backed by mutable list and during iterating on it we can resolve supertypes of that class via IDE light classes as IJ Java resolve may resolve a lot of stuff by light classes diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSyntheticCallGenerator.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSyntheticCallGenerator.kt index 0951e29b348..c46a0dcd225 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSyntheticCallGenerator.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSyntheticCallGenerator.kt @@ -62,6 +62,7 @@ class FirSyntheticCallGenerator( arguments += whenExpression.branches.map { it.result } } val reference = generateCalleeReferenceWithCandidate( + whenExpression, whenSelectFunction, argumentList, SyntheticCallableId.WHEN.callableName, @@ -85,6 +86,7 @@ class FirSyntheticCallGenerator( } val reference = generateCalleeReferenceWithCandidate( + tryExpression, trySelectFunction, argumentList, SyntheticCallableId.TRY.callableName, @@ -99,6 +101,7 @@ class FirSyntheticCallGenerator( if (stubReference !is FirStubReference) return null val reference = generateCalleeReferenceWithCandidate( + checkNotNullCall, checkNotNullFunction, checkNotNullCall.argumentList, SyntheticCallableId.CHECK_NOT_NULL.callableName, @@ -116,6 +119,7 @@ class FirSyntheticCallGenerator( arguments += elvisExpression.rhs } val reference = generateCalleeReferenceWithCandidate( + elvisExpression, elvisFunction, argumentList, SyntheticCallableId.ELVIS_NOT_NULL.callableName, @@ -134,6 +138,7 @@ class FirSyntheticCallGenerator( val reference = generateCalleeReferenceWithCandidate( + callableReferenceAccess, idFunction, argumentList, SyntheticCallableId.ID.callableName, @@ -156,13 +161,14 @@ class FirSyntheticCallGenerator( } private fun generateCalleeReferenceWithCandidate( + callSite: FirExpression, function: FirSimpleFunction, argumentList: FirArgumentList, name: Name, callKind: CallKind = CallKind.SyntheticSelect, context: ResolutionContext ): FirNamedReferenceWithCandidate? { - val callInfo = generateCallInfo(name, argumentList, callKind) + val callInfo = generateCallInfo(callSite, name, argumentList, callKind) val candidate = generateCandidate(callInfo, function, context) val applicability = components.resolutionStageRunner.processCandidate(candidate, context) if (applicability <= CandidateApplicability.INAPPLICABLE) { @@ -182,7 +188,8 @@ class FirSyntheticCallGenerator( ) } - private fun generateCallInfo(name: Name, argumentList: FirArgumentList, callKind: CallKind) = CallInfo( + private fun generateCallInfo(callSite: FirExpression, name: Name, argumentList: FirArgumentList, callKind: CallKind) = CallInfo( + callSite = callSite, callKind = callKind, name = name, explicitReceiver = null, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt index 78ce3337228..1b8f1a0acd6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt @@ -50,9 +50,11 @@ class FirTypeResolveTransformer( } private val typeResolverTransformer: FirSpecificTypeResolverTransformer = FirSpecificTypeResolverTransformer(session) + private var currentFile: FirFile? = null override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult { checkSessionConsistency(file) + currentFile = file return withScopeCleanup { scopes.addAll(createImportingScopes(file, session, scopeSession)) super.transformFile(file, data) @@ -169,7 +171,7 @@ class FirTypeResolveTransformer( } override fun transformTypeRef(typeRef: FirTypeRef, data: Nothing?): CompositeTransformResult { - return typeRef.transform(typeResolverTransformer, towerScope) + return typeResolverTransformer.withFile(currentFile) { typeRef.transform(typeResolverTransformer, towerScope) } } override fun transformValueParameter(valueParameter: FirValueParameter, data: Nothing?): CompositeTransformResult { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt index 4591351e1ec..8288ed65f37 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt @@ -66,7 +66,9 @@ open class FirBodyResolveTransformer( if (typeRef is FirResolvedTypeRef) { return typeRef.compose() } - return typeResolverTransformer.transformTypeRef(typeRef, FirCompositeScope(components.createCurrentScopeList())) + return typeResolverTransformer.withFile(context.file) { + transformTypeRef(typeRef, FirCompositeScope(components.createCurrentScopeList())) + } } override fun transformImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef, data: ResolutionMode): CompositeTransformResult { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index fc7b9d97a62..03b1936e178 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -201,6 +201,8 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor }.toTypedArray(), isNullable = false ) + }.also { + session.lookupTracker?.recordTypeResolveAsLookup(it, propertyReferenceAccess.source ?: source, null) } ) } @@ -716,11 +718,17 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor returnStatements.mapNotNull { (it as? FirExpression)?.resultType?.coneType } ) ?: session.builtinTypes.unitType.type } - lambda.replaceReturnTypeRef(lambda.returnTypeRef.resolvedTypeFromPrototype(returnType)) + lambda.replaceReturnTypeRef( + lambda.returnTypeRef.resolvedTypeFromPrototype(returnType).also { + session.lookupTracker?.recordTypeResolveAsLookup(it, lambda.source, null) + } + ) lambda.replaceTypeRef( lambda.constructFunctionalTypeRef( isSuspend = expectedTypeRef.coneTypeSafe()?.isSuspendFunctionType(session) == true - ) + ).also { + session.lookupTracker?.recordTypeResolveAsLookup(it, lambda.source, null) + } ) lambda.addReturn().compose() } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 25634c0996e..1f15e55bd08 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -718,7 +718,11 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform } val typeRef = symbol?.constructType(typeArguments, isNullable = false) if (typeRef != null) { - lhs.replaceTypeRef(buildResolvedTypeRef { type = typeRef }) + lhs.replaceTypeRef( + buildResolvedTypeRef { type = typeRef }.also { + session.lookupTracker?.recordTypeResolveAsLookup(it, getClassCall.source, null) + } + ) typeRef } else { lhs.resultType.coneType diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirImplicitBodyResolve.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirImplicitBodyResolve.kt index caccfb7499b..9aa1ac78749 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirImplicitBodyResolve.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirImplicitBodyResolve.kt @@ -219,13 +219,18 @@ private class ReturnTypeCalculatorWithJump( if (declaration.isIntersectionOverride) { val result = tryCalculateReturnType(declaration.symbol.baseForIntersectionOverride!!.fir) declaration.replaceReturnTypeRef(result) + session.lookupTracker?.recordTypeResolveAsLookup(result, declaration.source, null) return result } runIf(declaration.isSubstitutionOverride) { val overriddenDeclaration = declaration.originalForSubstitutionOverride ?: return@runIf tryCalculateReturnType(overriddenDeclaration) - return FakeOverrideTypeCalculator.Forced.computeReturnType(declaration) + val result = FakeOverrideTypeCalculator.Forced.computeReturnType(declaration) + (declaration.returnTypeRef as? FirResolvedTypeRef)?.let { + session.lookupTracker?.recordTypeResolveAsLookup(it, declaration.source, null) + } + return result } return when (val status = implicitBodyResolveComputationSession.getStatus(declaration.symbol)) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirExplicitSimpleImportingScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirExplicitSimpleImportingScope.kt index 656e1b5c68b..b97347a97b0 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirExplicitSimpleImportingScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirExplicitSimpleImportingScope.kt @@ -19,4 +19,8 @@ class FirExplicitSimpleImportingScope( imports.filterIsInstance() .filter { !it.isAllUnder && it.importedName != null } .groupBy { it.aliasName ?: it.importedName!! } + + override val scopeOwnerLookupNames: List by lazy(LazyThreadSafetyMode.PUBLICATION) { + simpleImports.values.flatMapTo(LinkedHashSet()) { it.map { it.packageFqName.asString() } }.toList() + } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirExplicitStarImportingScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirExplicitStarImportingScope.kt index 042fcac1400..9f2dac50336 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirExplicitStarImportingScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirExplicitStarImportingScope.kt @@ -17,4 +17,8 @@ class FirExplicitStarImportingScope( filter: FirImportingScopeFilter ) : FirAbstractStarImportingScope(session, scopeSession, filter, lookupInFir = true) { override val starImports = imports.filterIsInstance().filter { it.isAllUnder } + + override val scopeOwnerLookupNames: List by lazy(LazyThreadSafetyMode.PUBLICATION) { + starImports.mapTo(LinkedHashSet()) { it.packageFqName.asString() }.toList() + } } \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirNestedClassifierScopeWithSubstitution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirNestedClassifierScopeWithSubstitution.kt index 6b974ee2d83..28a226ed367 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirNestedClassifierScopeWithSubstitution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirNestedClassifierScopeWithSubstitution.kt @@ -43,6 +43,9 @@ private class FirNestedClassifierScopeWithSubstitution( override fun getCallableNames(): Set = scope.getContainingCallableNamesIfPresent() override fun getClassifierNames(): Set = scope.getContainingClassifierNamesIfPresent() + + override val scopeOwnerLookupNames: List + get() = scope.scopeOwnerLookupNames } fun FirScope.wrapNestedClassifierScopeWithSubstitutionForSuperType( diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirOnlyCallablesScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirOnlyCallablesScope.kt index 1e145ffce37..284b780aba6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirOnlyCallablesScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirOnlyCallablesScope.kt @@ -18,4 +18,7 @@ class FirOnlyCallablesScope(val delegate: FirScope) : FirScope() { override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { return delegate.processPropertiesByName(name, processor) } + + override val scopeOwnerLookupNames: List + get() = delegate.scopeOwnerLookupNames } \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirPackageMemberScope.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirPackageMemberScope.kt index b2c72878612..7e17e22c2ed 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirPackageMemberScope.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirPackageMemberScope.kt @@ -10,10 +10,14 @@ import org.jetbrains.kotlin.fir.resolve.symbolProvider import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedForCalls import org.jetbrains.kotlin.fir.scopes.FirScope -import org.jetbrains.kotlin.fir.symbols.impl.* +import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.SmartList class FirPackageMemberScope(val fqName: FqName, val session: FirSession) : FirScope() { private val symbolProvider = session.symbolProvider @@ -56,4 +60,6 @@ class FirPackageMemberScope(val fqName: FqName, val session: FirSession) : FirSc processor(symbol) } } + + override val scopeOwnerLookupNames: List = SmartList(fqName.asString()) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirScopeWithFakeOverrideTypeCalculator.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirScopeWithFakeOverrideTypeCalculator.kt index 62d2e0d49f5..e7990f762e3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirScopeWithFakeOverrideTypeCalculator.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/impl/FirScopeWithFakeOverrideTypeCalculator.kt @@ -80,4 +80,7 @@ class FirScopeWithFakeOverrideTypeCalculator( fakeOverrideTypeCalculator.computeReturnType(declaration) } } + + override val scopeOwnerLookupNames: List + get() = delegate.scopeOwnerLookupNames } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirCompositeScope.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirCompositeScope.kt index 16037f8c429..eba9be8c759 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirCompositeScope.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirCompositeScope.kt @@ -52,4 +52,8 @@ class FirCompositeScope(val scopes: Iterable) : FirScope(), FirContain override fun getClassifierNames(): Set { return scopes.flatMapTo(hashSetOf()) { it.getContainingClassifierNamesIfPresent() } } + + override val scopeOwnerLookupNames: List by lazy(LazyThreadSafetyMode.PUBLICATION) { + scopes.flatMap { it.scopeOwnerLookupNames } + } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt index ca1d6e293c1..a28902171de 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt @@ -34,6 +34,8 @@ abstract class FirScope { } open fun mayContainName(name: Name) = true + + open val scopeOwnerLookupNames: List get() = emptyList() } fun FirScope.getSingleClassifier(name: Name): FirClassifierSymbol<*>? = mutableListOf>().apply { diff --git a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/fir/SessionTestUtils.kt b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/fir/SessionTestUtils.kt index b595f7b76c7..f84b69e681b 100644 --- a/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/fir/SessionTestUtils.kt +++ b/compiler/tests-compiler-utils/tests/org/jetbrains/kotlin/fir/SessionTestUtils.kt @@ -9,6 +9,7 @@ import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl +import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.load.kotlin.PackagePartProvider import org.jetbrains.kotlin.name.Name @@ -17,13 +18,15 @@ fun createSessionForTests( sourceScope: GlobalSearchScope, librariesScope: GlobalSearchScope = GlobalSearchScope.notScope(sourceScope), moduleName: String = "TestModule", - friendPaths: List = emptyList() + friendPaths: List = emptyList(), + lookupTracker: LookupTracker? = null ): FirSession = createSessionForTests( environment.project, sourceScope, librariesScope, moduleName, friendPaths, + lookupTracker, environment::createPackagePartProvider ) @@ -33,6 +36,7 @@ fun createSessionForTests( librariesScope: GlobalSearchScope, moduleName: String = "TestModule", friendPaths: List = emptyList(), + lookupTracker: LookupTracker? = null, packagePartProvider: (GlobalSearchScope) -> PackagePartProvider ): FirSession { return createSessionWithDependencies( @@ -43,6 +47,7 @@ fun createSessionForTests( languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, sourceScope, librariesScope, + lookupTracker, packagePartProvider ) } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/resolver/candidateInfoProviders.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/resolver/candidateInfoProviders.kt index 8f2ce95f48b..753bd15fa9d 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/resolver/candidateInfoProviders.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/resolver/candidateInfoProviders.kt @@ -36,6 +36,7 @@ abstract class AbstractCandidateInfoProvider( ) : CandidateInfoProvider { override fun callInfo(): CallInfo = with(resolutionParameters) { CallInfo( + firFile, // TODO: consider passing more precise info here, if needed callKind = callKind(), name = callableSymbol.callableId.callableName, explicitReceiver = explicitReceiver,