org.jetbrains.kotlin.fir.QualifiedNameResolution.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2019 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.KtSourceElement
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.FirResolvedQualifier
import org.jetbrains.kotlin.fir.expressions.builder.buildResolvedQualifier
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.calls.getSingleVisibleClassifier
import org.jetbrains.kotlin.fir.resolve.createCurrentScopeList
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDeprecated
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
import org.jetbrains.kotlin.fir.resolve.typeForQualifier
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.types.FirTypeProjection
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
const val ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE = "_root_ide_package_"
fun BodyResolveComponents.resolveRootPartOfQualifier(
namedReference: FirSimpleNamedReference,
source: KtSourceElement?,
typeArguments: List,
nonFatalDiagnosticsFromExpression: List?,
): FirResolvedQualifier? {
val name = namedReference.name
if (name.asString() == ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE) {
return buildResolvedQualifier {
this.source = source
packageFqName = FqName.ROOT
this.nonFatalDiagnostics.addAll(nonFatalDiagnosticsFromExpression.orEmpty())
}.apply {
resultType = typeForQualifier(this)
}
}
for (scope in createCurrentScopeList()) {
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 = source
packageFqName = classId.packageFqName
relativeClassFqName = classId.relativeClassName
symbol = it
this.typeArguments.addAll(typeArguments)
this.nonFatalDiagnostics.addAll(
extractNonFatalDiagnostics(
source,
explicitReceiver = null,
it,
extraNotFatalDiagnostics = nonFatalDiagnosticsFromExpression,
session
)
)
}.apply {
resultType = typeForQualifier(this)
}
}
}
return FqName.ROOT.continueQualifierInPackage(
name,
typeArguments,
nonFatalDiagnosticsFromExpression,
this,
source
)
}
fun FirResolvedQualifier.continueQualifier(
namedReference: FirSimpleNamedReference,
source: KtSourceElement?,
typeArguments: List,
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)
?.getSingleVisibleClassifier(session, components, name)
?.takeIf { it is FirClassLikeSymbol<*> }
?.let { nestedClassSymbol ->
buildResolvedQualifier {
this.source = source
packageFqName = [email protected]
relativeClassFqName = [email protected]?.child(name)
symbol = nestedClassSymbol as FirClassLikeSymbol<*>
isFullyQualified = true
this.typeArguments.clear()
this.typeArguments.addAll(typeArguments)
this.typeArguments.addAll([email protected])
this.nonFatalDiagnostics.addAll(nonFatalDiagnosticsFromExpression.orEmpty())
this.nonFatalDiagnostics.addAll(
extractNonFatalDiagnostics(
source,
explicitReceiver = null,
nestedClassSymbol,
extraNotFatalDiagnostics = [email protected],
session
)
)
}.apply {
resultType = components.typeForQualifier(this)
}
}
}
return packageFqName.continueQualifierInPackage(
name,
typeArguments,
nonFatalDiagnosticsFromExpression,
components,
source
)
}
private fun FqName.continueQualifierInPackage(
name: Name,
typeArguments: List,
nonFatalDiagnosticsFromExpression: List?,
components: BodyResolveComponents,
source: KtSourceElement?
): FirResolvedQualifier? {
val childFqName = this.child(name)
if (components.symbolProvider.getPackage(childFqName) != null) {
return buildResolvedQualifier {
this.source = source
packageFqName = childFqName
this.typeArguments.addAll(typeArguments)
this.nonFatalDiagnostics.addAll(nonFatalDiagnosticsFromExpression.orEmpty())
}.apply {
resultType = components.typeForQualifier(this)
}
}
val classId = ClassId.topLevel(childFqName)
val symbol = components.symbolProvider.getClassLikeSymbolByClassId(classId) ?: return null
return buildResolvedQualifier {
this.source = source
packageFqName = this@continueQualifierInPackage
relativeClassFqName = classId.relativeClassName
this.symbol = symbol
this.typeArguments.addAll(typeArguments)
this.nonFatalDiagnostics.addAll(
extractNonFatalDiagnostics(
source,
explicitReceiver = null,
symbol,
extraNotFatalDiagnostics = nonFatalDiagnosticsFromExpression,
components.session
)
)
isFullyQualified = true
}.apply {
resultType = components.typeForQualifier(this)
}
}
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
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy