org.jetbrains.kotlin.fir.resolve.QualifiedNameResolution.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* Copyright 2010-2024 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.resolve
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass
import org.jetbrains.kotlin.fir.declarations.getDeprecationForCallSite
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.expressions.builder.buildResolvedQualifier
import org.jetbrains.kotlin.fir.lookupTracker
import org.jetbrains.kotlin.fir.recordNameLookup
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.resolve.calls.getSingleVisibleClassifier
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDeprecated
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeNestedClassAccessedViaInstanceReference
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.visibilityChecker
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE
fun BodyResolveComponents.resolveRootPartOfQualifier(
namedReference: FirSimpleNamedReference,
qualifiedAccess: FirQualifiedAccessExpression,
nonFatalDiagnosticsFromExpression: List?,
): FirResolvedQualifier? {
val name = namedReference.name
if (name.asString() == ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE) {
return buildResolvedQualifier {
this.source = qualifiedAccess.source
packageFqName = FqName.ROOT
this.nonFatalDiagnostics.addAll(nonFatalDiagnosticsFromExpression.orEmpty())
annotations += qualifiedAccess.annotations
}.apply {
setTypeOfQualifier(this@resolveRootPartOfQualifier)
}
}
val scopes = createCurrentScopeList()
session.lookupTracker?.recordNameLookup(
name,
scopes.asSequence().flatMap { it.scopeOwnerLookupNames }.asIterable(),
qualifiedAccess.source,
file.source
)
for (scope in scopes) {
scope.getSingleVisibleClassifier(session, this, name)?.let {
val klass = (it as? FirClassLikeSymbol<*>)?.fullyExpandedClass(session)
?: return@let
val isVisible = session.visibilityChecker.isClassLikeVisible(
klass.fir,
session,
file,
containingDeclarations,
)
if (!isVisible) {
return@let
}
val classId = it.classId
return buildResolvedQualifier {
this.source = qualifiedAccess.source
packageFqName = classId.packageFqName
relativeClassFqName = classId.relativeClassName
symbol = it
this.typeArguments.addAll(qualifiedAccess.typeArguments)
this.nonFatalDiagnostics.addAll(
extractNonFatalDiagnostics(
qualifiedAccess.source,
explicitReceiver = null,
it,
extraNotFatalDiagnostics = nonFatalDiagnosticsFromExpression,
session
)
)
annotations += qualifiedAccess.annotations
}.apply {
setTypeOfQualifier(this@resolveRootPartOfQualifier)
}
}
}
return FqName.ROOT.continueQualifierInPackage(
name,
qualifiedAccess,
nonFatalDiagnosticsFromExpression,
this
)
}
fun FirResolvedQualifier.continueQualifier(
namedReference: FirSimpleNamedReference,
qualifiedAccess: FirQualifiedAccessExpression,
nonFatalDiagnosticsFromExpression: List?,
session: FirSession,
components: BodyResolveComponents,
): FirResolvedQualifier? {
val name = namedReference.name
symbol?.let { outerClassSymbol ->
val firClass = outerClassSymbol.fir
if (firClass !is FirClass) return null
return firClass.scopeProvider.getNestedClassifierScope(firClass, components.session, components.scopeSession)
?.also {
session.lookupTracker?.recordNameLookup(name, it.scopeOwnerLookupNames, qualifiedAccess.source, components.file.source)
}
?.getSingleVisibleClassifier(session, components, name)
?.takeIf { it is FirClassLikeSymbol<*> }
?.let { nestedClassSymbol ->
buildResolvedQualifier {
this.source = qualifiedAccess.source
packageFqName = [email protected]
relativeClassFqName = [email protected]?.child(name)
symbol = nestedClassSymbol as FirClassLikeSymbol<*>
isFullyQualified = true
this.typeArguments.clear()
this.typeArguments.addAll(qualifiedAccess.typeArguments)
this.typeArguments.addAll([email protected])
this.nonFatalDiagnostics.addAll(nonFatalDiagnosticsFromExpression.orEmpty())
this.nonFatalDiagnostics.addAll(
extractNonFatalDiagnostics(
qualifiedAccess.source,
explicitReceiver = null,
nestedClassSymbol,
extraNotFatalDiagnostics = [email protected],
session
)
)
}.apply {
setTypeOfQualifier(components)
}
}
}
return packageFqName.continueQualifierInPackage(
name,
qualifiedAccess,
nonFatalDiagnosticsFromExpression,
components
)
}
private fun FqName.continueQualifierInPackage(
name: Name,
qualifiedAccess: FirQualifiedAccessExpression,
nonFatalDiagnosticsFromExpression: List?,
components: BodyResolveComponents
): FirResolvedQualifier? {
val childFqName = this.child(name)
if (components.symbolProvider.getPackage(childFqName) != null) {
return buildResolvedQualifier {
this.source = qualifiedAccess.source
packageFqName = childFqName
this.typeArguments.addAll(qualifiedAccess.typeArguments)
this.nonFatalDiagnostics.addAll(nonFatalDiagnosticsFromExpression.orEmpty())
annotations += qualifiedAccess.annotations
}.apply {
setTypeOfQualifier(components)
}
}
val classId = ClassId.topLevel(childFqName)
val symbol = components.symbolProvider.getClassLikeSymbolByClassId(classId) ?: return null
return buildResolvedQualifier {
this.source = qualifiedAccess.source
packageFqName = this@continueQualifierInPackage
relativeClassFqName = classId.relativeClassName
this.symbol = symbol
this.typeArguments.addAll(qualifiedAccess.typeArguments)
this.nonFatalDiagnostics.addAll(
extractNonFatalDiagnostics(
qualifiedAccess.source,
explicitReceiver = null,
symbol,
extraNotFatalDiagnostics = nonFatalDiagnosticsFromExpression,
components.session
)
)
isFullyQualified = true
annotations += qualifiedAccess.annotations
}.apply {
setTypeOfQualifier(components)
}
}
internal fun extractNestedClassAccessDiagnostic(
source: KtSourceElement?,
explicitReceiver: FirExpression?,
symbol: FirClassLikeSymbol<*>
): ConeDiagnostic? {
if ((explicitReceiver as? FirResolvedQualifier)?.typeArguments?.isNotEmpty() == true)
return ConeNestedClassAccessedViaInstanceReference(source!!, symbol)
return null
}
internal fun extractNonFatalDiagnostics(
source: KtSourceElement?,
explicitReceiver: FirExpression?,
symbol: FirClassLikeSymbol<*>,
extraNotFatalDiagnostics: List?,
session: FirSession,
): List {
val prevDiagnostics = (explicitReceiver as? FirResolvedQualifier)?.nonFatalDiagnostics ?: emptyList()
var result: MutableList? = null
val deprecation = symbol.getDeprecationForCallSite(session)
if (deprecation != null) {
result = mutableListOf()
result.addAll(prevDiagnostics)
result.add(ConeDeprecated(source, symbol, deprecation))
}
if (extraNotFatalDiagnostics != null && extraNotFatalDiagnostics.isNotEmpty()) {
if (result == null) {
result = mutableListOf()
result.addAll(prevDiagnostics)
}
result.addAll(extraNotFatalDiagnostics)
}
return result?.toList() ?: prevDiagnostics
}