K2 IC: refactor and optimize lookup tracking

- encapsulate semantic more into helpers
- allow lazy scopes iteration
- simplify reporting code in tower resolver
- fix some inconsistencies and wrong lookups
- remove redundant lookup recordings
- remove lookup scopes for non-star imports

The commit is a refactoring and doesn't change the behaviour of
neither IC nor CRI. Changes in the lookups are mostly due to the
previous obviously wrong lookups (see changed test data).
This commit is contained in:
Ilya Chernikov
2024-02-27 16:44:39 +01:00
committed by Space Team
parent fe4e0e9c2e
commit a823bfd600
29 changed files with 176 additions and 179 deletions
@@ -7,36 +7,74 @@ package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.resolve.calls.AbstractCallInfo
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.utils.SmartList
abstract class FirLookupTrackerComponent : FirSessionComponent {
abstract fun recordLookup(name: Name, inScopes: List<String>, source: KtSourceElement?, fileSource: KtSourceElement?)
abstract fun recordLookup(name: String, inScopes: Iterable<String>, source: KtSourceElement?, fileSource: KtSourceElement?)
abstract fun recordLookup(name: Name, inScope: String, source: KtSourceElement?, fileSource: KtSourceElement?)
abstract fun recordLookup(name: String, inScope: String, source: KtSourceElement?, fileSource: KtSourceElement?)
}
fun FirLookupTrackerComponent.recordCallLookup(callInfo: AbstractCallInfo, inType: ConeKotlinType) {
val classId = inType.classId
if (classId?.isLocal == true) return
val scopes = SmartList(inType.renderForDebugging().replace('/', '.'))
if (classId != null && classId.shortClassName.asString() == "Companion") {
classId.outerClassId?.asString()?.replace('/', '.')?.let {
val classId = inType.classId ?: return
if (classId.isLocal) return
val scopes = SmartList(classId.asFqNameString())
if (classId.shortClassName == DEFAULT_NAME_FOR_COMPANION_OBJECT) {
classId.outerClassId?.asFqNameString()?.also {
scopes.add(it)
}
}
recordLookup(callInfo.name, scopes, callInfo.callSite.source, callInfo.containingFile.source)
recordNameLookup(callInfo.name, scopes, callInfo.callSite.source, callInfo.containingFile.source)
}
fun FirLookupTrackerComponent.recordCallLookup(callInfo: AbstractCallInfo, inScopes: List<String>) {
recordLookup(callInfo.name, inScopes, callInfo.callSite.source, callInfo.containingFile.source)
fun FirLookupTrackerComponent.recordCallLookup(callInfo: AbstractCallInfo, inScopes: Iterable<String>) {
recordNameLookup(callInfo.name, inScopes, callInfo.callSite.source, callInfo.containingFile.source)
}
fun FirLookupTrackerComponent.recordTypeLookup(typeRef: FirTypeRef, inScopes: List<String>, fileSource: KtSourceElement?) {
if (typeRef is FirUserTypeRef) recordLookup(typeRef.qualifier.first().name, inScopes, typeRef.source, fileSource)
fun FirLookupTrackerComponent.recordTypeLookup(typeRef: FirTypeRef, inScopes: Iterable<String>, fileSource: KtSourceElement?) {
if (typeRef is FirUserTypeRef) recordNameLookup(typeRef.qualifier.first().name, inScopes, typeRef.source, fileSource)
}
fun FirLookupTrackerComponent.recordClassLikeLookup(classId: ClassId, source: KtSourceElement?, fileSource: KtSourceElement?) {
if (!classId.isLocal && classId !in StandardClassIds.allBuiltinTypes) {
recordLookup(classId.relativeClassName.asString(), classId.packageFqName.asString(), source, fileSource)
if (classId.shortClassName == DEFAULT_NAME_FOR_COMPANION_OBJECT) {
recordLookup(
classId.outerClassId!!.relativeClassName.asString(),
classId.outerClassId!!.packageFqName.asString(),
source, fileSource
)
}
}
}
fun FirLookupTrackerComponent.recordClassMemberLookup(
memberName: String, classId: ClassId, source: KtSourceElement?, fileSource: KtSourceElement?
) {
recordLookup(memberName, classId.asFqNameString(), source, fileSource)
}
fun FirLookupTrackerComponent.recordFqNameLookup(fqName: FqName, source: KtSourceElement?, fileSource: KtSourceElement?) {
recordLookup(fqName.shortName().asString(), fqName.parent().asString(), source, fileSource)
}
fun FirLookupTrackerComponent.recordNameLookup(
name: Name, inScopes: Iterable<String>, source: KtSourceElement?, fileSource: KtSourceElement?
) {
recordLookup(name.asString(), inScopes, source, fileSource)
}
fun FirLookupTrackerComponent.recordNameLookup(name: Name, inScope: String, source: KtSourceElement?, fileSource: KtSourceElement?) {
recordLookup(name.asString(), inScope, source, fileSource)
}
fun FirLookupTrackerComponent.recordTypeResolveAsLookup(typeRef: FirTypeRef, source: KtSourceElement?, fileSource: KtSourceElement?) {
@@ -44,23 +82,26 @@ fun FirLookupTrackerComponent.recordTypeResolveAsLookup(typeRef: FirTypeRef, sou
recordTypeResolveAsLookup(typeRef.type, source, fileSource)
}
// TODO: review all places that record resolved type as lookup and consider minimize the number of them; see #KT-66366
fun FirLookupTrackerComponent.recordTypeResolveAsLookup(type: ConeKotlinType?, source: KtSourceElement?, fileSource: KtSourceElement?) {
if (type == null) return
if (source == null && fileSource == null) return // TODO: investigate all cases
if (type is ConeErrorType) return // TODO: investigate whether some cases should be recorded, e.g. unresolved
type.classId?.let {
if (!it.isLocal && it !in StandardClassIds.allBuiltinTypes) {
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.classId?.let { classId ->
recordClassLikeLookup(classId, source, fileSource)
}
type.typeArguments.forEach {
if (it is ConeKotlinType) recordTypeResolveAsLookup(it, source, fileSource)
}
}
fun FirLookupTrackerComponent.recordCallableCandidateAsLookup(
callableSymbol: FirCallableSymbol<*>, source: KtSourceElement?, fileSource: KtSourceElement?
) {
if (!callableSymbol.callableId.isLocal && callableSymbol !is FirConstructorSymbol) {
recordTypeResolveAsLookup(callableSymbol.fir.returnTypeRef, source, fileSource)
recordFqNameLookup(callableSymbol.callableId.asSingleFqName(), source, fileSource)
}
}
val FirSession.lookupTracker: FirLookupTrackerComponent? by FirSession.nullableSessionComponentAccessor()