FIR: Implement lookup tracking

This commit is contained in:
Ilya Chernikov
2020-12-01 10:38:27 +01:00
parent 7d29ae7cce
commit f8d50d585d
41 changed files with 423 additions and 97 deletions
@@ -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
}
@@ -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
}
@@ -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)
}
}
}
}
@@ -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<FirSourceElement, String>()
override fun recordLookup(name: Name, inScopes: List<String>, 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)
}
}
@@ -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)
)
}
}
/*
@@ -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)
@@ -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>) -> ModuleInfo,
@@ -84,6 +90,7 @@ private inline fun createSessionWithDependencies(
sourceScope,
project,
languageVersionSettings = languageVersionSettings,
lookupTracker = lookupTracker,
init = sessionConfigurator
)
}
@@ -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
}
@@ -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
@@ -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<String>
get() = declaredMemberScope.scopeOwnerLookupNames
}
@@ -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,
@@ -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<String>, 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<String>) {
recordLookup(callInfo.name, inScopes, callInfo.callSite.source, callInfo.containingFile.source)
}
fun FirLookupTrackerComponent.recordTypeLookup(typeRef: FirTypeRef, inScopes: List<String>, 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()
@@ -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? {
@@ -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("<SAM-CONSTRUCTOR>")
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)
}
@@ -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,
@@ -144,6 +144,7 @@ internal object CheckArguments : CheckerStage() {
for (argument in callInfo.arguments) {
val parameter = argumentMapping[argument]
candidate.resolveArgument(
callInfo,
argument,
parameter,
isReceiver = false,
@@ -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
@@ -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}")
@@ -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<AbstractFirBasedSymbol<*>>()
}
abstract fun processFunctionsByName(name: Name, processor: TowerScopeLevelProcessor<FirFunctionSymbol<*>>): ProcessResult
abstract fun processFunctionsByName(info: CallInfo, processor: TowerScopeLevelProcessor<FirFunctionSymbol<*>>): ProcessResult
abstract fun processPropertiesByName(name: Name, processor: TowerScopeLevelProcessor<FirVariableSymbol<*>>): ProcessResult
abstract fun processPropertiesByName(info: CallInfo, processor: TowerScopeLevelProcessor<FirVariableSymbol<*>>): ProcessResult
abstract fun processObjectsByName(name: Name, processor: TowerScopeLevelProcessor<AbstractFirBasedSymbol<*>>): ProcessResult
abstract fun processObjectsByName(info: CallInfo, processor: TowerScopeLevelProcessor<AbstractFirBasedSymbol<*>>): ProcessResult
interface TowerScopeLevelProcessor<in T : AbstractFirBasedSymbol<*>> {
fun consumeCandidate(
@@ -131,41 +125,50 @@ class MemberScopeTowerLevel(
}
override fun processFunctionsByName(
name: Name,
info: CallInfo,
processor: TowerScopeLevelProcessor<FirFunctionSymbol<*>>
): 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<FirVariableSymbol<*>>
): 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<AbstractFirBasedSymbol<*>>
): 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<FirLookupTrackerComponent?, SmartList<String>, CallInfo>) -> Unit
) {
lookupTracker?.recordCallLookup(info, dispatchReceiverValue.type)
val lookupScopes = SmartList<String>()
body(Triple(lookupTracker, lookupScopes, info))
if (lookupScopes.isNotEmpty()) {
lookupTracker?.recordCallLookup(info, lookupScopes)
}
}
private fun Triple<FirLookupTrackerComponent?, SmartList<String>, 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<FirFunctionSymbol<*>>
): 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<FirVariableSymbol<*>>
): 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<AbstractFirBasedSymbol<*>>
): ProcessResult {
var empty = true
scope.processClassifiersByName(name) {
session.lookupTracker?.recordCallLookup(info, scope.scopeOwnerLookupNames)
scope.processClassifiersByName(info.name) {
empty = false
processor.consumeCandidate(
it, dispatchReceiverValue = null,
@@ -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")
@@ -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)
}
}
}
@@ -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<FirStatement> {
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<ConeKotlinType>()
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) {
@@ -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<FirFile> {
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<FirImport> {
@@ -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)
}
@@ -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 <R> 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<FirResolvedTypeRef> {
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<FirResolvedTypeRef> {
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 {
@@ -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<FirTypeRef>
): List<FirTypeRef> {
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
@@ -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,
@@ -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<FirFile> {
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<FirResolvedTypeRef> {
return typeRef.transform(typeResolverTransformer, towerScope)
return typeResolverTransformer.withFile(currentFile) { typeRef.transform(typeResolverTransformer, towerScope) }
}
override fun transformValueParameter(valueParameter: FirValueParameter, data: Nothing?): CompositeTransformResult<FirStatement> {
@@ -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<FirTypeRef> {
@@ -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<ConeKotlinType>()?.isSuspendFunctionType(session) == true
)
).also {
session.lookupTracker?.recordTypeResolveAsLookup(it, lambda.source, null)
}
)
lambda.addReturn().compose()
}
@@ -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
@@ -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)) {
@@ -19,4 +19,8 @@ class FirExplicitSimpleImportingScope(
imports.filterIsInstance<FirResolvedImport>()
.filter { !it.isAllUnder && it.importedName != null }
.groupBy { it.aliasName ?: it.importedName!! }
override val scopeOwnerLookupNames: List<String> by lazy(LazyThreadSafetyMode.PUBLICATION) {
simpleImports.values.flatMapTo(LinkedHashSet()) { it.map { it.packageFqName.asString() } }.toList()
}
}
@@ -17,4 +17,8 @@ class FirExplicitStarImportingScope(
filter: FirImportingScopeFilter
) : FirAbstractStarImportingScope(session, scopeSession, filter, lookupInFir = true) {
override val starImports = imports.filterIsInstance<FirResolvedImport>().filter { it.isAllUnder }
override val scopeOwnerLookupNames: List<String> by lazy(LazyThreadSafetyMode.PUBLICATION) {
starImports.mapTo(LinkedHashSet()) { it.packageFqName.asString() }.toList()
}
}
@@ -43,6 +43,9 @@ private class FirNestedClassifierScopeWithSubstitution(
override fun getCallableNames(): Set<Name> = scope.getContainingCallableNamesIfPresent()
override fun getClassifierNames(): Set<Name> = scope.getContainingClassifierNamesIfPresent()
override val scopeOwnerLookupNames: List<String>
get() = scope.scopeOwnerLookupNames
}
fun FirScope.wrapNestedClassifierScopeWithSubstitutionForSuperType(
@@ -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<String>
get() = delegate.scopeOwnerLookupNames
}
@@ -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<String> = SmartList(fqName.asString())
}
@@ -80,4 +80,7 @@ class FirScopeWithFakeOverrideTypeCalculator(
fakeOverrideTypeCalculator.computeReturnType(declaration)
}
}
override val scopeOwnerLookupNames: List<String>
get() = delegate.scopeOwnerLookupNames
}
@@ -52,4 +52,8 @@ class FirCompositeScope(val scopes: Iterable<FirScope>) : FirScope(), FirContain
override fun getClassifierNames(): Set<Name> {
return scopes.flatMapTo(hashSetOf()) { it.getContainingClassifierNamesIfPresent() }
}
override val scopeOwnerLookupNames: List<String> by lazy(LazyThreadSafetyMode.PUBLICATION) {
scopes.flatMap { it.scopeOwnerLookupNames }
}
}
@@ -34,6 +34,8 @@ abstract class FirScope {
}
open fun mayContainName(name: Name) = true
open val scopeOwnerLookupNames: List<String> get() = emptyList()
}
fun FirScope.getSingleClassifier(name: Name): FirClassifierSymbol<*>? = mutableListOf<FirClassifierSymbol<*>>().apply {
@@ -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<String> = emptyList()
friendPaths: List<String> = 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<String> = emptyList(),
lookupTracker: LookupTracker? = null,
packagePartProvider: (GlobalSearchScope) -> PackagePartProvider
): FirSession {
return createSessionWithDependencies(
@@ -43,6 +47,7 @@ fun createSessionForTests(
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
sourceScope,
librariesScope,
lookupTracker,
packagePartProvider
)
}
@@ -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,