[FIR] Abstract away symbol.fir in FirImportsChecker

It's easier to reason about correctness of
`symbol.fir` when it's localized in small
helper functions.
This commit is contained in:
Nikolay Lunyak
2024-01-11 14:31:56 +02:00
committed by Space Team
parent 52d712e110
commit 965d8d2fd5
3 changed files with 29 additions and 22 deletions
@@ -19,10 +19,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.toInvisibleReferenceDiagnos
import org.jetbrains.kotlin.fir.analysis.getLastImportedFqNameSegmentSource
import org.jetbrains.kotlin.fir.analysis.getSourceForImportSegment
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass
import org.jetbrains.kotlin.fir.declarations.utils.isOperator
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.getContainingFile
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
@@ -31,7 +28,7 @@ import org.jetbrains.kotlin.fir.resolve.transformers.PackageResolutionResult
import org.jetbrains.kotlin.fir.resolve.transformers.resolveToPackageOrClass
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.visibilityChecker
import org.jetbrains.kotlin.name.ClassId
@@ -39,7 +36,6 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.utils.addToStdlib.filterIsInstanceWithChecker
@OptIn(SymbolInternals::class)
object FirImportsChecker : FirFileChecker() {
override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) {
declaration.imports.forEach { import ->
@@ -83,7 +79,7 @@ object FirImportsChecker : FirFileChecker() {
if (classSymbol != null && classSymbol.classKind.isObject) {
reporter.reportOn(import.source, FirErrors.CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON, classSymbol.classId.shortClassName, context)
}
if (!classLike.fir.isVisible(context)) {
if (!classLike.isVisible(context)) {
val source = import.getLastImportedFqNameSegmentSource() ?: error("`${import.source}` does not contain `$fqName`")
reporter.report(classLike.toInvisibleReferenceDiagnostic(source), context)
}
@@ -101,7 +97,7 @@ object FirImportsChecker : FirFileChecker() {
val parentClassSymbol = parentClassId.resolveToClass(context) ?: return
fun reportInvisibleParentClasses(classSymbol: FirRegularClassSymbol, depth: Int) {
if (!classSymbol.fir.isVisible(context)) {
if (!classSymbol.isVisible(context)) {
val source = import.getSourceForImportSegment(indexFromLast = depth)
reporter.report(classSymbol.toInvisibleReferenceDiagnostic(source), context)
}
@@ -130,12 +126,12 @@ object FirImportsChecker : FirFileChecker() {
return
}
var resolvedDeclaration: FirMemberDeclaration? = null
var resolvedDeclaration: FirBasedSymbol<*>? = null
ClassId.topLevel(importedFqName).resolveToClass(context)?.let {
resolvedDeclaration = it.fir
resolvedDeclaration = it
if (it.fir.isVisible(context)) {
if (it.isVisible(context)) {
return
}
}
@@ -145,18 +141,18 @@ object FirImportsChecker : FirFileChecker() {
val topLevelCallableSymbol = symbolProvider.getTopLevelCallableSymbols(importedFqName.parent(), importedName)
for (it in topLevelCallableSymbol) {
if (it.fir.isVisible(context)) {
if (it.isVisible(context)) {
return
}
if (resolvedDeclaration == null) {
resolvedDeclaration = it.fir
resolvedDeclaration = it
}
}
resolvedDeclaration?.let {
val source = import.getSourceForImportSegment(0) ?: import.source
reporter.report(it.symbol.toInvisibleReferenceDiagnostic(source), context)
reporter.report(it.toInvisibleReferenceDiagnostic(source), context)
return
}
@@ -167,18 +163,18 @@ object FirImportsChecker : FirFileChecker() {
}
}
private fun FirMemberDeclaration.isVisible(context: CheckerContext): Boolean {
private fun FirBasedSymbol<*>.isVisible(context: CheckerContext): Boolean {
val useSiteFile = context.containingFile ?: return false
val visibility = visibility
val fir = asMemberDeclarationResolvedTo(FirResolvePhase.STATUS) ?: return false
val visibility = fir.visibility
if (visibility != Visibilities.Unknown && !visibility.mustCheckInImports()) return true
if (visibility == Visibilities.Private || visibility == Visibilities.PrivateToThis) {
return useSiteFile == context.session.firProvider.getContainingFile(symbol)
return useSiteFile == context.session.firProvider.getContainingFile(this)
}
return context.session.visibilityChecker.isVisible(
this,
fir,
context.session,
useSiteFile,
emptyList(),
@@ -283,7 +279,7 @@ object FirImportsChecker : FirFileChecker() {
// Next, we try static scope, which can provide static (Java) members from super classes. Note that it's not available
// for pure Kotlin classes.
fir.staticScope(context.sessionHolder),
staticScope(context.sessionHolder),
// Finally, we fall back to unsubstitutedScope to catch all
unsubstitutedScope(context)
@@ -303,13 +299,13 @@ object FirImportsChecker : FirFileChecker() {
for (scope in scopes) {
scope.processFunctionsByName(name) { sym ->
if (sym.fir.isVisible(context) && isApplicable(sym)) found = true
if (sym.isVisible(context) && isApplicable(sym)) found = true
symbol = sym
}
if (found) return ImportStatus.OK
scope.processPropertiesByName(name) { sym ->
if (sym.fir.isVisible(context) && isApplicable(sym)) found = true
if (sym.isVisible(context) && isApplicable(sym)) found = true
symbol = sym
}
if (found) return ImportStatus.OK
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
import org.jetbrains.kotlin.fir.scopes.impl.wrapNestedClassifierScopeWithSubstitutionForSuperType
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeErrorType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
@@ -303,6 +304,9 @@ fun FirScope.asTowerDataElement(isLocal: Boolean): FirTowerDataElement =
fun FirScope.asTowerDataElementForStaticScope(staticScopeOwnerSymbol: FirRegularClassSymbol?): FirTowerDataElement =
FirTowerDataElement(scope = this, implicitReceiver = null, isLocal = false, staticScopeOwnerSymbol = staticScopeOwnerSymbol)
fun FirClassSymbol<*>.staticScope(sessionHolder: SessionHolder): FirContainingNamesAwareScope? =
fir.staticScope(sessionHolder)
fun FirClass.staticScope(sessionHolder: SessionHolder): FirContainingNamesAwareScope? =
staticScope(sessionHolder.session, sessionHolder.scopeSession)
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.declarations.utils
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.fir.types.isNullableAny
@@ -59,6 +60,12 @@ val FirMemberDeclaration.nameOrSpecialName: Name
is FirClassLikeDeclaration -> classId.shortClassName
}
fun FirBasedSymbol<*>.asMemberDeclarationResolvedTo(phase: FirResolvePhase): FirMemberDeclaration? {
return (fir as? FirMemberDeclaration)?.also {
lazyResolveToPhase(phase)
}
}
val FirNamedFunctionSymbol.isMethodOfAny: Boolean
get() {
if (receiverParameter != null) return false