From 965d8d2fd5682b5bad7c5b297cee559833b5ab65 Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Thu, 11 Jan 2024 14:31:56 +0200 Subject: [PATCH] [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. --- .../checkers/declaration/FirImportsChecker.kt | 40 +++++++++---------- .../fir/declarations/ImplicitReceiverUtils.kt | 4 ++ .../declarations/utils/FirDeclarationUtil.kt | 7 ++++ 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt index d4ed890f61a..aaf606705f5 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt @@ -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 diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt index 5cb876f8ecd..aa3bc07fbb3 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/declarations/ImplicitReceiverUtils.kt @@ -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) diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirDeclarationUtil.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirDeclarationUtil.kt index 50395cba089..a26dd1471f1 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirDeclarationUtil.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/FirDeclarationUtil.kt @@ -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